MCP Went Stateless: What Changed in the 2026-07-28 Spec
The 2026-07-28 MCP spec removes sessions and the handshake. What changed, what breaks, what is deprecated, and how to migrate, checked against the changelog.
- Author
- Kamran Khan
- Published
- Reading time
- 7 min read
On this page
MCP, the Model Context Protocol, is the standard that connects AI tools to your apps, databases and APIs. On 28 July 2026 it shipped a revision, 2026-07-28, whose headline change is that the protocol is now stateless. It is a breaking change, so if you run or build MCP servers it is worth reading the changelog before it reads you.
This is what I found in the official changelog and release post, in plain terms, with the parts that are vendor claims marked as such.
Transcript
MCP is the standard that connects AI tools to your apps. On the twenty-eighth of July, it shipped a breaking change. It's now stateless. Here's the old way. Every connection began with a handshake: initialize, then initialized. A session ID tied every later message to one server. Like a phone call, both ends stay on the line. The new way: every request is self-contained. It carries its own protocol version and capabilities. No handshake. No session ID. Like a letter with the address already written on it. That's why scaling gets easier. Any request can land on any server instance behind a plain load balancer. Cloudflare says a server can run in just a Worker, with no stateful infrastructure. And two new headers, MCP Method and MCP Name, let gateways route a request without reading the body. Servers can no longer hold a stream open to ask the user a question. They reply, input required, and the client retries with the answer. Lists now carry cache hints, and tasks became an optional extension. One gotcha. If a stream breaks, the in-flight request is lost, and the client must send it again as a new request. If you kept state in sessions, have a tool mint an explicit handle, and let the model pass it back. Auth got stricter: clients validate the issuer, and credentials stay bound to the server that issued them. Roots, Sampling, Logging and the old HTTP plus SSE transport are deprecated. That means they keep working for at least twelve months. To migrate, Cloudflare suggests running a stateless route next to the old one, then draining and removing the legacy path. The Tier one SDKs, TypeScript, Python, Go and C#, already support the new spec. So MCP is not just plug and play. It's a protocol with versions, deprecations and migrations. Check which spec your server speaks. Follow for sources, not hype.
The old way: a session
Under the 2025-11-25 revision, every connection began with a handshake: the client sent initialize, the server answered, and the client confirmed with notifications/initialized. Streamable HTTP then tied later messages together with an Mcp-Session-Id header, so a client talked to one particular server. Cloudflare, which runs remote MCP servers at scale, describes what that cost: sticky sessions, held-open streams and message replay, more overhead than a normal web server.
The new way: every request stands alone
In 2026-07-28 the handshake and the session header are gone. The changelog says every request now carries its protocol version and client capabilities in _meta (io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities), and clients should identify themselves on each request. A mismatch returns UnsupportedProtocolVersionError.
Servers must implement a new server/discover call, which advertises supported versions, capabilities and identity. A client may call it first to pick a version, but it does not create a session.
Why it matters: any request, any instance
With no session to remember, any request can be answered by any server instance behind an ordinary round-robin load balancer, with no shared storage. Cloudflare says an MCP server can run "in just a Worker, no stateful infrastructure needed". That is a vendor claim about its own platform, and it gives no latency or cost figures, so I treat it as a design benefit, not a measurement.
Two header changes help gateways: Streamable HTTP POST requests must now include Mcp-Method and Mcp-Name, so a gateway or rate limiter can route on headers without parsing the JSON body. List and read results also carry ttlMs and cacheScope hints so clients can cache them, and tools/list should return tools in a deterministic order.
Asking the user a question without holding a stream
Servers used to send their own requests to the client (roots/list, sampling/createMessage, elicitation/create), which needed a held-open stream. The spec replaces that with Multi Round-Trip Requests: the server returns a result with resultType: "input_required" and an inputRequests field, and the client answers with inputResponses on a retry of the original request. All results now carry a required resultType, either complete or input_required.
Tasks, which were experimental, moved out of the core into an official extension, io.modelcontextprotocol/tasks, with polling through tasks/get and a new tasks/update.
The gotchas
- A broken stream loses the request. SSE stream resumability and redelivery (
Last-Event-ID) were removed. If the response stream breaks, the in-flight request is lost and the client must re-issue it as a new request with a new ID. - State must be explicit. If your server kept state in a session, the changelog's advice is to use server-minted handles passed as ordinary tool arguments. A cart tool might look like this (names are illustrative):
// create_cart() -> { handle: "cart_81f2" }
// add_item({ handle: "cart_81f2", sku: "A-17" })- Old and new do not mix automatically. Per the maintainers, apps that depended on session identifiers face the largest migration cost, and modern-only clients will not automatically work with legacy-only servers.
Auth got stricter
Clients must validate the iss parameter (RFC 9207) in authorization responses before redeeming a code, and persisted credentials are bound to the issuer that minted them, so a client must not reuse them with a different authorization server. Dynamic Client Registration is deprecated in favour of Client ID Metadata Documents, though it stays available for compatibility.
What is deprecated
Roots, Sampling and Logging, the HTTP+SSE transport, and some includeContext values are deprecated. A new feature lifecycle policy defines Active, Deprecated and Removed states with a minimum twelve-month deprecation window, so they keep working for at least that long. The suggested replacements: pass directories through tool parameters or resource URIs instead of Roots, call model provider APIs directly instead of Sampling, and log to stderr or use OpenTelemetry instead of Logging.
How to migrate
Cloudflare's suggested path is a staged one: run a stateless route alongside the sessionful one, then drain and remove the legacy path. The /mcp endpoint it describes accepts both new stateless requests and 2025 Streamable HTTP clients during the transition. The release post lists Tier 1 SDK support for TypeScript, Python, Go and C#, with Rust in beta, and says the Tier 1 SDKs see close to half a billion downloads a month. That figure is the maintainers' own.
What I could not verify
- Any performance or cost improvement. Cloudflare gives none, and I left vendor-reported partner figures out.
- Real-world migration effort, which depends on how much your server leaned on sessions.
Sources
- Model Context Protocol, Key changes in the 2026-07-28 specification: every protocol, auth and deprecation detail above.
- MCP maintainers, The 2026-07-28 specification release post: SDK support, migration guidance and the download figure.
- Cloudflare, The next generation of MCP: the stateless design from a server operator's view, and the staged migration (vendor source).
- My own article, How AI Agents Actually Work, explains the tool-calling loop MCP plugs into.
Frequently asked questions
What changed in the MCP 2026-07-28 specification?
It removes protocol-level sessions and the Mcp-Session-Id header and drops the initialize handshake, so MCP is stateless. Every request carries its protocol version and client capabilities in _meta. It also adds server/discover, required Mcp-Method and Mcp-Name headers, Multi Round-Trip Requests, cache hints on list results, and moves Tasks into an extension.
Is the 2026-07-28 MCP spec a breaking change?
Yes. The maintainers describe breaking changes, and modern-only clients do not automatically work with legacy-only servers. Servers that depended on session identifiers face the largest migration cost, and SDKs ship migration notes.
How do I keep state without MCP sessions?
Use explicit, server-minted handles passed as ordinary tool arguments. For example, a create_cart tool returns a handle and later tools take that handle as a parameter, so any server instance can serve the call.
What is deprecated in MCP 2026-07-28?
Roots, Sampling and Logging, the HTTP+SSE transport, certain includeContext values and OAuth Dynamic Client Registration (in favour of Client ID Metadata Documents). Deprecated features keep working for at least twelve months under the new feature lifecycle policy.
Which SDKs support the new MCP spec?
The MCP release post lists the Tier 1 SDKs, TypeScript, Python, Go and C#, as supporting it, with Rust in beta.