
MCP Deleted the Handshake. Your 2025 Server Is Legacy.
Quick answer:
The 2026-07-28 MCP specification removes sessions entirely.
No initialize
exchange, no Mcp-Session-Id
header — every request carries its own version, identity and capabilities.
Roots, sampling, logging and the legacy HTTP+SSE transport are deprecated with a twelve-month minimum window.
If you shipped an MCP server in 2025, it still works, but it is now on a clock.
Most protocol revisions add things. This one mostly removed things, and the removals are the point.
MCP shipped in late 2024 modelled on a long-lived connection between one client and one server: open a stream, exchange capabilities, keep state. That is a sensible shape for a desktop app talking to a local process. It is a terrible shape for a load-balanced HTTP service behind a gateway, which is what most MCP servers turned out to be.
The 2026-07-28 specification resolves that by making the protocol stateless. Here is what changed and what it costs you.
Stateless means every request stands alone
The
initialize
/
initialized
handshake is gone, and so is
Mcp-Session-Id.
Each request now carries its protocol version, client identity and client capabilities in its
_meta
field.
Version negotiation follows the same logic.
The version travels under the
io.modelcontextprotocol/protocolVersion
key in
_meta
— mirrored in the
MCP-Protocol-Version
header on Streamable HTTP — and the server accepts or rejects
each request independently, returning an
UnsupportedProtocolVersionError
listing what it does support.
If you have ever run a stateful service across more than one instance, you already know why this is the right call. State meant sticky sessions, meant a session store, meant a whole class of bugs where a request landed on the wrong box mid-conversation. All of that is now somebody else's old problem.
The cost is per-request overhead: identity and capabilities now ride on every call rather than once per connection. For a chatty client that is real bytes. It is also the standard trade every REST API made a decade ago, and it went fine.
server/discover replaces the handshake's useful half
Removing
initialize
loses the one genuinely useful thing it did:
telling a client what it was talking to.
server/discover
puts that back as a single RPC returning supported protocol versions,
capabilities and identity.
The distinction that trips people up:
servers must implement it, clients need not call it.
A client is free to fire a request straight at you and handle a version error if one comes back.
So build
server/discover,
and do not assume it was called before anything else arrives.
Multi round-trip requests, without a stream
Statelessness creates an obvious problem: how does a tool ask the user something mid-call when there is no open bidirectional channel to ask down?
The answer is MRTR.
A server returns
resultType: "input_required"
along with the requests it needs satisfied, and the client comes back with them.
Elicitation survives; the long-lived connection does not.
Practically, this means any tool that prompts — a confirmation before a destructive action, a missing parameter, a disambiguation — needs rewriting around resumable request shapes rather than in-flight callbacks. If you are debugging what your server actually returns, a plain JSON formatter on the raw JSON-RPC payload will save you more time than any inspector UI.
Headers so gateways stop parsing your JSON
Streamable HTTP requests must now include
Mcp-Method
and
Mcp-Name
headers, so proxies can route and meter on headers instead of cracking open the body.
This is the most telling change in the whole revision. You do not add routing headers for a protocol running on someone's laptop. You add them because real deployments have gateways, rate limits and per-tool billing in front of them. MCP is being reshaped for production infrastructure, which is a good sign for anyone betting a product on it.
In the same spirit,
tools/list,
prompts/list,
resources/list
and
resources/read
now return
ttlMs
and
cacheScope,
so clients can cache listings instead of re-fetching a tool catalogue on every turn.
Set these deliberately.
A stale tool list is a worse failure mode than a slow one.
Auth got stricter, and DCR is on the way out
Three changes worth flagging for anyone who wrote the OAuth layer once and stopped thinking about it.
RFC 9207 issuer validation is now required:
clients must validate the issuer before redeeming an authorization code.
Credentials are bound to the authorization server that issued them,
with no cross-server reuse.
And Dynamic Client Registration is formally deprecated in favour of Client ID Metadata Documents,
with
application_type
now set during DCR to sort out the localhost redirect mess in the meantime.
The first two are hardening against mix-up attacks and are unambiguously good. The third is a migration for anyone whose onboarding flow relied on clients registering themselves. If you are inspecting tokens while you work through it, a browser-side JWT decoder beats pasting them into anything that phones home.
What is deprecated, and how long you have
| Deprecated | What replaces it |
|---|---|
| Roots | Pass scope explicitly per request |
| Sampling | Server-side model calls, or MRTR for user input |
| Logging | Your own observability stack |
| HTTP+SSE transport | Streamable HTTP |
| Dynamic Client Registration | Client ID Metadata Documents |
| Experimental tasks in core |
The
io.modelcontextprotocol/tasks
extension
|
The deprecation policy gives deprecated features a minimum of twelve months in the spec before they become eligible for removal, with a ninety-day expedited path in defined circumstances. That is a genuinely reasonable window — longer than several frameworks your stack already depends on offer — but it is a window, not a promise of permanence.
Sampling is the deprecation most likely to hurt. It was how a server borrowed the client's model, and losing it means servers that depended on it must bring their own inference and their own billing. That changes the economics of shipping a free MCP server, not just its code.
So should you ship an MCP server?
If you sell a developer tool with an API, yes — but ship it against 2026-07-28, not against a 2025 tutorial. The TypeScript, Python, Go and C# SDKs already support the new revision and the Rust SDK has it in beta, so the toolchain is not the blocker.
The honest caveat: protocol versions only increment when backwards compatibility breaks, which means the version string is a change log of breakages, and there have been several. A well-designed REST API with clear docs remains a perfectly respectable answer, and plenty of the tools in our API and backend category and AI tools and platforms category are getting agent adoption without one.
If you do ship one, list it where developers look — the official registry, plus submitting it here so it sits alongside the rest of your tooling rather than only in an agent's config file.
FAQ
Will my existing MCP server stop working?
Not immediately. The spec documents backward compatibility with the handshake-based revisions of 2025-11-25 and earlier, and deprecated features stay in the spec for at least twelve months. But new clients target the stateless protocol, so treat compatibility as a runway rather than a resting place.
Do I have to implement server/discover?
Yes. It is a mandatory RPC on the server side. Calling it is optional on the client side, so your server must also handle arbitrary requests arriving with no discovery call first.
What replaces sampling?
Nothing that hands you the client's model for free.
Servers that need inference call a model themselves;
servers that only needed user input use multi round-trip requests with
resultType: "input_required".
Budget for the inference cost you used to offload.
How does version negotiation work without initialize?
Every request declares its version in
_meta,
mirrored in the
MCP-Protocol-Version
header on Streamable HTTP.
The server accepts or rejects each request on its own and returns an error listing supported versions when it cannot comply.
Both sides may support several versions at once.
Why do requests need Mcp-Method and Mcp-Name headers?
So gateways and proxies can route, rate-limit and meter requests without parsing the JSON-RPC body. It is a deployment concession, and a strong hint about where the protocol expects to run.
Should a small team build an MCP server or just document their API?
Document the API first. A clean, well-described REST or GraphQL surface is what an MCP server wraps anyway, and it does not need re-porting every time the spec date changes. Add the MCP server when customers ask for it by name.
Build against the current spec date, not the tutorial you bookmarked last year.


