Devlery
Blog/AI

MCP가 세션을 버린다, 7월 28일 무상태 사양이 강제한 마이그레이션

MCP 코어가 세션 기반에서 무상태로 재설계된다. 2026-07-28 사양이 initialize 핸드셰이크와 세션 ID를 없애 로드밸런서 뒤 수평 확장을 열지만, 기존 서버와 SDK는 breaking change로 마이그레이션해야 한다.

MCP가 세션을 버린다, 7월 28일 무상태 사양이 강제한 마이그레이션
AI 요약
  • 무슨 일: MCP 차기 사양 2026-07-28이 프로토콜 코어를 세션 기반에서 무상태(stateless)로 재설계합니다. 릴리스 후보는 5월 21일 공개됐고, 최종 사양은 7월 28일 확정 예정입니다.
    • initialize/initialized 핸드셰이크와 Mcp-Session-Id 헤더가 사라집니다. 프로토콜 버전·클라이언트 정보는 매 요청 _meta에 담깁니다.
    • 총 15개 SEP(사양 개선 제안)가 함께 이 전환을 만듭니다. 이번 릴리스는 명시적으로 breaking change를 포함합니다.
  • 의미: 세션이 사라지면 원격 MCP 서버가 일반 라운드로빈 로드밸런서 뒤에서 돌아갑니다. 스티키 세션·공유 세션 저장소·게이트웨이 바디 검사가 필요 없어져 서버리스·수평 확장과의 마찰이 없어집니다.
  • 주의점: 기존 서버·클라이언트는 모두 마이그레이션해야 합니다. 2025-11-25 실험 Tasks API 사용자, -32002 오류 코드 매칭 클라이언트, Roots/Sampling/Logging 의존 구현이 대상입니다. Tier 1 SDK는 10주 안에 지원을 내야 합니다.

Model Context Protocol(MCP)의 다음 사양 버전이 프로토콜의 뼈대를 바꿉니다. 리드 메인테이너 David Soria Parra와 Den Delimarsky가 공개한 2026-07-28 릴리스 후보는 MCP를 세션 기반에서 무상태 프로토콜로 재설계합니다. 후보 문서는 5월 21일에 나왔고, 최종 사양은 7월 28일에 확정됩니다. 그 사이 10주가 검증 기간입니다.

메인테이너들도 이번 릴리스가 예외라는 점을 문서에 못 박았습니다. "이 릴리스는 breaking change를 포함합니다. 이것이 규범이 되기를 바라지는 않습니다." 세션 제거가 전송 계층을 통째로 다시 짜는 작업이라, 한 번의 큰 단절을 감수한다는 뜻입니다. 지금 MCP 위에서 뭔가를 돌리고 있다면, 이건 사양이 확정된 뒤가 아니라 지금 계획해야 하는 변경입니다.

initialize 핸드셰이크가 만들던 문제

지금까지의 MCP(2025-11-25)에서 클라이언트는 먼저 initialize 핸드셰이크를 보내고, 서버로부터 Mcp-Session-Id를 받아야 이후 요청을 할 수 있었습니다. 이 세션 ID가 클라이언트와 특정 서버 인스턴스를 하나로 묶었습니다. 로컬에서 프로세스 하나를 붙여 쓰는 데스크톱 앱이라면 문제가 없습니다. 문제는 이 프로토콜을 프로덕션 HTTP 인프라에 얹을 때 생깁니다.

메인테이너들은 그 마찰을 세 가지로 정리했습니다. 로드밸런서가 JSON-RPC 바디를 파싱해야 라우팅할 수 있었고, 스티키 세션이 오토스케일링을 막았으며, 서버 한 대가 재시작되면 진행 중이던 모든 세션이 붕괴됐습니다. 세션 상태가 특정 인스턴스의 메모리에 살아 있으니, 그 인스턴스가 죽으면 상태도 같이 사라지는 구조였습니다.

MCP 세션 기반과 무상태 요청 흐름 비교

우회하는 방법이 없지는 않았습니다. 세션 저장소를 외부 Redis로 빼고, 로드밸런서에 스티키 규칙을 걸고, 바디를 뜯어보는 게이트웨이를 세우면 됩니다. 하지만 이건 서버리스 함수나 수평 확장된 배포에는 그대로 얹기 힘든 요구사항입니다. 실제로 프로덕션에 MCP를 올린 팀들은 이 부분을 각자의 커스텀 코드로 메우고 있었습니다. 무상태 코어는 그 커스텀 코드를 프로토콜 표준으로 흡수하는 변경입니다.

무상태 코어가 실제로 바꾸는 것

핵심 6개 SEP가 세션을 걷어냅니다(SEP-2575, SEP-2567 등). initialize/initialized 핸드셰이크가 완전히 폐기되고, Mcp-Session-Id 헤더도 사라집니다. 그 대신 프로토콜 버전, 클라이언트 정보, 기능 협상이 매 요청의 _meta 필드에 실립니다. 서버 기능을 미리 알아야 하면 server/discover로 조회합니다. 요청 하나하나가 자기 완결적이라, 어느 서버 인스턴스가 받아도 처리할 수 있습니다.

