튜토리얼

Stateless MCP란? 2026 무상태 아키텍처, JSON-RPC, Remote Server 완전 해설

2026-07-28 MCP는 프로토콜 계층을 무상태로: 각 JSON-RPC 요청이 버전과 capabilities를 스스로 담고, Remote Server는 일반 HTTP 로드밸런서 뒤에서 동작합니다. 도구 인자는 여전히 JSON — 운영에서도 로컬 검증이 필요합니다.

Model Context Protocol(MCP)는 AI 클라이언트가 도구·리소스·프롬프트를 발견하고 모델 컨텍스트에 연결하게 합니다. 2026년 가장 큰 아키텍처 변화는 MCP를 「먼저 handshake, Session ID를 붙이는 양방향 상태ful 프로토콜」에서 「각 요청이 자기서술·독립 라우팅 가능한 무상태 JSON-RPC」로 바꾸는 것입니다. Claude Desktop, Cursor, 자체 Agent로 Remote MCP Server를 부르고 있다면 배포·스케일·게이트웨이 레이트 제한에 직접 영향합니다. 읽고 나면 프로토콜 무상태와 애플리케이션 상태ful을 가르고, 도구 인자 JSON은 여전히 로컬 검증이 필요함을 알게 됩니다.

MCP와 Stateless가 푸는 문제

MCP가 푸는 것은 「모델이 외부 능력을 안전하고 발견 가능하게 호출하는 방법」입니다. 클라이언트(Claude, ChatGPT, IDE Agent)는 도구 목록·리소스 읽기·프롬프트 템플릿을 위한 표준이 필요하고, 서버(GitHub, DB, 내부 API의 MCP 어댑터)는 클라이언트마다 커스텀 플러그인 없이 능력을 노출하는 표준이 필요합니다.

초기 MCP는 전송 계층에 세션을 남겼습니다. 클라이언트는 먼저 initialize를 보내고, 서버가 capabilities를 돌려주며, 이후 요청도 Mcp-Session-Id를 붙여 트래픽을 한 인스턴스나 공유 Session Store에 고정합니다. 로컬 stdio에는 문제없습니다. Remote Server를 수평 확장하고 Cloud Run/Lambda에서 돌리거나 API 게이트웨이로 도구별 레이트 제한을 하면 세션 스티키니스가 병목이 됩니다.

2026-07-28 사양(Release Candidate)은 프로토콜 계층을 무상태로 바꿉니다. 임의 요청 처리에 필요한 메타데이터는 요청 자체에 있고, 일반 round-robin 로드밸런서 뒤의 어떤 인스턴스도 받을 수 있습니다. 공식 설명: MCP 2026-07-28 사양 발표 및 Statelessness 장.

상태ful 시대가 남긴 것

구 흐름에서는 Streamable HTTP 클라이언트가 보통 handshake를 먼저 거칩니다:

  1. 보내기: initialize — 프로토콜 버전과 client/server capabilities 교환.
  2. 받기: initialized 알림을 받고 서버가 Mcp-Session-Id 응답 헤더를 내림.
  3. 그다음 tools/call 및 resources/read는 같은 Session ID가 필요합니다. 없으면 게이트웨이나 인스턴스 메모리에 컨텍스트가 없습니다.

운영의 전형적 비용: 로드밸런서 sticky session, 레플리카 간 Redis Session, Serverless 콜드 스타트 후 Session 만료. GitHub MCP 같은 인기 Server는 Redis 계층이 필요했습니다. Google은 Scaling AI Agent Infrastructure에서 이 변경을 「MCP 공개 이후 최대 사양 변경」이라 부릅니다 — 핵심은 전송 계층 세션 관리 제거입니다.

관점 상태ful 시대(2025 이전) 무상태 핵심(2026-07-28)
Handshake initialize / initialized필수 폐지; 선택server/discover
세션 식별자 Mcp-Session-Id 응답 헤더 제거(SEP-2567)
Capability 협상 연결 수립 시 한 번 교환 각 요청의 _meta가 담음
수평 확장 스티키 라우팅 + 공유 Session Store 일반 round-robin이면 충분

2026-07-28 무상태 핵심

사양의 「무상태」 정의는 엄격합니다. 서버는 해서는 안 됩니다 같은 연결의 이전 요청으로 프로토콜 버전·클라이언트 identity·capabilities를 추론하는 것. 각 요청은 _meta에 이 정보를 담아야 합니다. 여러 작업·스레드·대화 요청이 같은 전송 위에서 교차할 수 있습니다. 연결이나 stdio 프로세스 자체는 아닙니다 세션 경계.

