Agentic AI Tools

Stateless MCP: What the 2026-07-28 Spec Breaks in Your Agents

Rushil ShahRushil Shah
14 min read
Share

SEP-2575 and SEP-2567 removed the MCP handshake and session header. Most deployments survive on SDK backward compatibility — but four common production patterns need work, and one needs a rewrite.

TL;DR

The 2026-07-28 MCP revision deletes the initialize/initialized handshake (SEP-2575) and the Mcp-Session-Id header (SEP-2567). Every Tier 1 SDK kept backward compatibility, so almost nothing breaks on day one — but four common production patterns do need work, and only one of them is a real rewrite. The auth hardening is the part you cannot defer. Budget two engineer-weeks for a typical single-server migration, six to ten for a gateway fleet, and do not expect statelessness to fix flaky agents.

The largest revision to the Model Context Protocol since launch shipped on 28 July 2026 under Agentic AI Foundation stewardship, and the thing people keep getting wrong about it is the blast radius. The wire format changed substantially. Your deployment mostly did not. All four Tier 1 SDKs — TypeScript, Python, Go, C# — shipped on launch day with down-level protocol support in both directions, which means a v2 client can drive a 2025-era server and a v2 server still answers the legacy handshake.

So the question is not "will it break". It is "what did I build on top of the session that the protocol no longer provides, and what does it cost to move that into my application layer". The gap between the cheapest and most expensive answer is roughly an order of magnitude.

~500M monthly downloads across the Tier 1 MCP SDKs Source: Model Context Protocol, 2026
98× growth in MCP tool calls from ChatGPT users, January to August 2026 Source: Agentic AI Foundation, Sept 2026
12 months minimum deprecation window under the new formal feature lifecycle Source: Model Context Protocol, 2026
83% package size reduction reported by Manufact after moving to the split SDK v2 Source: Model Context Protocol, 2026

What the spec actually deleted

Two SEPs carry almost all of the migration cost. SEP-2575 retired the initialize/initialized exchange and SEP-2567 retired the Mcp-Session-Id header. Protocol version, client identity and client capabilities now ride in _meta on every single request. If a client wants capabilities up front there is a new optional server/discover RPC, but it is a MAY, not a MUST, for clients.

Everything else in the release follows from that deletion. Method and tool names were promoted into the Mcp-Method and Mcp-Name HTTP headers (SEP-2243) so gateways can route and rate-limit without parsing bodies — and if the headers disagree with the JSON-RPC body, the server rejects the request with a -32020 header mismatch code rather than guessing. List responses from tools/list, prompts/list, resources/list and resources/read now carry ttlMs and cacheScope (SEP-2549), so clients can cache catalogs instead of holding an SSE connection open to watch for changes.

The clever bit is Multi Round-Trip Requests (SEP-2322). Server-initiated elicitation and sampling used to require a held-open bidirectional stream, which is precisely what you cannot have in a stateless world. Under MRTR the server returns resultType: "input_required" with an opaque requestState payload, the client gathers the answer and re-issues the original call with inputResponses attached. Any instance can pick up the retry. Supabase, which already ran statelessly and therefore could never support elicitation, cited MRTR as what unblocks confirmation prompts before destructive queries.

And there is a deprecation list: roots, sampling and logging are deprecated under SEP-2577, as is the legacy HTTP+SSE transport, all with a minimum twelve-month offramp. One smaller change bites clients that pattern-match on error codes: a missing resource now returns JSON-RPC -32602 instead of the MCP-custom -32002. That one is a five-minute fix and a four-hour outage if you find it in production.

Four patterns, four verdicts

Here is the grading that matters. These are the architectures teams actually shipped in 2025 and early 2026, and the honest verdict on each.

Pattern you shippedWhat the revision takes awayVerdictRealistic effort
Single-process tool server, state keyed on session ID No Mcp-Session-Id, so ctx.sessionId stops being a key you can trust Needs a shim, then a refactor 2–5 days per server
Sticky-session gateway / load balancer affinity Nothing — the affinity rules simply become dead weight Survives; delete config, keep the wins 1–2 days plus a rollout
Stateful auth broker holding tokens against a session The session that anchored the token cache; plus new MUSTs on audience binding Partial rewrite, and it is urgent 2–4 weeks
Long-lived streaming connection for elicitation / sampling / notifications The bidirectional channel itself; sampling and roots also deprecated Rewrite onto MRTR, Tasks and subscriptions/listen 3–8 weeks

