Skip to content

Commit c7601a2

Browse files
committed
Bundle workerd JSON schema validator in server shim
1 parent bd67be3 commit c7601a2

21 files changed

Lines changed: 219 additions & 71 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@modelcontextprotocol/core': minor
3+
'@modelcontextprotocol/client': minor
4+
'@modelcontextprotocol/server': minor
5+
---
6+
7+
Make JSON Schema validator backends optional inside core and bundle/re-export them from client/server.
8+
9+
`@modelcontextprotocol/core` now exposes runtime validator providers via explicit internal subpaths, `@modelcontextprotocol/core/validators/ajv` and `@modelcontextprotocol/core/validators/cfWorker`, with both AJV and `@cfworker/json-schema` treated as optional peer dependencies.
10+
The root core barrel no longer re-exports runtime validator providers, so importing core does not force either backend.
11+
12+
`@modelcontextprotocol/client` and `@modelcontextprotocol/server` still provide runtime defaults automatically: Node shims use AJV, while browser/workerd shims use `@cfworker/json-schema`. Those default backends are bundled into the shim chunks that select them, so client/server
13+
consumers do not need to install validator backends just to use the default runtime behavior.
14+
15+
For explicit custom validator configuration, client/server now re-export bundled validators from `@modelcontextprotocol/client/validators/ajv`, `@modelcontextprotocol/client/validators/cf-worker`, `@modelcontextprotocol/server/validators/ajv`, and
16+
`@modelcontextprotocol/server/validators/cf-worker`.

docs/migration-SKILL.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,21 @@ Replace all `@modelcontextprotocol/sdk/...` imports using this table.
5151
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
5252
| `@modelcontextprotocol/sdk/server/mcp.js` | `@modelcontextprotocol/server` |
5353
| `@modelcontextprotocol/sdk/server/index.js` | `@modelcontextprotocol/server` |
54-
| `@modelcontextprotocol/sdk/server/stdio.js` | `@modelcontextprotocol/server/stdio` |
54+
| `@modelcontextprotocol/sdk/server/stdio.js` | `@modelcontextprotocol/server/stdio` |
5555
| `@modelcontextprotocol/sdk/server/streamableHttp.js` | `@modelcontextprotocol/node` (class renamed to `NodeStreamableHTTPServerTransport`) OR `@modelcontextprotocol/server` (web-standard `WebStandardStreamableHTTPServerTransport` for Cloudflare Workers, Deno, etc.) |
5656
| `@modelcontextprotocol/sdk/server/sse.js` | REMOVED (migrate to Streamable HTTP) |
5757
| `@modelcontextprotocol/sdk/server/auth/*` | RS helpers (`requireBearerAuth`, `mcpAuthMetadataRouter`, `OAuthTokenVerifier`) → `@modelcontextprotocol/express`; AS helpers removed (use external IdP/OAuth library) |
5858
| `@modelcontextprotocol/sdk/server/middleware.js` | `@modelcontextprotocol/express` (signature changed, see section 8) |
5959

6060
### Types / shared imports
6161