요청 형태를 비교하면 차이가 분명합니다.

# 기존 (2025-11-25)
POST /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-3a3f-4f5b

# 신규 (2026-07-28)
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

여기서 Mcp-MethodMcp-Name 헤더가 필수가 된 것(SEP-2243)이 운영 관점에서 큽니다. 로드밸런서·게이트웨이·레이트 리미터가 바디를 뜯어보지 않고 헤더만으로 라우팅할 수 있게 됩니다. 메인테이너들의 요약을 그대로 옮기면, 예전에 스티키 세션과 공유 세션 저장소, 게이트웨이의 심층 패킷 검사가 필요했던 원격 MCP 서버가 이제 "평범한 라운드로빈 로드밸런서 뒤에서 돌아가고, Mcp-Method 헤더로 트래픽을 라우팅하며, 클라이언트가 tools/list 응답을 캐싱"할 수 있습니다.

그렇다면 상태가 정말 필요한 도구는 어떻게 할까요. 답은 HTTP API가 늘 해온 방식입니다. 도구가 명시적 핸들을 발급하고, 모델이 그걸 다음 호출의 인자로 되돌려주면 됩니다. 장바구니라면 basket_id, 브라우저 세션이라면 browser_id를 서버가 반환하고, 이후 호출에서 그 ID를 평범한 매개변수로 넘깁니다. 상태를 프로토콜의 숨은 세션이 아니라 도구 인자로 드러내는 방식입니다.

서버가 클라이언트에게 되묻는 흐름도 다시 짜였습니다(SEP-2260, SEP-2322). 서버 발행 요청은 이제 클라이언트 요청을 처리하는 동안에만 나갈 수 있고, 상시 열린 SSE 스트림에 의존하지 않습니다. 사용자 확인이 필요하면 서버는 InputRequiredResult를 돌려주는데, 여기에는 requestState라는 불투명 토큰이 들어 있습니다. 클라이언트가 답을 모아 원래 요청을 다시 보낼 때 이 토큰을 되돌려주면, 필요한 정보가 페이로드에 다 담겨 있으니 어느 서버 인스턴스든 재시도를 이어받습니다.

지금 코드를 건드려야 하는 breaking change

무상태 전환은 개념적으로 깔끔하지만, 실무에서는 마이그레이션 체크리스트로 다가옵니다. 가장 흔히 걸리는 것부터 정리합니다.

바뀌는 것기존대응
세션initialize + Mcp-Session-Id매 요청 _meta, 명시적 핸들 발급
Tasks실험 코어 API (2025-11-25)정식 확장, tasks/get·update·cancel로 재작성
오류 코드-32002 (MCP 커스텀)-32602 (JSON-RPC Invalid Params)
Roots·Sampling·Logging코어 기능폐기, 12개월 이상 유지 후 별도 SEP로 제거
인증느슨한 issuer 검증iss 검증 필수(RFC 9207), OIDC 정렬

Tasks 확장(SEP-2663) 이 대표적입니다. 장기 실행 작업을 위한 Tasks는 2025-11-25에서 실험적 코어 기능이었는데, 이번에 정식 확장으로 옮겨졌습니다. 이제 tools/call 응답이 태스크 핸들을 반환하고, 클라이언트가 tasks/get, tasks/update, tasks/cancel로 구동합니다. tasks/list는 세션 없이 안전하게 범위를 지정할 수 없어서 빠졌습니다. 문서는 분명하게 적었습니다. "2025-11-25 실험 Tasks API에 맞춰 구현한 사람은 새 생애주기로 마이그레이션해야 합니다."

폐기되는 기능(SEP-2577) 도 확인해야 합니다. Roots, Sampling, Logging 세 가지가 폐기 대상입니다. Roots는 도구 매개변수나 리소스 URI, 서버 설정으로, Sampling은 LLM 제공자 API 직접 통합으로, Logging은 stdio 전송의 stderr나 구조화된 관측용 OpenTelemetry로 대체하라는 안내입니다. 다만 이건 주석 전용 폐기라, 이번 릴리스와 발행 후 1년 안의 모든 버전에서 계속 작동합니다. 실제 제거는 별도 SEP를 거쳐야 합니다.

작은 변경이라 놓치기 쉬운 것도 있습니다. 누락된 리소스를 알리던 오류 코드가 MCP 커스텀 -32002에서 JSON-RPC 표준 -32602(Invalid Params)로 바뀌었습니다(SEP-2164). 리터럴 -32002 값을 하드코딩해 매칭하는 클라이언트는 이 한 줄 때문에 깨집니다. 도구 스키마도 JSON Schema 2020-12를 전면 지원해서(SEP-2106), 입력 스키마에 oneOf·anyOf·allOf·$ref·$defs를 쓸 수 있게 됐습니다. 대신 외부 $ref의 자동 역참조는 금지되고, 스키마 깊이와 검증 시간에 상한을 두도록 권고합니다.

