Before July 28, every MCP deployment that wanted to scale horizontally had the same problem: the initialize handshake minted an Mcp-Session-Id that pinned each client to whichever server instance handled the first request. Round-robin a second request to a different pod and the SDK returned 404.
Two ASP.NET Core MCP pods behind a round-robin load balancer hit this exactly: pod A handled initialize and minted a session ID; the follow-up SSE request hashed to pod B, which had never seen that client, and returned 404. Thirty seconds later the client threw TaskCanceledException. The usual fix was LB stickiness on Mcp-Session-Id - it works, but it is infrastructure duct tape over a protocol problem.
The 2026-07-28 spec removes the duct tape requirement entirely. On May 21, 2026, the MCP team locked the release candidate - the largest revision since the protocol launched - and the final specification shipped on July 28, 2026, after a ten-week validation window for SDK maintainers. The two lead maintainers, David Soria Parra and Den Delimarsky, called it "the last revision that breaks compatibility."
What the stateless core actually means for production
The headline change is a stateless protocol core: MCP transforms from a bidirectional stateful protocol into a request/response stateless protocol.
The concrete infrastructure consequence is direct.
A remote MCP server that previously needed sticky sessions, a shared session store, and deep packet inspection at the gateway can now run behind a plain round-robin load balancer, route traffic on an Mcp-Method header, and let clients cache tools/list responses for as long as the server's ttlMs permits.
Two specification enhancement proposals define the change.
SEP-2575 removes the initialize handshake, and SEP-2567 removes the Mcp-Session-Id header along with the protocol-level session.
Protocol version, client info, and capabilities now travel inline in a _meta field on each request
- making every call self-describing rather than relying on accumulated handshake context.
One thing worth being precise about: stateless transport does not mean stateless application.
Removing the protocol-level session does not mean your application has to be stateless. Servers that need to carry state across calls can mint an explicit handle - a basket_id, a browser_id - from a tool and have the model pass it back as an ordinary argument on later calls.
State that was previously hidden in the transport now has to be visible in the tool call. That is a meaningful design constraint, and it makes agent behavior easier to trace and debug.
How server-to-client requests work without a persistent connection
The hardest part of going stateless is what to do when a server needs to ask the client something mid-call - an "are you sure you want to delete these three files?" prompt. The old answer was: hold an SSE stream open.
Server-initiated requests like elicitations or sampling callbacks used to depend on holding a Server-Sent Events stream open. The new spec introduces InputRequiredResult: the server returns a result with resultType: input_required, a map of questions in inputRequests, and an opaque requestState token. The client collects the answers and re-issues the original call with inputResponses plus the echoed requestState. Because requestState carries everything needed to resume, the retry can land on a completely different server instance.
One InputRequiredResult can batch an elicitation and a sampling request together in a single round-trip.
And crucially,
server-initiated requests may now only be issued while the server is actively processing a client request. Earlier spec versions recommended this; it is now required. A user is never prompted out of nowhere, and every elicitation traces back to something they or their agent started.
The migration picture: what breaks, what does not, and the one real cliff
The honest scope of the work is: two changes are immediate for anyone who wants the new behaviour - removing the handshake dependency and removing Mcp-Session-Id - and the rest can be scheduled against a minimum 12-month deprecation window. Nothing switched off on July 28.
Three features enter formal deprecation on this release.
Three features enter deprecation: Roots (replaced by tool parameters or config), Sampling (call the LLM provider API directly), and Logging (use stderr or OpenTelemetry). A formal deprecation policy guarantees a minimum twelve-month window between deprecation and removal, so none of these break on July 28.
The one genuine cliff is version mixing with elicitations. If your gateway fronts an MCP server target that upgrades to 2026-07-28 before your clients do, it translates between versions, so a 2025-era client can call ordinary tools on a 2026-07-28 target and receive results in the format it expects. However, this translation does not currently support elicitations and sampling calls from servers to clients. If a 2025-era client calls a tool on a 2026-07-28 server that requires elicitation or sampling, it receives an error.
That means: if you run tools that prompt the user for confirmation and you upgrade the server before the clients, those flows break silently for old clients. Audit that before you deploy.
| What | Before 2026-07-28 | After 2026-07-28 |
|---|---|---|
| Session handshake | Required; mints Mcp-Session-Id |
Removed (SEP-2575 + SEP-2567) |
| Load balancer | Sticky sessions or shared session store | Plain round-robin, route on Mcp-Method header |
| Mid-call user prompts | Held SSE stream | InputRequiredResult + requestState retry |
| Long-running tasks | Experimental Tasks API | Stateless tasks/get / tasks/cancel lifecycle |
| SSE stream resumability | Last-Event-ID, event redelivery |
Removed; client re-issues with new request ID |
| App state | Hidden in transport session | Explicit tool handles passed as arguments |
The extensions framework and what ships alongside it
The stateless core is the structural change; the release also ships: an Extensions framework, Tasks, MCP Apps, authorization hardening, and a formal deprecation policy.
Extensions are now identified by reverse-DNS IDs, negotiated through an extensions map on client and server capabilities, live in their own ext-* repositories with delegated maintainers, and version independently of the specification. A new Extensions Track in the SEP process gives them a path from experimental to official.
Authorization hardening is worth understanding carefully because it is being misreported. The authorization rework is the part most likely to be misreported. MCP did not invent new security primitives in this release. It made two existing ones mandatory and reordered how clients register.
RFC 9207, "OAuth 2.0 Authorization Server Issuer Identification," was published by the IETF in March 2022 as a countermeasure to mix-up attacks. What is new in 2026 is the requirement, not the mechanism.
The Tasks extension is worth flagging separately.
The Tasks extension reshapes the lifecycle around the stateless model: a server can answer tools/call with a task handle, and the client drives it with tasks/get, tasks/update, and tasks/cancel.
If you were using the experimental Tasks API from 2025, this is a migration, not a drop-in - budget time for it.
Mcp-Method header routing - and app state carried as explicit tool handles the model passes backMCP 2026-07-28 stateless spec: common questions
What is the MCP 2026-07-28 specification?
It is the largest revision to the Model Context Protocol since its November 2024 launch. The headline change is that the protocol becomes stateless: the initialize handshake and Mcp-Session-Id header are removed, so any request can land on any server instance behind a plain round-robin load balancer. It also ships an Extensions framework, the Tasks extension, MCP Apps, and a formal deprecation policy.
Do I have to rewrite my existing MCP server?
No full rewrite. The two immediate changes are removing the handshake dependency and the session ID. Everything else - Roots, Sampling, Logging - enters a minimum 12-month deprecation window. Nothing stopped working on July 28. The new @modelcontextprotocol/server v2 SDK can serve both old and new clients from a single handler.
What replaces server-initiated elicitations over SSE?
The new Multi Round-Trip Request (MRTR) pattern. The server returns an InputRequiredResult with the questions it needs answered and an opaque requestState token. The client collects answers from the user and re-issues the original call with inputResponses and the echoed requestState. Because all state travels in the payload, the retry can hit a different server instance.
Will old 2025-era clients break against a 2026-07-28 server?
For ordinary tool calls: no, gateways translate between versions. The exception is elicitation and sampling: if a 2025-era client calls a tool that triggers an InputRequiredResult, it receives an error because the old client does not know the new result type. Audit any tools that prompt for confirmation before upgrading your server ahead of your clients.
What gets deprecated in this release?
Three features: Roots (use tool parameters or config instead), Sampling (call your LLM provider API directly), and Logging (use stderr or an OpenTelemetry exporter). All three carry a minimum twelve-month window before they can be removed - the earliest possible removal date is July 2027.