This guide covers upgrading from @modelcontextprotocol/sdk (v1.x) to the v2 packages.
It is written for shell-capable agents and humans alike: run the codemod first, then
work through the manual sections for what the codemod can't rewrite.
If you are already on v2 and want to adopt the 2026-07-28 protocol revision, see
support-2026-07-28.md instead.
both import and require('@modelcontextprotocol/…') resolve natively.
```bash
npx @modelcontextprotocol/codemod@latest v1-to-v2 .
```
Run it at the package root (.), not ./src — it also rewrites package.json,
and real projects import the SDK from test/, scripts/, and fixtures too.
marked in place:
```bash
grep -rn '@mcp-codemod-error' .
```
tsc --noEmit (or your build). Remaining errors map to themanual sections below.
the changed files (prettier --write / eslint --fix / biome format --write); the
codemod prints the exact command after it runs.
Migrating a large codebase gradually instead of in one pass? See
Migrating in stages (large codebases).
The codemod (@modelcontextprotocol/codemod)
mechanically applies every rename whose mapping is fixed. The mappings are the
source of truth — they live in the codemod package and are not reproduced here:
| Mapping | Source file |
|---|---|
@modelcontextprotocol/sdk/... import paths → v2 packages | mappings/importMap.ts |
Symbol renames (McpError → ProtocolError, JSONRPCError → JSONRPCErrorResponse, …) | mappings/symbolMap.ts |
setRequestHandler(Schema, …) → setRequestHandler('method/string', …) | mappings/schemaToMethodMap.ts |
extra.* → ctx.mcpReq.* / ctx.http?.* property remap | mappings/contextPropertyMap.ts |
In addition the codemod:
package.json dependencies (@modelcontextprotocol/sdk → the v2 packagesyour imports actually use).
.tool() / .prompt() / .resource() to registerTool / registerPrompt/ registerResource and wraps inputSchema / outputSchema / argsSchema /uriSchema raw Zod shapes with z.object(), adding import { z } from 'zod'
when the file has no z binding.
client.request() / client.callTool() forspec methods.
*Schema constants imported from sdk/types.js to@modelcontextprotocol/core (mixed imports are split; .parse() / .safeParse()
calls are left untouched). Task-handler schema constants
(GetTaskRequestSchema etc.) used as setRequestHandler args are not rewritten
— the experimental tasks feature was removed (SEP-2663), so each such registration
is marked with an action-required diagnostic instead (see
Experimental tasks interception removed).
ErrorCode → ProtocolErrorCode and routes the local-only members(RequestTimeout, ConnectionClosed) to SdkErrorCode — rewriting an all-SDK
condition's instanceof ProtocolError guard to SdkError, and marking guards
that mix the two enums.
StreamableHTTPError reference to SdkHttpError and adds the import(constructor calls are marked for review — argument shape changed).
IsomorphicHeaders with the Web Standard Headers type and drops theimport (a warning notes Headers uses .get()/.set(), not bracket access).
SchemaInput<T> → StandardSchemaWithJSON.InferInput<T>.RequestHandlerExtra → ServerContext / ClientContext and the extraparameter to ctx.
vi.mock / jest.mock and dynamic import() paths.ResourceTemplate type imported from @modelcontextprotocol/sdk/types.jsto ResourceTemplateType (the spec wire type). The ResourceTemplate URI-template
helper class from server/mcp.js keeps its name and is not renamed.
@modelcontextprotocol/sdk/server/zod-compat.js imports.completable(schema.optional(), cb) becomescompletable(schema, cb).optional() (see
Standard Schema objects); shapes it
cannot invert get an @mcp-codemod-error marker.
Protocol / mergeCapabilities imports from shared/protocol.js to theclient or server package root, like the module's other symbols.
Each of these maps to a manual section below. The codemod marks every site it
recognized but could not safely rewrite with an @mcp-codemod-error comment.
.get() rewrite — IsomorphicHeaders is renamed to Headersand extra.requestInfo?.headers[…] is remapped to ctx.http?.req?.headers[…], but
converting that bracket access to .get() is manual. (Headers you pass in viarequestInit.headers need no rewrite — plain objects remain valid.)
→ HTTP & headers
ctx.mcpReq.send() schema-arg drop — the codemod drops the schema arg fromclient.request() / client.callTool() but leaves nested ctx.mcpReq.send() calls
alone. → Low-level protocol
instanceof InvalidGrantError → OAuthError +OAuthErrorCode is a judgment rewrite. → Auth
SdkErrorCode branch selection — the codemod renames StreamableHTTPError →SdkHttpError; deciding which SdkErrorCode branch a given catch should match is
judgment. → Errors
import * as t from '…/types.js' +t.CallToolResultSchema.parse(…) can't be split per-symbol; the codemod flags it
action-required — re-import the schema from @modelcontextprotocol/core by hand.
→ Types & schemas
receives the SDK surface as a parameter (dependency injection, factory seams) and has
no SDK import is never rewritten, and the v1 idioms there fail at runtime, not
compile time — e.g. the v1 schema-first setRequestHandler(Schema, …) form throws aTypeError at registration. Grep such seams for v1 API tokens beyond import
statements (setRequestHandler(, ErrorCode., extra.) and apply the
handler-registration
and Errors sections by hand.
→ Low-level protocol
compilation, output-schema validation rules. → Behavioral changes
Each subsystem has its own reference file. Open the one that matches the type error, runtime failure or @mcp-codemod-error marker in front of you; most migrations need only a few of them.
| Reference file | Read it when |
|---|---|
| Packaging & runtime | Choosing which v2 packages to install, or dealing with Node/ESM/CommonJS setup, monorepo workspaces, Jest, nested zod copies, migrating in stages, or a library that peer-depends on the SDK |
| Imports & transports | A transport import needs a runtime decision (Node vs web-standard Streamable HTTP) or a stdio import moved to a ./stdio subpath |
Low-level protocol & handler context (ctx) | Code uses extra / ctx, setRequestHandler / setNotificationHandler, request(), ctx.mcpReq.send() or callTool() |
| Server registration API | Code registers tools, prompts or resources, or passes raw Zod shapes as schemas |
| HTTP & headers | Code reads HTTP request headers |
| Errors | Code throws or catches McpError / ProtocolError, ErrorCode, SdkError or SdkHttpError |
| Auth | Code uses OAuth (auth(), OAuthClientProvider, OAuth error classes) or bearer-token auth |
| Types & schemas | Code imports Zod *Schema constants or removed type aliases, or depends on JSON Schema details |
| Behavioral changes | The code compiles but tests or runtime behavior differ |
| Enhancements | Optional: v2 features worth adopting once the upgrade is done |
| Unchanged APIs | Checking whether an API changed at all before rewriting it |
@mcp-codemod-error markers pointat every site it could not safely rewrite.
for every subsystem.