“MCP v2” sounds like one upgrade. It is really two: a source-code migration to a
new SDK generation and a separate move to the stateless
2026-07-28 protocol. Treating them as one change is the fastest way
to turn a manageable rollout into an architectural surprise.
Upgrade the SDK and the protocol as two independently tested decisions. Your application state is a third concern—and it belongs to your application.
The name needs one qualification. MCP protocol versions are date-based, while
language SDKs use their own package versions. That means a Python or TypeScript
“v2” package and the 2026-07-28 protocol are related, but they are
not the same version number or the same migration.
Status note — 28 July 2026: the official
MCP
releases page still lists 2026-07-28 as a release candidate.
The Python v2 SDK
is 2.0.0rc1 and explicitly not recommended for production yet;
TypeScript v2 documentation is still published under the beta track. Check the
current status of your language SDK before adopting it in production.
Do not cross both boundaries in one unobservable deployment.
Name the change correctly.
Teams often say “MCP v2” to describe a cluster of changes arriving together. Technically, there are at least three separate layers:
| Layer | What is changing | Who owns the decision |
|---|---|---|
| SDK source | Packages, imports, types, handlers, transports, and helper APIs | Each language SDK and your application code |
| Wire protocol | Negotiation, state, server-to-client interaction, subscriptions, routing, and result lifecycles | The MCP specification and both endpoints |
| Application architecture | Identity, workflows, retry safety, resumability, authorization, caches, and observability | Your system |
This separation matters because SDK source compatibility does not guarantee protocol
compatibility. The official
TypeScript
protocol migration guide, for example, says SDK v2 defaults to legacy 2025
behavior and treats 2026-07-28 as an explicit opt-in. Conversely, the
Go SDK added support for the new protocol in a v1.x package. Package major versions
are not a reliable proxy for the wire revision.
Should this codebase move from its current SDK APIs to the new SDK generation?
Should this client-server pair start speaking the 2026-07-28 protocol?
Is application state explicit, durable, authorized, and safe to retry?
Answer those questions independently. A small local server may take the SDK migration while continuing to speak the legacy protocol. A remote platform may need the stateless protocol urgently but choose a gradual SDK rollout across languages.
The protocol stops owning your session.
The central architectural change in the
official
2026-07-28 release candidate is a stateless protocol core. Earlier implementations
commonly initialized a session, exchanged capabilities, received an
Mcp-Session-Id, and then routed later requests back to state associated
with that session. The modern path makes each request self-contained.
| Concern | Legacy 2025 behavior | 2026-07-28 generation |
|---|---|---|
| Startup | initialize, then initialized |
Request metadata plus cacheable server/discover |
| Transport state | Session ID may bind later requests to server state | No protocol session on the modern path |
| Application state | Often hidden behind the transport session | Explicit workflow, result, resource, or continuation handle |
| Server-to-client work | Server-initiated requests inside an active session | Multi Round-Trip Requests return input_required |
| Subscriptions | Several overlapping subscribe mechanisms | Unified subscriptions/listen stream |
| Retries | Transport/session behavior may mask interruption | Client retries; writes must be idempotent by application design |
01Discovery replaces the old handshake
server/discover
describes identity, supported revisions, capabilities, and server metadata before the
client makes normal requests. Because discovery is separate and cacheable, gateways
and clients can reason about compatibility without creating a stateful protocol
session.
02Application state becomes explicit
Stateless does not mean your product has no state. It means the protocol does not
secretly store it for you. A browser automation server, for example, can return a
server-generated handle such as browser_ref. Later tools accept that
handle, resolve it after authorization, and fetch the underlying state from a durable
store.
{
"workflow_id": "workflow_123",
"result_handle": "result_8f4",
"user_id": "user_42",
"expires_at": "2026-07-28T15:00:00Z"
}
Handles should be opaque, short-lived where appropriate, bound to the authenticated user, and safe to resolve on any server replica. Do not replace a protocol session with a raw database key or with unverified client claims.
03Long interactions get an explicit lifecycle
Multi Round-Trip Requests let an operation pause when it needs client input, then
resume from a returned handle. Results declare whether they are
complete or input_required. This makes a production
approval, clarification, or configuration prompt visible instead of relying on a
permanent back-channel.
{
"resultType": "input_required",
"requestInput": {
"type": "confirmation",
"message": "Deploy version 2.4.0 to production?"
}
}
The new protocol also makes extensions first-class, moves long-running Tasks into an
extension, adopts full JSON Schema 2020-12, adds routing metadata such as
Mcp-Method and Mcp-Name, and strengthens authorization and
trace propagation. Roots, Sampling, and protocol Logging are deprecated as core
primitives; deprecation is a migration signal, not an instruction to delete them
before all of your clients have an alternative.
Estimate impact from architecture, not tool count.
The number of exposed tools is a poor migration estimate. Transport topology, hidden session state, client ownership, and reliance on deprecated capabilities matter much more.
- Small local stdio server: usually a contained source migration. Pin the SDK, update imports and types, run the real client, and preserve legacy protocol behavior until the new path is needed.
- Remote server behind a load balancer: high architectural benefit and meaningful migration work. Stateless requests can remove sticky routing, but only after hidden session state becomes explicit.
- Custom MCP client or gateway: expect negotiation, discovery caching, MRTR, subscription, retry, and mixed-version work. Do not upgrade every connected server simultaneously.
- Session-heavy application: highest risk. Inventory authenticated identity, permissions, workflow state, temporary data, open transactions, caches, and resumable jobs before changing the transport.
- Roots, Sampling, Logging, or experimental Tasks user: create a capability-by-capability migration plan. Their replacements do not all live in the same layer.
The important distinction is between server configuration and user workflow state. A server may remain stateful internally—using a database, queue, object store, or cache—while still offering a stateless protocol surface. Every request must carry enough verified information to locate the right state safely.
Use a ten-step migration plan.
01Inventory before editing
Record the language, exact SDK and protocol versions, transports, clients, session state, server-initiated calls, Roots, Sampling, Logging, Tasks, custom extensions, and low-level protocol code. Search the repository; do not estimate from memory.
02Pin dependencies
Add an upper bound before prerelease testing so a routine install cannot silently cross a major version. Use the exact beta or release-candidate version in the migration branch and update it intentionally.
03Create an isolated migration branch
Keep the SDK change separate from new product features, data migrations, authentication redesigns, and unrelated refactors. A smaller diff makes regressions observable.
04Apply mechanical source changes first
Use official codemods and migration guides for package names, imports, renamed types, handler registration, error classes, and transport setup. Review every generated change. A codemod updates syntax; it cannot redesign a session-dependent architecture.
05Prove SDK parity on the legacy protocol
Before opting into 2026-07-28, prove that the migrated application still
works with the protocol behavior it used before. This creates a useful rollback point
and tells you which failures belong to the SDK migration.
06Remove hidden session dependencies
Give every piece of state a proper home: authenticated identity in verified credentials, permissions in authorization policy, tool inputs in explicit request parameters, workflow state behind an opaque handle, and resumable jobs in a durable queue or database.
07Make every write retry-safe
For each mutating tool, define an idempotency key, duplicate-request behavior, transaction boundary, partial-failure response, and rollback or reconciliation path. A retried response may arrive after the first operation already succeeded.
08Replace deprecated capabilities deliberately
Replace Roots with explicit tool parameters, resources, or server configuration. Move model invocation into your application or an appropriate provider API. Use normal observability infrastructure for logs and traces. Migrate experimental Tasks only after comparing their current extension lifecycle with your existing implementation.
09Test a mixed-version matrix
| Client | Server | What to prove |
|---|---|---|
| Legacy | Legacy | Existing behavior remains unchanged |
| Modern-capable | Legacy | Negotiation or fallback is predictable |
| Legacy | Modern-capable | Compatibility mode works where promised |
| Modern | Modern | Discovery, stateless requests, MRTR, retries, and subscriptions work |
Include the actual gateway, reverse proxy, load balancer, authentication provider, cache, and deployment topology. Local stdio tests do not prove a remote migration.
10Test failure, not only success
Disconnect during a response. Retry a write. Send the same idempotency key twice. Route the next request to another replica. Expire a workflow handle. Remove a required capability. Deny an authorization check. Interrupt an MRTR flow and resume it. A stateless design is credible only when these failures have explicit outcomes.
Apply SDK-specific changes.
Python v2
The Python v2 line replaces the familiar FastMCP class with
MCPServer, makes the client a first-class package, uses
snake_case model attributes, and reorganizes transport configuration.
High-level decorators remain familiar, but low-level integrations need closer manual
review. At the time of writing, the official repository says v1 remains the stable
production choice and recommends a bound such as mcp>=1.27,<2.
TypeScript v2
The TypeScript SDK splits client, server, core, and Node transport concerns into separate packages, requires Node.js 20 or newer, and is ESM-first while retaining a CommonJS build. The official upgrade guide recommends installing v2 packages alongside v1, migrating files incrementally, and removing v1 only after no old imports remain.
npx @modelcontextprotocol/codemod@beta v1-to-v2 .
For protocol behavior, TypeScript exposes explicit modern and legacy modes. Its
protocol-version
documentation also describes an automatic mode that probes
server/discover and falls back for legacy peers. Treat that as controlled
negotiation, not permission to skip the compatibility matrix.
Should you upgrade now?
Move sooner
- You operate a remote server across several replicas
- Sticky sessions or session recovery create operational pain
- You control both client and server rollout
- You are building a new MCP platform or gateway
- You need modern extensions or the new Tasks lifecycle
Move cautiously
- Your production service is stable and session-dependent
- Your main clients do not yet support the modern protocol
- Your language SDK remains prerelease
- You rely on low-level SDK internals
- You lack mixed-version and failure-path tests
New server baseline
- Design each request to reach any replica
- Keep application state behind explicit opaque handles
- Use Streamable HTTP for remote deployments
- Make write tools idempotent
- Enforce authorization server-side on every operation
Release gate
- The target SDK is acceptable for your production policy
- Legacy and modern peers behave as documented
- Retries, interruptions, and replica changes are tested
- Telemetry distinguishes protocol and application failures
- A tested rollback path remains available
A good answer can be “not yet.” Pin the current stable SDK, remove hidden state, add idempotency, build the compatibility matrix, and wait for the SDK or client ecosystem to reach your production threshold. That work is not wasted; it reduces migration risk and improves the existing server.
For a new remote server, the design direction is clearer: make requests stateless, application state explicit, writes retry-safe, and authorization independent of whatever the model says. Then adopt the modern protocol when your chosen SDK and clients support it at the maturity level you need.
What MCP v2 does not solve.
The new generation improves the protocol and SDK architecture. It does not automatically reduce tool-token cost, choose the right tool boundaries, enforce your business permissions, make dangerous actions reversible, or teach an agent a non-obvious workflow.
Those remain design responsibilities. Use the token-efficient MCP API rules to keep discovery and results compact. Add an optional agent skill only when a good interface still needs a repeatable multi-tool workflow, domain decision rules, or setup and verification guidance.
MCP should transport requests and results. It should not be the place where your application secretly keeps identity, permissions, workflow state, or retry semantics.
The practical recommendation is simple: inventory first, migrate the SDK and protocol separately, make state explicit, test mixed versions and failure paths, then roll out gradually. “MCP v2” is an important direction—not a reason to replace a working production system overnight.