Vollständiges Transkript anzeigen (1.539 Wörter)
MCP just shipped its biggest change since it launched, and the headline is the entire protocol is now stateless, as it probably should have been from the start. There's no more handshakes, no more session IDs, everything just got way simpler, except for upgrading, because there's been a lot of deprecations and breaking changes in here. So let's jump in and see what's changed.
I'll start by giving you some context on the old version of MCP, the stateful version, and why this caused so much pain. The old flow went like this: the client posts initialize to your MCP endpoint, and your server would then mint a session ID and send that back. Every follower request would then have to carry that session ID, and that meant the session ID pins the client to whichever server instance issued it, and that is the part that caused all of the issues.
Say you had a load balancer, and you scaled your MCP server up to three instances. The next request that comes in gets routed to a different instance than the one that ran initialize, and that instance had never heard of the session before. You would end up with a 400 session not found error. The same thing could happen if one of those pods went down. The session state would simply be lost, and every request after would fail. Now, obviously, there were workarounds for this. You could use sticky sessions so the client always hits the same instance, or you could have a shared Redis instance so every session can be looked up. But those just added unnecessary complexity and also latency and costs.
Something that doesn't cost you anything is subscribing. If you want to stay up-to-date with developer and AI news, it really helps us out. So those were the problems with stateful MCP, and this is what the new spec has fixed. The spec is called 2026-07-28 because MCP versions are actually dates, and it has two key proposals in it. SEP-2575 removes the initialize and initialized handshake, and SEP-2567 removes the MCP session ID header and the protocol-level session that came with it. This means that the handshake is gone, and from a protocol level, every single request is completely independent now. These changes make the code for an MCP tool call go from something like this, with initialize and session headers, to this, a single self-contained request. It is much, much simpler. And it also solves all of our earlier pain points.
We can now use standard round-robin routing because any container can now handle any request. So we can use a completely traditional load balancer, and we don't need a Redis instance sat there holding our sessions. So if a server does crash or gets restarted, the load balancer can just send the request to the next working instance, and the client never notices. But the best advantage for me is in deployment. On something like Cloudflare Workers or Google Cloud Run, the server doesn't need to be up 24/7 anymore, since there's no connections to hold open. So it can scale down to zero when no one's using it, which should save you a bit of money and also just give you way more deployment options.
On Cloudflare's own post about this, they say that MCP no longer requires Durable Objects to speak the protocol. So everything is getting way simpler, and the new spec is basically just MCP built on top of normal HTTP infrastructure, which everyone already knows how to deal with. In fact, talking about HTTP, there's also two other changes that have been inspired by it. Previously, all of the MCP information lived inside the JSON body of a request, but now there's two new HTTP headers, MCP method and MCP name. And this means that a gateway, rate limiter, or firewall can make decisions using those headers without having to parse the JSON. So it should help reduce some latency. They also added time to live and cache scope hints to tool, prompt, and resource list calls, again modeled on HTTP caching. So now a client should know exactly how long a tool list is fresh for and whether it's safe to share across users. It doesn't need a persistent connection to stay up-to-date anymore.
Now you might be wondering where all of that handshake information actually went, as it wasn't useless information. The server might still need to know what protocol version you're on and what your client can do. But this information now just rides along on a meta field within the JSON of a single request. So the server can simply read that to understand what the client can do. And if a client wants to know what a server can do, there's now a new optional method called server discover that returns that information.
So far then, we've seen a lot of simplification, but you still might have two questions. First, what if you actually wanted state, and second, if there's no persistent connection, how does the server ask the client something, like a follow-up question? Well, I'll start with question one: what if you actually wanted some state, and guess what? You just do this the same way that HTTP APIs have done it for as long as they've existed. You could have a tool mint an explicit handle, something like basket ID or browser ID, and then the model just passes this back as an ordinary argument on the later tool calls. So now it's completely up to you how you manage the state and not the protocol, which is a way more flexible approach. And it's worth noting, authorization still works, and they've actually done a lot of work hardening it in this update as well.
As for the second question, what if the server wants to send a follow-up question, like "are you sure"? Well, the old way needed a constant open stream to send that message down to the client. This actually meant that the user could be prompted out of nowhere without having asked for anything, which is a pretty bad experience and also a possible security problem. So in this new spec, they've completely rebuilt the workflow as a multi-round-trip request. So say I had a tool that deleted a file on some cloud provider and I called it. Instead of pushing a follow-up question to me, the server actually returns an input required result and attached to that is a request state payload, which is all of the context for that call serialized. This input required result can actually be something as simple as "are you sure," typed as a boolean. And this will prompt the client to ask me. And when I answer, the client then re-issues the original call, but this time with my input responses attached and it also echoes that request state back. That request state actually contains all of the context needed to resume this work, which means that any instance on my load balancer can actually pick this up and retry it, and it doesn't have to be the one that initially requested the answer.
But what about a tool call that takes a long time? You don't want it to be holding that connection open and blocking the entire conversation. Well, this is why they've graduated tasks from experimental to an official extension. Let's say we have a tool for processing a refund, and this is a task that takes a while. You would simply write that task state into a database somewhere as working and kick off the async job, and then immediately return a response for that tool call, telling the agent and the user that it's running. From here, the client can then poll that tool call with tasks/get or subscribe with subscriptions/listen to track its progress and pull in the final result when it's done.
So those are the key changes that make MCP stateless now, and as I mentioned in the intro, this comes with a lot of breaking changes and deprecations. They have said though that all of these features will have a minimum of 12 months in deprecation before they're officially removed. So there is still some time to update your servers. And talking about updating, all of the SDKs now support this spec, with most of them having a major version bump up to version two. And if you use TypeScript like me, they've actually replaced the monolithic SDK package with modular libraries, one for the server and one for the client, and they also made a codemod that handles the standard API renames for you. Obviously, though, we have seen a lot of changes in this update, so it's not going to be a simple update the package and leave. But all of these changes are genuinely worth making as it feels like a great reset for MCP, doing things the way they should have been done from the start, and I'm pretty excited to see how much further MCP goes. What do you think? Let me know in the comments down below, or you're there. Subscribe, and as always, see you in the next one.