클라이언트는 각 요청의 params._meta(또는 동등 위치)에:

  • io.modelcontextprotocol/protocolVersion — 필수. 예: 2026-07-28.
  • io.modelcontextprotocol/clientCapabilities — 필수. 빈 객체는 선택 capability 미지원.
  • io.modelcontextprotocol/clientInfo — 로그·디버깅용 권장(서버는 보안 결정에 쓰지 않음).

서버 capability를 먼저 알려면 새 server/discover RPC를 호출할 수 있지만 필수는 아닙니다 — 어떤 요청이든 임의 인스턴스의 첫 요청이 될 수 있습니다. 서버는 tools/list 같은 응답에 ttlMs를 붙여 TTL 안에 도구 목록을 캐시하게 할 수 있습니다.

여러 도구 호출에 걸친 업무 상태(장바구니, 브라우저 세션, 티켓 초안)는 전송 Session에 숨기지 마세요. 일반 HTTP API처럼: 도구가 명시적 handle(basket_id 및 draft_id)을 반환하고, 모델이 이후 tools/call 인자 JSON으로 돌려줍니다. 모델이 handle을 볼 수 있어 블랙박스 Session보다 디버깅이 쉽습니다.

MCP에서 JSON-RPC가 도는 방식

MCP 메시지 계층은 항상 JSON-RPC 2.0: 각 요청에 jsonrpc 및 id 및 method 및 params; 응답은 result 또는 error; 알림에는 id. Apple Agent 글의 「도구명 + 인자 객체」와 같은 형태 — MCP는 메서드명을 tools/call로 표준화하고 params에 name 및 arguments.

전형적인 무상태 tools/call는 이렇습니다(HTTP 헤더는 다음 절):

POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: searchInvoices

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "searchInvoices",
    "arguments": {
      "status": "unpaid",
      "limit": 10
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {},
      "io.modelcontextprotocol/clientInfo": {
        "name": "jsonvue-demo",
        "version": "1.0.0"
      }
    }
  }
}

성공 시 result에는 보통 content 배열의 도구 출력(대개 type: text JSON 문자열 또는 구조화 블록). 실패 시 JSON-RPC error에 code 및 message. Streamable HTTP에서 HTTP 헤더와 body method/name이 다르면 사양은 -32020급 header mismatch 오류를 요구합니다.

JSONVue 독자가 볼 것은 arguments: 외부 Agent는 숫자를 문자열로 보내거나 필수 키를 빼기 쉽습니다. MCP 무상태화는 하지 않습니다 업무 JSON 검증 — Structured Output이 모델 출력, MCP가 도구 호출을 담당하는 분업과 같습니다. 사이트 Apple AI Agent와 JSON에서 설명: 같은 도메인 함수가 App Intent, Foundation Models Tool, MCP를 서비스하고 차이는 어댑터 계층뿐.

Remote Server와 Streamable HTTP

Remote MCP Server는 클라이언트가 HTTPS로 접근하는 MCP 엔드포인트이며 로컬 stdio 자식 프로세스가 아닙니다. Streamable HTTP가 현재 Remote 배포의 주 전송: 단일 POST로 RPC 완료. 긴 작업은 열린 알림 스트림을 반환할 수 있지만 상태는 연결 Session이 아니라 해당 요청에 scoped됩니다.

2026-07-28부터 Streamable HTTP 요청은 반드시 body와 일치하는 세 헤더(SEP-2243)를 포함해 게이트웨이·WAF·레이트 리미터가 JSON body를 parse하지 않고 라우팅:

  • MCP-Protocol-Version — _meta의 protocolVersion과 일치해야 함. 아니면 400.
  • Mcp-Method — JSON-RPC method에 대응. 예: tools/call.
  • Mcp-Name — 도구·프롬프트·리소스 이름. 예: searchInvoices.

배포가 단순해집니다: 같은 Docker 이미지 다중 복제 + 일반 ALB/nginx round-robin. Cloud Run/Cloud Functions는 MCP 전용 Redis Session 불필요. Mcp-Name별 QPS 쿼터는 body 심층 검사보다 저렴. GitHub MCP Server 등 운영 서비스가 무상태 사양으로 업그레이드 중.

stdio 로컬 Server도 가능. 다만 같은 stdio 프로세스에서 무관 요청이 교차할 수 있고 Server는 프로세스 identity를 세션 ID로 삼으면 안 됩니다. 로컬 개발과 클라우드 Remote는 같은 도구 구현을 공유하고 전송 어댑터만 다릅니다.

애플리케이션은 여전히 상태ful일 수 있다