The sticky-session gateway is the happy case and it is also the most common one. If all you did was configure affinity at the load balancer and run a shared Redis session store, the revision is pure subtraction. GitHub upgraded its MCP server before the spec formally shipped and described exactly three changes: it removed Redis sessions (a database write on every initialize, a read on every call), stopped doing deep packet inspection because the values it needs for logging and secret scanning now arrive in guaranteed headers, and reworked URL elicitation so each step is a separate HTTP request. Cloudflare's servers now run each request on a fresh stateless instance with no protocol session and no protocol-specific Durable Object.

The session-pinned tool server is where most in-house builds land. The fix is not conceptually hard — mint an explicit handle from a tool (basketId, browserId) and let the model pass it back as an ordinary argument — and the maintainers argue this beats hidden transport state because the model can see the handle and compose it across tools. True, and also a prompt-engineering problem you did not have before. Models drop handles, invent handles, and pass last turn's handle after the object expired. Validate every handle server-side and return an error string that tells the model to re-fetch, because "invalid basketId" with no recovery hint sends an agent into a retry loop.

The long-lived streaming connection is the genuine rewrite. Your handler stops being a coroutine that awaits a user answer and becomes a state machine that resumes from a token. The TypeScript SDK docs are blunt about the consequence: inputResponses are per round and never accumulate, so a multi-step flow has to thread everything it has learned through requestState as a discriminated union of phases. If you have a five-step approval wizard, you are writing a five-state machine.

!

Treating "upgrade the SDK" and "speak 2026-07-28" as one migration

They are separate, deliberately, and in some SDKs they are separate in opposite directions. In TypeScript, nothing puts a 2026-07-28 byte on the wire by default — a hand-constructed Client or McpServer keeps speaking the 2025 protocol until you opt in via createMcpHandler or versionNegotiation. The Go SDK is the same: you must set StreamableHTTPOptions.Stateless = true. But the C# v2 HTTP transport is stateless by default (HttpServerTransportOptions.Stateless flips to true), and a Python v2 server answers both revisions from one endpoint on upgrade. Teams that assume one behaviour across a polyglot fleet ship a surprise.

Fix: run the two migrations as separate PRs with separate rollbacks. Move to v2 packages first, keep the 2025 wire, verify in staging, then flip the protocol era behind a flag per service.

Statelessness is a scaling win, not a reliability win

This is the counter-position worth stating plainly, because a lot of the launch coverage blurred it. The stateless core solves an infrastructure problem: sticky routing, shared session stores, the 400 Session Not Found you get when a second request lands on a different pod, and the total loss of session state when a pod restarts. Google's engineering write-up lists exactly those four as the production bottlenecks that motivated the push to decouple the protocol from stateful transports. All real. All fixed.

None of them were why your agent picked the wrong tool. If your complaints are about tool selection degrading as the catalog grows, hallucinated arguments, multi-step plans losing the thread, or two agents racing on the same record, migrating to a stateless protocol changes nothing. That coordination problem lives above the transport. The new model arguably makes it more visible: state that used to hide in the transport now sits in tool arguments the model has to manage correctly.

The maintainers themselves flagged the actual reliability frontier in the roadmap published on 22 August 2026 — standardising the tool-result contract so a server author knows which form of output a client will show the model, and a progressive discovery effort so a server with a hundred tools does not force the model to pay for the entire surface before the user has asked anything. Those are the agent-reliability items. They are next, not now. If you want a broader read on where the coordination layer sits, our research notes and model coverage pages cover it separately.

It is a leap in serving scalable MCP servers.

— David Soria Parra, MCP Co-Inventor, Model Context Protocol

The auth hardening you cannot defer

Everything above can be sequenced. This part cannot, because it closes a class of issue rather than adding a feature.

