feat!: drop Zod v3 support (#1460)

This commit is contained in:
Matt 2026-02-03 19:48:08 +00:00 • committed by GitHub
commit be5670f4fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 669 additions and 947 deletions

View file

@ -209,10 +209,12 @@ if (error instanceof OAuthError && error.code === OAuthErrorCode.InvalidClient)
The variadic `.tool()`, `.prompt()`, `.resource()` methods are removed. Use the `register*` methods with a config object.
**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`.
### Tools
```typescript
// v1: server.tool(name, schema, callback)
// v1: server.tool(name, schema, callback) - raw shape worked
server.tool('greet', { name: z.string() }, async ({ name }) => {
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
});
@ -227,7 +229,7 @@ server.registerTool(
'greet',
{
description: 'Greet a user',
inputSchema: { name: z.string() }
inputSchema: z.object({ name: z.string() })
},
async ({ name }) => {
return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
@ -240,7 +242,7 @@ Config object fields: `title?`, `description?`, `inputSchema?`, `outputSchema?`,
### Prompts
```typescript
// v1: server.prompt(name, schema, callback)
// v1: server.prompt(name, schema, callback) - raw shape worked
server.prompt('summarize', { text: z.string() }, async ({ text }) => {
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
});
@ -249,7 +251,7 @@ server.prompt('summarize', { text: z.string() }, async ({ text }) => {
server.registerPrompt(
'summarize',
{
argsSchema: { text: z.string() }
argsSchema: z.object({ text: z.string() })
},
async ({ text }) => {
return { messages: [{ role: 'user', content: { type: 'text', text } }] };
@ -275,6 +277,15 @@ server.registerResource('config', 'config://app', {}, async uri => {
Note: the third argument (`metadata`) is required — pass `{}` if no metadata.
### Schema Migration Quick Reference
| v1 (raw shape) | v2 (Zod schema) |
|----------------|-----------------|
| `{ name: z.string() }` | `z.object({ name: z.string() })` |
| `{ count: z.number().optional() }` | `z.object({ count: z.number().optional() })` |
| `{}` (empty) | `z.object({})` |
| `undefined` (no schema) | `undefined` or omit the field |
## 7. Headers API
Transport constructors and `RequestInfo.headers` now use the Web Standard `Headers` object instead of plain objects.
@ -385,9 +396,10 @@ Access validators via `_shims` export: `import { DefaultJsonSchemaValidator } fr
2. Replace all imports from `@modelcontextprotocol/sdk/...` using the import mapping tables (sections 3-4), including `StreamableHTTPServerTransport` → `NodeStreamableHTTPServerTransport`
3. Replace removed type aliases (`JSONRPCError` → `JSONRPCErrorResponse`, etc.) per section 5
4. Replace `.tool()` / `.prompt()` / `.resource()` calls with `registerTool` / `registerPrompt` / `registerResource` per section 6
5. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
6. If using `hostHeaderValidation` from server, update import and signature per section 8
7. If using server SSE transport, migrate to Streamable HTTP
8. If using server auth from the SDK, migrate to an external auth library
9. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
10. Verify: build with `tsc` / run tests
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.
6. Replace plain header objects with `new Headers({...})` and bracket access (`headers['x']`) with `.get()` calls per section 7
7. If using `hostHeaderValidation` from server, update import and signature per section 8
8. If using server SSE transport, migrate to Streamable HTTP
9. If using server auth from the SDK, migrate to an external auth library
10. If relying on `listTools()`/`listPrompts()`/etc. throwing on missing capabilities, set `enforceStrictCapabilities: true`
11. Verify: build with `tsc` / run tests

View file

@ -195,6 +195,7 @@ server.resource('config', 'config://app', async uri => {
```typescript
import { McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
const server = new McpServer({ name: 'demo', version: '1.0.0' });
@ -219,6 +220,42 @@ server.registerResource('config', 'config://app', {}, async uri => {
});
```
### Zod schemas required (raw shapes no longer supported)
v2 requires full Zod schemas for `inputSchema` and `argsSchema`. Raw object shapes are no longer accepted.
**Before (v1):**
```typescript
// Raw shape (object with Zod fields) - worked in v1
server.tool('greet', { name: z.string() }, async ({ name }) => { ... });
server.registerTool('greet', {
inputSchema: { name: z.string() } // raw shape
}, callback);
```
**After (v2):**
```typescript
import * as z from 'zod/v4';
// Must wrap with z.object()
server.registerTool('greet', {
inputSchema: z.object({ name: z.string() }) // full Zod schema
}, async ({ name }) => { ... });
// For tools with no parameters, use z.object({})
server.registerTool('ping', {
inputSchema: z.object({})
}, async () => { ... });
```
This applies to:
- `inputSchema` in `registerTool()`
- `outputSchema` in `registerTool()`
- `argsSchema` in `registerPrompt()`
### Host header validation moved
Express-specific middleware (`hostHeaderValidation()`, `localhostHostValidation()`) moved from the server package to `@modelcontextprotocol/express`. The server package now exports framework-agnostic functions instead: `validateHostHeader()`, `localhostAllowedHostnames()`,