aws
MCP Went Stateless. The State Didn't Go Anywhere.
MCP's 2026-07-28 revision removes sessions from the protocol — but the state doesn't disappear, it moves through the client as an integrity-protected blob you now have to defend. What actually changed, what the coverage got wrong, and which kind of server you need to know you're building.
Contents
The session is gone.
On 28 July the Model Context Protocol shipped its 2026-07-28 revision, and the project's own announcement does not bury the lede: "The highlight of this release is a stateless protocol core - MCP is transforming from a bidirectional stateful protocol into a request/response stateless protocol." No initialize handshake. No Mcp-Session-Id. Every request now declares its own protocol version in _meta, and the server accepts or rejects each one on its own terms.
Much of the coverage frames this as breakage — "what breaks" is doing a lot of work in the headlines. It mostly isn't, and that framing will cost you time you don't need to spend. What the change actually is gets described in most write-ups and interrogated in almost none.
Statelessness didn't remove the state. It moved it — through your client — and handed you a threat model on the way out.
"Nothing breaks" and "this is a breaking change" are both true
Both sentences are in MCP's own documentation right now, and reading only one of them gets you the wrong conclusion.
From the SDK beta announcement in June: "for existing clients and servers nothing breaks today, and nothing breaks on July 28 either." A v2 server still answers the legacy initialize handshake alongside the new server/discover, so clients pinned to 2025-11-25 keep connecting. From the Multi Round-Trip Requests specification: "The previous pattern of server-initiated requests is no longer supported. This is a breaking change."
Both accurate. The first is about deployments that stay where they are; the second about what you inherit the moment you adopt the new revision. AWS draws the same line for AgentCore Gateway, writing on 28 July that "Upgrading is also opt-in, and nothing changes until both you and your clients act."
So nothing is on fire, and you are not behind. You're facing a decision you get to make on your own schedule — a different and much better problem.
The part the coverage describes but doesn't interrogate
A stateless server can't hold a conversation. But servers still need to ask clients for things mid-request — a directory listing, a model completion, a bit of input from the user. The old answer was a server-initiated request over an open bidirectional stream. The new answer is Multi Round-Trip Requests, and the mechanism is a retry loop.
The server responds with an InputRequiredResult instead of an answer. The client gathers what was asked for, then sends the whole original request again with the responses attached — the spec requires the JSON-RPC id to "be different between the initial request and the retry, as they are independent requests."
To make that work without server-side storage, the server encodes whatever context it needs into a field called requestState: "An opaque string meaningful only to the server. Clients MUST NOT inspect, parse, modify, or make any assumptions about its contents."
Read that again with an adversarial eye. The server's state now makes a round trip through the client.
The trade
The specification does not pretend this is free. It says, in normative language:
If a client request contains a
requestStatefield, servers MUST treatrequestStateas an attacker-controlled input. IfrequestStateinfluences authorization, resource access, or business logic, servers MUST protect its integrity (e.g. HMAC or AEAD) and MUST reject state that fails verification.
There is a carve-out — integrity protection "MAY be omitted only when tampering can cause nothing worse than request failure" — and that exemption will cover a fair number of real servers. But note where the burden sits: you decide whether your requestState influences authorization, and you are wrong about that at your own cost.
The spec keeps going. To prevent replay, servers should bind three things into the integrity-protected payload: the authenticated principal, a short expiry, and an identifier for the originating request. Then it concedes the limit of its own advice — those measures "bound the replay window and prevent cross-user and cross-request reuse, but do not by themselves guarantee single-use." Anything that must be redeemed exactly once, you enforce server-side. Yourself.
So you deleted a session identifier and acquired a cryptographic obligation. Reading this text, my position is that it's the right trade for the protocol and a worse one for the individual implementer — and those two things aren't in conflict.
For the protocol it looks right. The spec's own rationale for MRTR is that it handles server-side requests "without requiring a shared storage layer across server instances or requiring stateful load balancing" — which only pays off if the servers that need round-trips are the exception rather than the rule. I haven't found published data on how many do, so treat that as the maintainers' read of their own ecosystem rather than a measured fact.
For the implementer, look at what changed about the failure mode. A session identifier that goes wrong breaks — requests get routed to the wrong place, and you find out. A requestState you forgot to sign works perfectly. It works in development, in staging, in production, and it keeps working right up until someone notices that the opaque blob your server trusts is a blob your client can edit. The spec tells you this in MUST language. But MUST in a specification is not a compiler error, and that gap is where this will actually go wrong for people.
Which is why the document's honesty matters more than usual here. It names HMAC and AEAD, names principal binding and TTLs, then tells you those still don't buy you single-use. That's a specification behaving well. It doesn't change the fact that a protocol revision has quietly become a cryptography assignment for a subset of readers who didn't sign up for one.
Why the December guide's server survived untouched
I host multiple MCP servers, so what this revision asks of me isn't a hypothetical question. The most direct test I have is public: last December I published a walkthrough for deploying custom MCP tools to Amazon Bedrock AgentCore. Read against the new specification, it holds up — for reasons worth naming, because they generalise.
The server was declared FastMCP(host="0.0.0.0", stateless_http=True). That one argument is the whole story: the server was already stateless, so a spec mandating statelessness asks nothing of it. Authentication used a Cognito app client created directly with aws cognito-idp create-user-pool-client — not Dynamic Client Registration, which is now deprecated. And the test call posts tools/call straight at the endpoint with no initialize handshake — which is how the new revision expects a request to start.
The client call would still need work, though, and it's worth being precise about which half of the guide ages. The new revision requires every request to carry io.modelcontextprotocol/protocolVersion in _meta, and Streamable HTTP requests to carry Mcp-Method and Mcp-Name headers. That December curl carries none of them. The server needs nothing; the client call needs three fields.
That isn't foresight. AWS's documentation says stateless mode "is recommended for basic MCP servers" on AgentCore Runtime, and following the platform's default happened to be following the protocol's future. Which is the transferable part: when a platform's opinionated default and a protocol's direction of travel point the same way, that alignment beats any amount of hand-rolled cleverness.
One footnote, an observation rather than a complaint. Mcp-Session-Id doesn't necessarily disappear if you're on AgentCore. AWS's protocol-contract documentation says the platform "automatically adds" the Mcp-Session-Id header "for session isolation," and separately that AgentCore "uses the Mcp-Session-Id header to route requests to the same microVM instance." Worth flagging that neither that page nor the runtime-MCP page has been updated for 2026-07-28 — the protocol-contract page still references the Streamable HTTP transport at revision 2025-03-26 — so read both as snapshots of the pre-stateless model, not as current guidance.
The shape is still instructive. Taking a session identifier out of a protocol doesn't necessarily delete it; it can convert it into a platform routing header. Statelessness at one layer has a habit of reappearing as state at another.
Two of these migrations point out of the protocol
The deprecated features registry is the most useful page in this release and the least quoted. It carries six entries; four of them are newly deprecated in this revision, each with a documented migration path:
- Roots → "Pass directories or files via tool parameters, resource URIs, or server configuration"
- Sampling → "Integrate directly with LLM provider APIs"
- Logging → "Log to
stderrfor stdio transports; use OpenTelemetry for observability" - Dynamic Client Registration → Client ID Metadata Documents
Look at the shape of that list. Roots and DCR get replaced within MCP. Sampling and Logging get replaced by leaving it — go talk to your model provider directly, go run OpenTelemetry.
There's a live consequence for anyone on AgentCore. In March, AWS added stateful MCP support to Runtime, unlocking elicitation, sampling and progress notifications. Four months later two of those three are deprecated. Elicitation isn't — it's Active, and it's the lead example on the MRTR page. But if you turned statefulness on in March specifically for sampling, the protocol has since told you to go straight to your provider instead.
I read that as discipline rather than retreat. MCP was never going to beat OpenTelemetry at observability, and I'd rather talk to a model provider's own client than to a protocol intermediary wrapping it. A specification that stops doing things other layers do better is getting smaller on purpose, and smaller protocols age better. The cost is real but uneven: it lands on whoever adopted MCP because it bundled these, and they now maintain that themselves, on a clock.
Two clocks, and a ninety-day door
The write-ups almost all describe a twelve-month runway. That's roughly right and precisely wrong, in two ways that matter if you're planning work.
First, twelve months is a floor before eligibility, not a deadline. The deprecated registry says earliest removal "marks when a feature becomes eligible for removal; the actual removal is a Core Maintainer decision taken during release preparation and may happen later," and the lifecycle policy adds that features "may remain Deprecated, without removal, for much longer than the minimum deprecation window."
Second, the registry carries three different removal schedules, not one. Roots, Sampling, Logging and DCR become eligible in the first revision released on or after 2027-07-28. The includeContext values follow Sampling. And the legacy HTTP+SSE transport sits on its own — "Three months after SEP-2596 reaches Final." Much shorter. If you still have anything on HTTP+SSE, that's your real deadline, and it isn't next July.
There's also a door in the floor. The twelve-month minimum "may be shortened when the feature presents an active security risk" — defined tightly as "a vulnerability with a published security advisory or documented in-the-wild exploitation for which no in-place mitigation exists" — requiring Core Maintainer approval recorded in a SEP, and still leaving at least ninety days between deprecation and earliest removal. Narrow and well-guarded. It's stated plainly on the versioning page, and none of the migration write-ups I've seen picks it up.
Where this argument stops
The honest limit: if your server never round-trips for input, none of the above applies to you.
Run a plain tool server — some functions, some schemas, no elicitation, no sampling — and requestState never appears in your code. You get the upside with none of the homework. AWS puts that upside in its own words: "By removing sessions, remote MCP servers effectively become standard HTTPS endpoints, which scale cleanly with enterprise workloads." Read the first half as architecture and the second as marketing — but the architecture half is right. No sticky sessions, no shared state store.
So the security argument here applies only to servers that need to ask the user or the model for something mid-request. Which makes the practical advice simpler than a migration checklist — know which kind of server you're building. If you never round-trip for input, adopt the revision and enjoy it. If you do, budget for the cryptography before the protocol work.
One other thing costs five minutes. MCP advises anyone publishing a library that depends on the Python mcp package to "add an upper bound now (for example mcp>=1.27,<2) so the stable v2 release does not surprise your users." That advice dates from the June beta announcement and the stable v2 has not landed as of writing. My December guide, for the record, pinned nothing.
What I'd take from this
The instinct when a protocol goes stateless is to audit for breakage. Mostly there isn't any — and that time is better spent reading what replaced the thing that left.
Because state is conserved. Take it out of the session and it turns up in a signed blob, a platform routing header, or a store you now maintain yourself. The question was never whether to have state. It was where to put it, and who carries the risk when it's wrong. This release answers that clearly and writes the answer down, which is more than most protocol changes manage.
Innovation rarely fails. Simplification almost always does — and the tell is whether the complexity actually went away, or just moved somewhere you weren't looking.
If you've started migrating, I'd like to hear where the friction actually landed.
Sources / Further reading
- The 2026-07-28 Specification — Model Context Protocol blog, 28 July 2026
- Multi Round-Trip Requests — Model Context Protocol specification, revision 2026-07-28
- Beta SDKs for the 2026-07-28 MCP Spec Release Candidate Are Here — Model Context Protocol blog, 29 June 2026
- Versioning — Model Context Protocol
- Deprecated Features registry — Model Context Protocol
- Feature Lifecycle and Deprecation Policy (SEP-2596) — Model Context Protocol
- How AgentCore Gateway supports the MCP 2026-07-28 spec — AWS, 28 July 2026
- Deploy MCP servers in AgentCore Runtime — AWS documentation
- MCP protocol contract — AWS documentation
- Amazon Bedrock AgentCore Runtime now supports stateful MCP server features — AWS, 10 March 2026
- How to Deploy Custom AI Tools to Amazon Bedrock AgentCore in 3 Minutes — Invent and Simplify, 30 December 2025
Note on sources 8 and 9: both AWS AgentCore documentation pages predate the 2026-07-28 revision and describe the earlier session model.
Views expressed here are my own and do not represent the positions of AWS or any employer.