Skip to content

Commit ca5bb57

Browse files
Merge branch 'main' into feature/ts-sdk-hooks
2 parents ac71aa8 + faeb03e commit ca5bb57

File tree

76 files changed

+3039
-1890
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+3039
-1890
lines changed

CLAUDE.md

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,11 @@ Located in `packages/*/src/experimental/`:
8888

8989
- **Tasks**: Long-running task support with polling/resumption (`packages/core/src/experimental/tasks/`)
9090

91-
### Zod Compatibility
91+
### Zod Schemas
9292

93-
The SDK uses `zod/v4` internally but supports both v3 and v4 APIs. Compatibility utilities:
93+
The SDK uses `zod/v4` internally. Schema utilities live in:
9494

95-
- `packages/core/src/util/zod-compat.ts` - Schema parsing helpers that work across versions
96-
- `packages/core/src/util/zod-json-schema-compat.ts` - Converts Zod schemas to JSON Schema
95+
- `packages/core/src/util/schema.ts` - AnySchema alias and helpers for inspecting Zod objects
9796

9897
### Validation
9998

@@ -145,37 +144,51 @@ When a request arrives from the remote side:
145144
2. **`Protocol.connect()`** routes to `_onrequest()`, `_onresponse()`, or `_onnotification()`
146145
3. **`Protocol._onrequest()`**:
147146
- Looks up handler in `_requestHandlers` map (keyed by method name)
148-
- Creates `RequestHandlerExtra` with `signal`, `sessionId`, `sendNotification`, `sendRequest`
147+
- Creates `BaseContext` with `signal`, `sessionId`, `sendNotification`, `sendRequest`, etc.
148+
- Calls `buildContext()` to let subclasses enrich the context (e.g., Server adds `requestInfo`)
149149
- Invokes handler, sends JSON-RPC response back via transport
150150
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('sampling/createMessage', async (request, extra) => {
156+
client.setRequestHandler('sampling/createMessage', async (request, ctx) => {
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('tools/call', async (request, extra) => {
162+
server.setRequestHandler('tools/call', async (request, ctx) => {
163163
// Handle tool call from client
164164
return { content: [...] };
165165
});
166166
```
167167

168-
### Request Handler Extra
168+
### Request Handler Context
169+
170+
The `ctx` parameter in handlers provides a structured context:
171+
172+
**`BaseContext`** (common to both Server and Client), fields organized into nested groups:
173+
174+
- `sessionId?`: Transport session identifier
175+
- `mcpReq`: Request-level concerns
176+
- `id`: JSON-RPC message ID
177+
- `method`: Request method string (e.g., 'tools/call')
178+
- `_meta?`: Request metadata
179+
- `signal`: AbortSignal for cancellation
180+
- `send(request, schema, options?)`: Send related request (for bidirectional flows)
181+
- `notify(notification)`: Send related notification back
182+
- `http?`: HTTP transport info (undefined for stdio)
183+
- `authInfo?`: Validated auth token info
184+
- `task?`: Task context (`{ id?, store, requestedTtl? }`) when task storage is configured
185+
186+
**`ServerContext`** extends `BaseContext.mcpReq` and `BaseContext.http?` via type intersection:
169187

170-
The `extra` parameter in handlers (`RequestHandlerExtra`) provides:
188+
- `mcpReq` adds: `log(level, data, logger?)`, `elicitInput(params, options?)`, `requestSampling(params, options?)`
189+
- `http?` adds: `req?` (HTTP request info), `closeSSE?`, `closeStandaloneSSE?`
171190

172-
- `signal`: AbortSignal for cancellation
173-
- `sessionId`: Transport session identifier
174-
- `authInfo`: Validated auth token info (if authenticated)
175-
- `requestId`: JSON-RPC message ID
176-
- `sendNotification(notification)`: Send related notification back
177-
- `sendRequest(request, schema)`: Send related request (for bidirectional flows)
178-
- `taskStore`: Task storage interface (if tasks enabled)
191+
**`ClientContext`** is currently identical to `BaseContext`.
179192

180193
### Capability Checking
181194

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ This monorepo publishes split packages:
3939
- **`@modelcontextprotocol/server`**: build MCP servers
4040
- **`@modelcontextprotocol/client`**: build MCP clients
4141

42-
Both packages have a **required peer dependency** on `zod` for schema validation. The SDK internally imports from `zod/v4`, but remains compatible with projects using Zod v3.25+.
42+
Both packages have a **required peer dependency** on `zod` for schema validation. The SDK uses Zod v4.
4343

4444
### Middleware packages (optional)
4545

docs/migration-SKILL.md

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ Replace all `@modelcontextprotocol/sdk/...` imports using this table.
4747

4848
### Server imports
4949

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) |
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`) OR `@modelcontextprotocol/server` (web-standard `WebStandardStreamableHTTPServerTransport` for Cloudflare Workers, Deno, etc.) |
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) |
5959

6060
### Types / shared imports
6161

@@ -203,17 +203,18 @@ import { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/core';
203203
if (error instanceof OAuthError && error.code === OAuthErrorCode.InvalidClient) { ... }
204204
```
205205

206-
**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
207-
schemas, all callback return types.
206+
**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.
208207

209208
## 6. McpServer API Changes
210209

211210
The variadic `.tool()`, `.prompt()`, `.resource()` methods are removed. Use the `register*` methods with a config object.
212211

212+
**IMPORTANT**: v2 requires full Zod schemas — raw shapes like `{ name: z.string() }` are no longer supported. You must wrap with `z.object()`. This applies to `inputSchema`, `outputSchema`, and `argsSchema`.
213+
213214
### Tools
214215

215216
```typescript
216-
// v1: server.tool(name, schema, callback)
217+
// v1: server.tool(name, schema, callback) - raw shape worked
217218
server.tool('greet', { name: z.string() }, async ({ name }) => {
218219
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
219220
});
@@ -228,7 +229,7 @@ server.registerTool(
228229
'greet',
229230
{
230231
description: 'Greet a user',
231-
inputSchema: { name: z.string() }
232+
inputSchema: z.object({ name: z.string() })
232233
},
233234
async ({ name }) => {
234235
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
@@ -241,7 +242,7 @@ Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`,
241242
### Prompts
242243

243244
```typescript
244-
// v1: server.prompt(name, schema, callback)
245+
// v1: server.prompt(name, schema, callback) - raw shape worked
245246
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
246247
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
247248
});
@@ -250,7 +251,7 @@ server.prompt('summarize', { text: z.string() }, async ({ text }) => {
250251
server.registerPrompt(
251252
'summarize',
252253
{
253-
argsSchema: { text: z.string() }
254+
argsSchema: z.object({ text: z.string() })
254255
},
255256
async ({ text }) => {
256257
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
@@ -276,6 +277,15 @@ server.registerResource('config', 'config://app', {}, async uri => {
276277

277278
Note: the third argument (`metadata`) is required — pass `{}` if no metadata.
278279

280+
### Schema Migration Quick Reference
281+
282+
| v1 (raw shape) | v2 (Zod schema) |
283+
|----------------|-----------------|
284+
| `{ name: z.string() }` | `z.object({ name: z.string() })` |
285+
| `{ count: z.number().optional() }` | `z.object({ count: z.number().optional() })` |
286+
| `{}` (empty) | `z.object({})` |
287+
| `undefined` (no schema) | `undefined` or omit the field |
288+
279289
## 7. Headers API
280290

281291
Transport constructors and `RequestInfo.headers` now use the Web Standard `Headers` object instead of plain objects.
@@ -287,7 +297,7 @@ extra.requestInfo?.headers['mcp-session-id']
287297

288298
// v2: Headers object, .get() access
289299
headers: new Headers({ 'Authorization': 'Bearer token' })
290-
extra.requestInfo?.headers.get('mcp-session-id')
300+
ctx.http?.req?.headers.get('mcp-session-id')
291301
```
292302

293303
## 8. Removed Server Features
@@ -356,19 +366,70 @@ Schema to method string mapping:
356366

357367
Request/notification params remain fully typed. Remove unused schema imports after migration.
358368

359-
## 10. Client Behavioral Changes
369+
## 10. Request Handler Context Types
370+
371+
`RequestHandlerExtra` → structured context types with nested groups. Rename `extra``ctx` in all handler callbacks.
372+
373+
| v1 | v2 |
374+
|----|-----|
375+
| `RequestHandlerExtra` | `ServerContext` (server) / `ClientContext` (client) / `BaseContext` (base) |
376+
| `extra` (param name) | `ctx` |
377+
| `extra.signal` | `ctx.mcpReq.signal` |
378+
| `extra.requestId` | `ctx.mcpReq.id` |
379+
| `extra._meta` | `ctx.mcpReq._meta` |
380+
| `extra.sendRequest(...)` | `ctx.mcpReq.send(...)` |
381+
| `extra.sendNotification(...)` | `ctx.mcpReq.notify(...)` |
382+
| `extra.authInfo` | `ctx.http?.authInfo` |
383+
| `extra.sessionId` | `ctx.sessionId` |
384+
| `extra.requestInfo` | `ctx.http?.req` (only `ServerContext`) |
385+
| `extra.closeSSEStream` | `ctx.http?.closeSSE` (only `ServerContext`) |
386+
| `extra.closeStandaloneSSEStream` | `ctx.http?.closeStandaloneSSE` (only `ServerContext`) |
387+
| `extra.taskStore` | `ctx.task?.store` |
388+
| `extra.taskId` | `ctx.task?.id` |
389+
| `extra.taskRequestedTtl` | `ctx.task?.requestedTtl` |
390+
391+
`ServerContext` convenience methods (new in v2, no v1 equivalent):
392+
393+
| Method | Description | Replaces |
394+
|--------|-------------|----------|
395+
| `ctx.mcpReq.log(level, data, logger?)` | Send log notification (respects client's level filter) | `server.sendLoggingMessage(...)` from within handler |
396+
| `ctx.mcpReq.elicitInput(params, options?)` | Elicit user input (form or URL) | `server.elicitInput(...)` from within handler |
397+
| `ctx.mcpReq.requestSampling(params, options?)` | Request LLM sampling from client | `server.createMessage(...)` from within handler |
398+
399+
## 11. Client Behavioral Changes
360400

361401
`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.
362402

363-
## 11. Migration Steps (apply in this order)
403+
## 12. Runtime-Specific JSON Schema Validators (Enhancement)
404+
405+
The SDK now auto-selects the appropriate JSON Schema validator based on runtime:
406+
- Node.js → `AjvJsonSchemaValidator` (no change from v1)
407+
- Cloudflare Workers (workerd) → `CfWorkerJsonSchemaValidator` (previously required manual config)
408+
409+
**No action required** for most users. Cloudflare Workers users can remove explicit `jsonSchemaValidator` configuration:
410+
411+
```typescript
412+
// v1 (Cloudflare Workers): Required explicit validator
413+
new McpServer({ name: 'server', version: '1.0.0' }, {
414+
jsonSchemaValidator: new CfWorkerJsonSchemaValidator()
415+
});
416+
417+
// v2 (Cloudflare Workers): Auto-selected, explicit config optional
418+
new McpServer({ name: 'server', version: '1.0.0' }, {});
419+
```
420+
421+
Access validators via `_shims` export: `import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';`
422+
423+
## 13. Migration Steps (apply in this order)
364424

365425
1. Update `package.json`: `npm uninstall @modelcontextprotocol/sdk`, install the appropriate v2 packages
366426
2. Replace all imports from `@modelcontextprotocol/sdk/...` using the import mapping tables (sections 3-4), including `StreamableHTTPServerTransport``NodeStreamableHTTPServerTransport`
367427
3. Replace removed type aliases (`JSONRPCError``JSONRPCErrorResponse`, etc.) per section 5
368428
4. Replace `.tool()` / `.prompt()` / `.resource()` calls with `registerTool` / `registerPrompt` / `registerResource` per section 6
369-
5. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
370-
6. If using `hostHeaderValidation` from server, update import and signature per section 8
371-
7. If using server SSE transport, migrate to Streamable HTTP
372-
8. If using server auth from the SDK, migrate to an external auth library
373-
9. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
374-
10. Verify: build with `tsc` / run tests
429+
5. **Wrap all raw Zod shapes with `z.object()`**: Change `inputSchema: { name: z.string() }``inputSchema: z.object({ name: z.string() })`. Same for `outputSchema` in tools and `argsSchema` in prompts.
430+
6. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
431+
7. If using `hostHeaderValidation` from server, update import and signature per section 8
432+
8. If using server SSE transport, migrate to Streamable HTTP
433+
9. If using server auth from the SDK, migrate to an external auth library
434+
10. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
435+
11. Verify: build with `tsc` / run tests

0 commit comments

Comments
 (0)