Skip to content

Commit 16d13ab

Browse files
authored
feat(client,server): bundle default validators, expose customisation via subpaths (#2088)
1 parent 4a5c863 commit 16d13ab

46 files changed

Lines changed: 749 additions & 314 deletions

Some content is hidden

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

.changeset/cfworker-out-of-barrel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
'@modelcontextprotocol/client': patch
44
---
55

6-
Stop bundling `@cfworker/json-schema` into the main package barrel. Previously `CfWorkerJsonSchemaValidator` was re-exported from the core internal barrel, so tsdown inlined the `@cfworker/json-schema` dev dependency into every consumer's bundle even when it was never used. The validator is now reachable only via the `_shims` conditional (workerd/browser) and the explicit `@modelcontextprotocol/{server,client}/validators/cf-worker` subpath, so consumers that don't opt into it no longer ship that code. No public API change.
6+
Stop bundling `@cfworker/json-schema` into the main package barrel. Previously `CfWorkerJsonSchemaValidator` was re-exported from the core internal barrel, so tsdown inlined the `@cfworker/json-schema` dependency into every consumer's bundle even when it was never used. The named validator classes are now reachable only via the explicit `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths and the runtime `_shims` conditional, so consumers that import only from the root entry point no longer ship the validator dep.

.changeset/support-standard-json-schema.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ server.registerTool('greet', {
2121
For raw JSON Schema (e.g. TypeBox output), use the new `fromJsonSchema` adapter:
2222

2323
```typescript
24-
import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core';
24+
import { fromJsonSchema } from '@modelcontextprotocol/server';
2525

2626
server.registerTool('greet', {
27-
inputSchema: fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } } }, new AjvJsonSchemaValidator())
27+
inputSchema: fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } } })
2828
}, handler);
2929
```
3030

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@modelcontextprotocol/core': minor
3+
'@modelcontextprotocol/client': patch
4+
'@modelcontextprotocol/server': patch
5+
---
6+
7+
Bundle automatic JSON Schema validator defaults in `@modelcontextprotocol/client` and `@modelcontextprotocol/server` runtime shims.
8+
9+
Client and server pick the right validator automatically based on the runtime: the Node shim uses AJV, the browser/workerd shim uses `@cfworker/json-schema`. Both backends are bundled into the shim chunks that select them, so the default code path needs no extra installs — `import { McpServer } from '@modelcontextprotocol/server'` does not pull `ajv` or `@cfworker/json-schema` into the root entry chunk.
10+
11+
The named validator classes remain part of the public surface for consumers who want to customize the built-in backend (pre-register schemas by `$id`, register custom AJV formats, switch dialects, change `@cfworker/json-schema` draft). They are exposed through explicit subpaths so they do not bloat the root index chunk:
12+
13+
- `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/ajv'`
14+
- `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/{client,server}/validators/cf-worker'`
15+
16+
Importing from one of these subpaths means the corresponding peer dep (`ajv` + `ajv-formats`, or `@cfworker/json-schema`) must be in your `package.json`. The shim keeps its own vendored copy for the default path, so a project can use the subpath in some files and rely on the default in others.
17+
18+
The `jsonSchemaValidator` interface remains the public extension point for replacing validation entirely with a custom implementation.

docs/migration-SKILL.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,8 @@ Type changes in handler context:
509509

510510
The SDK now auto-selects the appropriate JSON Schema validator based on runtime:
511511

512-
- Node.js → `AjvJsonSchemaValidator` (no change from v1)
513-
- Cloudflare Workers (workerd) → `CfWorkerJsonSchemaValidator` (previously required manual config)
512+
- Node.js → AJV (no change from v1)
513+
- Cloudflare Workers (workerd) → `@cfworker/json-schema` (previously required manual config)
514514

515515
**No action required** for most users. Cloudflare Workers users can remove explicit `jsonSchemaValidator` configuration:
516516

@@ -527,11 +527,12 @@ new McpServer(
527527
new McpServer({ name: 'server', version: '1.0.0' }, {});
528528
```
529529

530-
Access validators explicitly:
530+
Validator behavior:
531531

532-
- Runtime-aware default: `import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';`
533-
- AJV (Node.js): `import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';`
534-
- CF Worker: `import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';`
532+
- Do not add validator imports for normal migrations.
533+
- Do not install `ajv`, `ajv-formats`, or `@cfworker/json-schema` for the default path; client/server bundle the runtime-selected defaults and the root entry point does not pull either dep in.
534+
- To customize the built-in backend (e.g. register custom AJV formats, change `@cfworker/json-schema` draft), import the named class from the package subpath: `@modelcontextprotocol/{client,server}/validators/ajv` for `AjvJsonSchemaValidator`, `@modelcontextprotocol/{client,server}/validators/cf-worker` for `CfWorkerJsonSchemaValidator`. Importing from a subpath means the corresponding peer dep must be in your `package.json`.
535+
- To replace validation entirely, pass `jsonSchemaValidator: myCustomValidator` with your own implementation of the `jsonSchemaValidator` interface.
535536

536537
## 15. Migration Steps (apply in this order)
537538

docs/migration.md

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -901,8 +901,8 @@ server.setRequestHandler('tools/call', async (request, ctx) => {
901901

902902
The SDK now automatically selects the appropriate JSON Schema validator based on your runtime environment:
903903

904-
- **Node.js**: Uses `AjvJsonSchemaValidator` (same as v1 default)
905-
- **Cloudflare Workers**: Uses `CfWorkerJsonSchemaValidator` (previously required manual configuration)
904+
- **Node.js**: Uses AJV (same as v1 default)
905+
- **Cloudflare Workers**: Uses `@cfworker/json-schema` (previously required manual configuration)
906906

907907
This means Cloudflare Workers users no longer need to explicitly pass the validator:
908908

@@ -933,17 +933,45 @@ const server = new McpServer(
933933
);
934934
```
935935

936-
You can still explicitly override the validator if needed:
936+
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, so a normal `import { McpServer } from '@modelcontextprotocol/server'` does not pull `ajv` or `@cfworker/json-schema` into your bundle until you choose to customize.
937+
938+
If you want to customize the **built-in** backend (for example, pre-register schemas by `$id`, register custom AJV formats, or change the `@cfworker/json-schema` draft), import the named class from the explicit subpath and pass an instance through `jsonSchemaValidator`:
937939

938940
```typescript
939-
// Runtime-aware default (auto-selects AjvJsonSchemaValidator or CfWorkerJsonSchemaValidator)
940-
import { DefaultJsonSchemaValidator } from '@modelcontextprotocol/server/_shims';
941+
import { Ajv } from 'ajv';
942+
import addFormats from 'ajv-formats';
943+
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server/validators/ajv';
944+
945+
const ajv = new Ajv({ strict: true, allErrors: true });
946+
addFormats(ajv);
941947

942-
// Specific validators
943-
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/server';
948+
const server = new McpServer(
949+
{ name: 'my-server', version: '1.0.0' },
950+
{
951+
capabilities: { tools: {} },
952+
jsonSchemaValidator: new AjvJsonSchemaValidator(ajv)
953+
}
954+
);
955+
```
956+
957+
```typescript
944958
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker';
959+
960+
const server = new McpServer(
961+
{ name: 'my-server', version: '1.0.0' },
962+
{
963+
capabilities: { tools: {} },
964+
jsonSchemaValidator: new CfWorkerJsonSchemaValidator({ draft: '2020-12', shortcircuit: false })
965+
}
966+
);
945967
```
946968

969+
(both subpaths are also available on `@modelcontextprotocol/client/validators/...`)
970+
971+
If you import from one of these subpaths in your own code, the corresponding peer dep (`ajv` + `ajv-formats`, or `@cfworker/json-schema`) needs to be installed in your `package.json`. The runtime shim continues to vendor a copy for the default code path, so you can use the subpath in some files and rely on the default in others.
972+
973+
To replace validation wholesale rather than customizing the built-in classes, implement the `jsonSchemaValidator` interface and pass your own implementation through the option above.
974+
947975
## Unchanged APIs
948976

949977
The following APIs are unchanged between v1 and v2 (only the import paths changed):

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/client/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export type ClientOptions = ProtocolOptions & {
161161
* The validator is used to validate structured content returned by tools
162162
* against their declared output schemas.
163163
*
164-
* @default {@linkcode DefaultJsonSchemaValidator} ({@linkcode index.AjvJsonSchemaValidator | AjvJsonSchemaValidator} on Node.js, `CfWorkerJsonSchemaValidator` on Cloudflare Workers)
164+
* @default Runtime-selected validator (AJV-backed on Node.js, `@cfworker/json-schema`-backed on browser/workerd runtimes)
165165
*/
166166
jsonSchemaValidator?: jsonSchemaValidator;
167167

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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Customisation entry point for the AJV validator. Re-exports `Ajv` + `addFormats` from the
3+
* SDK's bundled copy, so customising the validator needs no extra installs.
4+
*
5+
* @example
6+
* ```ts
7+
* import { Ajv, addFormats, AjvJsonSchemaValidator } from '@modelcontextprotocol/client/validators/ajv';
8+
*
9+
* const ajv = new Ajv({ strict: true, allErrors: true });
10+
* addFormats(ajv);
11+
* const validator = new AjvJsonSchemaValidator(ajv);
12+
* ```
13+
*/
14+
export { addFormats, Ajv, AjvJsonSchemaValidator } from '@modelcontextprotocol/core/validators/ajv';
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
/**
2-
* Cloudflare Workers JSON Schema validator, available as a sub-path export.
3-
*
4-
* @example
5-
* ```ts
6-
* import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/client/validators/cf-worker';
7-
* ```
8-
*/
1+
/** Customisation entry point for the `@cfworker/json-schema` validator. */
92
export type { CfWorkerSchemaDraft } from '@modelcontextprotocol/core/validators/cfWorker';
103
export { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/core/validators/cfWorker';

0 commit comments

Comments
 (0)