fix: keep validator providers off root declarations (#2425)

Co-authored-by: Sehlani042 <257166922+Sehlani042@users.noreply.github.com>
This commit is contained in:
Sehlani042 2026-07-07 02:34:24 +08:00 • committed by GitHub
commit e8de519d31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 46 additions and 10 deletions

View file

@ -0,0 +1,6 @@
---
'@modelcontextprotocol/client': patch
'@modelcontextprotocol/server': patch
---
Stop advertising validator provider classes from the root client/server type declarations. The provider classes remain available from the explicit validator subpaths.

View file

@ -12,6 +12,7 @@ const requireDist = createRequire(join(pkgDir, 'package.json'));
const NODE_ONLY = /\b(child_process|cross-spawn|node:stream|node:child_process)\b/;
// Anchored at start-of-line so JSDoc-example `from 'ajv'` strings in vendored chunks don't match.
const VALIDATOR_BACKEND_IMPORT = /^import[^\n]*?from\s+["'](?:ajv|ajv-formats|@cfworker\/json-schema)["']/m;
const ROOT_VALIDATOR_EXPORTS = ['AjvJsonSchemaValidator', 'CfWorkerJsonSchemaValidator', 'CfWorkerSchemaDraft'];
function chunkImportsOf(entryPath: string): string[] {
const visited = new Set<string>();
@ -29,6 +30,12 @@ function chunkImportsOf(entryPath: string): string[] {
return [...visited];
}
function rootExportBlockOf(content: string): string {
const blocks = content.match(/(?:^|\n)export \{[\s\S]*?\};/g);
expect(blocks).toBeTruthy();
return blocks!.at(-1)!;
}
describe('@modelcontextprotocol/client root entry is browser-safe', () => {
beforeAll(() => {
if (!existsSync(join(distDir, 'index.mjs')) || !existsSync(join(distDir, 'stdio.mjs'))) {
@ -80,4 +87,13 @@ describe('@modelcontextprotocol/client root entry is browser-safe', () => {
expect(new AjvJsonSchemaValidator(ajv)).toBeInstanceOf(AjvJsonSchemaValidator);
});
test('root declarations do not advertise validator provider classes', () => {
for (const declaration of ['index.d.mts', 'index.d.cts']) {
const rootExportBlock = rootExportBlockOf(readFileSync(join(distDir, declaration), 'utf8'));
for (const symbol of ROOT_VALIDATOR_EXPORTS) {
expect(rootExportBlock).not.toMatch(new RegExp(`\\b(?:type\\s+)?${symbol}\\b`));
}
}
});
});

View file

@ -131,10 +131,9 @@ export {
export type { SpecTypeName, SpecTypes } from '../../types/specTypeSchema';
export { isSpecType, specTypeSchemas } from '../../types/specTypeSchema';
export type { StandardSchemaV1, StandardSchemaV1Sync, StandardSchemaWithJSON } from '../../util/standardSchema';
// Validator providers are type-only here — import the runtime classes from the explicit
// `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths to customise.
export type { AjvJsonSchemaValidator } from '../../validators/ajvProvider';
export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from '../../validators/cfWorkerProvider';
// Validator provider classes stay subpath-only. Re-exporting them here, even as
// `type`, can make generated root declarations advertise runtime-shaped root
// exports that the package root does not provide.
// fromJsonSchema is intentionally NOT exported here — the server and client packages
// provide runtime-aware wrappers that default to the appropriate validator via _shims.
export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from '../../validators/types';

View file

@ -33,9 +33,8 @@ export * from './util/standardSchema';
export * from './util/zodCompat';
export { codecForVersion, MODERN_WIRE_REVISION } from './wire/codec';
// Validator providers are type-only here — import the runtime classes from the explicit
// `@modelcontextprotocol/{client,server}/validators/{ajv,cf-worker}` subpaths to customise.
export type { AjvJsonSchemaValidator } from './validators/ajvProvider';
export type { CfWorkerJsonSchemaValidator, CfWorkerSchemaDraft } from './validators/cfWorkerProvider';
// Validator provider classes stay subpath-only. Re-exporting them here, even as
// `type`, can make generated client/server root declarations advertise
// runtime-shaped root exports that the package root does not provide.
export * from './validators/fromJsonSchema';
export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './validators/types';

View file

@ -12,6 +12,7 @@ const requireDist = createRequire(join(pkgDir, 'package.json'));
const NODE_ONLY = /\b(child_process|cross-spawn|node:stream|node:child_process)\b/;
// Anchored at start-of-line so JSDoc-example `from 'ajv'` strings in vendored chunks don't match.
const VALIDATOR_BACKEND_IMPORT = /^import[^\n]*?from\s+["'](?:ajv|ajv-formats|@cfworker\/json-schema)["']/m;
const ROOT_VALIDATOR_EXPORTS = ['AjvJsonSchemaValidator', 'CfWorkerJsonSchemaValidator', 'CfWorkerSchemaDraft'];
function chunkImportsOf(entryPath: string): string[] {
const visited = new Set<string>();
@ -29,6 +30,12 @@ function chunkImportsOf(entryPath: string): string[] {
return [...visited];
}
function rootExportBlockOf(content: string): string {
const blocks = content.match(/(?:^|\n)export \{[\s\S]*?\};/g);
expect(blocks).toBeTruthy();
return blocks!.at(-1)!;
}
describe('@modelcontextprotocol/server root entry is browser-safe', () => {
beforeAll(() => {
if (!existsSync(join(distDir, 'index.mjs')) || !existsSync(join(distDir, 'stdio.mjs'))) {
@ -81,4 +88,13 @@ describe('@modelcontextprotocol/server root entry is browser-safe', () => {
expect(new AjvJsonSchemaValidator(ajv)).toBeInstanceOf(AjvJsonSchemaValidator);
});
test('root declarations do not advertise validator provider classes', () => {
for (const declaration of ['index.d.mts', 'index.d.cts']) {
const rootExportBlock = rootExportBlockOf(readFileSync(join(distDir, declaration), 'utf8'));
for (const symbol of ROOT_VALIDATOR_EXPORTS) {
expect(rootExportBlock).not.toMatch(new RegExp(`\\b(?:type\\s+)?${symbol}\\b`));
}
}
});
});

View file

@ -14,7 +14,7 @@ try {
path.join(dir, 'consumer.ts'),
[
"import { Client } from '@modelcontextprotocol/client';",
"import type { AjvJsonSchemaValidator as ClientAjv } from '@modelcontextprotocol/client';",
"import type { JsonSchemaType as ClientSchema } from '@modelcontextprotocol/client';",
"import { AjvJsonSchemaValidator } from '@modelcontextprotocol/client/validators/ajv';",
"import { CfWorkerJsonSchemaValidator as ClientCf } from '@modelcontextprotocol/client/validators/cf-worker';",
"import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';",
@ -24,7 +24,7 @@ try {
"import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';",
"export const c = new Client({ name: 'smoke', version: '1.0.0' });",
"export const s = new McpServer({ name: 'smoke', version: '1.0.0' });",
'export type T = ClientAjv;',
'export type T = ClientSchema;',
'export { AjvJsonSchemaValidator, ServerAjv, ClientCf, ServerCf, StdioClientTransport, StdioServerTransport };',
''
].join('\n')