Marketing & Growth

MCP Deleted the Handshake. Your 2025 Server Is Legacy.

The 2026-07-28 MCP spec removes sessions, deprecates roots, sampling and logging, and hardens auth. What that means if you shipped a server in 2025.

TechLogHub Editorial
September 16, 2026
6 min read
0 views

Share Article

Diagram contrasting a crossed-out MCP session with three independent requests each carrying meta

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.

Stay Updated

Get the next deep dive in your inbox

Subscribe for product analysis, engineering explainers, and practical guides published on TechLogHub.

See what launched this week

One email a week: new and trending developer tools, fresh comparisons, and what shipped. Unsubscribe in one click.