|
| 1 | +--- |
| 2 | +name: migrate-v1-to-v2 |
| 3 | +description: Migrate MCP TypeScript SDK code from v1 (@modelcontextprotocol/sdk) to v2 (@modelcontextprotocol/core, /client, /server). Use when a user asks to migrate, upgrade, or port their MCP TypeScript code from v1 to v2. |
| 4 | +--- |
| 5 | + |
| 6 | +# MCP TypeScript SDK: v1 → v2 Migration |
| 7 | + |
| 8 | +Apply these changes in order: dependencies → imports → API calls → type aliases. |
| 9 | + |
| 10 | +## 1. Environment |
| 11 | + |
| 12 | +- Node.js 20+ required (v18 dropped) |
| 13 | +- ESM only (CJS dropped). If the project uses `require()`, convert to `import`/`export` or use dynamic `import()`. |
| 14 | + |
| 15 | +## 2. Dependencies |
| 16 | + |
| 17 | +Remove the old package and install only what you need: |
| 18 | + |
| 19 | +```bash |
| 20 | +npm uninstall @modelcontextprotocol/sdk |
| 21 | +``` |
| 22 | + |
| 23 | +| You need | Install | |
| 24 | +|----------|---------| |
| 25 | +| Client only | `npm install @modelcontextprotocol/client` | |
| 26 | +| Server only | `npm install @modelcontextprotocol/server` | |
| 27 | +| Server + Node.js HTTP | `npm install @modelcontextprotocol/server @modelcontextprotocol/node` | |
| 28 | +| Server + Express | `npm install @modelcontextprotocol/server @modelcontextprotocol/express` | |
| 29 | +| Server + Hono | `npm install @modelcontextprotocol/server @modelcontextprotocol/hono` | |
| 30 | + |
| 31 | +`@modelcontextprotocol/core` is installed automatically as a dependency. |
| 32 | + |
| 33 | +## 3. Import Mapping |
| 34 | + |
| 35 | +Replace all `@modelcontextprotocol/sdk/...` imports using this table. |
| 36 | + |
| 37 | +### Client imports |
| 38 | + |
| 39 | +| v1 import path | v2 package | |
| 40 | +|----------------|------------| |
| 41 | +| `@modelcontextprotocol/sdk/client/index.js` | `@modelcontextprotocol/client` | |
| 42 | +| `@modelcontextprotocol/sdk/client/auth.js` | `@modelcontextprotocol/client` | |
| 43 | +| `@modelcontextprotocol/sdk/client/streamableHttp.js` | `@modelcontextprotocol/client` | |
| 44 | +| `@modelcontextprotocol/sdk/client/sse.js` | `@modelcontextprotocol/client` | |
| 45 | +| `@modelcontextprotocol/sdk/client/stdio.js` | `@modelcontextprotocol/client` | |
| 46 | +| `@modelcontextprotocol/sdk/client/websocket.js` | `@modelcontextprotocol/client` | |
| 47 | + |
| 48 | +### Server imports |
| 49 | + |
| 50 | +| v1 import path | v2 package | |
| 51 | +|----------------|------------| |
| 52 | +| `@modelcontextprotocol/sdk/server/mcp.js` | `@modelcontextprotocol/server` | |
| 53 | +| `@modelcontextprotocol/sdk/server/index.js` | `@modelcontextprotocol/server` | |
| 54 | +| `@modelcontextprotocol/sdk/server/stdio.js` | `@modelcontextprotocol/server` | |
| 55 | +| `@modelcontextprotocol/sdk/server/streamableHttp.js` | `@modelcontextprotocol/node` (class renamed to `NodeStreamableHTTPServerTransport`) | |
| 56 | +| `@modelcontextprotocol/sdk/server/sse.js` | REMOVED (migrate to Streamable HTTP) | |
| 57 | +| `@modelcontextprotocol/sdk/server/auth/*` | REMOVED (use external auth library) | |
| 58 | +| `@modelcontextprotocol/sdk/server/middleware.js` | `@modelcontextprotocol/express` (signature changed, see section 8) | |
| 59 | + |
| 60 | +### Types / shared imports |
| 61 | + |
| 62 | +| v1 import path | v2 package | |
| 63 | +|----------------|------------| |
| 64 | +| `@modelcontextprotocol/sdk/types.js` | `@modelcontextprotocol/core` | |
| 65 | +| `@modelcontextprotocol/sdk/shared/protocol.js` | `@modelcontextprotocol/core` | |
| 66 | +| `@modelcontextprotocol/sdk/shared/transport.js` | `@modelcontextprotocol/core` | |
| 67 | +| `@modelcontextprotocol/sdk/shared/stdio.js` | `@modelcontextprotocol/core` | |
| 68 | +| `@modelcontextprotocol/sdk/shared/uriTemplate.js` | `@modelcontextprotocol/core` | |
| 69 | +| `@modelcontextprotocol/sdk/shared/auth.js` | `@modelcontextprotocol/core` | |
| 70 | + |
| 71 | +Notes: |
| 72 | +- `@modelcontextprotocol/client` and `@modelcontextprotocol/server` both re-export everything from `@modelcontextprotocol/core`, so you can import types from whichever package you already depend on. |
| 73 | +- When multiple v1 imports map to the same v2 package, consolidate them into a single import statement. |
| 74 | +- If code imports from `sdk/client/...`, install `@modelcontextprotocol/client`. If from `sdk/server/...`, install `@modelcontextprotocol/server`. If from `sdk/types.js` or `sdk/shared/...` only, install `@modelcontextprotocol/core`. |
| 75 | + |
| 76 | +## 4. Renamed Symbols |
| 77 | + |
| 78 | +| v1 symbol | v2 symbol | v2 package | |
| 79 | +|-----------|-----------|------------| |
| 80 | +| `StreamableHTTPServerTransport` | `NodeStreamableHTTPServerTransport` | `@modelcontextprotocol/node` | |
| 81 | + |
| 82 | +## 5. Removed / Renamed Type Aliases and Symbols |
| 83 | + |
| 84 | +| v1 (removed) | v2 (replacement) | |
| 85 | +|--------------|------------------| |
| 86 | +| `JSONRPCError` | `JSONRPCErrorResponse` | |
| 87 | +| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` | |
| 88 | +| `isJSONRPCError` | `isJSONRPCErrorResponse` | |
| 89 | +| `isJSONRPCResponse` | `isJSONRPCResultResponse` | |
| 90 | +| `ResourceReference` | `ResourceTemplateReference` | |
| 91 | +| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` | |
| 92 | +| `IsomorphicHeaders` | REMOVED (use Web Standard `Headers`) | |
| 93 | +| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now in `@modelcontextprotocol/core`) | |
| 94 | + |
| 95 | +All other symbols from `@modelcontextprotocol/sdk/types.js` retain their original names (e.g., `CallToolResultSchema`, `ListToolsResultSchema`, etc.). |
| 96 | + |
| 97 | +**Unchanged APIs** (only import paths changed): `Client` constructor and methods, `McpServer` constructor, `server.connect()`, `server.close()`, all client transports (`StreamableHTTPClientTransport`, `SSEClientTransport`, `StdioClientTransport`), `StdioServerTransport`, all Zod schemas, all callback return types. |
| 98 | + |
| 99 | +## 6. McpServer API Changes |
| 100 | + |
| 101 | +The variadic `.tool()`, `.prompt()`, `.resource()` methods are removed. Use the `register*` methods with a config object. |
| 102 | + |
| 103 | +### Tools |
| 104 | + |
| 105 | +```typescript |
| 106 | +// v1: server.tool(name, schema, callback) |
| 107 | +server.tool('greet', { name: z.string() }, async ({ name }) => { |
| 108 | + return { content: [{ type: 'text', text: `Hello, ${name}!` }] }; |
| 109 | +}); |
| 110 | + |
| 111 | +// v1: server.tool(name, description, schema, callback) |
| 112 | +server.tool('greet', 'Greet a user', { name: z.string() }, async ({ name }) => { |
| 113 | + return { content: [{ type: 'text', text: `Hello, ${name}!` }] }; |
| 114 | +}); |
| 115 | + |
| 116 | +// v2: server.registerTool(name, config, callback) |
| 117 | +server.registerTool('greet', { |
| 118 | + description: 'Greet a user', |
| 119 | + inputSchema: { name: z.string() }, |
| 120 | +}, async ({ name }) => { |
| 121 | + return { content: [{ type: 'text', text: `Hello, ${name}!` }] }; |
| 122 | +}); |
| 123 | +``` |
| 124 | + |
| 125 | +Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`, `annotations?`, `_meta?` |
| 126 | + |
| 127 | +### Prompts |
| 128 | + |
| 129 | +```typescript |
| 130 | +// v1: server.prompt(name, schema, callback) |
| 131 | +server.prompt('summarize', { text: z.string() }, async ({ text }) => { |
| 132 | + return { messages: [{ role: 'user', content: { type: 'text', text } }] }; |
| 133 | +}); |
| 134 | + |
| 135 | +// v2: server.registerPrompt(name, config, callback) |
| 136 | +server.registerPrompt('summarize', { |
| 137 | + argsSchema: { text: z.string() }, |
| 138 | +}, async ({ text }) => { |
| 139 | + return { messages: [{ role: 'user', content: { type: 'text', text } }] }; |
| 140 | +}); |
| 141 | +``` |
| 142 | + |
| 143 | +Config object fields: `title?`, `description?`, `argsSchema?` |
| 144 | + |
| 145 | +### Resources |
| 146 | + |
| 147 | +```typescript |
| 148 | +// v1: server.resource(name, uri, callback) |
| 149 | +server.resource('config', 'config://app', async (uri) => { |
| 150 | + return { contents: [{ uri: uri.href, text: '{}' }] }; |
| 151 | +}); |
| 152 | + |
| 153 | +// v2: server.registerResource(name, uri, metadata, callback) |
| 154 | +server.registerResource('config', 'config://app', {}, async (uri) => { |
| 155 | + return { contents: [{ uri: uri.href, text: '{}' }] }; |
| 156 | +}); |
| 157 | +``` |
| 158 | + |
| 159 | +Note: the third argument (`metadata`) is required — pass `{}` if no metadata. |
| 160 | + |
| 161 | +## 7. Headers API |
| 162 | + |
| 163 | +Transport constructors and `RequestInfo.headers` now use the Web Standard `Headers` object instead of plain objects. |
| 164 | + |
| 165 | +```typescript |
| 166 | +// v1: plain object, bracket access |
| 167 | +headers: { 'Authorization': 'Bearer token' } |
| 168 | +extra.requestInfo?.headers['mcp-session-id'] |
| 169 | + |
| 170 | +// v2: Headers object, .get() access |
| 171 | +headers: new Headers({ 'Authorization': 'Bearer token' }) |
| 172 | +extra.requestInfo?.headers.get('mcp-session-id') |
| 173 | +``` |
| 174 | + |
| 175 | +## 8. Removed Server Features |
| 176 | + |
| 177 | +### SSE server transport |
| 178 | + |
| 179 | +`SSEServerTransport` removed entirely. Migrate to `NodeStreamableHTTPServerTransport` (from `@modelcontextprotocol/node`). Client-side `SSEClientTransport` still available for connecting to legacy servers. |
| 180 | + |
| 181 | +### Server-side auth |
| 182 | + |
| 183 | +All server OAuth exports removed: `mcpAuthRouter`, `OAuthServerProvider`, `OAuthTokenVerifier`, `requireBearerAuth`, `authenticateClient`, `ProxyOAuthServerProvider`, `allowedMethods`, and associated types. Use an external auth library (e.g., `better-auth`). See `examples/server/src/` for demos. |
| 184 | + |
| 185 | +### Host header validation (Express) |
| 186 | + |
| 187 | +`hostHeaderValidation()` and `localhostHostValidation()` moved from server package to `@modelcontextprotocol/express`. Signature changed: takes `string[]` instead of options object. |
| 188 | + |
| 189 | +```typescript |
| 190 | +// v1 |
| 191 | +import { hostHeaderValidation } from '@modelcontextprotocol/sdk/server/middleware.js'; |
| 192 | +app.use(hostHeaderValidation({ allowedHosts: ['example.com'] })); |
| 193 | + |
| 194 | +// v2 |
| 195 | +import { hostHeaderValidation } from '@modelcontextprotocol/express'; |
| 196 | +app.use(hostHeaderValidation(['example.com'])); |
| 197 | +``` |
| 198 | + |
| 199 | +The server package now exports framework-agnostic alternatives: `validateHostHeader()`, `localhostAllowedHostnames()`, `hostHeaderValidationResponse()`. |
| 200 | + |
| 201 | +## 9. Client Behavioral Changes |
| 202 | + |
| 203 | +`Client.listPrompts()`, `listResources()`, `listResourceTemplates()`, `listTools()` now return empty results when the server lacks the corresponding capability (instead of sending the request). Set `enforceStrictCapabilities: true` in `ClientOptions` to throw an error instead. |
| 204 | + |
| 205 | +## 10. Migration Steps (apply in this order) |
| 206 | + |
| 207 | +1. Update `package.json`: `npm uninstall @modelcontextprotocol/sdk`, install the appropriate v2 packages |
| 208 | +2. Replace all imports from `@modelcontextprotocol/sdk/...` using the import mapping tables (sections 3-4), including `StreamableHTTPServerTransport` → `NodeStreamableHTTPServerTransport` |
| 209 | +3. Replace removed type aliases (`JSONRPCError` → `JSONRPCErrorResponse`, etc.) per section 5 |
| 210 | +4. Replace `.tool()` / `.prompt()` / `.resource()` calls with `registerTool` / `registerPrompt` / `registerResource` per section 6 |
| 211 | +5. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7 |
| 212 | +6. If using `hostHeaderValidation` from server, update import and signature per section 8 |
| 213 | +7. If using server SSE transport, migrate to Streamable HTTP |
| 214 | +8. If using server auth from the SDK, migrate to an external auth library |
| 215 | +9. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true` |
| 216 | +10. Verify: build with `tsc` / run tests |
0 commit comments