Skip to content
Brian Sithu
Go back

HTTP for agents, sessions for nothing

Cover image for HTTP for agents, sessions for nothing

MCP deleted its session handshake, so every agent tool call is now a plain stateless request, and I would build for that.

Brian Sithu

Written by

Brian Sithu

View profile

On this page

03 sections

Late July, the MCP consortium shipped the biggest change to the agent protocol since MCP itself, and almost nobody outside the spec crowd noticed. Spec version 2026-07-28 deletes the session. The initialize/initialized handshake is gone, and the Mcp-Session-Id header with it. Every request now stands alone. The consortium says each one carries its protocol version, the client identity, and client capabilities in its metadata, and there is a new server/discover call for clients that want capabilities up front, but using it is optional.

The sentence that matters is this one. The consortium says any request can now land on any instance behind a plain round-robin load balancer, with no shared storage. That turns an MCP server from a stateful protocol endpoint into an ordinary HTTP service. Sticky routing, session replay, and held-open streams all drop out of the deployment picture at once.

Before, every call leaned on a handshake and a session pinned to one server; after, each request stands alone and any instance can answer

Route on headers

If I were putting an MCP server behind infrastructure today, I would start with the headers. Method and tool names now travel in Mcp-Method and Mcp-Name, so a gateway can route and authorize without parsing a single JSON body. That is the normal web playbook, and it is why I read this release as MCP growing up. The exotic transport is gone. Everything I already know about running HTTP at scale applies again.

The callback problem

The harder problem was the reverse direction. Tools sometimes need something mid-call: a confirmation, a missing parameter. The old answer was a server-initiated request back down the open stream, which is exactly the thing statelessness kills. The new answer is the multi-round-trip request. The server replies with input_required plus the questions it needs answered, and the client retries the original call with the answers attached. Nobody holds a connection open. The client always drives.

A tool that needs input no longer calls back; it answers input_required, and the client retries with the answers attached

I am guessing at the failure modes here, since I have not run this in production, but the retry shape has one property I already like: every round trip is a normal request, so it retries, times out, and load-balances like everything else. My guess is the pain moves to idempotency, because a retried call that already did half its work needs the server to recognize the second attempt. I would check how the SDKs mark retried calls before building anything long-running on top of this.

State moves up a layer

Dropping the transport session does not mean the server remembers nothing. It means state moves up a layer, into the application. The consortium’s suggested pattern is to mint an explicit handle from a tool and have the model pass it back as an argument on later calls. I like this better than sessions for one reason: the model can see the handle. State hidden in the transport was invisible to the thing actually driving the loop. A handle threaded between tools is state the agent can reason about, keep, or drop.

Two smaller changes compound the same way. List responses now carry cache hints and a deterministic order, so clients can cache tool catalogs and keep upstream prompt caches stable across reconnects. I would cache tool lists aggressively from day one. A catalog that barely changes should not be refetched constantly. And authorization gets real hardening, with issuer validation and a formal move away from dynamic client registration toward client metadata documents. Long-running work moves to a Tasks extension. Roots, Sampling, and Logging are deprecated, with a twelve-month minimum window the consortium now guarantees as policy, and the legacy HTTP+SSE transport gets the same year-long offramp.

So here is my migration-day list, in the order I would work it. Kill the handshake and stop storing session ids. Route and authorize on the new headers. Rework any server-initiated flow into retries. Cache the list endpoints. Move client registration to metadata documents. None of this is subtle, which is the compliment. It is ordinary web work now.

The opinion, stated plainly: this is the second time the boring wire protocol won. The first was plain request/response HTTP outlasting every stateful bidirectional scheme the enterprise world threw at it. Sessions felt correct, and statelessness felt like giving something up, right until everyone tried to scale the correct thing. If you spent this year building session-adjacent MCP middleware, sticky routers and session stores and replay layers, I would treat that code as dead. The tool surface of an agent is a web service now. Build it like one.



Previous Post
Postgres was right all along
Next Post
Price by thinking, not by token