Skip to content

Commit 78bd6c2

Browse files
committed
Bundle automatic validator defaults in client and server shims
1 parent 2c0c481 commit 78bd6c2

21 files changed

Lines changed: 185 additions & 112 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@modelcontextprotocol/core': minor
3+
'@modelcontextprotocol/client': patch
4+
'@modelcontextprotocol/server': patch
5+
---
6+
7+
Make JSON Schema validator backends optional inside core and bundle client/server runtime defaults.
8+
9+
`@modelcontextprotocol/core` now keeps runtime validator providers behind explicit internal provider subpaths, with both AJV and `@cfworker/json-schema` treated as optional peer dependencies. The root core barrel no longer re-exports runtime validator providers, so importing core
10+
does not force either backend.
11+
12+
`@modelcontextprotocol/client` and `@modelcontextprotocol/server` 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 or import explicit validators for the default runtime behavior.
14+
15+
Advanced users can still pass their own `jsonSchemaValidator` implementation through client/server options.

docs/migration-SKILL.md

Lines changed: 19 additions & 18 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

@@ -518,11 +519,11 @@ new McpServer(
518519
new McpServer({ name: 'server', version: '1.0.0' }, {});
519520
```
520521

521-
Access validators explicitly:
522+
Validator behavior:
522523

523-
- 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';`
524+
- Do not add validator imports for normal migrations.
525+
- Do not install `ajv`, `ajv-formats`, or `@cfworker/json-schema`; client/server bundle the runtime-selected defaults.
526+
- Advanced users may pass `jsonSchemaValidator: myCustomValidator` with their own validator implementation.
526527

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

docs/migration.md

Lines changed: 41 additions & 28 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

@@ -932,15 +942,18 @@ const server = new McpServer(
932942
);
933943
```
934944

935-
You can still explicitly override the validator if needed:
945+
You do not need to install or import validator packages for the default behavior. The client and server packages bundle the validator backend selected by the runtime shim.
936946

937-
```typescript
938-
// Runtime-aware default (auto-selects AjvJsonSchemaValidator or CfWorkerJsonSchemaValidator)
939-
import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';
947+
Advanced users can still override validation by passing an object that implements the SDK's JSON Schema validator interface:
940948

941-
// Specific validators
942-
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';
943-
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';
949+
```typescript
950+
const server = new McpServer(
951+
{ name: 'my-server', version: '1.0.0' },
952+
{
953+
capabilities: { tools: {} },
954+
jsonSchemaValidator: myCustomValidator
955+
}
956+
);
944957
```
945958

946959
## Unchanged APIs

packages/client/package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@
2828
"types": "./dist/stdio.d.mts",
2929
"import": "./dist/stdio.mjs"
3030
},
31-
"./validators/cf-worker": {
32-
"types": "./dist/validators/cfWorker.d.mts",
33-
"import": "./dist/validators/cfWorker.mjs"
34-
},
3531
"./_shims": {
3632
"workerd": {
3733
"types": "./dist/shimsWorkerd.d.mts",
@@ -54,9 +50,6 @@
5450
"types": "./dist/index.d.mts",
5551
"typesVersions": {
5652
"*": {
57-
"validators/cf-worker": [
58-
"dist/validators/cfWorker.d.mts"
59-
],
6053
"stdio": [
6154
"dist/stdio.d.mts"
6255
]
@@ -93,6 +86,8 @@
9386
"@modelcontextprotocol/eslint-config": "workspace:^",
9487
"@modelcontextprotocol/test-helpers": "workspace:^",
9588
"@cfworker/json-schema": "catalog:runtimeShared",
89+
"ajv": "catalog:runtimeShared",
90+
"ajv-formats": "catalog:runtimeShared",
9691
"@types/content-type": "catalog:devTools",
9792
"@types/cross-spawn": "catalog:devTools",
9893
"@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 —

packages/client/src/validators/cfWorker.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)