62-
| v1 import path | v2 package |
63-
| ------------------------------------------------- | ---------------------------------------------------------------- |
64-
| `@modelcontextprotocol/sdk/types.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
65-
| `@modelcontextprotocol/sdk/shared/protocol.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
66-
| `@modelcontextprotocol/sdk/shared/transport.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
67-
| `@modelcontextprotocol/sdk/shared/uriTemplate.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
68-
| `@modelcontextprotocol/sdk/shared/auth.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
62+
| v1 import path | v2 package |
63+
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
64+
| `@modelcontextprotocol/sdk/types.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
65+
| `@modelcontextprotocol/sdk/shared/protocol.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
66+
| `@modelcontextprotocol/sdk/shared/transport.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
67+
| `@modelcontextprotocol/sdk/shared/uriTemplate.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
68+
| `@modelcontextprotocol/sdk/shared/auth.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` |
6969
| `@modelcontextprotocol/sdk/shared/stdio.js` | `@modelcontextprotocol/client` or `@modelcontextprotocol/server` (`ReadBuffer`, `serializeMessage`, `deserializeMessage` are in the root barrel; the `./stdio` subpath only has the transport class) |
7070

7171
Notes:
@@ -323,7 +323,8 @@ new URL(ctx.http?.req?.url).searchParams.get('debug')
323323

324324
### Server-side auth
325325

326-
Resource Server helpers (`requireBearerAuth`, `mcpAuthMetadataRouter`, `getOAuthProtectedResourceMetadataUrl`, `OAuthTokenVerifier`) are first-class in `@modelcontextprotocol/express`. Authorization Server helpers (`mcpAuthRouter`, `OAuthServerProvider`, `ProxyOAuthServerProvider`, `authenticateClient`, `allowedMethods`, etc.) are removed from the core SDK; use an external IdP/OAuth library. See `examples/server/src/` for demos.
326+
Resource Server helpers (`requireBearerAuth`, `mcpAuthMetadataRouter`, `getOAuthProtectedResourceMetadataUrl`, `OAuthTokenVerifier`) are first-class in `@modelcontextprotocol/express`. Authorization Server helpers (`mcpAuthRouter`, `OAuthServerProvider`,
327+
`ProxyOAuthServerProvider`, `authenticateClient`, `allowedMethods`, etc.) are removed from the core SDK; use an external IdP/OAuth library. See `examples/server/src/` for demos.
327328

328329
### Host header validation (Express)
329330

@@ -464,12 +465,12 @@ Remove unused schema imports: `CallToolResultSchema`, `CompatibilityCallToolResu
464465

465466
If a `*Schema` constant was used for **runtime validation** (not just as a `request()` argument), replace with `isSpecType` / `specTypeSchemas`:
466467

467-
| v1 pattern | v2 replacement |
468-
| -------------------------------------------------- | -------------------------------------------------------------------------------------- |
469-
| `CallToolResultSchema.safeParse(value).success` | `isSpecType.CallToolResult(value)` |
470-
| `<TypeName>Schema.safeParse(value).success` | `isSpecType.<TypeName>(value)` |
468+
| v1 pattern | v2 replacement |
469+
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
470+
| `CallToolResultSchema.safeParse(value).success` | `isSpecType.CallToolResult(value)` |
471+
| `<TypeName>Schema.safeParse(value).success` | `isSpecType.<TypeName>(value)` |
471472
| `<TypeName>Schema.parse(value)` | `await specTypeSchemas.<TypeName>['~standard'].validate(value)` (returns a `Result`, not the value) |
472-
| Passing `<TypeName>Schema` as a validator argument | `specTypeSchemas.<TypeName>` (a `StandardSchemaV1<In, Out>`) |
473+
| Passing `<TypeName>Schema` as a validator argument | `specTypeSchemas.<TypeName>` (a `StandardSchemaV1<In, Out>`) |
473474

474475
`isCallToolResult(value)` still works, but `isSpecType` covers every spec type by name.
475476

@@ -521,8 +522,8 @@ new McpServer({ name: 'server', version: '1.0.0' }, {});
521522
Access validators explicitly:
522523

523524
- Runtime-aware default: `import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';`
524-
- AJV (Node.js): `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';`
525-
- CF Worker: `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';`
525+
- AJV (Node.js): `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';` (or `/client/validators/ajv` for client code)
526+
- CF Worker: `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';` (or `/client/validators/cf-worker` for client code)
526527

527528
## 15. Migration Steps (apply in this order)
528529

