Back
8 min read

MCP Went Stateless: What Breaks in 2026-07-28

The largest MCP revision since launch removes the initialize handshake and the session header, deprecates Roots, Sampling and Logging, and replaces server-initiated calls with a retry. Here is the actual list, and what it costs to migrate.

MCPAICloudSystems

The 2026-07-28 MCP specification is out, and it is not a point release. It rewrites the transport, deletes the handshake, deprecates three features that have been in the protocol since launch, and inverts how a server asks a client for anything.

If you have shipped an MCP server, this is the revision that will cost you a weekend. Here is what actually changed, in the order it will hit you.

Background, if you need it: what MCP is and why it exists.

1. The handshake is gone

Removed: the initialize / initialized exchange. Removed: the Mcp-Session-Id header. Removed: the protocol-level session model entirely.

This is the change everything else hangs off. Previously a client opened a connection, negotiated protocol version and capabilities once, got a session id back, and every subsequent request rode that session. The server held state about who it was talking to.

Now every request is self-describing. Protocol version, client identity and capabilities travel in a _meta field on the request itself. There is no negotiation step and nothing to resume.

The practical consequence is the point of the whole release: any server instance can answer any request. No sticky sessions, no session affinity in the load balancer, no shared session store between replicas. An MCP server becomes an ordinary stateless HTTP service, which is what most infrastructure is already built to run.

Capability discovery is now an explicit call rather than a side effect of connecting. Servers MUST implement a new server/discover RPC advertising their supported protocol versions, capabilities and identity; clients MAY call it before anything else, or use it as a backward-compatibility probe on STDIO. So the obligation did not go away, it moved: discovery used to be mandatory and implicit for both sides, and is now mandatory to offer and optional to ask for.

2. Servers can no longer call you

Multi Round-Trip Requests (MRTR) replaces elicitation/create, sampling/createMessage and roots/list.

Under the old model, a server handling your tool call could turn around mid-flight and issue its own request back at the client: ask the user a question, ask the model for a completion, ask for the filesystem roots. That required a live bidirectional channel, which required a session, which is exactly what was just deleted.

The replacement is a retry loop. The server returns a normal result with resultType: "input_required" and a list of what it needs. The client gathers the answers and calls the original tool again, this time with an inputResponses field.

Two things follow that are easy to miss.

Your tool handler must now be re-entrant. It will be invoked more than once for what the user experiences as one action. If your handler has side effects before the point where it asks for input, those side effects happen twice. Anything that writes, charges, sends or increments before an input request is now a bug.

Any state between the ask and the answer is yours to carry. The protocol will not hold it for you. Either recompute it on the retry or round-trip it through the request.

3. Three features are on the way out

Deprecated, with a stated minimum twelve-month offramp:

  • Roots - the client telling the server which directories or URIs it is scoped to
  • Sampling - the server asking the client's model for a completion
  • Logging - server-to-client log messages
  • The legacy HTTP+SSE transport
  • Dynamic Client Registration, in favour of Client ID Metadata Documents

Twelve months is real breathing room, and the deprecations are consistent rather than arbitrary. Roots and Sampling both needed the server to initiate; Logging needed a persistent stream to push into. All three were casualties of the same decision.

Dynamic Client Registration is a different case. It is being replaced rather than removed, and the replacement is better: Client ID Metadata Documents let a client be identified by a document it hosts at a URL rather than by a record it registered with each authorization server in advance.

4. Routing headers are now required

Two new required headers: Mcp-Method and Mcp-Name.

They duplicate what is already in the JSON-RPC body. That is deliberate. A gateway, a WAF or a proxy can now route, rate-limit or block a request by looking at headers alone, without parsing a JSON body it may not be allowed to read.

This is a small change with a large operational payoff. Per-tool rate limits at the edge, method-level access rules in the WAF, and useful request routing all become possible without putting a JSON parser in the hot path. If you run MCP behind any kind of gateway, this is the feature to actually use.

Cheap and worth doing on day one: log both headers. Per-tool call volume stops requiring body inspection.

5. List results are cacheable

Responses from tools/list, prompts/list, resources/list, resources/read and resources/templates/list now carry two required fields: ttlMs and cacheScope.

The tool list was being re-fetched constantly under the old model and it almost never changed. Now the server declares how long the answer is good for and who may share it. Set these honestly. A long TTL on a tool list that changes on deploy will serve stale tools to clients that have no way of knowing.

Note that resources/read is on that list, not just the list endpoints. Cacheable resource reads is the bigger win of the two.

Pair it with a quieter line in the same revision: servers SHOULD return tools from tools/list in a deterministic order, explicitly to enable client-side caching and improve prompt cache hit rates. If your server builds its tool list by iterating a map, you are defeating both.

6. Authorization got stricter

  • RFC 9207 iss validation is now required. The authorization response must identify its issuer and the client must check it. This closes a mix-up attack where a response from one authorization server is accepted as though it came from another.
  • Client credentials are bound to the issuing authorization server. A credential minted by one server is not valid at another.
  • An application_type parameter was added so localhost redirects work properly during development.

None of this is optional and none of it is difficult. It is the kind of hardening that arrives once a protocol has enough deployments to be worth attacking.

7. Tasks moved out of the core

The Tasks feature left the experimental core and became a formal extension, io.modelcontextprotocol/tasks, with tasks/get for polling and a new tasks/update method. Change notifications go through a subscriptions/listen stream.

More importantly, this release establishes a formal extensions framework. Tasks, MCP Apps and Enterprise Managed Authorization are its first residents.

That framework is the structural change worth watching. It gives the core spec a way to stay small while letting genuinely useful but non-universal features ship on their own timeline. MCP Apps, which lets a server ship an interactive HTML interface that the host renders in a sandboxed iframe, is the clearest example of something that should never have been core and now does not have to be.

What this costs you

Rough order, for an existing server:

  1. Drop the handshake. Read version and capabilities from _meta per request. Usually small.
  2. Delete your session store. Usually a relief.
  3. Add the two headers. Trivial on the server; check your client library sends them.
  4. Rewrite anything that called back to the client. This is the real work. If you used elicitation or sampling, budget properly, and audit for side effects before the input request.
  5. Set ttlMs and cacheScope. Ten minutes, immediate benefit.
  6. Update the auth checks. Mechanical.
  7. Move Tasks to the extension. Only if you used it.

Tier 1 SDKs for TypeScript, Python, Go and C# shipped with the spec. Rust is in beta.

The one-line summary

MCP stopped being a conversation and became a series of letters, each with its own return address.

Everything in this release follows from that. The handshake went because a letter does not need one. Server-initiated calls went because a letter cannot interrupt you. Roots, Sampling and Logging went because all three depended on the server being able to speak first. Caching and routing headers arrived because stateless requests are the kind of thing ordinary HTTP infrastructure already knows how to handle well.

It is a real break, and it is the right one. The protocol was carrying a session model that most deployments were paying for and few were using, and it made every MCP server harder to run than it needed to be. Serving one is now a solved infrastructure problem rather than a special case.

If you are standing one up from scratch, the deployment shape is simpler than it was: running an MCP server on an Azure Function App.

Sources: the 2026-07-28 specification and the release announcement.

ShareEmailLinkedIn