MCP Goes Stateless — What It Means for Your Gateway
MCP is stateless now — at its protocol core. On July 28, 2026 the Model Context Protocol shipped 2026-07-28 — the revision its maintainers call the most important since remote MCP launched, and the start of a countdown. If you operate MCP servers, three capabilities your setup may quietly rely on — Sampling, Roots, and protocol Logging — are now deprecated, with removal possible after twelve months. Protocol sessions are gone entirely: every request now stands on its own.
This post answers three operator questions: what actually changed, what to check in your own MCP estate while the clock runs, and why the new spec — read closely — assumes there is a gateway between your agents and your servers. The spec-level detail, every breaking change with its SEP reference, waits in the reference table at the end of this post.
What changed, in plain terms
Section titled “What changed, in plain terms”The release post explains the pressure behind the revision: the maintainers report close to half a billion SDK downloads per month across the Tier 1 SDKs. At that scale a protocol inherits infrastructure problems, and MCP’s biggest one was the session. A client was pinned to whichever server instance held its session — load balancers needed sticky sessions, deployments had to drain them, and serverless platforms fought the protocol at every step.
The 2026-07-28 changelog answers with four moves:
- Sessions and the
initializehandshake are gone. Version, identity, and capabilities travel inside each request, so any request can land on any instance behind a plain round-robin load balancer. - Two routing headers become mandatory. Every Streamable HTTP request carries
Mcp-Method(what is being called); tool calls also carryMcp-Name(which tool). The point: infrastructure between client and server can route, rate-limit, and meter MCP traffic without opening the JSON body. - Servers no longer send their own JSON-RPC requests to clients. The old server-initiated pattern behind Sampling, Elicitation, and Roots is replaced by Multi Round-Trip Requests (MRTR): the server answers “I need more input” (
input_required), and the client retries the request with the answer attached. Notifications survive — request-scoped ones flow on the response stream, and one long-livedsubscriptions/listenstream carries the change notifications a client opts in to. One misreading to avoid: Elicitation is not deprecated — only its server-initiated form is gone; elicitation itself lives on inside MRTR. - Deprecation becomes policy, not habit. Roots, Sampling, and Logging keep working for at least twelve months, but new implementations should not adopt them. The new feature lifecycle guarantees the window; only an actively exploited security risk can shorten it, and never below ninety days.
Sessions are gone — where did the state go?
Section titled “Sessions are gone — where did the state go?”Stateless is a statement about the protocol, not about your application. The changelog says where cross-call state goes now: servers that need it “use explicit, server-minted handles passed as ordinary tool arguments” (SEP-2567). Your database cursor, your SSH session, your half-finished workflow — none of that disappeared. It moved up a layer, out of the transport and into the application. Something up there now has to mint those handles, store what they point to, expire them, and decide who may use them.
Hold that thought. First, the practical part.
Which of your MCP servers use deprecated capabilities?
Section titled “Which of your MCP servers use deprecated capabilities?”The twelve-month clock started on July 28. Whether you run three MCP servers or thirty, the transition is an audit before it is a migration:
- Transports. Which servers still speak the 2024-11-05 HTTP+SSE transport? It is formally deprecated; Streamable HTTP is the target.
- Sampling. Which servers call
sampling/createMessage? The documented migration is direct integration with an LLM provider API — a real architecture decision (whose key, whose budget, whose logs), not a search-and-replace. - Roots. Which servers expect
roots/list? Migration: pass directories and files as tool parameters, resource URIs, or server configuration. - Logging. Which servers rely on
logging/setLevelandnotifications/message? Note thatlogging/setLevelis removed outright in 2026-07-28 — log level moves into each request’s_meta. Migration:stderron stdio, or OpenTelemetry. - Sessions. What breaks when
Mcp-Session-Iddisappears? Sticky-session load balancer rules, every tool that assumes implicit per-connection state — and interrupted SSE streams, which are no longer resumed viaLast-Event-IDbut simply re-requested. Redesign around explicit handles. - Auth. Dynamic Client Registration is deprecated in favor of Client ID Metadata Documents (CIMD); clients must validate a present
issparameter (RFC 9207). - SDKs. The Tier 1 SDKs (TypeScript, Python, Go, C#) already speak 2026-07-28; they must mark deprecated API surfaces and should warn at runtime when one is used. Treat those warnings as inventory data, not noise.
The practical problem: answering “which servers?” means observing capability usage across your whole estate. That is awkward server by server — and natural at a chokepoint. A gateway terminates every client connection, so it is the one place where deprecated-capability usage shows up as data, per backend and per client, and where a bridge between spec versions can live during the window. We made the broader visibility argument in Why MCP Gateways Alone Don’t Solve the Real Problem: the gateway is where you see; what you enforce there is a separate design decision.
Why the stateless spec assumes a gateway
Section titled “Why the stateless spec assumes a gateway”To be clear up front: the spec does not require a gateway — a client can still talk to an MCP server directly. But read the Streamable HTTP transport spec with infrastructure eyes and a pattern appears: the protocol is visibly built so that a layer in the middle becomes maximally effective. The spec states outright that request fields are mirrored into HTTP headers so that “intermediaries (load balancers, gateways, observability tooling)” can act on requests without parsing the body. A stateless request looks like this:
POST /mcp HTTP/1.1Content-Type: application/jsonMCP-Protocol-Version: 2026-07-28Mcp-Method: tools/callMcp-Name: get_device
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_device", "arguments": { "name": "sw-core-01" }, "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {}, "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" } } }}Three details show how seriously the spec takes that middle layer:
- Header integrity is enforced. Servers must reject requests whose headers disagree with the body (HTTP 400, error
HeaderMismatch) — because a load balancer routing on a header while the server executes a different body would be a security hole. You only harden a mechanism like that if you expect components in the middle to act on it. - Parameter routing is in the protocol. A tool schema can mark parameters for header mirroring (
x-mcp-header→Mcp-Param-*), so tenant, region, or project routing can happen at the edge, without body inspection. - Shared caches are first-class. Tool listings now declare how long they may be cached (
ttlMs) and by whom (cacheScope); the value"public"exists precisely to allow shared caches, and deterministic tool ordering is recommended so catalog caches stay stable. (Catalog size is its own problem; we wrote about it in Tool Discovery for 4,800 MCP Tools.)
Put the halves together. Remote MCP traffic now behaves much more like ordinary HTTP traffic — something your infrastructure can route, throttle, meter, and cache. Cross-call application state becomes explicit: a server mints handles and manages their lifecycle. And credentials, token exchange, policies, and audit remain operator responsibilities either way. In larger MCP estates those responsibilities bundle naturally in one place: an application-layer control plane between agents and servers.
This is not just our reading. AWS shipped AgentCore Gateway support for 2026-07-28 on release day, including per-request version bridging so old and new clients coexist. An enterprise deployment paper on arXiv (August 11, 2026) describes the governance problem of dozens of independently authenticated MCP servers and resolves it with exactly this component: one gateway fronting every downstream server. And InfoQ’s coverage (August 12, 2026) observes that the new headers hand gateways the same primitives they already apply to every other API.
The skeptics see the same facts and invert them. InfoQ’s headline asks whether stateless MCP is “just an API again”; the Hacker News thread adds sharper versions: the revision is wire-incompatible in both directions, dropping implicit session state is a real regression for tools that leaned on it, and date-based spec versions make the churn hard to track. Fair objections. But notice what they concede: if the protocol layer is now ordinary HTTP, then everything still specific to MCP in your deployment — which agents may call which tools, with whose credentials, under which policies, leaving which audit trail — is decided by whatever you place in the middle. The spec did not make that layer unnecessary. It made it the place where the decisions live.
What a gateway does not solve
Section titled “What a gateway does not solve”Honesty cuts both ways, so here is the list we would want to read ourselves:
- It does not rewrite your servers. If server code calls
sampling/createMessage, that code has to change. A gateway shows you where; it does not do the work. - Sampling needs a real replacement, not a shim. Moving model access to a provider API relocates keys, budgets, and logging. Decide it deliberately rather than letting the deadline decide it for you.
- Stateful designs need redesign, not translation. The Hacker News objection is legitimate: explicit handles cost schema surface and tokens compared to implicit session context. The spec chose operability; some tool designs pay for it.
- Bridging buys time, not completion. A gateway that speaks both revisions extends coexistence. The deprecation window still ends.
- Header-based policy has a trust boundary. The spec itself warns intermediaries to trust mirrored headers only when the declared protocol version enforces header–body validation, and to reject older traffic rather than act on unvalidated headers. And origin servers should keep validating regardless — a gateway must never become the only checkpoint.
Where ToolMesh stands
Section titled “Where ToolMesh stands”ToolMesh is an Apache-2.0, self-hosted MCP gateway written in Go that sits between AI agents and backend systems and runs every tool call through one fail-closed pipeline: authenticate → authorize → inject credentials → gate output → execute → audit. The state the new spec pushes out of the protocol is the kind of state a control plane holds on purpose: backend credentials are injected server-side and never travel through the model, and every call lands in a structured audit log — the raw material for exactly the deprecated-capability inventory described above. Backends are declared in DADL, YAML files in git, so the tool catalog is deterministic by construction — which is what the new caching rules (ttlMs, cacheScope, stable ordering) are designed to reward. The pillars behind that pipeline are laid out in Anatomy of an Enterprise Tool Library.
Our own production instance speaks Streamable HTTP and STDIO today, and its migration to 2026-07-28 is in progress — transport, SDK, and a session audit of our own backends. We would rather report findings than predictions, so we will share those notes once the migration lands.
If you are running MCP servers and starting the same audit, we would genuinely like to compare notes — GitHub Discussions is open.
Reference: the changes at a glance
Section titled “Reference: the changes at a glance”Every breaking move with its SEP reference — the spec-level detail behind the summary above:
| Change | What it means | Reference |
|---|---|---|
Protocol sessions removed — Mcp-Session-Id is gone | Any request can hit any instance; cross-call state becomes explicit handles | SEP-2567 |
initialize/initialized handshake removed | Version, identity, and capabilities travel per request in _meta; optional server/discover RPC for up-front discovery | SEP-2575 |
subscriptions/listen replaces the HTTP GET endpoint and resources/subscribe | One long-lived, opt-in response stream carries change notifications | SEP-2575 |
ping, logging/setLevel, notifications/roots/list_changed removed | Log level is set per request via _meta (io.modelcontextprotocol/logLevel) | SEP-2575 |
Mcp-Method / Mcp-Name headers required on Streamable HTTP | Intermediaries route, authorize, and meter without parsing JSON bodies | SEP-2243 |
ttlMs / cacheScope required on list results and resources/read | Tool catalogs become cacheable; "public" explicitly allows shared caches | SEP-2549 |
| Multi Round-Trip Requests (MRTR) replace server-initiated requests | sampling/createMessage, elicitation/create, roots/list become input_required round-trips | SEP-2322 |
All results carry a required resultType | "complete" or "input_required"; results from earlier-protocol servers without it are treated as complete | SEP-2322 |
| Tasks move out of the core | Official extension io.modelcontextprotocol/tasks, poll-based | SEP-2663 |
| Roots, Sampling, Logging deprecated | Still work for at least twelve months; new implementations should not adopt them | SEP-2577 |
| Legacy HTTP+SSE transport reclassified as Deprecated | Migrate to Streamable HTTP | SEP-2596 |
| Dynamic Client Registration deprecated | Client ID Metadata Documents (CIMD) become the registration path; RFC 9207 iss validation required | changelog |
Servers must additionally reject requests whose routing headers disagree with the body: HTTP 400 with JSON-RPC error -32020, HeaderMismatch.