The 2026-07-28 MCP spec publishes in a week, and you don't have to wait for it to start migrating. The official SDKs shipped betas on June 29 — Python, TypeScript, Go, and C# — and they already speak the release-candidate protocol. If you ship an MCP server, this is the week to install the beta on a branch, run the codemod, and see what breaks while the fix is cheap.

The short version: Python barely changes, TypeScript changes a lot but a codemod does most of it, and Go and C# just need a version bump. Here's exactly what to install and what to rewrite.

Install the beta (all four SDKs)#

# Python — same `mcp` package, new major
uv add "mcp[cli]==2.0.0b1"      # or: pip install "mcp[cli]==2.0.0b1"

# TypeScript — v2 is TWO new packages, not a bump of @modelcontextprotocol/sdk
npm install @modelcontextprotocol/server@beta @modelcontextprotocol/client@beta

# Go
go get github.com/modelcontextprotocol/go-sdk@v1.7.0-pre.1

# C#
dotnet add package ModelContextProtocol --prerelease   # 2.0.0-preview.1

That last point about TypeScript is the one that trips people up, so say it plainly: v2 does not ship as a new version of @modelcontextprotocol/sdk. It ships as two brand-new packages — @modelcontextprotocol/server and @modelcontextprotocol/client. If you npm update your old dependency and wait for v2, you'll wait forever.

Python: FastMCP becomes MCPServer, and that's most of it#

The Python migration is deliberately small. FastMCP is renamed to MCPServer, and the decorator API you already use carries over unchanged.

# Before (v1)
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("invoices")

@mcp.tool()
def total(rows: list[float]) -> float:
    return sum(rows)
# After (v2, 2.0.0b1)
from mcp.server import MCPServer

mcp = MCPServer("invoices")

@mcp.tool()                       # decorators are unchanged
def total(rows: list[float]) -> float:
    return sum(rows)

The genuinely useful part is invisible in the code: a v2 Python server negotiates the protocol revision per request and serves both the old 2025-11-25 clients and the new 2026-07-28 ones from a single endpoint. You can upgrade the library before every client on the other end has upgraded — no flag day.

TypeScript: new packages, registerTool(), and a codemod#

TypeScript carries the weight of this release. Three things move at once — the package split, the schema layer, and the method names — but they're mechanical, and the maintainers shipped a codemod for exactly that.

Run it first, on a clean branch:

npx @modelcontextprotocol/codemod@beta v1-to-v2 .

It rewrites the split-package imports, renames .tool() to registerTool(), and updates the renamed error types. Here's the shape of what it produces:

// Before (v1)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({ name: "invoices", version: "1.0.0" });

server.tool(
  "total",
  { rows: z.array(z.number()) },
  async ({ rows }) => ({ content: [{ type: "text", text: String(rows.reduce((a, b) => a + b, 0)) }] })
);
// After (v2 — split package, registerTool, Standard Schema)
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";                       // Zod v4 — or Valibot, ArkType, any Standard Schema lib

const server = new McpServer({ name: "invoices", version: "1.0.0" });

server.registerTool(
  "total",
  { inputSchema: { rows: z.array(z.number()) } },
  async ({ rows }) => ({ content: [{ type: "text", text: String(rows.reduce((a, b) => a + b, 0)) }] })
);

The schema change is worth pausing on: v2 validates against Standard Schema, the shared interface that Zod v4, Valibot, and ArkType all implement. You're no longer locked to one validation library — but you do need Zod v4, not v3, if that's your pick.

The codemod handles the imports, the rename, and the error types. What it can't do is reason about runtime shape — anything that assumed a held-open SSE stream or a live session won't be flagged. That's the hand-migration, and it's the same work whether you use the SDK or not: return-and-resume instead of push-down-a-stream.

Go and C#: bump the version, opt into stateless#

Go and C# got the easy path. As the release notes put it, there's no package split and no rework of the API you use day to day. You bump the dependency and, when you're ready, opt into stateless mode on the HTTP transport.

// Go — same module path, new pre-release
import mcp "github.com/modelcontextprotocol/go-sdk"

srv := mcp.NewServer("invoices")
// ... register tools as before ...
// stateless is a transport option, opt in when you deploy behind >1 replica

Flip on stateless — the reason any of this matters#

The whole point of the 2026-07-28 revision is that the protocol lost its session. There's no initialize handshake and no Mcp-Session-Id; client info and capabilities ride in _meta on every request. In the SDKs, that surfaces as an opt-in on the streamable-HTTP transport for TypeScript and Go, and as automatic per-request negotiation in Python.

Turn it on and the operational payoff is immediate: any replica can answer any request. You delete the sticky-routing config, you delete the shared session store, and you put the server behind a plain round-robin load balancer. For a solo founder running a remote MCP server on one small box today, that's the difference between "scaling means a rewrite" and "scaling means adding a replica."

What to actually do this week#

  1. Branch, then npm install @modelcontextprotocol/server@beta (or uv add "mcp[cli]==2.0.0b1").
  2. Run the codemod if you're on TypeScript; read the diff, don't trust it blind.
  3. Fix anything that assumed a session or a held-open stream by hand — that's the only creative work.
  4. Turn on stateless HTTP and run your test suite against both a 2025-11-25 and a 2026-07-28 client.

Do it now, while it's a beta on a branch and not a production incident on July 28. The betas exist precisely so this migration is boring — and boring, for once, is the goal.