You cannot put a load balancer in front of a conversation. That single operational fact, discovered independently by every team that tried to run a Model Context Protocol server for more than one user, is what produced the spec published on July 28 — the largest revision to MCP since it launched [1].
The protocol's original design made a reasonable assumption: one client, one server, one connection that stays open long enough to remember who you are. That assumption was true when MCP servers ran on a developer's laptop next to the editor they were extending. It stopped being true somewhere around the point where, by The Register's count, at least 10,000 MCP servers were deployed and the SDK was pulling over 97 million downloads a month [3]. The protocol had been dragged into production without anyone updating the contract.
The new revision updates it by deleting the part everyone had been working around.
What actually got removed
Two things are gone, and they are the two things every MCP implementation was built on.
The initialize / initialized handshake is retired. So is the Mcp-Session-Id header [1]. Together those defined MCP as a stateful conversation: connect, negotiate, receive an identity, and carry that identity through every subsequent request. The spec now describes something else entirely — a transformation, in its own words, "from a bidirectional stateful protocol into a request/response stateless protocol" [1].
Protocol version and client capabilities no longer arrive once at the start. They ride in the metadata of every request. A new server/discover RPC lets a client ask up front which versions and capabilities a server supports, rather than learning it through a handshake that then has to be remembered [1][2].
The practical difference is that a request now contains everything needed to serve it. Which means any request can go to any instance. Which means the round-robin load balancer works.
Four mechanisms that replace the session
Removing state is easy. Removing state without losing the features that depended on it is the actual work, and it took four separate additions.
Multi Round-Trip Requests. Some server operations genuinely need to ask the client something mid-flight — a credential, a confirmation, a disambiguation. The old design handled this with server-initiated requests over a held-open stream. The new one has the server return resultType: "input_required" along with the responses it needs, and the client comes back with them [1]. The interaction still has multiple rounds. It just no longer requires a socket that survives between them.
Header-based routing. Requests now carry Mcp-Method and Mcp-Name as HTTP headers [1]. This looks like a small thing and is not. A gateway can route an MCP request by reading a header, the way it routes everything else, instead of parsing a JSON body to find out what the request wants. Anyone who has written a proxy rule that had to inspect a payload understands why this matters.
Cacheable list results. tools/list, prompts/list, resources/list, and resources/read now return ttlMs and cacheScope [1]. A client can hold a tool list for as long as the server permits instead of re-fetching it on every connection. Tool lists are the single most repeated payload in MCP traffic and they change rarely — this is the cheapest performance win in the revision.
Tasks became an extension. Long-running operations moved out of the core protocol into io.modelcontextprotocol/tasks, with poll-based tasks/get and tasks/update [1]. Polling is less elegant than a pushed update. It is also the only model that works when there is no session to push into.
The extensions framework is the structural change
One item in the release is easy to skim past and will shape MCP more than anything else in it: the protocol now has a formal extensions framework, and Tasks was the first thing pushed through it [1].
Every successful protocol faces the same pressure. Users need capabilities that not everyone needs, and the core either absorbs them and bloats, or refuses them and gets forked. MCP absorbed for two years — which is how Roots, Sampling, Logging, and Tasks all ended up in a core that a minimal server has no use for. Three of those four are now deprecated and the fourth is an extension.
A formal extension mechanism changes what "supporting MCP" means. A server can implement the stateless core and nothing else and be fully compliant. A client can discover, via server/discover, exactly which extensions it is talking to rather than probing for features and handling failures [1][2]. Capability negotiation moves from convention to protocol.
The risk is the familiar one: extensions are where interoperability goes to die if nobody governs which ones matter. But the alternative — a core that grows every feature any large user requests — is how protocols become impossible to implement from scratch. Given the choice, moving Tasks out was the right call even though polling is a downgrade from pushed updates.
The change that will bite hardest is the one about auth
Buried under the stateless headline is a rewrite of the authorization model, and it will cause more incident tickets than anything else in the release.
RFC 9207 issuer validation is now required. Dynamic Client Registration is out, replaced by Client ID Metadata Documents. Client credentials are bound to the authorization server that issued them, and there is a new application_type parameter for localhost redirects [1].
Read that list as a threat model rather than a changelog. Binding credentials to their issuing server closes token-replay across authorization servers. Requiring issuer validation closes a class of confused-deputy attacks. Moving from DCR to CIMD means a client's identity is a document you can fetch and verify, rather than a registration that happened once and now exists only as a row in someone's database.
Every one of those is a correct security decision. Every one of them also breaks a working deployment.
Twelve months, and a maintainer telling you the truth
The deprecations come with a clock. Roots, Sampling, and Logging are deprecated, along with the legacy HTTP+SSE transport, and the spec commits to keeping deprecated features functional for at least twelve months [1]. That is a real deprecation policy, published alongside the breakage — which is more than most protocols manage.
What is genuinely unusual is how the lead maintainer described the cost. David Soria Parra called this the "most substantial changes since adding authorization" and said plainly that "if you built your own implementation, it's going to be a lot of uplift to make this correct" [3].
That is not marketing language. It is a maintainer telling a large installed base that the next few weeks will hurt, and it deserves to be taken at face value. Servers on the new revision may not work with older clients, and vice versa [3]. If you wrote your own MCP implementation rather than using an SDK, you own that uplift.
The SDK path is considerably gentler. TypeScript, Python, Go, and C# are all Tier 1 and updated; the Rust SDK is in beta [1]. The scale of that SDK layer is also the reason the spec could not simply break and move on: the MCP blog puts Tier 1 SDK usage at close to half a billion downloads a month, with TypeScript and Python each past a billion downloads in total [1]. A protocol with that footprint gets exactly one chance to do a breaking change properly.
The obvious pushback
The reasonable objection is that this is churn. MCP is barely two years old, has enormous adoption, and just invalidated a large fraction of the code written against it. Protocols are supposed to be the stable layer.
The objection is half right, and the half it gets wrong is instructive. Stateless was not a stylistic preference — it was the only way to make MCP survive contact with the infrastructure people were already running it on. Sessions were being terminated by load balancers, re-established constantly, and worked around with sticky routing that nobody wanted to maintain. The Register's reporting is blunt about the original spec's failure to adequately define how sessions should be preserved at all [3]. The state was already unreliable in practice. The revision deletes a guarantee that was not being kept.
The fair criticism is timing, not direction. This change would have been nearly free eighteen months ago and is expensive now. That is the cost of a protocol succeeding faster than it stabilized.
What to do this week
Triage by how you built.
If you consume MCP through a Tier 1 SDK, your migration is a dependency bump and a test pass. Do it early, not because it is urgent but because the version-skew window between new servers and old clients is where the confusing bugs live.
If you wrote your own client or server, start with session identifiers. Every place your code stores, reads, or forwards Mcp-Session-Id is a place that now needs to carry per-request metadata instead. That refactor is mechanical but wide, and it touches error handling in ways that are easy to miss.
If you operate MCP servers at any scale, the header routing and TTL fields are the immediate wins — a gateway rule on Mcp-Method and a client that respects ttlMs will cut load before you finish the rest of the migration.
And if you maintain anything that touches auth, treat the CIMD move as a project rather than a task. Credential binding and issuer validation change how clients are provisioned, not just how requests are signed.
MCP spent two years being the protocol that made agents useful and one week becoming the protocol that can be operated. Those are different achievements, and the second one is the one that decides whether it is still here in five years.
References
[1] David Soria Parra and Den Delimarsky, Model Context Protocol — The 2026-07-28 Specification — (2026-07-28). Blog
[2] Model Context Protocol — Model Context Protocol Specification, version 2026-07-28 — (2026-07-28). Documentation
[3] Joab Jackson, The Register — Model Context Protocol prepares to break with its stateful past — (2026-07-23). Article