「프로토콜 무상태」≠「업무 무상태」. 장바구니, 다단계 승인, 브라우저 자동화의 미완성 폼은 여전히 상태ful일 수 있고 그래야 합니다 — 상태는 명시적이어야 하며 Mcp-Session-Id에 묶이면 안 됩니다.

권장 패턴:

  1. 첫 도구 호출이 리소스 생성, 반환: { "draftId": "dr_8k2", ... }.
  2. 도구 설명에: 이후 단계는 draftId.
  3. 서버는 draftId로 DB/캐시 조회. 없으면 JSON-RPC 업무 오류. 불가사의 Session 404가 아님.

긴 작업은 Tasks 등 확장으로 MRTR(Multi-Request Task Routing): 도구가 먼저 status: input_required를 반환하고, 클라이언트가 사용자 추가 답을 이후 요청의 _meta에 붙여 계속. 여전히 무상태 request/response. 응답이 여러 라운드일 수 있음.

Structured Output과의 관계

MCP와 Structured Output은 다른 층의 문제를 풀지만 JSON 형태는 같은 Agent 파이프라인에서 만납니다:

층 메커니즘 무엇을 제약하는가
모델 출력 Structured Output + JSON Schema 최종 답변 또는 추출 결과의 필드와 타입
도구 호출 MCP tools/call + 도구 inputSchema Server로 전달되는 arguments 객체
업무 API REST / GraphQL JSON body Server 내부 또는 하류 HTTP의 실제 페이로드

모범 사례: 필드 표 하나를 유지하고 MCP 도구 inputSchema, REST OpenAPI, 모델용 Structured Output Schema 생성. 사이트 Gemini API JSON 출력 가이드가 모델 측; Gemini Structured Output 튜토리얼에 클라우드 예제. MCP 무상태화 후 도구 목록 캐시 가능 — Schema 버전 변경 시 도구명/프로토콜 버전 bump로 stale 캐시가 잘못된 형태를 arguments.

운영에서 JSON을 어떻게 볼까

Remote MCP Server 연동 시 JSON 세 개를 나란히: 클라이언트 tools/call 인자, 도메인 서비스 HTTP body, 모델에 반환되는 result.content. 형태 불일치면 거의 어댑터 계층 문제. 「모델이 멍청해서」가 아님.

브라우저에서 한번: JSON 포맷로 parse 확인; JSON 검증로 후행 쉼표·타입 오류; JSON Schema로 도구 inputSchema와 API body 공통 필드; JSON Diff「모델 arguments」와 「실제 HTTP 요청 body」 비교. 고정 fixture 세 개: mcp-args.valid.json 및 http-body.valid.json 및 mcp-tool-error.json — CI에서 같은 Schema.

자주 묻는 질문 FAQ

무상태 MCP에 WebSocket 장연결 필요?

Remote는 주로 Streamable HTTP: 단일 POST로 RPC. 긴 알림 스트림도 요청 단위. 구식 「handshake 후 Session 고정」 아님. stdio는 장수명 프로세스지만 프로토콜상 각 요청 독립.

Mcp-Session-Id 있는 구 클라이언트가 새 Server에 연결?

2026-07-28 Server는 프로토콜급 Session ID 미인식. 각 요청 _meta에 protocolVersion·clientCapabilities, 필수 HTTP 헤더로 업그레이드. 혼재 시 게이트웨이에서 MCP-Protocol-Version 분기.

tools/list 매번 호출?

아님. Server가 ttlMs 반환, 클라이언트 TTL 내 캐시. 도구/Schema 변경 시 TTL 단축 또는 도구명/버전 변경.

MCP가 Server 대신 arguments 검증?

도구는 inputSchema 선언 가능, Server는 서버 검증 필수. 외부 Agent 타입 오류 흔함. 무상태화는 줄이지 않음. 구조화 JSON-RPC error가 조용한 500보다 모델 재시도에 유리.

요약과 다음 단계

Stateless MCP는 2026 Remote Server를 일반 HTTP 운영으로: JSON-RPC 2.0이 메서드, _meta가 프로토콜 컨텍스트, Mcp-Method / Mcp-Name 헤더로 게이트웨이가 읽음. initialize·Mcp-Session-Id 퇴장, 임의 인스턴스·Serverless 친화·도구별 레이트 제한 단순화.

업무 상태는 arguments의 명시 ID. JSON 계약은 로컬 검증. 다음: 2026-07-28 사양으로 Remote 엔드포인트 _meta·HTTP 헤더 확인; MCP arguments와 REST body를 한 Schema에; JSONVue로 왕복 JSON 검증.