Convert mcp sdk v1 to v2
Skill yigitkonur/skills-by-yigitkonur/skills/convert-mcp-sdk-v1-to-v2
Use if porting an MCP TypeScript server from @modelcontextprotocol/sdk v1.x to the v2 SDK.From its SKILL.md
npx -y skills add yigitkonur/skills-by-yigitkonur --skill convert-mcp-sdk-v1-to-v2Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 11 stars11 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
15.4 KB, as published. Nobody here has run it
Convert MCP Server (SDK v1 → v2)
Port an existing MCP TypeScript server from @modelcontextprotocol/sdk v1.x (single package) to the v2 split-package SDK: @modelcontextprotocol/server, /client, /node, /express, /hono. The v2 surface changes are package split, extra → ctx handler-context mapping, Zod v3→v4 with raw-shape removal, McpError → ProtocolError, method-string request-handler keys, framework adapter packages, and OAuth-router removal.
v2 is currently a pre-release alpha. Latest published: 2.0.0-alpha.2 (verified on npm, 2026-05-09). Most production servers should stay on @modelcontextprotocol/sdk@^1.x and use this skill to plan, test, and stage the migration — not to flip a production switch.
When to use this skill
Trigger on actual migration intent applied to an existing v1 codebase. Italicized phrases below are concrete tells:
- "port my MCP server to v2", "upgrade @modelcontextprotocol/sdk to the new split packages"
- "replace
@modelcontextprotocol/sdk/server/mcp.jsimports with@modelcontextprotocol/server" - "my handlers use
extra.signal/extra.authInfoand I need the v2 equivalent" - "convert
inputSchema: { name: z.string() }raw shapes to v2", "upgrade Zod v3 to v4 in MCP tools" - "replace
mcpAuthRouter/requireBearerAuth/OAuthServerProvider" - "swap
StreamableHTTPServerTransportforNodeStreamableHTTPServerTransport" - "
McpError/ErrorCode→ProtocolError/ProtocolErrorCoderename" - "
setRequestHandler(CallToolRequestSchema, ...)→ method-string keys"
Detection signals (all should be true)
package.jsoncontains@modelcontextprotocol/sdk(the v1 single package).- The user states intent to migrate, upgrade, port, or convert — not just maintain v1.
- There is existing handler/transport/auth code to transform — not a greenfield build.
Do NOT use this skill for
- New v1 server (no existing code) → use
build-mcp-server-sdk-v1. - New v2 server (greenfield on v2 alpha) → use
build-mcp-server-sdk-v2. - Maintaining or bug-fixing a v1 server with no migration intent → use
build-mcp-server-sdk-v1. - Already on v2 and just need to extend it → use
build-mcp-server-sdk-v2. - Using the
mcp-usewrapper (not the official SDK) → usebuild-mcp-use-server.
Core rules — load-bearing
- Pick a strategy before touching files. Full rewrite, meta-package shim (only if the target alpha actually publishes one), HTTP-layer auth transition, or stay on v1. Verify package availability on npm before committing.
- Never mix v1 and v2 packages in the same module graph except deliberately during a staged migration. Two
McpServerclasses from two packages do not interoperate; types silently diverge andinstanceofchecks break at runtime. - Pin to exact alpha versions (
@modelcontextprotocol/[email protected]).^ranges across alphas surface breaking changes mid-migration. Always use--save-exact(or pnpm/yarn equivalents). - Migrate handler context (
extra → ctx) and schemas (ZodRawShape → z.object) together for any tool you touch. Half-migrated handlers are the single biggest source of runtime errors. - Replace OAuth deliberately. Server-side OAuth (
mcpAuthRouter,requireBearerAuth,OAuthServerProvider) is removed from v2. If@modelcontextprotocol/server-auth-legacyis published for the target alpha, use it as a transition; otherwise stay on v1 or move auth to the HTTP layer (Bearer middleware, Passport, jose) and forward identity viareq.auth. - Upgrade Node to 20+ and add
"type": "module"topackage.json. v2 is ESM-only — CommonJS dual-publish is unsupported. - Keep a working v1 branch alive until v2 graduates from alpha. v2 is a delivery target; v1 is the running production until then.
v1 → v2 surface map
The most-used renames at a glance. Detailed per-area guides linked below.
| Area | v1 | v2 |
|---|---|---|
| Server class import | @modelcontextprotocol/sdk/server/mcp.js | @modelcontextprotocol/server |
| Stdio transport | @modelcontextprotocol/sdk/server/stdio.js | @modelcontextprotocol/server |
| HTTP transport | StreamableHTTPServerTransport from …/server/streamableHttp.js | NodeStreamableHTTPServerTransport from @modelcontextprotocol/node |
| SSE transport | SSEServerTransport | removed (clients must move to Streamable HTTP first) |
| Express adapter | createMcpExpressApp from SDK subpath | createMcpExpressApp from @modelcontextprotocol/express |
| Hono adapter | (none) | createMcpHonoApp from @modelcontextprotocol/hono |
| Client | @modelcontextprotocol/sdk/client/index.js | @modelcontextprotocol/client |
| Errors | McpError / ErrorCode from …/types.js | ProtocolError / ProtocolErrorCode from @modelcontextprotocol/server |
| Request-handler key | setRequestHandler(CallToolRequestSchema, …) | setRequestHandler("tools/call", …) |
| Zod | import { z } from "zod" (v3) | import * as z from "zod/v4" |
| Tool input schema | inputSchema: { name: z.string() } raw shape | inputSchema: z.object({ name: z.string() }) full schema |
| Handler signature | (args, extra) => … | (args, ctx) => … |
| Auth router | mcpAuthRouter, requireBearerAuth, OAuthServerProvider | removed (HTTP-layer auth or transition package) |
extra → ctx (most-frequent moves)
| v1 | v2 |
|---|---|
extra.signal | ctx.mcpReq.signal |
extra.requestId | ctx.mcpReq.id |
extra.sendNotification(n) | ctx.mcpReq.notify(n) |
extra.sendRequest(r, s) | ctx.mcpReq.send(r, s) |
extra.authInfo | ctx.http?.authInfo |
extra.requestInfo | ctx.http?.req |
extra.closeSSEStream?.() | ctx.http?.closeSSE?.() |
extra.sessionId | ctx.sessionId (top-level, unchanged) |
ctx.http? is nullable — stdio transport leaves it undefined. Any code that assumed extra.authInfo was always defined needs an explicit branch.
Workflow
1 — Inventory the v1 server
Read package.json, tsconfig.json, and every file under src/. Record:
- Every
@modelcontextprotocol/sdk/*import path (subpath exports are the migration unit). - Every
extra.*field accessed in handlers. - Every transport class instantiated.
- Every Zod schema shape: raw-object shorthand vs full
z.object(). - Every
McpError(ErrorCode.X, …)call site and the codes used. - Every
setRequestHandler(SomeRequestSchema, …)call. - Every framework wiring point:
createMcpExpressApp,requireBearerAuth,mcpAuthRouter, custom middleware that depends on the SDK.
For a deterministic first pass, run bash scripts/check-v2-feasibility.sh <project-dir> from this skill directory and read scripts/check-v2-feasibility.md. Use the report to focus the manual inventory; do not treat it as a substitute for reading the code.
2 — Choose the migration strategy
| Strategy | When | Effort | Trade-off |
|---|---|---|---|
| Full rewrite | Small server (≤200 LOC tools, ≤2 transports, no OAuth router) | Hours | Cleanest end state, full v2 API access |
| Meta-package shim | Medium server, many subpath imports, target alpha publishes the shim | Hours | Keeps v1 import paths working under v2; defer rewrites tool-by-tool |
| HTTP-layer auth transition | Production OAuth server using mcpAuthRouter | Days | Replace SDK OAuth with app/framework middleware in a separate auth migration |
| Stay on v1 | OAuth-heavy, large, or alpha-allergic | Zero | No code change; revisit when v2 reaches stable |
Read references/guides/migration-strategy.md before committing. Record the choice in the change description.
3 — Rewrite packages and imports
Per references/guides/package-and-imports.md. Smallest unit: one import line at a time.
For direct-package migrations, preview the mechanical import portion with bash scripts/migrate-imports.sh <project-dir> and read scripts/migrate-imports.md. Rerun with --write only after reviewing the dry-run. Do not use it for schema, ctx, auth-router, request-handler-key, or transport-lifecycle rewrites — those need hand edits.
4 — Rewrite schemas
Per references/guides/schema-and-errors.md.
import { z } from "zod"→import * as z from "zod/v4"- Raw shape
{ name: z.string() }→ full schemaz.object({ name: z.string() }). v2 rejects raw shapes outright. - Drop
zod-to-json-schema— v2 emits JSON Schema 2020-12 natively viaz.toJSONSchema().
5 — Rewrite handlers (extra → ctx)
Per references/guides/handler-context-mapping.md. Use the mapping table above. No-args tool handler: (extra) => … becomes (ctx) => … — same shape, renamed.
6 — Rewrite errors and request-handler keys
Per references/guides/schema-and-errors.md. McpError / ErrorCode → ProtocolError / ProtocolErrorCode. setRequestHandler(CallToolRequestSchema, …) → setRequestHandler("tools/call", …).
7 — Replace auth
Per references/guides/auth-replacements.md.
- If using
mcpAuthRouterand the target alpha publishes@modelcontextprotocol/server-auth-legacy, keep the v1 router through that transition package; otherwise stay on v1 until auth can move out of the SDK. - If integrating fresh: do auth at the HTTP layer (Express/Hono middleware) and forward identity into
authInfoviareq.auth. The Express adapter passesreq.auththrough toctx.http?.authInfoautomatically. - The
better-authMCP plugin currently targets v1 import paths and is flagged for deprecation — do not adopt it new.
8 — Replace transports and adapters
Per references/guides/transports-and-adapters.md. Use the surface map table above. Hono is new in v2 via @modelcontextprotocol/hono (the official SDK package, not the unrelated community @hono/mcp package).
9 — Validate and stage rollout
Per references/patterns/validation-and-rollback.md.
- Add
"type": "module"topackage.json. Bump engines to Node 20+. - Run type-check first, then the existing unit/integration test suite.
- Smoke-test with
npx @anthropic-ai/mcp-inspectorfor browser/manual coverage. - Use
test-by-mcpc-clifor headless CLI smoke/regression checks whenmcpcis available. - Connect at least one real MCP client before production rollout.
- Stage in a non-prod environment for at least one week before flipping production traffic.
- Keep the v1 branch deployable until v2 reaches stable — alpha versions can break.
Quick diff — minimal hello-world before/after
// v1
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.registerTool("greet", {
inputSchema: { name: z.string() }, // raw shape
}, async ({ name }, extra) => { // (args, extra)
await extra.sendNotification({ method: "...", params: {} });
return { content: [{ type: "text", text: `Hi ${name}` }] };
});
await server.connect(new StdioServerTransport());
// v2
import { McpServer, StdioServerTransport } from "@modelcontextprotocol/server";
import * as z from "zod/v4";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.registerTool("greet", {
inputSchema: z.object({ name: z.string() }), // full schema
}, async ({ name }, ctx) => { // (args, ctx)
await ctx.mcpReq.notify({ method: "...", params: {} });
return { content: [{ type: "text" as const, text: `Hi ${name}` }] };
});
await server.connect(new StdioServerTransport());
Decision rules
- Prefer the meta-package shim only when the target alpha actually publishes it; otherwise direct packages or stay on v1.
- Prefer separating auth migration from the SDK port — auth is high-stakes; only use a verified transition package.
- Prefer pinned alpha versions over
^ranges — alphas can publish breaking changes between any two patches. - Prefer migrating one handler end-to-end (imports + schema + ctx + errors) over one concern across all handlers — bounds the test surface per PR.
- Treat
ctx.http?as nullable everywhere — stdio leaves itundefined.
Guardrails
- Never run an alpha SDK in production before staging it in a non-prod environment with realistic traffic for at least one week.
- Never mix
@modelcontextprotocol/sdkand@modelcontextprotocol/serverin the same compiled bundle without the meta-package shim — TypeScript accepts duplicate types butinstanceofchecks and class identity break at runtime. - Never assume
req.authpropagates without explicitly wiring HTTP-layer auth middleware — v2 has no server-side OAuth router. - Never delete the v1 branch or
package-lock.jsonuntil v2 has been stable in production for at least one full release cycle. - Never
npm installv2 packages without--save-exact. - Never adopt the
better-authMCP plugin as a new dependency in a v2 migration — flagged for deprecation, currently targets v1 import paths.
Output contract
When a port finishes, report:
- migration strategy chosen and why
- package/version changes, exact alpha pins, and whether the meta-package shim remains
- handlers/tools migrated, especially schema and
ctxrewrites - auth path chosen: stay on v1, verified transition package, HTTP-layer auth, or no auth
- transports/adapters changed
- validation rung reached: type-check, unit tests, Inspector,
test-by-mcpc-cli, real client, staging/canary - rollback status: v1 branch/image/lockfile preserved, or blocker if not verified
- residual risks from v2 alpha status
After the port lands, hand off to build-mcp-server-sdk-v2 for ongoing v2 maintenance.
Reference routing
Use the smallest set relevant to the migration step.
Plan and decide
| Reference | When to read |
|---|---|
references/guides/migration-strategy.md | Choosing between full rewrite, meta-package shim, HTTP-layer auth transition, "stay on v1" |
Rewrite mechanics
| Reference | When to read |
|---|---|
references/guides/package-and-imports.md | Package split table, import-by-import rewriter, meta-package shim usage |
references/guides/schema-and-errors.md | Zod v3→v4, raw shapes, JSON Schema dialect, error class rename, request-handler key strings |
references/guides/handler-context-mapping.md | Full extra → ctx field mapping, no-args handlers, http nullability, new ctx-only methods |
references/guides/transports-and-adapters.md | Transport renames, Express/Hono adapters, DNS rebinding, hostHeaderValidation |
references/guides/auth-replacements.md | OAuth-router replacement, custom Bearer/Passport/jose patterns, why not better-auth |
Validate and ship
| Reference | When to read |
|---|---|
references/patterns/validation-and-rollback.md | Migration test plan, dual-version coexistence, rollback playbook, alpha-pinning |
Compatibility note
Source-verified against the v1.x branch (latest stable: @modelcontextprotocol/sdk@^1.x) and the v2 alpha packages (@modelcontextprotocol/[email protected], /[email protected], /[email protected], /[email protected], /[email protected]). npm verification on 2026-05-09 found no published @modelcontextprotocol/core, @modelcontextprotocol/[email protected], or @modelcontextprotocol/server-auth-legacy; re-check the v2 changelog and npm package availability before each migration sprint.