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