Where the migration actually stands
A month ago the Model Context Protocol tore out its handshake. By the usual standards of a breaking protocol change, the month since should have been ugly. It was not. Tooling shipped ahead of the ink drying, the compatibility story was designed rather than bolted on, and most teams running MCP servers were carried across without ever scheduling a cutover.
- Day-zero tooling. Cloudflare's Agents SDK added support the day before the specification's own date stamp. The Tier 1 SDKs — TypeScript, Python, Go and C# — were updated, with the Rust SDK in beta.
- No flag day. Gateways negotiate client-side and upstream protocol versions independently and fall back to the 2025 handshake when the upstream needs it. Nobody had to coordinate.
- The deprecations are the real backlog. Roots, Sampling and Logging sit on a minimum twelve-month clock, and Dynamic Client Registration to Client ID Metadata Documents is a genuine authorisation migration.
- The silent risk. A server still importing
mcp.server.fastmcpis on the 1.x line and still speaking the retired handshake — and because the fallback works, nothing tells you.
The recap, compressed: the 2026-07-28 specification retired the initialize and initialized exchange and the Mcp-Session-Id header, added Multi Round-Trip Requests so servers can still ask clients for confirmations and missing parameters over a stateless protocol, made the Mcp-Method and Mcp-Name headers a requirement for Streamable HTTP so gateways can route on headers instead of parsing bodies, added ttlMs and cacheScope to list results, hardened authorisation with RFC 9207 issuer validation and issuer-bound credentials, and formalised extensions including Tasks, MCP Apps and Enterprise Managed Authorization. We covered all of that in detail when it landed, in MCP goes stateless: the 2026-07-28 spec is final. This piece is about what happened next.
The shipping timeline
Within days of the release, SDK maintainers and cloud platforms announced support, published migration guidance and shipped production implementations. Here are the dates that matter.
| Date | Who | What shipped |
|---|---|---|
| 27 July 2026 | Cloudflare Agents SDK | v0.20.0 adds MCP Specification 2026-07-28 support, with migration guidance for MCP SDK v2 |
| 28 July 2026 | Cloudflare product MCP servers | Each request now runs on a fresh stateless server, with no MCP protocol session and no protocol-specific Durable Object |
| July 2026 | MCP SDK maintainers | Tier 1 SDKs updated — TypeScript, Python, Go, C#. Rust SDK in beta |
| 25 August 2026 | Cloudflare MCP server portals | Portal /mcp endpoints accept stateless 2026-07-28 and earlier 2025 Streamable HTTP clients, with independent upstream negotiation |
The 28 July change to Cloudflare's own product MCP servers is the one worth sitting with, because it is the clearest demonstration of what the spec bought. Each request now runs on a fresh stateless server with no protocol session and no protocol-specific Durable Object behind it. A whole class of stateful primitive stopped being necessary; if you pay for coordination infrastructure whose only job is keeping a handshake alive, that line item now has an argument against it.
Why this migration did not need a flag day
Breaking changes normally fail on coordination, not on code: somebody has to upgrade first, and whoever goes first breaks. The 2026-07-28 rollout dodged that almost entirely, and the mechanism is worth copying.
Cloudflare's MCP server portals, which shipped support on 25 August, put the pattern most plainly: the portal's /mcp endpoint automatically accepts stateless MCP 2026-07-28 requests and earlier 2025 Streamable HTTP clients, and when the portal connects upstream it checks for 2026-07-28 support and falls back to the 2025 handshake where needed. Crucially, the client-side and upstream protocol selections are independent. A client can upgrade without waiting for the servers behind the portal, a server can upgrade without breaking older clients, and no portal configuration changes in between. Legacy SSE connections carry on under the older specification.
That is the whole trick: put the version negotiation in the middle, on both sides, and the flag day disappears. For a Bengaluru platform team running a dozen internal MCP servers behind a shared gateway, it means the transport upgrade stopped being a programme and became a series of unremarkable individual deploys. For a London fintech that has to run change advisory on anything touching an authenticated surface, it means the transport change and the authorisation change can be separated — which matters enormously when one of them is routine and the other is not.
The design did not appear from nowhere. Google pushed for decoupling the protocol from stateful transport constraints and co-founded the MCP Transports Working Group with Hugging Face and other partners. Working groups born of operators feeling the pain tend to produce migration paths operators can walk.
The silent non-migration: your server may still be on v1.x
Here is the part that should go in your notes. Because the fallback works so well, an unmigrated server behaves exactly like a migrated one. It serves traffic. Health checks pass. Dashboards are green. Nothing in your stack raises a hand to say this server is still speaking a handshake the specification retired a month ago.
In the Python SDK the tell is an import. The v2 line renamed the in-SDK FastMCP to MCPServer and moved transport options off the constructor onto run(). Anything still importing mcp.server.fastmcp is on 1.x.
# --- v1.x: illustrative shape only. If this import resolves, you have not migrated ---
from mcp.server.fastmcp import FastMCP
app = FastMCP("orders", stateless_http=True) # transport options on the constructor
app.run()
# --- v2: illustrative shape only. Confirm the exact import path and
# argument names against the current Python SDK documentation. ---
from mcp.server import MCPServer # FastMCP renamed to MCPServer
app = MCPServer("orders") # constructor no longer carries transport config
app.run(transport="streamable-http") # transport options moved onto run()
Fallback is a compatibility feature, not a migration. A gateway quietly negotiating the 2025 handshake with your upstream server will keep doing so indefinitely, and your monitoring will never mention it. The failure mode is not an outage next week — it is discovering in twelve months, under time pressure, that a service you assumed was current never moved at all.
Check two things, not one. First, grep the entire repository for mcp.server.fastmcp — not just the entry point, because helper modules and fixture servers routinely pin the old import long after the main file was updated. Second, confirm on the wire: send a tools/call with Mcp-Method and Mcp-Name headers and no prior handshake, and see whether the server accepts it. Then wire that request into CI as a contract test, so a dependency rollback cannot quietly put you back on 1.x. Our guide to contract-testing an MCP server with golden fixtures covers the harness.
The deprecations are the work that is left
With the transport largely handled, the honest status report is that the remaining migration is a deprecation backlog. Nothing on this list is on fire. Everything on it has a clock.
| Feature | Status | Replacement | Deadline |
|---|---|---|---|
initialize / initialized |
Retired | Per-request self-description | Already gone in 2026-07-28 |
Mcp-Session-Id |
Retired | Your own application-level key | Already gone in 2026-07-28 |
| Roots | Deprecated | None announced | Minimum twelve months before removal |
| Sampling | Deprecated | None announced | Minimum twelve months before removal |
| Logging | Deprecated | None announced | Minimum twelve months before removal |
| Dynamic Client Registration | Deprecated | Client ID Metadata Documents (CIMD) | No removal date published; deprecation policy applies |
Roots, Sampling and Logging are the easier half: for most servers they are additive features replaceable with ordinary application code. The harder half is DCR to CIMD, and it is harder for a reason worth naming: it is not a refactor, it is an identity migration. Dynamic Client Registration let a client turn up at an authorisation server and register itself on the spot. CIMD replaces that runtime negotiation with a metadata document the client publishes and the server resolves. Somebody must host that document, keep it current, and coordinate its acceptance with every authorisation server in the path.
For a London fintech running MCP servers under Enterprise Managed Authorization, that is a change with a paper trail attached — new external dependencies, new failure modes if a metadata document is unreachable, and a review to satisfy. It is also, plainly, the more defensible design: a resolvable artefact you can inspect beats a registration call you have to decide whether to trust. Given what a large-scale audit of MCP servers found about how loosely much of this ecosystem was assembled, moving client identity onto something auditable is not a nicety. Schedule it as its own piece of work with its own review, not as a subtask of the transport upgrade.
Every article here is written by a Verified Builder. Want your name on the next one?
AI Tech Connect lists AI engineers, founders and researchers across India and the UK — and the people hiring browse it to find them. Adding your profile is free.
Become a Verified Builder →Header routing is quietly a billing feature
The change with the least discussion and the most commercial consequence is the mandatory Mcp-Method and Mcp-Name headers. A gateway can now see which method a request is and which tool it names without deserialising a JSON body. That sounds like a performance footnote. It is actually what makes per-tool economics cheap.
If you run a gateway in front of paid tools, metering and rate limiting previously meant parsing every request body at the edge — expensive, awkward in a proxy, and a place where malformed input becomes your problem. With the discriminator in a header, a rate limit on one costly tool, a per-tool usage counter for billing, a separate backend pool for tools/call versus tools/list, or load shedding at the edge are all ordinary configuration in nginx, Envoy, Kong or a Worker. Anyone building a commercial MCP offering — the Bengaluru team charging per API-backed tool call, the UK vendor packaging internal tools for enterprise customers — just had the cost of their metering layer cut to almost nothing.
Multi Round-Trip Requests deserve a similar note. The worry when sessions disappeared was that human-in-the-loop confirmations would go with them, because those flows depended on the server calling back to the client mid-request. MRTR keeps them: the server returns a result with resultType set to "input_required" listing what it needs, and the client answers and retries. Refund approvals, missing-parameter prompts and destructive-action confirmations all survive the stateless world. The cost, and it is the detail most likely to bite, is that your tool handler now runs more than once per logical operation — so any side effect before the input check happens twice. Our step-by-step migration guide works through the re-entrancy checks in order.
What to do this week
If you own an MCP server and you have not deliberately looked at it since July, this is a short afternoon rather than a sprint.
- Confirm which protocol you are actually speaking. Grep for
mcp.server.fastmcpacross the whole repository, then verify on the wire with a headers-only, handshake-free request. Do not infer it from a passing health check. - Pin the check into CI. One contract test that fails if the server accepts a 2025-style handshake is the cheapest insurance available against a silent regression.
- Open backlog tickets for the deprecations now. Roots, Sampling and Logging with a twelve-month minimum; DCR to CIMD as a separate, review-bearing piece of authorisation work.
- Take the free wins. Set
ttlMsandcacheScopeon list results, and move any body-parsing routing or metering at your gateway ontoMcp-MethodandMcp-Name. - Then delete the scaffolding. Sticky sessions, shared session stores and any coordination primitive that existed only to keep a handshake alive can go once you are genuinely stateless.
There is a hiring read here. In July, a migrated production MCP server was rare because nobody had one. In August it is rare for a different reason: the transport migration was easy enough to be carried through without learning anything from it. Engineers who can talk concretely about re-entrancy in tool handlers, header-level metering at a gateway, or a CIMD rollout across several authorisation servers are a genuinely small group, and Indian GCCs and UK agent studios are already writing those words into job specs. If you do this work, write down what you found — especially if you found a server that quietly never migrated. That note is worth more on a profile than another framework in a list.
Primary sources: the Model Context Protocol specification blog at blog.modelcontextprotocol.io, and the Cloudflare changelog entry for MCP portals at developers.cloudflare.com.