MCP threw sessions away — and it is the most honest move in the spec
The 2026-07-28 release removed the initialization handshake and the session header. What you lost was not elegance, it was glue. Here is what changed and how to migrate.
Bu yazının Türkçesi: Türkçe sürüm.
The 28 July 2026 release of the Model Context Protocol is out, and I think it contains the most notable protocol decision of the last two years: sessions are gone.
This should be read not as "a new feature shipped" but as "an old mistake was admitted". Below: what changed, why, and what you need to touch in your code.
What it used to be
MCP's original design behaved like a connection protocol. The client connects, sends initialize, the server declares its capabilities, the client confirms with initialized, and then the conversation begins. State in between was carried in the Mcp-Session-Id header.
That is perfectly sensible for a socket protocol. The problem is that MCP servers run over HTTP, and HTTP is stateless. The protocol was asking for something contrary to the nature of its own transport, and closing that gap was dumped on the operations side:
- Your load balancer needed sticky sessions, or the second request landed on a server that had no state.
- Horizontal scaling meant either moving sessions into a shared store or having each instance keep its own.
- Putting an MCP server in a serverless function was awkward from the start; every invocation is a fresh instance.
- Restarting the server dropped every open session.
None of this was framed as the protocol's fault. The advice was "configure your infrastructure correctly". The new release accepts that this was not sustainable.
What it is now
From the release announcement, the breaking changes in summary:
| Before | Now |
|---|---|
initialize and initialized handshake | Gone. Each request travels on its own |
Mcp-Session-Id header | Removed |
| Capabilities learned during the handshake | Every request carries protocol version, client identity and capabilities in _meta |
| Routing required parsing the JSON body | Mcp-Method and Mcp-Name HTTP headers are required |
| Held-open streams for server-initiated requests | Multi round-trip requests (MRTR) |
Or, in the announcement's own framing: the same request can now be answered by any server instance behind the scenes.
The consequence is that your MCP server is now an ordinary HTTP service. Put any load balancer in front of it, no stickiness required. Restarting drops nothing. You can put it in a Lambda. If a client does want capabilities up front, there is an optional server/discover call — but it is not mandatory.
Why the Mcp-Method header matters so much
The most boring-looking item on that list is actually the most practical one. Previously, understanding what an MCP request was doing required parsing the JSON body. Which meant every intervening layer — API gateway, router, rate limiter, logger — had to read the body.
Now the method and the name sit in HTTP headers. Which means:
- A load balancer can route
tools/callto heavy machines andtools/listto cheap ones. - You can rate limit per tool: cap an expensive tool at three per minute, leave listing calls alone.
- An access log can record which tool was invoked without ever opening the body. Sensitive data stays in the body.
All of this was possible before, but each of them needed bespoke code. Now it is a matter of looking at a standard HTTP header. This is the change that lifts the protocol out of "its own ecosystem" and drops it inside the network infrastructure that already exists.
Cacheable list results
A less-discussed change that lands directly on your bill: responses to tools/list, prompts/list, resources/list and resources/read can now carry ttlMs and cacheScope.
I costed out why that matters in the post on the hidden token bill of agent tools: tool definitions are re-sent on every turn, and across an agent loop that line item is bigger than you think. A server being able to say "you may keep this list for ten minutes" is a standard way to cut that repetition on the client side. It is a non-breaking change, but one of the few with a monetary effect.
Deprecations
This release retired a good deal. All of it has a minimum twelve-month transition, so nothing breaks tomorrow:
| What | What replaces it |
|---|---|
| Dynamic Client Registration (DCR) | Client ID Metadata Documents (CIMD) |
| Roots, Sampling, Logging | Keep working for at least 12 months |
| Legacy HTTP+SSE transport | One-year transition period |
| Tasks in the experimental core | The io.modelcontextprotocol/tasks extension |
On the authorization side there are two tightenings: authorization servers must return the iss parameter per RFC 9207, and application_type is now required during dynamic registration. Credentials are also bound to their issuing authorization server — so taking a token from one server and using it somewhere else is closed off.
Moving Tasks from the core into an extension makes sense to me. Putting long-running work in the protocol core meant loading the core with all of that work's mess: retries, how long results are kept. The 2026 roadmap says those questions will be handled on the extension side.
There is also a gain that gets missed during migration: because _meta now carries client identity and capabilities, the answer to "what does this client support" is in your hand on every request. You used to have to remember it from the handshake. Handling version compatibility per request is now easier, not harder.
What to do
If you operate an MCP server, this would be my order:
- Find your session dependencies first. Grep for every occurrence of
Mcp-Session-Id. Any state you hang off a session has to move either into the request or into a shared store. This is the long part of the migration. - Add the routing headers.
Mcp-MethodandMcp-Nameare required. Once they are in, you can strip body parsing out of your gateway. - Put
ttlMson list responses. Non-breaking, one line, direct token savings. - If you use DCR, schedule the move to CIMD. It still works today, but backward compatibility is not permanent.
- Drop the legacy SSE transport. A one-year transition sounds long; this kind of work gets remembered in month eleven.
My take
In protocol design, holding state always looks more elegant. You shake hands once, every subsequent request is smaller, nothing repeats. Clean on paper.
But in a distributed system state has a price, and the person paying it is not the person who wrote the protocol — it is the person operating it. MCP's first shape quietly pushed that price onto operations. The new release accepts carrying a little more data on every request — a little more waste, in theory — and in exchange makes the whole stickiness problem disappear.
That trade looks right to me. Sending a few hundred extra bytes over the wire is not a problem in 2026; failing to configure sticky sessions correctly is a real one. And a specification walking back its own original design is not something you see often. Credit where it is due.
Advertise on this blog, or work with us
MCALAB is an independent studio. For sponsorship, cross-promotion or a partnership:
ads@mcalab.com.trDetails: Advertise & partner. For user support, see the support page.