· 10 min read
MCP v2: What's Changing, What's Deprecated, and Why
MCP v2 breaking changes explained: the protocol goes stateless and deprecates sampling, roots, and logging. What changed across every MCP SDK, why, and how to plan your migration.
Copy a command, then paste it into the command palette (Ctrl K to open).
Introduction
If you have built anything on the Model Context Protocol, this one matters. MCP v2 (protocol revision 2026-07-28) is final. The release candidate was locked on May 21, 2026, SDK maintainers validated it against real workloads during a ten-week window, and the spec was published on July 28, 2026.
This is not a point release. v2 makes the protocol stateless, formalizes extensions as first-class components, and deprecates three subsystems that many existing servers rely on: sampling, roots, and logging.
This article is the language-agnostic companion to our SDK-specific guides. It covers what changed and why, so you understand the shape of the migration regardless of whether you write TypeScript, Python, Go, or C#.
If you want to build on v2 today, two hands-on guides pick up where this one ends: Build an MCP v2 Server in TypeScript walks through a working server and the v1 to v2 migration, and Securing an MCP v2 Server with OAuth and Keycloak covers what changes for auth. The MCP TypeScript SDK: A Complete Guide remains the v1 deep dive, and will get a v2 rewrite if the SDK surface settles enough to justify one.
NOTE
This article was written while v2 was still a release candidate and the SDKs were in beta. Both have since shipped: the spec was published on July 28, 2026, and the TypeScript v2 packages went stable at 2.0.0 the day before, with Python, Go, and C# following. The concepts below are unchanged, but where the text talks about waiting for stable, that wait is over.
What you'll learn:
- The headline change: why MCP is going stateless
- Which subsystems are deprecated (sampling, roots, logging) and what replaces each
- What the stateless shift means for the SDKs you build on
- What extensions are, and the two official ones shipping with v2
- Whether you should migrate now or wait for stable
The Headline Change: MCP Goes Stateless
The single biggest change in v2 is that the protocol becomes stateless.
In v1, every session began with an initialize / initialized handshake, and the server issued an Mcp-Session-Id that the client sent back on every subsequent request. That session ID pinned a client to a specific server instance. If you scaled your server horizontally, you needed sticky sessions so that follow-up requests landed on the same process that ran the handshake.
v2 removes all of that:
- No
initialize/initializedhandshake. - No
Mcp-Session-Idheader. - Client information now travels in
_metafields on each request, so any request is self-contained. - Two new operational headers,
Mcp-MethodandMcp-Name, let infrastructure route and observe requests without parsing the body. - Caching metadata (
ttlMsandcacheScope) is now part of the protocol.
The practical payoff: a request can be handled by any server instance. No sticky sessions, no session affinity, no shared session store. This is a much better fit for serverless and autoscaled deployments, where you cannot assume the next request reaches the same box.
This one change is also the reason behind most of the deprecations below. Several v1 features quietly assumed a long-lived, stateful connection between one client and one server process. Once that assumption is gone, those features no longer fit.
What's Deprecated, and Why
Three subsystems are deprecated under v2's new lifecycle policy. Deprecated does not mean removed. Each remains functional during a one-year grace period, so existing v1 servers keep working. But new code should adopt the replacements.
Sampling
What it was: Sampling let a server ask the client's LLM to generate text mid-execution (via createMessage in the TypeScript SDK). It powered "agentic servers" that could reason and make decisions internally by borrowing the client's model.
Why it's going away: Sampling requires the server to reach back into the client while it is not handling a client request, which only works over a persistent, stateful connection. That is exactly the assumption v2 removes. In a stateless world, the server processing your request may not be the one holding a connection to your client at all.
What replaces it:
- Direct integration with LLM provider APIs. If your server needs a model, call the provider (Anthropic, OpenAI, etc.) directly from the server. You control the model, the keys, and the cost.
- The
InputRequiredResultpattern for the cases where you genuinely need something from the client mid-task. Instead of a live callback, the server returns a result that says "I need this input," and the client retries the request with the answer. Because each round-trip is a fresh, self-contained request, it can be retried against any server instance, keeping the interaction stateless.
If you use sampling today, this is the deprecation most likely to require real rework, because the replacement changes where the model call happens (server-side, not client-side).
Roots
What it was: Roots were URIs the client provided to scope what the server should operate on, for example file:///home/user/my-project to tell a code-analysis server which directory to scan. Servers read them with listRoots().
Why it's going away: Roots were another piece of session-scoped state pushed from client to server and held for the life of a connection.
What replaces it: Pass the same information explicitly, per request:
- Tool parameters — accept the working directory or scope as a tool input.
- Resource URIs — encode the scope directly in the resource being requested.
- Server configuration — set boundaries at deploy time when they are static.
Logging
What it was: Structured log messages sent from the server to the client over the MCP protocol, filtered by a client-set level (logging/setLevel).
Why it's going away: Protocol-level logging tied observability to a live client connection, which is awkward for stateless, multi-instance deployments and duplicates tooling that already exists.
What replaces it:
- stderr for stdio transports. Write logs to standard error; the host captures them. (This was already the recommended practice for stdio servers in v1, since stdout is reserved for the protocol.)
- OpenTelemetry for structured, production-grade observability. Emit traces and metrics to your existing OTel pipeline rather than through MCP.
What the Stateless Shift Means for the SDKs
Beyond the deprecations, statelessness ripples through every SDK's surface. The specifics differ by language, so this is a map of what kind of change to expect rather than a list of exact symbols. Three patterns show up regardless of which SDK you use:
- Transports get reshaped. Removing sessions is a transport-level change, so expect HTTP transports to be renamed or split by runtime, and expect the old SSE transport (a two-endpoint design built around a persistent stream) to disappear. A single, unified request/response transport fits the stateless model; a long-lived stream does not.
- Errors split into protocol errors and local SDK errors. v2 draws a clearer line between "the request itself was malformed" (a wire-protocol error the other side should see) and "something failed locally, like the HTTP connection dropped." If your code inspects error types, expect that distinction to surface in the API.
- Request context becomes transport-aware. Because a stdio server has no HTTP request behind it, the per-request context object separates protocol-level fields from transport-specific ones (like auth info that only exists over HTTP). Handlers read those optional fields defensively.
It is a map of what the migration touches so you can gauge its size for your codebase, whatever language you build in. For the concrete TypeScript renames, Build an MCP v2 Server in TypeScript works through them against real code.
AGENT BRIEFINGS
What actually matters for building and scaling AI agents in production — and what's just hype. Straight from the work, no filler.
Should You Migrate Now?
Short answer: you can, and there is no rush. Here is the state of play:
- The v2 SDKs are stable. TypeScript shipped
2.0.0on July 27, 2026, and Python, Go, and C# have been updated to match the spec. Rust is still pre-stable. Check each SDK's releases rather than trusting a version number quoted here. - Upgrading the SDK is not the same as adopting v2. The new packages serve both protocol eras. A v2 server falls back to legacy behaviour for older clients, so moving your dependencies does not force your clients to move.
- Pin exact versions anyway. Not because anything is unstable now, but because reproducible builds are worth more than automatic minor bumps in a protocol layer.
- Nothing is being taken away yet. The deprecated subsystems have a one-year grace period from July 28, 2026.
A reasonable plan for most teams:
- Audit first. Find where you use sampling, roots, and logging, and where you rely on session state. That tells you the real size of the job.
- Migrate a non-critical server. Work through the renamed imports and the deprecated subsystems on something low-stakes. Build an MCP v2 Server in TypeScript covers this end to end, including the official codemod that automates the mechanical renames.
- Within the grace year: Migrate the rest before the deprecated subsystems are removed.
What's New: Extensions
v2 does not only subtract. It also formalizes extensions as first-class protocol components with reverse-DNS identifiers and independent versioning. Instead of bolting capabilities onto the core spec, features can now evolve as versioned extensions.
Two official extensions launch with v2:
- MCP Apps — server-rendered UIs, so a server can present a rich interface to the user rather than only returning text and structured data.
- Tasks — a standard pattern for long-running operations, so a server can kick off work that outlives a single request and report on it. This pairs naturally with the stateless core: a task is addressable across instances rather than tied to one connection.
Expect the extension model to be where much of MCP's future capability growth happens, precisely because extensions can ship and version without waiting on a full spec revision.
What This Means for Your Existing v1 Servers
If you have MCP servers in production today, nothing broke on July 28. To recap:
- v1 servers keep working. Deprecations have a one-year grace period.
- You are not forced to migrate on a deadline; you are forced to migrate before the grace period ends.
- The biggest real change is sampling. Roots and logging have straightforward replacements you may already be halfway to. Sampling moves the model call from client to server, which is an architectural shift, not a rename.
- Statelessness is a gift if you run at scale. It removes sticky-session complexity from your infrastructure.
Plan for it now, migrate on stable, and you will have a full year of runway.
Resources
- MCP 2026-07-28 Release Candidate — the protocol changes, straight from the source
- MCP SDK v2 Betas — per-language beta status and versions
- TypeScript SDK v2 Migration Guide — the concrete TS upgrade path
- MCP Specification — the full protocol spec
Related Articles
- Build an MCP v2 Server in TypeScript — the hands-on v2 walkthrough and migration path
- Securing an MCP v2 Server with OAuth and Keycloak — what v2 changes for auth
- The MCP TypeScript SDK: A Complete Guide — the v1 SDK deep dive
- Create Your First MCP Server in 5 Minutes — beginner quickstart
- Getting Started with FastMCP in TypeScript — a streamlined framework
- Securing MCP Servers with OAuth and Keycloak — authentication
- Top AI Agent Protocols in 2026 — where MCP fits among agent protocols
AGENT BRIEFINGS
Stay measured as the field moves.
What actually matters for building and scaling AI agents in production — and what's just hype. Straight from the work, no filler.
$ subscribe agent-briefings
→ what works in production, what doesn't.
→ frameworks, MCP, evals, managed services.
→ signal over hype.