The 2026-07-28 authorization text makes token audience binding normative. MCP clients MUST include the resource parameter per RFC 8707, MCP servers MUST validate that tokens presented to them were issued specifically for their use, and an MCP server calling an upstream API MUST NOT pass through the token it received from the MCP client — the upstream call needs a separate token from the upstream authorization server. Token passthrough is explicitly forbidden, not discouraged.

If you built an MCP server that fronts an internal API and forwards the caller's bearer token, that is the pattern being closed. It is also the pattern that shows up constantly in gateway builds, because it is the shortest path to "the tool works". The fix is a token exchange at the boundary and audience validation on the way in, and it takes longer than anyone budgets.

Two more that are cheaper but still mandatory for conformance. Authorization servers should return the iss parameter per RFC 9207 and clients must validate it before redeeming a code (SEP-2468), closing an authorization-server mix-up hole; client credentials are now bound to the issuer that minted them (SEP-2352); and Dynamic Client Registration is formally deprecated in favour of Client ID Metadata Documents. DCR keeps working for now. It will not keep working forever.

Note the sequencing trap: in the TypeScript SDK these auth requirements are implemented as SDK-level opt-ins rather than protocol-era gates, which means they apply on every era once enabled and, conversely, upgrading your wire format does not turn them on for you. Conformance is a checklist you tick, not a side effect of migrating.

!

Trusting requestState because the client echoed it back

The MRTR continuation token round-trips through the client, which makes it attacker-controllable input on re-entry. The SDK docs say this outright: requestState is untrusted input and should be integrity-protected with HMAC or AEAD, bound to principal, originating method and parameters, and an expiry. The shipped helper is signed, not encrypted — the client can base64url-decode the payload, so do not put secrets in it.

Fix: use the SDK's request-state codec with a real key and a TTL, wire the verify hook so failures reject before your handler runs, and treat the payload as public.

A 30/60/90 sequence that does not require a flag day

Nothing forces a cutover. The spec's twelve-month deprecation floor and the SDKs' bidirectional down-level support mean you can run both eras from one endpoint for as long as your client population needs. That is the whole point of the compatibility window — use it.

Staged migration for an existing MCP deployment

1
Days 0–15: inventory and classify

Grep every server for session-ID reads, held-open streams, -32002 matches, and token forwarding to upstream APIs. Classify each service into the four patterns above. This is the step that sets the budget, and it is the one teams skip.

2
Days 0–30: auth hardening, era-independent

Resource indicators, audience validation, kill token passthrough, iss validation on the client. Ship this against your current wire format. It is the only work that should not wait for the protocol decision.

3
Days 15–45: SDK v2 upgrade, wire unchanged

TypeScript teams run npx @modelcontextprotocol/codemod v1-to-v2 and absorb the package split; Python teams handle FastMCP becoming MCPServer; C# teams explicitly set Stateless = false if they are not ready. Prove parity in staging before touching the protocol era.

4
Days 45–75: dual-era endpoint

Serve both revisions from one route. In TypeScript that is createMcpHandler with the default legacy: 'stateless', or a strict handler fronted by isLegacyRequest() if you still run a sessionful v1 transport. Instrument the split so you know what fraction of traffic is still 2025-era.

5
Days 75–90: retire session infrastructure

Only once legacy traffic is near zero: drop sticky affinity, delete the Redis session store, move catalog caching onto ttlMs, and turn on header-based routing at the gateway. Keep the rollback path for one more release cycle.

Two notes from the SDK docs that are easy to miss. If you enable client-side 'auto' version negotiation, the probe costs an extra round trip against 2025-only servers, and an HTTP 401 or 403 on the probe is never treated as era evidence — it rejects with a typed auth failure instead of falling back, so gateways that answer 403 before authenticating will look like a negotiation bug. And on a 2026-era request, handler logs are suppressed unless the client opts in via the logLevel _meta key; absence means opt-out, not "no filter". Expect your first stateless deployment to look suspiciously quiet.

When to defer — and the one case where you should not

Defer if you run a single-tenant internal MCP server on one pod, your clients are all under your control, and your traffic does not justify horizontal scale. The stateless core buys you round-robin routing, serverless scale-to-zero and transparent failover. If none of those are constraints you currently have, you are paying migration cost for a benefit you will not observe. Do the auth work, pin your SDK, and revisit in two quarters.

