Skip to content

Commit 3dbc7c0

Browse files
committed
merge commit
2 parents b733470 + f6e8204 commit 3dbc7c0

30 files changed

+601
-1007
lines changed

CLAUDE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,19 @@ When a request arrives from the remote side:
147147
- Looks up handler in `_requestHandlers` map (keyed by method name)
148148
- Creates `RequestHandlerExtra` with `signal`, `sessionId`, `sendNotification`, `sendRequest`
149149
- Invokes handler, sends JSON-RPC response back via transport
150-
4. **Handler** was registered via `setRequestHandler(Schema, handler)`
150+
4. **Handler** was registered via `setRequestHandler('method', handler)`
151151

152152
### Handler Registration
153153

154154
```typescript
155155
// In Client (for server→client requests like sampling, elicitation)
156-
client.setRequestHandler(CreateMessageRequestSchema, async (request, extra) => {
156+
client.setRequestHandler('sampling/createMessage', async (request, extra) => {
157157
// Handle sampling request from server
158158
return { role: "assistant", content: {...}, model: "..." };
159159
});
160160

161161
// In Server (for client→server requests like tools/call)
162-
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
162+
server.setRequestHandler('tools/call', async (request, extra) => {
163163
// Handle tool call from client
164164
return { content: [...] };
165165
});
@@ -206,7 +206,7 @@ const result = await server.createMessage({
206206
});
207207

208208
// Client must have registered handler:
209-
client.setRequestHandler(CreateMessageRequestSchema, async (request, extra) => {
209+
client.setRequestHandler('sampling/createMessage', async (request, extra) => {
210210
// Client-side LLM call
211211
return { role: "assistant", content: {...} };
212212
});
@@ -217,7 +217,7 @@ client.setRequestHandler(CreateMessageRequestSchema, async (request, extra) => {
217217
### Request Handler Registration (Low-Level Server)
218218

219219
```typescript
220-
server.setRequestHandler(SomeRequestSchema, async (request, extra) => {
220+
server.setRequestHandler('tools/call', async (request, extra) => {
221221
// extra contains sessionId, authInfo, sendNotification, etc.
222222
return {
223223
/* result */

docs/migration-SKILL.md

Lines changed: 107 additions & 79 deletions
Large diffs are not rendered by default.

docs/migration.md

Lines changed: 105 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@ This guide covers the breaking changes introduced in v2 of the MCP TypeScript SD
44

55
## Overview
66

7-
Version 2 of the MCP TypeScript SDK introduces several breaking changes to improve modularity, reduce dependency bloat, and provide a cleaner API surface. The biggest change is the split from a single `@modelcontextprotocol/sdk` package into separate `@modelcontextprotocol/core`,
8-
`@modelcontextprotocol/client`, and `@modelcontextprotocol/server` packages.
7+
Version 2 of the MCP TypeScript SDK introduces several breaking changes to improve modularity, reduce dependency bloat, and provide a cleaner API surface. The biggest change is the split from a single `@modelcontextprotocol/sdk` package into separate `@modelcontextprotocol/core`, `@modelcontextprotocol/client`, and `@modelcontextprotocol/server` packages.
98

109
## Breaking Changes
1110

1211
### Package split (monorepo)
1312

1413
The single `@modelcontextprotocol/sdk` package has been split into three packages:
1514

16-
| v1 | v2 |
17-
| --------------------------- | ---------------------------------------------------------- |
15+
| v1 | v2 |
16+
|----|-----|
1817
| `@modelcontextprotocol/sdk` | `@modelcontextprotocol/core` (types, protocol, transports) |
19-
| | `@modelcontextprotocol/client` (client implementation) |
20-
| | `@modelcontextprotocol/server` (server implementation) |
18+
| | `@modelcontextprotocol/client` (client implementation) |
19+
| | `@modelcontextprotocol/server` (server implementation) |
2120

2221
Remove the old package and install only the packages you need:
2322

@@ -65,19 +64,18 @@ Note: `@modelcontextprotocol/client` and `@modelcontextprotocol/server` both re-
6564
v2 requires **Node.js 20+** and ships **ESM only** (no more CommonJS builds).
6665

6766
If your project uses CommonJS (`require()`), you will need to either:
68-
6967
- Migrate to ESM (`import`/`export`)
7068
- Use dynamic `import()` to load the SDK
7169

7270
### Server decoupled from HTTP frameworks
7371

7472
The server package no longer depends on Express or Hono. HTTP framework integrations are now separate middleware packages:
7573

76-
| v1 | v2 |
77-
| -------------------------------------- | ------------------------------------------- |
74+
| v1 | v2 |
75+
|----|-----|
7876
| Built into `@modelcontextprotocol/sdk` | `@modelcontextprotocol/node` (Node.js HTTP) |
79-
| | `@modelcontextprotocol/express` (Express) |
80-
| | `@modelcontextprotocol/hono` (Hono) |
77+
| | `@modelcontextprotocol/express` (Express) |
78+
| | `@modelcontextprotocol/hono` (Hono) |
8179

8280
Install the middleware package for your framework:
8381

@@ -130,12 +128,12 @@ This affects both transport constructors and request handler code that reads hea
130128
```typescript
131129
// Transport headers
132130
const transport = new StreamableHTTPClientTransport(url, {
133-
requestInit: {
134-
headers: {
135-
Authorization: 'Bearer token',
136-
'X-Custom': 'value'
137-
}
138-
}
131+
requestInit: {
132+
headers: {
133+
'Authorization': 'Bearer token',
134+
'X-Custom': 'value',
135+
},
136+
},
139137
});
140138

141139
// Reading headers in a request handler
@@ -147,12 +145,12 @@ const sessionId = extra.requestInfo?.headers['mcp-session-id'];
147145
```typescript
148146
// Transport headers
149147
const transport = new StreamableHTTPClientTransport(url, {
150-
requestInit: {
151-
headers: new Headers({
152-
Authorization: 'Bearer token',
153-
'X-Custom': 'value'
154-
})
155-
}
148+
requestInit: {
149+
headers: new Headers({
150+
'Authorization': 'Bearer token',
151+
'X-Custom': 'value',
152+
}),
153+
},
156154
});
157155

158156
// Reading headers in a request handler
@@ -172,22 +170,22 @@ const server = new McpServer({ name: 'demo', version: '1.0.0' });
172170

173171
// Tool with schema
174172
server.tool('greet', { name: z.string() }, async ({ name }) => {
175-
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
173+
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
176174
});
177175

178176
// Tool with description
179177
server.tool('greet', 'Greet a user', { name: z.string() }, async ({ name }) => {
180-
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
178+
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
181179
});
182180

183181
// Prompt
184182
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
185-
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
183+
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
186184
});
187185

188186
// Resource
189-
server.resource('config', 'config://app', async uri => {
190-
return { contents: [{ uri: uri.href, text: '{}' }] };
187+
server.resource('config', 'config://app', async (uri) => {
188+
return { contents: [{ uri: uri.href, text: '{}' }] };
191189
});
192190
```
193191

@@ -200,29 +198,28 @@ const server = new McpServer({ name: 'demo', version: '1.0.0' });
200198

201199
// Tool with schema
202200
server.registerTool('greet', { inputSchema: { name: z.string() } }, async ({ name }) => {
203-
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
201+
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
204202
});
205203

206204
// Tool with description
207205
server.registerTool('greet', { description: 'Greet a user', inputSchema: { name: z.string() } }, async ({ name }) => {
208-
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
206+
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
209207
});
210208

211209
// Prompt
212210
server.registerPrompt('summarize', { argsSchema: { text: z.string() } }, async ({ text }) => {
213-
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
211+
return { messages: [{ role: 'user', content: { type: 'text', text: `Summarize: ${text}` } }] };
214212
});
215213

216214
// Resource
217-
server.registerResource('config', 'config://app', {}, async uri => {
218-
return { contents: [{ uri: uri.href, text: '{}' }] };
215+
server.registerResource('config', 'config://app', {}, async (uri) => {
216+
return { contents: [{ uri: uri.href, text: '{}' }] };
219217
});
220218
```
221219

222220
### Host header validation moved
223221

224-
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`,
225-
`hostHeaderValidationResponse()`.
222+
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`, `hostHeaderValidationResponse()`.
226223

227224
**Before (v1):**
228225

@@ -240,6 +237,66 @@ app.use(hostHeaderValidation(['example.com']));
240237

241238
Note: the v2 signature takes a plain `string[]` instead of an options object.
242239

240+
### `setRequestHandler` and `setNotificationHandler` use method strings
241+
242+
The low-level `setRequestHandler` and `setNotificationHandler` methods on `Client`, `Server`, and `Protocol` now take a method string instead of a Zod schema.
243+
244+
**Before (v1):**
245+
246+
```typescript
247+
import { Server, InitializeRequestSchema, LoggingMessageNotificationSchema } from '@modelcontextprotocol/sdk/server/index.js';
248+
249+
const server = new Server({ name: 'my-server', version: '1.0.0' });
250+
251+
// Request handler with schema
252+
server.setRequestHandler(InitializeRequestSchema, async (request) => {
253+
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
254+
});
255+
256+
// Notification handler with schema
257+
server.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
258+
console.log(notification.params.data);
259+
});
260+
```
261+
262+
**After (v2):**
263+
264+
```typescript
265+
import { Server } from '@modelcontextprotocol/server';
266+
267+
const server = new Server({ name: 'my-server', version: '1.0.0' });
268+
269+
// Request handler with method string
270+
server.setRequestHandler('initialize', async (request) => {
271+
return { protocolVersion: '...', capabilities: {}, serverInfo: { name: '...', version: '...' } };
272+
});
273+
274+
// Notification handler with method string
275+
server.setNotificationHandler('notifications/message', (notification) => {
276+
console.log(notification.params.data);
277+
});
278+
```
279+
280+
The request and notification parameters remain fully typed via `RequestTypeMap` and `NotificationTypeMap`. You no longer need to import the individual `*RequestSchema` or `*NotificationSchema` constants for handler registration.
281+
282+
Common method string replacements:
283+
284+
| Schema (v1) | Method string (v2) |
285+
|-------------|-------------------|
286+
| `InitializeRequestSchema` | `'initialize'` |
287+
| `CallToolRequestSchema` | `'tools/call'` |
288+
| `ListToolsRequestSchema` | `'tools/list'` |
289+
| `ListPromptsRequestSchema` | `'prompts/list'` |
290+
| `GetPromptRequestSchema` | `'prompts/get'` |
291+
| `ListResourcesRequestSchema` | `'resources/list'` |
292+
| `ReadResourceRequestSchema` | `'resources/read'` |
293+
| `CreateMessageRequestSchema` | `'sampling/createMessage'` |
294+
| `ElicitRequestSchema` | `'elicitation/create'` |
295+
| `LoggingMessageNotificationSchema` | `'notifications/message'` |
296+
| `ToolListChangedNotificationSchema` | `'notifications/tools/list_changed'` |
297+
| `ResourceListChangedNotificationSchema` | `'notifications/resources/list_changed'` |
298+
| `PromptListChangedNotificationSchema` | `'notifications/prompts/list_changed'` |
299+
243300
### Registered primitives are now classes
244301

245302
`RegisteredTool`, `RegisteredPrompt`, `RegisteredResource`, and `RegisteredResourceTemplate` are now proper classes instead of plain object types. They are exported from `@modelcontextprotocol/server`.
@@ -297,27 +354,24 @@ mcpServer.resourceTemplates;
297354
To restore v1 behavior (throw an error when capabilities are missing), set `enforceStrictCapabilities: true`:
298355

299356
```typescript
300-
const client = new Client(
301-
{ name: 'my-client', version: '1.0.0' },
302-
{
303-
enforceStrictCapabilities: true
304-
}
305-
);
357+
const client = new Client({ name: 'my-client', version: '1.0.0' }, {
358+
enforceStrictCapabilities: true,
359+
});
306360
```
307361

308362
### Removed type aliases and deprecated exports
309363

310364
The following deprecated type aliases have been removed from `@modelcontextprotocol/core`:
311365

312-
| Removed | Replacement |
313-
| ---------------------------------------- | ------------------------------------------------ |
314-
| `JSONRPCError` | `JSONRPCErrorResponse` |
315-
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
316-
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
317-
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
318-
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
319-
| `ResourceReference` | `ResourceTemplateReference` |
320-
| `IsomorphicHeaders` | Use Web Standard `Headers` |
366+
| Removed | Replacement |
367+
|---------|-------------|
368+
| `JSONRPCError` | `JSONRPCErrorResponse` |
369+
| `JSONRPCErrorSchema` | `JSONRPCErrorResponseSchema` |
370+
| `isJSONRPCError` | `isJSONRPCErrorResponse` |
371+
| `isJSONRPCResponse` | `isJSONRPCResultResponse` |
372+
| `ResourceReferenceSchema` | `ResourceTemplateReferenceSchema` |
373+
| `ResourceReference` | `ResourceTemplateReference` |
374+
| `IsomorphicHeaders` | Use Web Standard `Headers` |
321375
| `AuthInfo` (from `server/auth/types.js`) | `AuthInfo` (now in `@modelcontextprotocol/core`) |
322376

323377
All other types and schemas exported from `@modelcontextprotocol/sdk/types.js` retain their original names in `@modelcontextprotocol/core`.
@@ -348,8 +402,7 @@ The following APIs are unchanged between v1 and v2 (only the import paths change
348402

349403
## Using an LLM to migrate your code
350404

351-
An LLM-optimized version of this guide is available at [`docs/migration-SKILL.md`](migration-SKILL.md). It contains dense mapping tables designed for tools like Claude Code to mechanically apply all the changes described above. You can paste it into your LLM context or load it as
352-
a skill.
405+
An LLM-optimized version of this guide is available at [`docs/migration-SKILL.md`](migration-SKILL.md). It contains dense mapping tables designed for tools like Claude Code to mechanically apply all the changes described above. You can paste it into your LLM context or load it as a skill.
353406

354407
## Need Help?
355408

examples/client/src/elicitationUrlExample.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import type {
2121
import {
2222
CallToolResultSchema,
2323
Client,
24-
ElicitationCompleteNotificationSchema,
25-
ElicitRequestSchema,
2624
ErrorCode,
2725
getDisplayName,
2826
ListToolsResultSchema,
@@ -560,10 +558,10 @@ async function connect(url?: string): Promise<void> {
560558
console.log('👤 Client created');
561559

562560
// Set up elicitation request handler with proper validation
563-
client.setRequestHandler(ElicitRequestSchema, elicitationRequestHandler);
561+
client.setRequestHandler('elicitation/create', elicitationRequestHandler);
564562

565563
// Set up notification handler for elicitation completion
566-
client.setNotificationHandler(ElicitationCompleteNotificationSchema, notification => {
564+
client.setNotificationHandler('notifications/elicitation/complete', notification => {
567565
const { elicitationId } = notification.params;
568566
const pending = pendingURLElicitations.get(elicitationId);
569567
if (pending) {

examples/client/src/multipleClientsParallel.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/client';
2-
import {
3-
CallToolResultSchema,
4-
Client,
5-
LoggingMessageNotificationSchema,
6-
StreamableHTTPClientTransport
7-
} from '@modelcontextprotocol/client';
2+
import { CallToolResultSchema, Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
83

94
/**
105
* Multiple Clients MCP Example
@@ -42,7 +37,7 @@ async function createAndRunClient(config: ClientConfig): Promise<{ id: string; r
4237
};
4338

4439
// Set up client-specific notification handler
45-
client.setNotificationHandler(LoggingMessageNotificationSchema, notification => {
40+
client.setNotificationHandler('notifications/message', notification => {
4641
console.log(`[${config.id}] Notification: ${notification.params.data}`);
4742
});
4843

examples/client/src/parallelToolCallsClient.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
import type { CallToolResult, ListToolsRequest } from '@modelcontextprotocol/client';
2-
import {
3-
CallToolResultSchema,
4-
Client,
5-
ListToolsResultSchema,
6-
LoggingMessageNotificationSchema,
7-
StreamableHTTPClientTransport
8-
} from '@modelcontextprotocol/client';
2+
import { CallToolResultSchema, Client, ListToolsResultSchema, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
93

104
/**
115
* Parallel Tool Calls MCP Client
@@ -44,7 +38,7 @@ async function main(): Promise<void> {
4438
console.log('Successfully connected to MCP server');
4539

4640
// Set up notification handler with caller identification
47-
client.setNotificationHandler(LoggingMessageNotificationSchema, notification => {
41+
client.setNotificationHandler('notifications/message', notification => {
4842
console.log(`Notification: ${notification.params.data}`);
4943
});
5044

0 commit comments

Comments
 (0)