MCP 2026-07-28: 무상태 스펙
2026년 7월 28일 Model Context Protocol은 런칭 이후 가장 큰 개정을 확정했습니다. 헤드라인: MCP는 무상태입니다. initialize 핸드셰이크와 Mcp-Session-Id 헤더는 사라졌고, 모든 요청은 _meta 안에 자신의 아이덴티티를 실어 나르며, 로드 밸런서 뒤의 어떤 서버 인스턴스도 어떤 호출에 응답할 수 있습니다. 서버리스 MCP는 더 이상 우회책이 아니라 — 프로토콜의 모양 그 자체입니다.
- 2026-07-28 스펙에서 실제로 무엇이 바뀌었나 — 중요한 네 개의 삭제와 네 개의 추가
- Multi Round-Trip Requests (MRTR): 무상태 서버가 세션 없이 사용자에게 후속 질문을 하는 방법
- Extensions 프레임워크와 두 개의 공식 확장: MCP Apps와 Tasks
- 인증 강화: OAuth 2.1, RFC 9207 iss 검증, 그리고 Dynamic Client Registration이 이제 요구하는 것
- 오늘의 2025-11-25 클라이언트를 깨뜨리지 않는 구체적 마이그레이션 경로 — 오늘 설치할 SDK 베타 버전과 함께
한 단락 버전
이전: initialize 핸드셰이크 → Mcp-Session-Id 쿠키 → 세션 수명 동안 스티키한 클라이언트/서버 쌍. 이후: 핸드셰이크 없음, 세션 아이디 없음, 스티키성 없음. 클라이언트 아이덴티티와 능력은 매 요청마다 _meta 오브젝트 안에 실립니다. 새로운 server/discover 메서드가 초기 능력 교환을 대체합니다. 애플리케이션 상태 — 장바구니, 진행 중인 작업 — 는 도구가 반환하고 클라이언트가 다음 호출에서 다시 넘기는 핸들에 살며, REST 리소스 id와 정확히 같습니다. 이 단일 변경이 서버리스와 엣지 배포, 실제 수평 확장, 그리고 두 개의 경쟁 구현이 같은 URL 뒤에 앉을 수 있게 하는 것을 잠금 해제합니다.
무엇이 삭제되었나
- Mcp-Session-Id 헤더 — 그리고 프로토콜 수준 세션이라는 개념 전체
- initialize / initialized 핸드셰이크 — 매 요청의 _meta + 온디맨드 server/discover로 대체
- Roots, Sampling, Logging — deprecated. Roots: 경로를 도구 파라미터로 전달. Sampling: LLM을 직접 호출. Logging: stderr 또는 OpenTelemetry 사용.
- tasks/list — 새 Tasks 확장 안에서조차 삭제됨. 세션 없이 작업을 나열하면 테넌트 간 유출이 발생하기 때문
Roots/Sampling/Logging deprecations는 기존 서버가 실제로 가장 많이 건드리는 것들입니다. 셋 모두 지속적인 양방향 서버↔클라이언트 채널을 가정했습니다. 무상태 세계에서는 클라이언트가 LLM, 경로, 로그 싱크를 소유합니다 — 서버는 그저 도구 호출에 응답합니다.
무엇이 추가되었나
- 서버가 제공하는 것을 알아야 할 때마다 클라이언트가 호출하는 무상태 RPC. 옛 핸드셰이크가 반환하던 능력을 대체합니다. 응답 자체의 ttlMs / cacheScope 필드로 응답을 캐시하세요 — 스펙은 HTTP Cache-Control 시맨틱을 상속합니다.
- Mcp-Method와 Mcp-Name(예: tools/call, search)은 로드 밸런서가 JSON-RPC를 파싱하지 않고 라우팅할 수 있게 합니다. MCP-Protocol-Version이 버전 협상자 역할을 세션 대신 맡습니다.
- elicitation에 대한 무상태 답. 도구가 실행 중 입력이 필요하면 서버는 질문과 불투명한 requestState 블롭을 담은 InputRequiredResult를 반환합니다. 클라이언트는 inputResponses와 되돌려받은 requestState를 넣어 호출을 다시 발행합니다 — 어떤 서버 인스턴스도 이어받을 수 있습니다.
- 역-DNS 네임스페이스, 독립적으로 버전 관리, extensions 능력 맵으로 협상. 공식 확장이 먼저 배포됩니다: MCP Apps(샌드박스 HTML UI, SEP-1865)와 Tasks(장시간 작업 tasks/get, tasks/update, tasks/cancel; SEP-2663). 예전에 코어 스펙 변경을 요구했던 모든 것이 이제 확장으로 배포됩니다.
- 도구 inputSchema와 outputSchema가 이제 oneOf / anyOf / allOf, 조건부, $ref를 받습니다. MCP의 옛 하위 집합에 맞추려고 스키마를 평평하게 만들었다면 이제 그만하세요.
- traceparent, tracestate, baggage가 _meta에 실려 이동합니다. 클라이언트 → 커넥터 → 서버 체인 전반의 분산 추적이 마침내 별도 설정 없이 작동합니다.
- Active → Deprecated → Removed 사이 최소 12개월. 2026년 7월 28일에 deprecated된 것은 최소 2027년 7월 28일까지 계속 동작하며, 제거는 자체 SEP를 필요로 합니다.
모두를 사로잡는 JSON 변경 하나
리소스 없음 에러 코드가 **-32002**에서 **-32602 (Invalid Params)**로 이동했습니다. 클라이언트 어딘가에 if (err.code === -32002) 분기가 있다면 7월 28일에 조용히 동작을 멈춥니다. 이것이 RC의 단일 최다 통합 버그입니다.
Before / After
// BEFORE (2025-11-25): stateful handshake
POST /mcp { "method": "initialize", "params": { "capabilities": {...} } }
→ sets Mcp-Session-Id: abc123
POST /mcp Mcp-Session-Id: abc123
{ "method": "tools/call", "params": { "name": "search", ... } }
// server assumes it "knows" you because of the session cookie
// AFTER (2026-07-28): self-describing request
POST /mcp Mcp-Method: tools/call
Mcp-Name: search
MCP-Protocol-Version: 2026-07-28
{
"method": "tools/call",
"params": { "name": "search", "arguments": {...} },
"_meta": {
"clientInfo": { "name": "claude-code", "version": "..." },
"capabilities": { "extensions": { "com.anthropic.apps": "1" } },
"traceparent": "00-..."
}
}
// any instance can serve it; no session, no stickiness
Multi Round-Trip Requests, 구체적으로
스펙에서 우아한 부분. 실행 중 "어떤 캘린더?"를 물어야 하는 서버는 소켓을 열어둘 필요가 없습니다. 이렇게 답합니다:
{
"resultType": "input_required",
"inputRequests": {
"calendarId": { "type": "string", "prompt": "Which calendar?" }
},
"requestState": "base64(<opaque server-signed blob>)"
}
클라이언트가 프롬프트를 보여주고, inputResponses를 모아, 두 필드를 모두 담아 원 요청을 다시 발사합니다. 서버는 requestState를 권위로 취급합니다 — 종종 서명하여 — 이전 시도를 전혀 기억할 필요가 없습니다. 이것이 무상태 elicitation의 전체 트릭입니다: 상태는 서버가 아니라 유선을 타고 이동합니다.
두 개의 공식 확장
- MCP Apps (SEP-1865): 서버가 HTML UI를 배포할 수 있고, 클라이언트가 샌드박스된 iframe에 렌더링합니다. UI 내부의 모든 행동은 여전히 일반 도구 호출과 같은 JSON-RPC 감사 경로를 거칩니다 — 뒷문 쓰기 없음. 임의의 웹페이지가 아니라 인터랙티브 리포트 + 실행 전 확인이라고 생각하세요.
- Tasks (SEP-2663): 장시간 작업 패턴, 세션 없는 세계용으로 재설계. tools/call이 task 핸들을 반환하고, 클라이언트가 tasks/get과 tasks/update로 폴링·스트리밍하며, tasks/cancel로 중단합니다. tasks/list는 의도적으로 사라졌습니다 — 세션 없이 작업을 열거하는 것은 테넌트 간 유출입니다.
- 브레이킹 체인지: 2025-11-25 실험적 Tasks API는 새 확장과 호환되지 않습니다. 그것을 대상으로 배포했다면 마이그레이션을 업그레이드가 아닌 재작성으로 취급하세요.
인증: OAuth 정리
옛 스펙은 OAuth 스러웠습니다. 새 것은 OAuth 2.1 / OIDC 모양입니다:
- 클라이언트는 인증 응답의
iss파라미터를 반드시 RFC 9207에 따라 검증해야 합니다 — 올해 초 MCP 서버를 강타한 mix-up 공격에 대한 수정입니다. - Dynamic Client Registration은 이제 클라이언트가 OpenID Connect
application_type을 선언하도록 요구하므로, 아이덴티티 프로바이더가 native/web/machine 클라이언트에 대해 서로 다른 규칙을 강제할 수 있습니다. - Refresh 토큰은 표준 OIDC refresh 플로를 따릅니다 — 즉 엔터프라이즈 SSO(Entra, Okta, PingID)가 처음으로 커스텀 미들웨어 없이 동작합니다.
실용 요약: MCP를 Okta에 맞추려고 커스텀 OAuth 접착제를 만들었다면 대부분 삭제할 수 있습니다.
오늘 베타 설치하기
Python — mcp v2.0.0b1 (single endpoint serves both revisions)
uv add "mcp[cli]==2.0.0b1" # or pip install "mcp[cli]==2.0.0b1"
TypeScript — split packages, explicit opt-in for stateless
npm install @modelcontextprotocol/server@beta npm install @modelcontextprotocol/client@beta
Go — v1.7.0-pre.1
go get github.com/modelcontextprotocol/go-sdk@v1.7.0-pre.1
C# — v2.0.0-preview.1
dotnet add package ModelContextProtocol --prerelease
SDK 팀의 호환성 약속: "오늘 아무것도 깨지지 않고, 7월 28일에도 아무것도 깨지지 않는다." 새 클라이언트는 2025-11-25 서버에 부딪히면 옛 핸드셰이크로 자동 협상하고, Python v2 서버는 같은 엔드포인트에서 기본으로 두 개정 모두에 응답하며, TypeScript와 Go는 무상태 변형을 노출하려면 명시적 opt-in이 필요합니다. TypeScript v1.x는 최소 6개월간 버그 픽스와 보안 업데이트를 받습니다.
마이그레이션 플레이북
- 2027년 7월 28일까지 여전히 동작합니다. 이들을 대상으로 새 서버를 짓지 마세요. 경로: 도구 인자로 받으세요. LLM 호출: 자체 클라이언트를 사용하세요. 로그: stderr에 쓰고 하니스가 집계하도록 하세요.
- 오늘 서버가 '사용자가 체크아웃 도중이다'를 기억한다면, 도구 호출에서 basket_id를 반환하고 다음 호출에서 그것을 요구하세요. 상태를 메모리가 아니라 유선에 두세요.
- 지금은 옛 핸드셰이크를 유지하더라도 server/discover 노출은 2026-07-28 클라이언트가 initialize를 완전히 건너뛸 수 있게 합니다. 서버리스를 잠금 해제하는 단일 변경입니다.
- 소유한 모든 코드베이스에서 32002를 grep하세요. 이것이 마이그레이션의 조용한 실패 함정입니다.
- 모든 요청의 _meta에 clientInfo와 capabilities를 보내세요. 그 김에 traceparent도 전파하세요 — 프로덕션에서 무언가가 처음 깨질 때 그 추적을 원하게 됩니다.
- MCP Apps는 UI가 채팅 턴보다 나을 때(데이터 그리드 확인, 차트 기반 승인) 가치가 있습니다. Tasks는 작업이 클라이언트의 HTTP 유휴 타임아웃을 넘길 수 있을 때 언제나 가치가 있습니다. 어느 것도 공짜가 아닙니다 — 둘 다 클라이언트 표면을 추가합니다.
- 그것은 업그레이드되지 않습니다. 확장을 대상으로 재작성하고, 롤아웃 동안 옛 엔드포인트를 계속 살려두고, 자체 일정에 따라 제거하세요.
RC에서 사람들이 실제로 부딪히는 함정들
- 스티키 로드 밸런서는 여전히 '작동'합니다 — 어느 순간까지는요. 스티키 LB 뒤의 무상태 서버는 개발에서 괜찮아 보이다가 프로덕션에서 캐시 히트율을 파괴합니다. 스티키성을 명시적으로 끄세요.
- requestState는 클라이언트에게 불투명합니다 — 하지만 무료 저장소는 아닙니다. 절반 메가바이트의 컨텍스트를 그 안에 채워 넣는 서버는 클라이언트 메모리를 폭발시킵니다. 작은 핸들에 서명하고, 나머지는 핸들에 키를 두어 서버 측에 저장하세요.
- MCP Apps iframe은 샌드박스일 뿐 정화되지 않았습니다. 악의적 서버는 여전히 사용자가 그 UI에 입력하는 무엇이든 유출할 수 있습니다. MCP App을 서드파티 코드처럼 취급하세요 — 어떤 서버가 UI를 렌더링할 수 있는지 허용 목록으로 관리하세요.
- server/discover는 기본 스펙에 인증 요구 사항이 없습니다. 거기에 노출하는 무엇이든 URL에 도달하는 모든 클라이언트가 발견할 수 있습니다. 내부 도구 메타데이터를 거기에 두지 마세요.
- JSON Schema 2020-12 업그레이드는 옛 하위 집합에 대해 검증자를 손으로 짠 클라이언트가 이제 조용히 과소 검증할 수 있음을 의미합니다. 손수 만든 것이 아니라 실제 JSON Schema 라이브러리를 사용하세요.
AILmanac 지도상에서 이것이 놓이는 자리
- MCP & Connecting to Tools — API 쪽 커넥터. 여전히 현재 유효; 커넥터가 전송을 추상화하므로 유선 변경은 그 요청 형태에는 보이지 않습니다. 커넥터가 대화하는 서버만 마이그레이션합니다.
- MCP in Claude Code — Claude Code가 로컬 + 원격 서버에 MCP로 말하는 방법. 무상태 모델이 이상한 타임아웃 없이 Claude Code를 서버리스 MCP 엔드포인트에 마침내 가리킬 수 있게 하는 이유입니다.
- The MCP Token Tax — 지연 로딩은 토큰 쪽 레버이고, 확장 프레임워크는 같은 문제에 대한 프로토콜 쪽 레버입니다.
- Securing MCP Servers — NSA의 2026년 5월 MCP 보안 가이드와 RC의 인증 강화는 서로를 강화합니다. 둘 다 읽으세요.
빠른 점검
Check yourself
0/4이번 주 GitHub에서 볼 어휘
Sources & further reading
- The 2026-07-28 MCP Specification Release Candidate — 삭제, 추가, SEP 목록이 담긴 주 공지.
- Beta SDKs for the 2026-07-28 MCP Spec RC — Python, TypeScript, Go, C# 베타 버전과 하위 호환 약속.
- Bringing MCP 2026-07-28 to Claude — Claude와 Claude Code에 대한 Anthropic의 롤아웃 노트.
- MCP 2026-07-28: From Local Tool to Distributed Protocol — 가장 예리한 서드파티 마이그레이션 워크스루.
- MCP Just Went Stateless — What the 2026 Spec Changes About Scaling — App Service의 무상태 MCP에 대한 Microsoft의 관점.
- MCP Is Going Stateless. Here's What That Means — 운영 함의에 유용한 Arcade.dev의 실무자 시각.
- NSA CSI: MCP Security Design Considerations (PDF) — NSA의 2026년 5월 강화 가이드. 이 스펙의 인증 변경과 함께 읽으세요.