The 2026-07-28 revision of the Model Context Protocol deleted the two things that made an MCP server stateful: the initialize/initialized handshake and the Mcp-Session-Id header. A remote server can now sit behind a plain round-robin load balancer with no shared session store — a genuine operational win. But "stateless" describes the wire, not the system. The session's bookkeeping did not vanish; it moved onto every request and into your application. And the durability that long-running agents actually need came straight back through a new extension. Read the pivot as a relocation of state, not a deletion of it, and the migration gets a lot less surprising.
What changed
The headline of the 2026-07-28 spec is a stateless protocol core. Previously an MCP client opened a session with an initialize exchange, received an Mcp-Session-Id, and every later request rode on that session — which meant the transport was stateful and the infrastructure had to keep a client pinned to the server instance that held its session. That handshake and that header are both gone. Every request now carries its own protocol version, client identity, and capabilities inline, so any request can land on any instance.
| Concern | Before (stateful core) | After (2026-07-28) |
|---|---|---|
| Session setup | initialize / initialized handshake | None — every request is self-describing |
| Session identity | Mcp-Session-Id header | Removed |
| Per-request metadata | Negotiated once at init | MCP-Protocol-Version, Mcp-Method, Mcp-Name, and a _meta object carrying clientInfo |
| Capability discovery | Returned by the handshake | Optional server/discover call, or cached by the client |
| Load balancing | Sticky sessions, shared session store | Plain round-robin, route on Mcp-Method |
Alongside the stateless core, the revision formalised an extensions framework (Tasks and MCP Apps join the existing Enterprise Managed Authorization), hardened authorization, and — quietly the most useful line for anyone operating a server — added a formal deprecation policy with a twelve-month minimum window. Roots, Sampling, and Logging are the first features to go on that clock.
The operational win is real
If you have ever run a stateful remote server at scale, the appeal is immediate. Sticky routing is a tax that shows up everywhere: the load balancer needs session affinity, a restarted instance drops every session pinned to it, autoscaling has to drain rather than just terminate, and a shared session store becomes a availability dependency of its own. A self-describing request removes all of it. Any instance can serve any call, a deploy is a rolling restart with no session migration, and the gateway can route on the Mcp-Method header without cracking open the body. For a server that is mostly tools/list and tools/call, this is the difference between running like a normal HTTP API and running like a WebSocket fleet.
None of that is marketing. It is the same reason REST APIs are stateless: statelessness at the transport is what lets horizontal scale be boring. The mistake is to conclude that because the transport forgot the session, the system no longer has one.
Statelessness is a property of the wire, not of the problem
A protocol can be stateless while the interaction it carries is not. The client still needs to know which protocol version and capabilities are in play; the spec's answer is that this now travels inline on every request, in _meta and the new headers, instead of being agreed once. That is not less state — it is the same state, re-sent, with the client responsible for carrying it and, if it wants to avoid a discovery round-trip, for caching the server's capabilities itself.
So the ledger of who-holds-what shifted rather than shrank:
This is a familiar trade, and usually a good one: a simpler core with more responsibility at the edges. But it is worth being honest that the edges are now yours. The server no longer remembers your client between calls, which means anything the interaction needs to remember — a multi-step negotiation, a partially built request, the fact that this is the same agent as a second ago — is your application's job to thread through, or the extensions' job to hold.
Tasks bought the durability back — as handles
The clearest evidence that the state did not disappear is that the spec had to add a place to put it. Tasks — one of the first official extensions, contributed by AWS — moved out of the experimental core into io.modelcontextprotocol/tasks specifically to support reliable, long-running agents. A long-running tool call is the most stateful thing MCP does: you start work, you come back later, you expect it to still be there. A stateless core cannot express that on its own, so Tasks does, with poll-based tasks/get and tasks/update calls and an opt-in subscriptions/listen stream for change notifications.
The mechanism is the tell. The protocol stays stateless because the state lives behind an explicit handle: a tool returns a task handle, the client stores it, and passes it back to poll or update. The durable work is real and server-side; what makes it compatible with a stateless wire is that the reference to it is a value the client carries, exactly like the _meta block carries the session facts. The pattern is consistent across the whole revision — the model of "server remembers you" was replaced everywhere by "you carry a reference the server can resolve."
This is a better design than a stateful core that tried to serve both the trivial tools/list call and the hour-long agent job with one session model. But "MCP is stateless now" is a half-sentence. The full one is: the core is stateless, durability is an opt-in extension, and cross-call context is a client responsibility — three answers where there used to be one, each better suited to its job, and none of them free.
The parts that will bite quietly
The stateless pivot is what everyone will talk about, but two less-loud changes in the same revision are the ones likely to break a real deployment.
- Authorization hardening changes correct clients. Authorization servers must now return the
issparameter per RFC 9207 and clients must validate it before redeeming an authorization code — a real fix for authorization-server mix-up attacks, and a behavioural requirement your client either meets or fails. Dynamic Client Registration is now formally deprecated in favour of Client ID Metadata Documents (CIMD), though DCR still works for now, and credentials are bound to their issuing authorization server so you cannot reuse them across servers. - The deprecation clock is now a feature you can plan against — if you read it. A twelve-month minimum window is a gift compared to the old "it changed, react" cadence, but Roots, Sampling, and Logging are already on it. If your server or client leans on any of the three, the migration is now dated, and pretending it is not just means doing it in a hurry later.
Neither of these is a stateless-core problem; both ride in on the same revision, and both are the kind of change that passes CI and fails in production against a real authorization server or an old feature you forgot you used.
What to actually do
If you run an MCP server
Audit for session assumptions before you upgrade — anything that expected a client to be pinned to an instance, or that stashed per-client state keyed by session id, has to move to a shared store the client addresses by handle, or go away. The reward is that once it does, you can drop sticky routing and the session store entirely and run the server like a normal stateless service. Decide separately whether you need the Tasks extension: if your tools are fast request/response calls you may never touch it; if you expose long-running work, adopt it rather than reinventing durable jobs on the side.
If you build an MCP client or host
Your client now owns capability caching and the per-request metadata it used to receive once. Implement the iss validation now — it is not optional for a correct OAuth flow — and plan the move from DCR to CIMD on the twelve-month clock rather than the day it is removed. If you rely on Roots, Sampling, or Logging, put the migration on a roadmap with a date, because the spec now gives you one.
If you are choosing an MCP stack
Prefer implementations that already speak 2026-07-28 and ship it in their SDKs — the release came with updated TypeScript, Python, Go, and C# SDKs, so "supports the latest spec" is a checkable claim, not a promise. And treat statelessness as the operational feature it is, not as a reason to skip designing where your interaction's state will live. It will live somewhere; the only question the spec settled is that it will not be in the core.
The durable principle: a protocol going stateless relocates state, it does not remove it. The 2026-07-28 core is genuinely simpler to operate, and that simplicity is worth taking. But the session's job got redistributed — inline onto every request, into the Tasks extension as handles, and into your application as cross-call context — and the teams that get burned will be the ones who read "stateless" as "I no longer have to think about state." You do; you just get to choose where it lives now.
FAQ
Does upgrading to the 2026-07-28 spec break my existing MCP integration?
It can. The removed initialize handshake and Mcp-Session-Id header mean any client or server that assumed a persistent session must change, and the new iss validation is a hard requirement for a correct OAuth flow. Fast tool servers and simple clients port easily; anything that stored per-session state, or relied on Dynamic Client Registration, needs work.
Is a stateless protocol just worse for long-running agents?
No — that is what the Tasks extension is for. Long-running work stays durable and server-side; the stateless core is compatible with it because the client holds a task handle and polls or subscribes, rather than the server keeping the client pinned. You get durability without sticky sessions.
Do I have to adopt the Tasks extension?
Only if you expose long-running work. If your server is fast request/response tool calls, the stateless core alone is enough and you may never touch Tasks. Extensions are opt-in by design; the point of moving Tasks out of the core was so servers that do not need it do not carry it.
What is the practical benefit of dropping the session handshake?
A remote server can run behind a plain round-robin load balancer with no session affinity and no shared session store, route on the Mcp-Method header without parsing the body, and treat a deploy as an ordinary rolling restart. It is the same reason stateless REST APIs are easier to scale than stateful connections.
What is CIMD and why is DCR deprecated?
Client ID Metadata Documents let a client be identified by a URL that resolves to its metadata, rather than registering dynamically with each authorization server (Dynamic Client Registration). DCR still works for backward compatibility but is now formally deprecated; combined with binding credentials to their issuing server, the change closes a set of client-registration and mix-up weaknesses.
Further reading
On this wiki:
- What is the Model Context Protocol? — the model, hosts, clients and servers.
- Streamable HTTP: the current MCP transport — the transport this revision reshapes.
- MCP Auth: the OAuth 2.1 profile — the base the authorization hardening builds on.
- MCP Ops in Production — running servers, now without sticky sessions.
- Durable State & Resumability — the pattern Tasks formalises.