Technical Research Report · Visual Edition
MCP Goes Stateless
The 2026-07-28 Model Context Protocol specification shipped today — the largest revision since launch
The handshake is gone, sessions are gone, server→client calls are gone. What that costs to migrate, and what it changes for MCP server builders, MCP Apps, and the MCPA exam.
TL;DR — it’s final, not an RC, and it lands today
Revision 2026-07-28 is published as a stable, final release — the RC was locked 21 May 2026 and shipped on schedule ten weeks later. The core protocol is now stateless request/response: no initialize handshake, no Mcp-Session-Id, no server-initiated calls. For most builders the practical news is narrower than the headline: a server that never leaned on the removed session machinery has little to unwind, but every SDK bump and every client is a dual-era problem for the next twelve months.
Version & status
2026‑07‑28 final
Stable tag on GitHub; supersedes 2025-11-25.
Breaking changes
9 major
Plus 12 minor and 6 newly-deprecated features.
Stream resumability
Removed
A dropped stream now loses the in-flight request.
Deprecation grace
12 months
Roots/Sampling/Logging/DCR removable 2027-07-28.
server/discover mandatory
MRTR replaces callbacks
MCP Apps = official extension
OAuth: CIMD over DCR
Legacy client → modern server fails
Bottom line: make your MCP server dual-era (implement server/discover + accept per-request _meta while keeping initialize), and if you are studying for the MCPA exam, learn this delta alongside the 2025-11-25 baseline in the MCPA exam prep guide.
What Just Released
The spec the MCPA exam prep guide flagged as a locked release candidate is now the current protocol version — published final today, on the date it was named for.
2025-11-25 ships
The stateful baseline: initialize handshake, Mcp-Session-Id, server→client sampling/elicitation/roots.
RC locked
Announced as “the largest revision of the protocol since launch.” A ten-week window opens for SDK maintainers to validate against real workloads.
Beta SDKs
Tier-1 SDK betas published against the RC tag.
2026-07-28 final
Stable release. TypeScript, Python, Go and C# SDKs updated; Rust in beta. Claude product support “rolling out,” no forced migration date announced.
Earliest removals
Roots, Sampling, Logging and DCR become eligible for removal under the new twelve-month lifecycle policy.
Two structural changes carry almost all the weight — and they pull in opposite directions.
Theme one
Stateless core
Version, identity and capabilities move into per-request _meta. A server can now sit behind a plain round-robin load balancer with no sticky routing and no shared session store — which is what makes serverless and edge deployment viable.
Theme two
Extensions framework
A formal {vendor}/{name} extension system (SEP-2133) that versions independently of the core. Tasks moved out of core into io.modelcontextprotocol/tasks; MCP Apps lands as io.modelcontextprotocol/ui.
The tension
A thinner core, a wider surface
Core shrinks — Roots, Sampling, Logging, ping all leave or deprecate. But extensions are opt-in and SDK support is discretionary, so real-world capability now varies by client in a way it didn’t before.
Stateless, Drawn
The old protocol made the first request special and every subsequent request dependent on it; the new one makes every request self-describing and independent.
Before — 2025-11-25, session-bound
1
initialize
version + capabilities negotiated once
2
Mcp-Session-Id
server mints, client echoes on every call
3
Sticky LB
affinity required, or shared session store
4
Open GET stream
server→client sampling / roots / elicitation
After — 2026-07-28, per-request
1
Any request
_meta carries protocolVersion, clientCapabilities, clientInfo
2
Round-robin LB
routes on Mcp-Method / Mcp-Name headers, no body parse
3
Any instance
accepts or returns UnsupportedProtocolVersionError
4
Result
resultType: complete — or input_required to ask for more
subscriptions/listen remains for opted-in change notifications, but it is one long-lived POST stream, not the connection identity.Sessions didn’t disappear — they stopped being the protocol’s job and became yours, as an explicit, server-minted handle you can see in the tool arguments. — SEP-2567, restated
The Delta, Line by Line
Every item below was verified against the published 2026-07-28 changelog today; three of the deltas carried in the earlier MCPA guide needed correction.
| Area | Was (2025-11-25) | Is (2026-07-28) | Kind | SEP |
|---|---|---|---|---|
| Handshake | initialize + notifications/initialized | None. Per-request _meta: protocolVersion, clientCapabilities, clientInfo; servers echo serverInfo in result _meta | ○ | 2575 |
| Sessions | Mcp-Session-Id header; per-connection list results | Removed. Cross-call state = explicit server-minted handles passed as tool arguments | ○ | 2567 |
| Discovery | Capabilities learned from initialize response | server/discover — servers MUST implement; clients MAY call. Returns supported versions, capabilities, identity | ● | 2575 |
| Server→client | sampling/createMessage, roots/list, elicitation/create over an open stream | MRTR: server returns InputRequiredResult (resultType:"input_required") with inputRequests; client retries the original request carrying inputResponses | ● | 2322 |
| Result envelope | No type discriminator | Required resultType on every result. Results from earlier-protocol servers that omit it MUST be read as "complete" | ● | 2322 |
| Subscriptions | HTTP GET endpoint + resources/subscribe / unsubscribe | subscriptions/listen — one long-lived POST stream, opt-in per notification type, tagged with io.modelcontextprotocol/subscriptionId | ● | 2575 |
| Resumability | Last-Event-ID + SSE event IDs; redelivery on reconnect | Removed. A broken stream loses the in-flight request; client re-issues with a new request ID | ○ | 2575 |
| Utilities | ping, logging/setLevel, notifications/roots/list_changed | All removed. Log level per-request via _meta["io.modelcontextprotocol/logLevel"]; no notifications/message unless that field was sent | ○ | 2575 |
| Transport headers | Optional | Mcp-Method and Mcp-Name required on Streamable HTTP POST; x-mcp-header allows custom headers from tool parameters | ● | 2243 |
| Caching | Only listChanged notifications | CacheableResult: ttlMs + cacheScope (public/private) required on the four list methods, resources/read, and resources/templates/list. Tools SHOULD be returned in deterministic order | ● | 2549 |
| Tasks | Experimental, in core; blocking tasks/result; tasks/list | Official extension io.modelcontextprotocol/tasks. Polling via tasks/get, new tasks/update for mid-flight input, tasks/list removed, unsolicited task handles allowed | ● | 2663 |
| MCP Apps | SEP-1865, first announced extension (Jan 2026) | Official extension io.modelcontextprotocol/ui in the ext-apps repo, negotiated via capabilities.extensions with a mimeTypes settings object | ● | 2133 |
| Roots / Sampling / Logging | Core client features | Deprecated. Migrate: tool params or resource URIs (Roots) · direct LLM provider API (Sampling) · stderr or OpenTelemetry (Logging) | ◐ | 2577 |
| HTTP+SSE transport | Deprecated since 2025-03-26, informally | Reclassified Deprecated under the formal policy — earliest removal three months after SEP-2596 reaches Final, the shortest fuse on the board | ◐ | 2596 |
| Error codes | Resource-not-found -32002; ad-hoc server-error range | Resource-not-found → -32602 (Invalid Params). Range policy: -32000..-32019 implementation-defined, -32020..-32099 reserved to the spec. New codes renumbered: HeaderMismatch -32020, MissingRequiredClientCapability -32021, UnsupportedProtocolVersion -32022 | ● | — |
| Schema | Constrained subset | inputSchema/outputSchema accept any JSON Schema 2020-12 keyword; structuredContent accepts any JSON value; $ref resolution rules and composition-keyword bounds added | ● | 2106 |
| Authorization | OAuth 2.1 + DCR (RFC 7591) | OAuth 2.1 retained, hardened: iss validation per RFC 9207 (clients MUST validate); credentials keyed by issuer and never reused across authorization servers; application_type required at DCR; DCR deprecated in favour of Client ID Metadata Documents | ◐ | 2468 / 2352 / 837 |
| Elicitation | notifications/elicitation/complete + elicitationId | Both removed. Outcome is learned by retrying the original request; correlate with your own identifier in requestState | ○ | 2322 |
| Observability | Undefined | OpenTelemetry trace-context conventions documented for _meta: traceparent, tracestate, baggage | ● | 414 |
Corrections against earlier draft coverage, including the MCPA exam prep guide, all verified today: (1) the new error codes were themselves renumbered during the RC period — UnsupportedProtocolVersion is -32022, not -32004; (2) DCR is deprecated, not removed, and still required reading because application_type became mandatory within it; (3) SSE resumability removal and the loss of ping/logging/setLevel did not appear in the earlier delta list and are the changes most likely to break a long-running client.
Hard Cut vs. Grace
The single most important operational fact: a legacy client talking to a modern-only server fails, and legacy clients have no fall-forward mechanism — so the compatibility burden sits entirely on servers.
| Client era | Server era | Outcome |
|---|---|---|
| Modern | Modern | Works. server/discover optional; mismatches surface as UnsupportedProtocolVersionError and the client retries. |
| Modern | Legacy | Fails. Server may error, stay silent, or process an era-ambiguous method under legacy semantics. On stdio, probe with server/discover first to fail deterministically. |
| Dual-era | Modern | Works. Client stays modern. |
| Dual-era | Legacy | Works. Falls back to initialize on a non-modern error or a 4xx without a modern error body. |
| Legacy | Modern | Fails. On HTTP the request lacks required headers → 400. No fall-forward exists. |
| Legacy | Dual-era | Works, on the negotiated legacy revision. |
initialize — that error string may be the only diagnostic a legacy user ever sees.- ✗Hard cut, no grace:
initialize,Mcp-Session-Id,ping,logging/setLevel,resources/subscribe, the HTTPGETendpoint, SSE resumability (Last-Event-ID),notifications/elicitation/complete,tasks/list— gone in 2026-07-28, reachable only by serving the legacy revision alongside. - !Deprecated, ~12-month grace to 2027-07-28: Roots, Sampling, Logging, Dynamic Client Registration, and the
includeContextvalues. Fully functional; new implementations should not adopt them. - !Shortest fuse: HTTP+SSE — removable three months after SEP-2596 reaches Final, not twelve.
- ✓Unchanged: host/client/server model, the three primitives and their control semantics, JSON-RPC 2.0 framing, stdio transport, OAuth 2.1 as the auth foundation, and the security threat model.
Migrating
For anyone running MCP servers today the safe path is a single decision — go dual-era — followed by six mechanical steps.
A dual-era server selects its behaviour from how the client opens: a request carrying modern _meta is served statelessly; an initialize request selects legacy semantics for that process or session.
The steps, in dependency order — one through three are required for any modern request to succeed at all.
Implement server/discover
Mandatory. Return supported versions, capabilities (including extensions), identity, plus ttlMs/cacheScope.
Read version and capabilities from _meta, per request
Stop trusting handshake state. Return UnsupportedProtocolVersionError (-32022) with a supported list on mismatch.
Stamp resultType on every result
And on the client side, treat a missing resultType from an older server as "complete".
Convert server→client calls to MRTR
Any sampling, roots or elicitation call becomes an InputRequiredResult plus idempotent handling of the client’s retry. Carry your own correlation id in requestState.
Re-home session state into explicit handles
Anything that lived behind Mcp-Session-Id becomes a server-minted token in the tool arguments — visible, auditable, and yours to expire.
Transport, caching, errors, auth
Require Mcp-Method/Mcp-Name; add ttlMs/cacheScope to list and read results; move resource-not-found to -32602; validate iss; key OAuth credentials by issuer; plan the CIMD move off DCR.
The quiet one that bites: stream resumability is gone. Any client that relied on Last-Event-ID to survive a dropped connection must now re-issue the request under a new request ID — which means server-side handlers for long operations need to be idempotent or task-backed, or a reconnect silently double-executes.
Source Notes & Premise Checks
| Item | Resolution |
|---|---|
| “It may now have shipped” | Confirmed shipped. GitHub tag 2026-07-28 is marked stable release (28 Jul 2026), preceded by 2026-07-28 RC (29 May 2026). The blog post is titled “The 2026-07-28 Specification” and states Final Release. |
| Versioning page says “current is 2025-11-25” | Stale render, caught and discounted. The same page’s negotiation section, its deprecated-features link, and every substantive reference point at /specification/2026-07-28/. Treated as a docs-site propagation lag on release day; the GitHub release tag and the blog post are the authorities used here. |
“UnsupportedProtocolVersion is -32004” | Superseded. The error-code allocation policy renumbered the draft codes: -32020 / -32021 / -32022. The earlier MCPA guide carried the draft numbers. |
| “DCR removed” | Not removed — deprecated. Remains available for authorization servers that don’t support CIMD; and application_type became a new requirement within DCR (SEP-837), so it still needs implementing. |
| Claude-side migration deadline | None published. The Anthropic post says support is “rolling out” with no forced cutoff — which is why dual-era, not a hard cut, is the recommendation. |
| MCP Apps extension identifier | Registry page names the extension “MCP Apps” in ext-apps; the negotiation examples on both the extensions overview and the versioning page use the identifier io.modelcontextprotocol/ui. Both cited. |
The protocol got simpler; the compatibility surface got wider. Plan for the second, not the first.
Go dual-era on your MCP server, add iss validation to the auth path, advertise the MCP Apps extension if you ship UI, and re-learn MCPA Domain 3 and 4 material against the delta table above. The one condition on all of it: none of the deprecated features (Roots, Sampling, Logging, DCR) should appear in anything built from release day onward, because the twelve-month clock has started.
References
All URLs accessed 28 July 2026. primary = specification / vendor · secondary = independent.
Specification — primary
- primary Key Changes — 2026-07-28 changelog (the normative delta list) — modelcontextprotocol.io/specification/2026-07-28/changelog
- primary Versioning and Compatibility — era terminology, compatibility matrix, extension negotiation — modelcontextprotocol.io/specification/2026-07-28/basic/versioning
- primary Versioning (protocol index) — revision states,
server/discover, negotiation — modelcontextprotocol.io/specification/versioning - primary Deprecated Features Registry — earliest-removal dates — modelcontextprotocol.io/specification/2026-07-28/deprecated
- primary Extensions Overview — SEP-2133, official extensions, negotiation examples — modelcontextprotocol.io/docs/extensions/overview
- primary Feature Lifecycle & Deprecation Policy — modelcontextprotocol.io/community/feature-lifecycle
Announcements & releases — primary
- primary The 2026-07-28 Specification (final release announcement, 28 Jul 2026) — blog.modelcontextprotocol.io/posts/2026-07-28/
- primary The 2026-07-28 MCP Specification Release Candidate (RC lock, 21 May 2026) — blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/
- primary Beta SDKs for the 2026-07-28 Spec RC — blog.modelcontextprotocol.io/posts/sdk-betas-2026-07-28/
- primary GitHub releases —
2026-07-28stable tag — github.com/modelcontextprotocol/modelcontextprotocol/releases - primary Full diff, 2025-11-25 → 2026-07-28 — github.com/modelcontextprotocol/specification/compare
- primary Anthropic — Bringing MCP 2026-07-28 to Claude — claude.com/blog/bringing-mcp-2026-07-28-to-claude
Key SEPs — primary
- primary SEP-2575 (stateless core,
server/discover,subscriptions/listen) — PR #2575 - primary SEP-2567 (remove sessions and
Mcp-Session-Id) — PR #2567 - primary SEP-2322 (Multi Round-Trip Requests,
resultType) — PR #2322 - primary SEP-2577 (deprecate Roots, Sampling, Logging) — PR #2577
- primary SEP-2596 (feature lifecycle, HTTP+SSE reclassification) — PR #2596
- primary SEP-2663 (Tasks extension) · SEP-2549 (cacheable results) · SEP-2243 (transport headers) · SEP-2106 (JSON Schema 2020-12) — github.com/modelcontextprotocol/modelcontextprotocol/pulls
- primary SEP-2468 (RFC 9207
issvalidation) · SEP-2352 (issuer-bound credentials) · SEP-837 (application_type) · PR #2858 (DCR → CIMD) — PR #2858 - primary RFC 9207 — OAuth 2.0 Authorization Server Issuer Identification — datatracker.ietf.org/doc/html/rfc9207
Related How-To Guide
- MCPA Exam Prep: MCP Associate Study Guide — exam domain weights and the 2025-11-25 baseline