docs/migration.md

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ const transport = new StreamableHTTPClientTransport(new URL('http://localhost:30
137137

138138
Resource Server helpers (`requireBearerAuth`, `mcpAuthMetadataRouter`, `getOAuthProtectedResourceMetadataUrl`, `OAuthTokenVerifier`) are now first-class in `@modelcontextprotocol/express`.
139139

140-
Authorization Server helpers (`mcpAuthRouter`, `OAuthServerProvider`, `ProxyOAuthServerProvider`, `authenticateClient`, `allowedMethods`, etc.) have been removed from the core SDK; new code should use a dedicated IdP/OAuth library. See the [examples](../examples/server/src/) for a working demo with `better-auth`.
140+
Authorization Server helpers (`mcpAuthRouter`, `OAuthServerProvider`, `ProxyOAuthServerProvider`, `authenticateClient`, `allowedMethods`, etc.) have been removed from the core SDK; new code should use a dedicated IdP/OAuth library. See the [examples](../examples/server/src/) for
141+
a working demo with `better-auth`.
141142

142143
Note: `AuthInfo` has moved from `server/auth/types.ts` to the core types and is now re-exported by `@modelcontextprotocol/client` and `@modelcontextprotocol/server`.
143144

@@ -379,7 +380,11 @@ const AcmeSearch = z.object({
379380
params: z.object({ query: z.string(), limit: z.number().int() })
380381
});
381382
server.setRequestHandler(AcmeSearch, async request => {
382-
return { items: [/* ... */] };
383+
return {
384+
items: [
385+
/* ... */
386+
]
387+
};
383388
});
384389
```
385390

@@ -390,7 +395,11 @@ const SearchParams = z.object({ query: z.string(), limit: z.number().int() });
390395
const SearchResult = z.object({ items: z.array(z.string()) });
391396

392397
server.setRequestHandler('acme/search', { params: SearchParams, result: SearchResult }, async (params, ctx) => {
393-
return { items: [/* ... */] };
398+
return {
399+
items: [
400+
/* ... */
401+
]
402+
};
394403
});
395404
```
396405

@@ -429,8 +438,8 @@ Common method string replacements:
429438

430439
### `Protocol.request()`, `ctx.mcpReq.send()`, and `Client.callTool()` no longer require a schema parameter for spec methods
431440

432-
For **spec** methods, the public `Protocol.request()`, `BaseContext.mcpReq.send()`, and `Client.callTool()` methods no longer require a Zod result schema argument. The SDK now resolves the correct result schema internally based on the method name. This means you no longer need to import result schemas
433-
like `CallToolResultSchema` or `ElicitResultSchema` when making spec-method requests.
441+
For **spec** methods, the public `Protocol.request()`, `BaseContext.mcpReq.send()`, and `Client.callTool()` methods no longer require a Zod result schema argument. The SDK now resolves the correct result schema internally based on the method name. This means you no longer need to
442+
import result schemas like `CallToolResultSchema` or `ElicitResultSchema` when making spec-method requests.
434443

435444
**`client.request()` — Before (v1):**
436445

@@ -510,7 +519,8 @@ import { specTypeSchemas } from '@modelcontextprotocol/client';
510519
const result = await specTypeSchemas.CallToolResult['~standard'].validate(value);
511520
```
512521

513-
`isSpecType` and `specTypeSchemas` are keyed by `SpecTypeName` — a literal union of every named type in the MCP spec — so you get autocomplete and a compile error on typos. `specTypeSchemas.X` is a `StandardSchemaV1<In, Out>`, which composes with any Standard-Schema-aware library. The pre-existing `isCallToolResult(value)` guard still works.
522+
`isSpecType` and `specTypeSchemas` are keyed by `SpecTypeName` — a literal union of every named type in the MCP spec — so you get autocomplete and a compile error on typos. `specTypeSchemas.X` is a `StandardSchemaV1<In, Out>`, which composes with any Standard-Schema-aware
523+
library. The pre-existing `isCallToolResult(value)` guard still works.
514524

515525
### Client list methods return empty results for missing capabilities
516526

@@ -706,22 +716,22 @@ try {
706716

707717
The new `SdkErrorCode` enum contains string-valued codes for local SDK errors:
708718

709-
| Code | Description |
710-
| ------------------------------------------------- | ------------------------------------------- |
711-
| `SdkErrorCode.NotConnected` | Transport is not connected |
712-
| `SdkErrorCode.AlreadyConnected` | Transport is already connected |
713-
| `SdkErrorCode.NotInitialized` | Protocol is not initialized |
714-
| `SdkErrorCode.CapabilityNotSupported` | Required capability is not supported |
715-
| `SdkErrorCode.RequestTimeout` | Request timed out waiting for response |
716-
| `SdkErrorCode.ConnectionClosed` | Connection was closed |
717-
| `SdkErrorCode.SendFailed` | Failed to send message |
719+
| Code | Description |
720+
| ------------------------------------------------- | ---------------------------------------------- |
721+
| `SdkErrorCode.NotConnected` | Transport is not connected |
722+
| `SdkErrorCode.AlreadyConnected` | Transport is already connected |
723+
| `SdkErrorCode.NotInitialized` | Protocol is not initialized |
724+
| `SdkErrorCode.CapabilityNotSupported` | Required capability is not supported |
725+
| `SdkErrorCode.RequestTimeout` | Request timed out waiting for response |
726+
| `SdkErrorCode.ConnectionClosed` | Connection was closed |
727+
| `SdkErrorCode.SendFailed` | Failed to send message |
718728
| `SdkErrorCode.InvalidResult` | Response result failed local schema validation |
719-
| `SdkErrorCode.ClientHttpNotImplemented` | HTTP POST request failed |
720-
| `SdkErrorCode.ClientHttpAuthentication` | Server returned 401 after re-authentication |
721-
| `SdkErrorCode.ClientHttpForbidden` | Server returned 403 after trying upscoping |
722-
| `SdkErrorCode.ClientHttpUnexpectedContent` | Unexpected content type in HTTP response |
723-
| `SdkErrorCode.ClientHttpFailedToOpenStream` | Failed to open SSE stream |
724-
| `SdkErrorCode.ClientHttpFailedToTerminateSession` | Failed to terminate session |
729+
| `SdkErrorCode.ClientHttpNotImplemented` | HTTP POST request failed |
730+
| `SdkErrorCode.ClientHttpAuthentication` | Server returned 401 after re-authentication |
731+
| `SdkErrorCode.ClientHttpForbidden` | Server returned 403 after trying upscoping |
732+
| `SdkErrorCode.ClientHttpUnexpectedContent` | Unexpected content type in HTTP response |
733+
| `SdkErrorCode.ClientHttpFailedToOpenStream` | Failed to open SSE stream |
734+
| `SdkErrorCode.ClientHttpFailedToTerminateSession` | Failed to terminate session |
725735

726736
#### `StreamableHTTPError` removed
727737

@@ -938,8 +948,8 @@ You can still explicitly override the validator if needed:
938948
// Runtime-aware default (auto-selects AjvJsonSchemaValidator or CfWorkerJsonSchemaValidator)
939949
import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';
940950

941-
// Specific validators
942-
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';
951+
// Specific validators (no extra validator packages need to be installed)
952+
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';
943953
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';
944954
```
945955

packages/client/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
"types": "./dist/stdio.d.mts",
2929
"import": "./dist/stdio.mjs"
3030
},
31+
"./validators/ajv": {
32+
"types": "./dist/validators/ajv.d.mts",
33+
"import": "./dist/validators/ajv.mjs"
34+
},
3135
"./validators/cf-worker": {
3236
"types": "./dist/validators/cfWorker.d.mts",
3337
"import": "./dist/validators/cfWorker.mjs"
@@ -54,6 +58,9 @@
5458
"types": "./dist/index.d.mts",
5559
"typesVersions": {
5660
"*": {
61+
"validators/ajv": [
62+
"dist/validators/ajv.d.mts"
63+
],
5764
"validators/cf-worker": [
5865
"dist/validators/cfWorker.d.mts"
5966
],
@@ -93,6 +100,8 @@
93100
"@modelcontextprotocol/eslint-config": "workspace:^",
94101
"@modelcontextprotocol/test-helpers": "workspace:^",
95102
"@cfworker/json-schema": "catalog:runtimeShared",
103+
"ajv": "catalog:runtimeShared",
104+
"ajv-formats": "catalog:runtimeShared",
96105
"@types/content-type": "catalog:devTools",
97106
"@types/cross-spawn": "catalog:devTools",
98107
"@types/eventsource": "catalog:devTools",

packages/client/src/shimsNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* This file is selected via package.json export conditions when running in Node.js.
55
*/
6-
export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core';
6+
export { AjvJsonSchemaValidator as DefaultJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv';
77

88
/**
99
* Whether `fetch()` may throw `TypeError` due to CORS. CORS is a browser-only concept —
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* AJV JSON Schema validator re-export for explicit client configuration.
3+
*
4+
* The client package bundles this validator backend for its Node runtime default, so consumers can
5+
* import this subpath without installing `ajv` or `ajv-formats` themselves.
6+
*/
7+
export { AjvJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv';

0 commit comments

Comments
 (0)