Bundle automatic validator defaults in client/server shims#2088
Bundle automatic validator defaults in client/server shims#2088mattzcarey wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: a2b954b The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/server
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
54c18d7 to
ba08235
Compare
c7601a2 to
5db154c
Compare
5db154c to
78bd6c2
Compare
9c5c541 to
57c3a0b
Compare
| "types": "./dist/stdio.d.mts", | ||
| "import": "./dist/stdio.mjs" | ||
| }, | ||
| "./validators/cf-worker": { | ||
| "types": "./dist/validators/cfWorker.d.mts", | ||
| "import": "./dist/validators/cfWorker.mjs" | ||
| }, | ||
| "./_shims": { |
There was a problem hiding this comment.
🟡 nit: a few prose references to the removed validator paths survive — .changeset/cfworker-out-of-barrel.md:6 still says the validator is "reachable only via … the explicit @modelcontextprotocol/{server,client}/validators/cf-worker subpath … No public API change", packages/core/src/validators/ajvProvider.ts:36's @see still points at those same removed subpaths (this JSDoc is bundled into the published .d.mts), and .changeset/support-standard-json-schema.md:24-27 still shows import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core' + new AjvJsonSchemaValidator(), which is now a type-only export. Worth grepping for validators/cf-worker and updating these alongside the migration-doc rewrites so the next CHANGELOG and IDE hovers don't advertise paths this PR deletes.
Extended reasoning...
What the issue is
This PR removes the ./validators/cf-worker subpath from packages/{client,server}/package.json (and deletes both src/validators/cfWorker.ts files), and demotes AjvJsonSchemaValidator from a runtime re-export to export type in both core barrels. The PR updates the migration docs, the new changeset, and the JSDoc in packages/core/src/index.ts to match — but three pre-existing prose references to the old form survive untouched:
.changeset/cfworker-out-of-barrel.md:6— still reads: "The validator is now reachable only via the_shimsconditional (workerd/browser) and the explicit@modelcontextprotocol/{server,client}/validators/cf-workersubpath, so consumers that don't opt into it no longer ship that code. No public API change." This changeset is not in.changeset/pre.json's consumedchangesetsarray, so it is unreleased and will land in the same CHANGELOG version as this PR'sworkerd-shim-vendors-cfworker.md.packages/core/src/validators/ajvProvider.ts:36—@seeCfWorkerJsonSchemaValidatorfor an edge-runtime-compatible alternative (import from@modelcontextprotocol/server/validators/cf-workeror@modelcontextprotocol/client/validators/cf-worker). This file is not in the PR's changed-files list..changeset/support-standard-json-schema.md:24-27—import { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core';followed bynew AjvJsonSchemaValidator(). Afterpackages/core/src/index.ts:22becomesexport type { AjvJsonSchemaValidator }, that example is a TS error ("cannot be used as a value because it was exported using 'export type'"). This changeset is inpre.json(already applied to an alpha CHANGELOG), but in changesets pre-mode the.mdpersists and is re-aggregated into the final 2.0.0 CHANGELOG onchangeset pre exit.
A repo-wide grep for validators/cf-worker confirms (1) and (2) are the only two surviving references to the removed subpath.
Why existing review feedback doesn't cover it
The earlier inline comment on packages/core/src/exports/public/index.ts:145 enumerated four doc sites that pointed at @modelcontextprotocol/core/... (docs/migration.md, docs/migration-SKILL.md, .changeset/workerd-shim-vendors-cfworker.md, and the JSDoc in packages/core/src/index.ts). The current revision reworked all four. None of the three locations above were on that list, so they were missed in the same cleanup pass — this is the REVIEW.md "Completeness" recurring catch ("when a PR replaces a pattern, grep the package for surviving instances of the old form").
Step-by-step proof
- This PR deletes
"./validators/cf-worker"frompackages/server/package.jsonexports + typesVersions and frompackages/client/package.json, removes bothsrc/validators/cfWorker.tsfiles, and drops them from bothtsdown.config.tsentry arrays. changesets versionruns on the next release.cfworker-out-of-barrel.mdis not inpre.json'schangesets[], so it is consumed alongsideworkerd-shim-vendors-cfworker.md. The generatedpackages/server/CHANGELOG.mdfor that version contains both entries: one says "reachable only via …/validators/cf-workersubpath … No public API change", the other says explicit validator subpaths are removed. A user reading the release notes gets directly contradictory guidance.tsdownbundlesajvProvider.ts's class JSDoc intodist/shimsNode.d.mts(it's re-exported asDefaultJsonSchemaValidator) and into the root.d.mts(type-only). A consumer hoversDefaultJsonSchemaValidatororAjvJsonSchemaValidatorin their IDE and sees@see … import from @modelcontextprotocol/server/validators/cf-worker. They tryimport { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker'→ERR_PACKAGE_PATH_NOT_EXPORTED.- On
changeset pre exit,support-standard-json-schema.mdis re-emitted into the stable 2.0.0 CHANGELOG. A user copies thefromJsonSchemaexample, gets'AjvJsonSchemaValidator' cannot be used as a value because it was exported using 'export type'(and@modelcontextprotocol/coreisprivate: true, so the import path was already wrong for external consumers even before this PR).
Impact
Doc-only; no runtime effect. The cfworker-out-of-barrel.md case is the most concrete because it produces self-contradicting published release notes in the very next version bump. The ajvProvider.ts @see surfaces in end-user IDE tooltips. The support-standard-json-schema.md example was already broken for external users (private package), so this PR just makes it slightly more broken; still worth fixing while validator docs are being touched.
How to fix
.changeset/cfworker-out-of-barrel.md: either delete it (its purpose is subsumed byworkerd-shim-vendors-cfworker.md) or rewrite line 6 to drop the/validators/cf-workersubpath reference and the "No public API change" claim.packages/core/src/validators/ajvProvider.ts:36: change the@seeto reference automatic runtime selection (matching the updatedpackages/core/src/index.tsJSDoc), or simply@see {@link CfWorkerJsonSchemaValidator}without an import path..changeset/support-standard-json-schema.md:23-28: rewrite the example toimport { fromJsonSchema } from '@modelcontextprotocol/server'and drop the explicitnew AjvJsonSchemaValidator()argument, matching the updateddocs/migration.mdguidance.
There was a problem hiding this comment.
Thanks — ajvProvider.ts:36's @see is now fixed. The two changeset files are still untouched, though:
.changeset/cfworker-out-of-barrel.md:6still says the validator is "reachable only via … the explicit@modelcontextprotocol/{server,client}/validators/cf-workersubpath … No public API change". This changeset is unreleased and will land in the same CHANGELOG version asworkerd-shim-vendors-cfworker.md, producing directly contradictory release notes. Easiest fix is to delete it (its purpose is now subsumed by the new changeset)..changeset/support-standard-json-schema.md:24-27still showsimport { fromJsonSchema, AjvJsonSchemaValidator } from '@modelcontextprotocol/core'+new AjvJsonSchemaValidator(), which is now a type-only export. Suggest rewriting toimport { fromJsonSchema } from '@modelcontextprotocol/server'and dropping the explicit validator arg, matching the updateddocs/migration.mdexample.
(Repo-wide grep for validators/cf-worker now matches only cfworker-out-of-barrel.md, confirming the ajvProvider.ts reference is gone.)
57c3a0b to
a2b954b
Compare
| test('should register tool with raw JSON Schema input', async () => { | ||
| const inputSchema = fromJsonSchema<{ name: string }>( | ||
| { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }, | ||
| validator | ||
| ); | ||
| const inputSchema = serverFromJsonSchema<{ name: string }>({ | ||
| type: 'object', | ||
| properties: { name: { type: 'string' } }, | ||
| required: ['name'] | ||
| }); | ||
|
|
||
| mcpServer.registerTool('greet', { inputSchema }, async ({ name }) => ({ | ||
| content: [{ type: 'text', text: `Hello, ${name}!` }] |
There was a problem hiding this comment.
🟡 nit: this rewrite makes describe('Raw JSON Schema via fromJsonSchema') and describe('fromJsonSchema with default validator (server wrapper)') exercise the same code path — both now call serverFromJsonSchema(...) with no explicit validator on the same {name:string} / {count:number} schemas, so the second block is a strict subset of the first (the first additionally asserts the tools/list inputSchema shape). The explicit-validator coverage that block 1 used to provide moved to the new packages/{client,server}/test/**/jsonSchemaValidatorOverride.test.ts files, so the simplest cleanup is to delete the second describe block.
Extended reasoning...
What changed
Before this PR, the two adjacent describe blocks in standardSchema.test.ts covered distinct axes:
describe('Raw JSON Schema via fromJsonSchema')built schemas via core'sfromJsonSchema(schema, new AjvJsonSchemaValidator())— i.e. an explicit validator instance passed by the caller.describe('fromJsonSchema with default validator (server wrapper)')built schemas viaserverFromJsonSchema(schema)with no validator argument — i.e. the server wrapper's runtime-selected default.
This PR removes AjvJsonSchemaValidator and core fromJsonSchema from the file's imports and rewrites block 1 to use serverFromJsonSchema with no validator argument (and renames its second test from 'should reject invalid input via AJV validation' → '…via default validation'). After the rewrite, both blocks call exactly the same function with the same default-validator semantics.
Side-by-side after the diff
| Block 1: "Raw JSON Schema via fromJsonSchema" | Block 2: "fromJsonSchema with default validator (server wrapper)" | |
|---|---|---|
| Test 1 schema | serverFromJsonSchema<{name:string}>({…name…}) |
serverFromJsonSchema<{name:string}>({…name…}) |
| Test 1 assertions | tools/list inputSchema shape + tools/call returns Hello, World! |
tools/call returns Hello, World! |
| Test 2 schema | serverFromJsonSchema({…count:number…}) |
serverFromJsonSchema({…count:number…}) |
| Test 2 assertions | count:'not a number' → isError + 'Input validation error' |
identical |
Block 2 is now a strict subset of block 1 — the only delta is block 1's extra tools/list toMatchObject assertion. The two "reject invalid input" tests are functionally identical.
Why nothing was actually lost (addressing the refutation)
One reviewer argued this isn't worth flagging because (a) the blocks aren't strictly identical and (b) the explicit-validator coverage didn't disappear. Both points are correct and are why this is a nit, not a defect:
- The rewrite was forced by this PR's own change —
AjvJsonSchemaValidatoris no longer a runtime export from@modelcontextprotocol/core's root barrel, sonew AjvJsonSchemaValidator()here would have required rewiring to the/validators/ajvsubpath (aselicitation.test.tsdoes in this same diff). - The explicit-override path that block 1 used to cover did move, not vanish: this PR adds
packages/server/test/server/jsonSchemaValidatorOverride.test.tsandpackages/client/test/client/jsonSchemaValidatorOverride.test.ts, each containing a'fromJsonSchema uses an explicitly supplied custom validator'test with aRecordingValidatorthat asserts the exact schema and value passed through. That's stronger coverage than the old AJV smoke test.
So no coverage regression — the only residue is that this file now contains two describe blocks doing the same thing, which is the kind of test-hygiene cleanup that's cheap to do while the file is already being touched.
Step-by-step proof
- Pre-PR line 8 imports
AjvJsonSchemaValidator, fromJsonSchemafrom core; block 1 opens withconst validator = new AjvJsonSchemaValidator()and callsfromJsonSchema(schema, validator). - Diff replaces line 8 with
import { InMemoryTransport } from '@modelcontextprotocol/core'(dropping both symbols), deletes thevalidatorconst, and rewrites bothfromJsonSchema(schema, validator)calls toserverFromJsonSchema({...}). serverFromJsonSchemawas already imported on line 9 and is what block 2 (lines ~431-467, untouched by this diff) already uses.- Result: block 1 test 1 ≡ block 2 test 1 minus the
tools/listassertion; block 1 test 2 ≡ block 2 test 2 (tool name'double'vs'double-default'is the only difference).
Suggested fix
Delete describe('fromJsonSchema with default validator (server wrapper)') (lines ~431-467) — its tests are now fully covered by the rewritten block above it. Alternatively, fold block 1's tools/list assertion into block 2 and delete block 1; either way one block goes.
| * Client and server packages bundle their runtime default validator backends, so most users should | ||
| * rely on automatic runtime selection. Advanced users can pass their own validator implementation | ||
| * through client/server options. | ||
| * | ||
| * @example For Node.js with AJV | ||
| * ```ts source="./index.examples.ts#validation_ajv" |
There was a problem hiding this comment.
🟡 nit: the prose update here stops one line short — the two @example blocks immediately below (lines 45-53, sourced from index.examples.ts#validation_ajv / #validation_cfWorker) still render new AjvJsonSchemaValidator() / new CfWorkerJsonSchemaValidator(), which now directly contradicts the rewritten paragraph saying to rely on automatic selection or pass a custom jsonSchemaValidator. This is separate from the three sites in the open comment on packages/server/package.json:31 (the suggested validators/cf-worker grep won't find these); easiest fix is to drop both @example blocks and the corresponding regions in index.examples.ts, or rewrite them to show { jsonSchemaValidator: myCustomValidator }.
Extended reasoning...
What the issue is
This PR's hunk for packages/core/src/index.ts rewrites the @module validation JSDoc: lines 22/27 demote AjvJsonSchemaValidator and CfWorkerJsonSchemaValidator to export type, and lines 35-43 replace the old "Import from: …/validators/cf-worker" guidance with new prose saying "Client and server packages bundle their runtime default validator backends, so most users should rely on automatic runtime selection. Advanced users can pass their own validator implementation through client/server options." The diff hunk's last context line is @example For Node.js with AJV — i.e. the edit stops exactly at the example boundary.
Lines 45-53, immediately below, are unchanged and still render:
// @example For Node.js with AJV
const validator = new AjvJsonSchemaValidator();
// @example For Cloudflare Workers
const validator = new CfWorkerJsonSchemaValidator();Both snippets are sourced from packages/core/src/index.examples.ts (#validation_ajv at lines 16-21, #validation_cfWorker at lines 26-31), which still imports the concrete classes from ./validators/{ajv,cfWorker}Provider.js. So the examples file still compiles — this is purely a rendered-doc contradiction, not a build break.
Why it matters / why existing checks don't catch it
After this PR, both validator classes are type-only in both core barrels (src/index.ts:22,27 and src/exports/public/index.ts:144-145), and the published ./validators/cf-worker subpaths are removed from client and server. There is no published runtime path a reader could use to do new AjvJsonSchemaValidator() — yet the very JSDoc block this PR edits still demonstrates exactly that, two lines below prose telling them not to. Because index.examples.ts imports via internal relative paths, neither tsc nor the barrelClean tests flag the staleness.
Not a duplicate of the open comments
- The still-open inline comment on
packages/server/package.json:31enumerates three other stale-prose sites (.changeset/cfworker-out-of-barrel.md,ajvProvider.ts:36,.changeset/support-standard-json-schema.md) and suggests grepping forvalidators/cf-worker. These@exampleblocks contain neither that string nor any import path, so that grep would not find them. - The resolved inline comment on
exports/public/index.ts:145did name "the JSDoc inpackages/core/src/index.ts" — and the author updated the prose paragraph in response, but stopped before the adjacent@examplesnippets. This is the leftover half of that fix.
Step-by-step proof
- Open the rendered
@module validationJSDoc (or just readpackages/core/src/index.ts:30-53after this PR). - Lines 41-43 say: "most users should rely on automatic runtime selection. Advanced users can pass their own validator implementation through client/server options."
- Line 45 (
@example For Node.js with AJV) rendersconst validator = new AjvJsonSchemaValidator();. AjvJsonSchemaValidatorisexport typeon line 22 of this same file and on line 144 ofexports/public/index.ts; the/validators/ajvand/validators/cf-workersubpaths are gone frompackages/{client,server}/package.json. A reader following the example has no published constructor to call.- Line 50 repeats the same for
CfWorkerJsonSchemaValidator. - The same JSDoc block therefore tells readers "don't instantiate concrete validators" and then shows them doing so — an internal contradiction introduced by this PR's prose rewrite.
Impact
Doc-only. @modelcontextprotocol/core is private: true and this is the internal root barrel's @module-level comment, so end-user exposure is limited (it's unclear it even surfaces in published .d.mts). But it's an inconsistency within the very block this PR edits, cheap to fold into the same cleanup pass that addresses the open packages/server/package.json:31 comment — hence nit.
How to fix
Either:
- Delete the two
@exampleblocks (lines 45-53) and the correspondingvalidation_ajv/validation_cfWorkerregions inpackages/core/src/index.examples.ts; or - Rewrite them to demonstrate the override pattern the new prose teaches, e.g.
new McpServer(info, { jsonSchemaValidator: myCustomValidator }), mirroring the updateddocs/migration.mdsnippet.
| test('runtime shims vendor default validator backends instead of requiring consumers to install them', () => { | ||
| for (const shim of ['shimsNode.mjs', 'shimsWorkerd.mjs']) { | ||
| const entry = join(distDir, shim); | ||
| expect(readFileSync(entry, 'utf8')).not.toMatch(VALIDATOR_BACKEND_IMPORT); | ||
|
|
||
| for (const chunk of chunkImportsOf(entry)) { | ||
| expect({ chunk, content: readFileSync(chunk, 'utf8') }).not.toEqual( | ||
| expect.objectContaining({ content: expect.stringMatching(VALIDATOR_BACKEND_IMPORT) }) | ||
| ); | ||
| } | ||
| } | ||
| }); |
There was a problem hiding this comment.
🟡 nit (pre-existing): this regression test only covers .mjs, but the published .d.mts still bare-imports ajv — building packages/server emits dist/ajvProvider-*.d.mts with import { Ajv } from "ajv"; (for constructor(ajv?: Ajv)), transitively pulled in by dist/index.d.mts and dist/shimsNode.d.mts, and dist/types-*.d.mts likewise has import { JSONSchema } from "json-schema-typed";. Neither ajv nor json-schema-typed is in server/client dependencies/peerDependencies, so a skipLibCheck: false consumer who follows the new docs/migration-SKILL.md:524 instruction "Do not install ajv, ajv-formats, or @cfworker/json-schema" gets TS2307: Cannot find module 'ajv'. Either extend the scan to dist/*.d.mts and replace the Ajv ctor-arg type with a local structural type (matching what cfWorkerProvider already does — its .d.mts leaks no @cfworker/json-schema import), or add a skipLibCheck caveat to the migration-SKILL line. Same applies to packages/client/test/client/barrelClean.test.ts.
Extended reasoning...
What the issue is
This PR adds a regression test asserting that the runtime shim .mjs files (and their .mjs chunk imports) contain no bare from 'ajv'|'ajv-formats'|'@cfworker/json-schema' import. That correctly enforces the runtime half of the "users do not need to install validator packages" goal. But the published type declarations still leak a bare ajv import that this test does not cover, and this PR's new migration-doc line tells users not to install ajv.
Building packages/server at this PR's HEAD produces:
dist/ajvProvider-BD030R9d.d.mts:2→import { Ajv } from "ajv";(needed forconstructor(ajv?: Ajv)on line 39).dist/index.d.mts:3anddist/shimsNode.d.mts:1both import that chunk, so any consumer importing anything from@modelcontextprotocol/serverhas TypeScript load a.d.mtsthat doesimport { Ajv } from "ajv".dist/types-YaX0ZWcZ.d.mts:1→import { JSONSchema } from "json-schema-typed";.
Neither ajv nor json-schema-typed appears in packages/server/package.json dependencies or peerDependencies — ajv is added only to devDependencies in this PR, and json-schema-typed is only in private core's deps. By contrast, dist/cfWorkerProvider-*.d.mts leaks no @cfworker/json-schema import because its constructor uses a locally-declared CfWorkerSchemaDraft type — so the AJV side is asymmetrically worse and the fix pattern already exists in-tree.
Why existing code doesn't catch it
The new VALIDATOR_BACKEND_IMPORT check iterates only ['shimsNode.mjs', 'shimsWorkerd.mjs'], and chunkImportsOf() follows only ./*.mjs relative imports — .d.mts files are never visited. tsdown's noExternal bundles the runtime code but does not inline external type references in the DTS output, so the Ajv parameter type survives as a bare import.
Why this is worth a nit on this PR despite being pre-existing
The .d.mts leak itself is pre-existing — the parent commit 2c0c481 also emits from "ajv" in dist/index-*.d.mts — so it is not a regression. What this PR newly adds is docs/migration-SKILL.md:524: "Do not install ajv, ajv-formats, or @cfworker/json-schema; client/server bundle the runtime-selected defaults." That instruction, taken at face value by a consumer with "skipLibCheck": false, produces a compile error on the published artifacts. This PR also touches ajvProvider.ts directly (the @see line), so the file in question is in-diff. The new test gives a (mild) false sense that the "no validator install needed" goal is fully enforced — it covers runtime but not types.
This is not a duplicate of the open inline comments: #3241089399 covers stale prose referencing the removed /validators/cf-worker subpath, and #3241222796 covers stale @example blocks in core/src/index.ts. Neither mentions the .d.mts bare-import leak or the skipLibCheck interaction.
Step-by-step proof
- A consumer creates a fresh project with
"skipLibCheck": falseintsconfig.jsonand runsnpm install @modelcontextprotocol/server. - Following the new
docs/migration-SKILL.md:524guidance, they do not installajv,ajv-formats, or@cfworker/json-schema. - They write
import { McpServer } from '@modelcontextprotocol/server';and runtsc. - TypeScript resolves
node_modules/@modelcontextprotocol/server/dist/index.d.mts, which on line 3 doesimport … from './ajvProvider-BD030R9d.mjs';→ resolvesajvProvider-BD030R9d.d.mts. - Line 2 of that file is
import { Ajv } from "ajv";.ajvis not innode_modules(onlyzodis a runtime dependency of@modelcontextprotocol/server). tscfails witherror TS2307: Cannot find module 'ajv' or its corresponding type declarations.(and likewiseTS2307forjson-schema-typedviatypes-*.d.mts).- The new
barrelClean.test.tsregression test passes throughout because it never reads*.d.mts.
Impact
Low — most TypeScript projects set skipLibCheck: true (it's the tsc --init default), so the failure mode is narrow. Runtime behavior is correct: the bundled .mjs chunks contain the AJV/cfworker code and no consumer install is needed to run. The concrete harm is doc-vs-artifact contradiction for the skipLibCheck:false minority, plus a test that enforces only half of the stated goal. The json-schema-typed half is clearly out-of-scope for this PR; mentioned for completeness.
How to fix
Either of:
- Close the leak — in
packages/core/src/validators/ajvProvider.ts, replace theconstructor(ajv?: Ajv)parameter type with a locally-declared structural type (orunknown/an internal interface), mirroringcfWorkerProvider.ts'sCfWorkerSchemaDraftapproach so the emitted.d.mtsno longer needsimport { Ajv } from "ajv". Optionally extend this test (and the client twin) to also scandist/*.d.mtsforVALIDATOR_BACKEND_IMPORTso the invariant is enforced for types as well as runtime. - Soften the doc — add a brief caveat to
docs/migration-SKILL.md:524(and the correspondingdocs/migration.mdparagraph) noting that projects withskipLibCheck: falsemay still needajvinstalled for type resolution until the declaration leak is closed.
| Make validator backends symmetrical in core and bundle automatic defaults in client/server runtime shims. | ||
|
|
||
| Core no longer re-exports concrete validator providers as runtime values from the root/public barrels. AJV/AJV formats and `@cfworker/json-schema` are optional peer backends behind explicit core validator provider subpaths, used internally by client/server shims. | ||
|
|
||
| Client/server continue to select defaults automatically: Node shims use AJV, while browser/workerd shims use `@cfworker/json-schema`. Those backends are bundled into the shim chunks that select them, so users do not need to install validator packages or import explicit validators for default behavior. Advanced users can still pass their own `jsonSchemaValidator` implementation. |
There was a problem hiding this comment.
🟡 nit: this changeset describes the core barrel change and the shim bundling, but never says that the ./validators/cf-worker subpath export was removed from @modelcontextprotocol/{client,server} — line 11's "do not need to … import explicit validators" reads as a convenience, not a removal. Worth one explicit sentence here, especially since the open comment on packages/server/package.json:31 suggests deleting .changeset/cfworker-out-of-barrel.md, which would leave this as the only changeset covering the subpath and the removal entirely undocumented in the generated CHANGELOG.
Extended reasoning...
What the issue is
This PR removes a public subpath export from two published packages: ./validators/cf-worker is deleted from the exports and typesVersions maps in packages/{client,server}/package.json, both src/validators/cfWorker.ts re-export files are deleted, and the entry is dropped from both tsdown.config.ts arrays. The previously-documented pattern import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker' now resolves to ERR_PACKAGE_PATH_NOT_EXPORTED.
The PR's own changeset, .changeset/workerd-shim-vendors-cfworker.md, describes two things: (a) core no longer re-exporting concrete validator providers as runtime values from its barrels, and (b) client/server bundling default backends into their shim chunks. Line 11 says "users do not need to install validator packages or import explicit validators for default behavior" — but that frames explicit imports as no longer necessary, not as no longer possible. Nowhere does the changeset state that the ./validators/cf-worker subpath was removed from client/server.
Why this isn't covered by existing comments
The still-open inline comment on packages/server/package.json:31 is about other prose that still references the removed subpath (.changeset/cfworker-out-of-barrel.md, ajvProvider.ts:36's @see, .changeset/support-standard-json-schema.md). This finding is the inverse: the PR's own new changeset fails to announce the removal it introduces.
The two interact: that open comment's first suggested fix is "delete cfworker-out-of-barrel.md (its purpose is subsumed by workerd-shim-vendors-cfworker.md)". If the author follows that suggestion as-is, workerd-shim-vendors-cfworker.md becomes the only changeset touching this area — and it doesn't mention the subpath removal, so the generated CHANGELOG would contain no record that @modelcontextprotocol/{client,server}/validators/cf-worker ever went away.
The resolved comment on exports/public/index.ts:145 did raise the patch-vs-breaking concern, but for the earlier export type change. The author's resolution expanded the breaking surface (it removed the subpath entirely instead of adding a parallel one) without revisiting the changeset prose. The bump-level concern itself is muted by 2.0.0-alpha.2 pre-release status, so the actionable residue is just the missing prose.
Step-by-step proof
- A consumer on
@modelcontextprotocol/server@2.0.0-alpha.2hasimport { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/server/validators/cf-worker'— the exact pattern the pre-PRdocs/migration.mdanddocs/migration-SKILL.mddocumented. - They upgrade to the next alpha containing this PR.
packages/server/package.jsonno longer has"./validators/cf-worker"inexports; Node throwsERR_PACKAGE_PATH_NOT_EXPORTED. - They open the generated
packages/server/CHANGELOG.mdfor that version. The entry fromworkerd-shim-vendors-cfworker.mdreads: "Client/server continue to select defaults automatically … users do not need to install validator packages or import explicit validators for default behavior. Advanced users can still pass their ownjsonSchemaValidatorimplementation." - Nothing in that text says the subpath was removed. The consumer has to infer the API removal from a sentence about defaults, or grep the diff.
- If
.changeset/cfworker-out-of-barrel.mdis also deleted per the open comment's suggestion, there is no CHANGELOG entry mentioning/validators/cf-workerat all.
Impact
Doc-only; no runtime effect. The PR description and updated migration guides do call this out ("Public surface: explicit concrete validator subpaths are removed from client/server"), so the gap is specifically in the changeset → CHANGELOG path. Filed as a nit given the alpha pre-release context and that three related doc nits are already open — but it's a one-line addition while the changeset is being touched anyway.
How to fix
Add one sentence to .changeset/workerd-shim-vendors-cfworker.md, e.g. after line 11:
The explicit
./validators/cf-workersubpath export has been removed from@modelcontextprotocol/clientand@modelcontextprotocol/server; rely on automatic runtime selection or pass a customjsonSchemaValidator.
(If .changeset/cfworker-out-of-barrel.md is kept and rewritten per the other open comment instead of deleted, that would also cover it — either location works as long as one changeset states the removal.)
Summary
@cfworker/json-schemafor browser/workerd defaults.validators/cf-workersubpath exports. Validator selection is automatic for normal users; advanced users can provide their ownjsonSchemaValidatorimplementation.ajv,ajv-formats, or@cfworker/json-schemafor consumers to resolve.Why
Client and server choose runtime defaults via conditional
_shims:@cfworker/json-schema-backed validatorBecause client/server make those default choices, consumers should not need to know about or install validator implementation dependencies. Those backends are now bundled into the shim chunks that select them.
Impact
jsonSchemaValidator: myCustomValidatorwith their own implementation.@modelcontextprotocol/core,ajv,ajv-formats, or@cfworker/json-schema; those implementations are bundled where client/server need them.Follow-up for codemod reviewers
If this validator packaging change ships, the v1-to-v2 codemod should probably remove redundant manual SDK validator imports/configuration for the built-in AJV and Cloudflare Workers validators. Those validators are no longer exported from client/server as explicit public subpaths, and normal migrations should rely on automatic runtime defaults instead.
Examples the codemod should consider simplifying/removing when they refer to the SDK built-ins:
For custom user validators, the codemod should preserve the override:
Reviewer note: this PR intentionally makes built-in validator selection automatic for client/server users; codemod output should not teach users to import SDK concrete validators for the default case.