인증도 여섯 개 SEP로 조여졌습니다. RFC 9207에 맞춰 iss 파라미터 검증이 필수가 됐습니다. 동적 클라이언트 등록에서는 OpenID Connect의 application_type을 선언해야 하고, 등록 신원은 인증 서버 issuer에 바인딩됩니다. 갱신 토큰 요청 방식과 단계적 범위 상향, .well-known 발견 접미사도 이번에 함께 명시됐습니다.

MCP Apps와 확장이라는 방향

이번 릴리스가 세션만 걷어낸 건 아닙니다. 그동안 실 배포에서 커스텀 코드로 메우던 두 가지 구멍을 확장으로 정식화했습니다.

MCP Apps(SEP-1865) 는 서버가 대화형 HTML 인터페이스를 배포하고, 호스트가 그것을 샌드박스 iframe에서 렌더링하는 방식입니다. 여기서 보안 모델이 핵심입니다. 문서는 이렇게 적었습니다. "도구가 UI 템플릿을 미리 선언하므로, 호스트는 무엇이든 실행되기 전에 프리페치하고, 캐싱하고, 보안 검토를 할 수 있습니다." UI에서 발생하는 모든 동작은 직접 도구 호출과 똑같은 감시·동의 경로를 지납니다. 채팅 텍스트만 오가던 MCP에 서버 제공 UI가 들어오되, 그 UI가 권한 우회 통로가 되지 않도록 사전 선언을 강제한 설계입니다.

관측성도 표준으로 들어왔습니다. _meta에서 W3C Trace Context(traceparent, tracestate, baggage)를 전파해(SEP-414), 호스트 앱에서 클라이언트 SDK, MCP 서버, 다운스트림 호출까지 하나의 스팬 트리로 이어집니다. OpenTelemetry 백엔드를 쓰는 팀이라면 별도 배관 없이 분산 추적이 붙습니다. 리스트·리소스 응답에는 ttlMscacheScope가 추가돼(SEP-2549), HTTP Cache-Control처럼 응답이 얼마나 유효한지, 사용자 간 공유가 가능한지를 클라이언트가 판단합니다.

10주라는 마감, 그리고 그다음

이 사양이 지금 다뤄야 할 소식인 이유는 일정에 있습니다. 릴리스 후보는 5월 21일에 확정됐고, 최종 사양은 7월 28일입니다. 그 사이 10주가 검증 기간이고, SDK 등급 체계에서 Tier 1 SDK는 이 기간 안에 지원을 배포하도록 기대됩니다. 공식 SDK를 채점하는 적합성 스위트(SEP-2484)가 있어서, 표준 트랙 SEP는 대응 시나리오가 스위트에 포함돼야 최종 상태에 도달합니다.

규모를 생각하면 이 마감의 무게가 실감납니다. 공개된 MCP 서버는 이미 9,400개를 넘고, 사설·내부 서버는 그 3배에서 4배로 추정됩니다. Stacklok의 2026년 조사에서 소프트웨어 조직의 41%가 제한적 또는 광범위한 프로덕션에서 MCP 서버를 돌리고 있고, Fortune 500의 28%가 프로덕션 AI 워크플로에 MCP 서버를 배포했습니다. 2025년 12월 Anthropic이 MCP를 Linux Foundation 산하로 기증한 뒤로, 이 프로토콜은 한 회사의 사양이 아니라 벤더 중립 표준으로 움직입니다. 그만큼 코어 변경의 파급도 넓어졌습니다.

MCP를 프로토콜 표준으로 정착시키려는 작업은 모델 API 안으로 라우터 루프를 넣은 vLLM Micro-Agent처럼 인프라 계층에서 이어져 왔는데, 이번 무상태 전환은 그 표준화의 가장 근본적인 단계입니다.

거버넌스 장치도 이번에 함께 들어왔습니다. 기능 생애주기 정책(SEP-2596)은 Active에서 Deprecated, Removed로 가는 단계를 정하고, 폐기부터 제거까지 최소 12개월을 보장합니다. 확장 프레임워크(SEP-2133)는 역DNS 방식 ID(io.modelcontextprotocol/xxx)로 확장을 식별하고, 클라이언트·서버가 extensions 맵으로 협상하며, 확장별로 독립 버전을 관리하게 합니다. 이 장치들 덕분에, 메인테이너들은 2026-07-28을 겨냥해 구현하는 팀이 앞으로의 개정을 "전송이나 생애주기 코드를 다시 쓰지 않고" 도입할 수 있으리라 기대한다고 밝혔습니다. 한 번의 큰 단절을 지금 감수하면, 다음부터는 확장과 폐기 창구로 완만하게 진화한다는 약속입니다.

정리하면, MCP 위에 서버든 클라이언트든 무언가를 올려둔 팀에게 이번 사양은 선택이 아니라 예정된 작업입니다. 세션 ID를 하드코딩한 곳, 2025-11-25 Tasks에 맞춘 구현, -32002를 문자 그대로 매칭하는 코드, Roots·Sampling·Logging에 의존하는 부분을 지금 목록으로 뽑아 두는 편이 낫습니다. 7월 28일은 사양이 확정되는 날이지, 마이그레이션을 시작하는 날이 아닙니다.