Do not defer if any of the following is true: you run MCP servers behind a multi-instance load balancer and have been papering over it with sticky sessions; you forward client tokens to upstream APIs; you publish a public MCP server whose client population you do not control; or you are about to build a new server, in which case building it stateless is strictly cheaper than retrofitting. For new gateway and tool-server builds, stateless-first is now the obvious default — it is how we scope automation builds and integration engagements that involve MCP at all.

The ecosystem signal is unambiguous. Infrastructure providers shipped production implementations within days rather than months, AAIF launched the first official MCP Associate certification on 14 September 2026 aligned to this revision, and the roadmap's next priorities — DPoP, workload identity federation, agent identity and delegation — all assume the stateless core as baseline. Building new MCP surface against 2025-era assumptions now is choosing to migrate later at a higher price. For a second opinion on sequencing across your fleet, start here.

Frequently Asked Questions

Does the 2026-07-28 spec break my existing MCP server?

No, not on its own. All four Tier 1 SDKs preserved backward compatibility in both directions: a v2 client falls back to the legacy initialize handshake against an older server, and a v2 server still accepts that handshake from an older client. What breaks is application code that reads a session ID, holds a bidirectional stream open, or matches on the old -32002 resource error code.

What is the difference between upgrading to SDK v2 and speaking 2026-07-28?

They are two separate decisions. SDK v2 is a package-level major version with renames and, in TypeScript, a split into @modelcontextprotocol/server and @modelcontextprotocol/client. Speaking the new revision is a wire-level opt-in. TypeScript and Go require you to explicitly enable it; C# v2 defaults its HTTP transport to stateless, and a Python v2 server answers both revisions from one endpoint. Migrate the packages first, then flip the era.

Do I still need Redis for an MCP server?

Not for protocol sessions. GitHub removed its Redis-backed session storage entirely after adopting the revision, eliminating a database write on every initialize and a read on every subsequent call. You may still want durable shared storage for application state, long-running Tasks that must survive process restarts, or idempotency keys. The distinction is that state becomes an explicit application concern rather than a transport requirement.

How does elicitation work without a persistent connection?

Through Multi Round-Trip Requests. The tool returns an input_required result carrying the questions plus an opaque requestState blob, the client collects the answers, and it re-issues the same call with inputResponses attached. Because the continuation state travels with the request, any instance can handle the retry. Note that inputResponses are per round and do not accumulate, so multi-step flows must thread prior answers through requestState themselves.

Which authentication change cannot be deferred?

Token audience binding and the ban on passthrough. The spec requires clients to send the RFC 8707 resource parameter, requires servers to validate that presented tokens were issued for them specifically, and states that a server calling an upstream API must not forward the token it received from the client. That is a security fix rather than a feature, so it should ship against your current protocol version rather than waiting for the migration.

How long before the legacy transport is removed?

At least twelve months from 28 July 2026. The revision introduced a formal deprecation policy with a minimum twelve-month transition window, and the legacy HTTP+SSE transport, roots, sampling and logging were the first features to enter it. They keep working throughout. New implementations should not adopt them, and a removal date will be announced against a future spec revision rather than arriving unannounced.

Will going stateless make my agents more reliable?

Only if your failures were transport failures — lost sessions on pod restarts, requests landing on the wrong instance, session-store latency. Those genuinely go away. Tool-selection errors, hallucinated arguments, broken multi-step plans and concurrency conflicts between agents are coordination problems in the layer above MCP, and the revision does not touch them. Standardising the tool-result contract and progressive tool discovery are on the roadmap as the next reliability items.

MCPstateless MCPprotocol migrationagentic AIAPI architectureOAuthAgentic AI FoundationSDK migration

Published

AI-assisted writing · Reviewed by the Twarx research team

Share:
Share

Research digest

AI Research Briefing

Honest insights on AI agents, Small Language Models, and local RAG. No hype. Only when we have something worth sending.

  • No hype, just measurable outcomes
  • Read by 2,400+ engineers
  • Unsubscribe anytime