Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-unknown-format-warnings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modelcontextprotocol/sdk': patch
---

Silence unknown-format warnings from the default AJV validator. Servers using custom formats no longer spam one warning per subschema on listTools; other warnings and known-format validation are unchanged.
13 changes: 12 additions & 1 deletion src/validation/ajv-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@ function createDefaultAjvInstance(): Ajv {
strict: false,
validateFormats: true,
validateSchema: false,
allErrors: true
allErrors: true,
// Servers may use custom formats Ajv does not know (e.g. google-duration).
// Ajv skips validation for those with one warning per subschema, which
// spams listTools output. Drop only that noise; keep other warnings.
logger: {
log: console.log.bind(console),
error: console.error.bind(console),
warn: (message: string, ...params: unknown[]) => {
if (message.startsWith('unknown format')) return;
console.warn(message, ...params);
}
}
});

const addFormats = _addFormats as unknown as typeof _addFormats.default;
Expand Down
39 changes: 39 additions & 0 deletions test/validation/ajv-unknown-format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Unknown custom formats (e.g. google-duration) should not spam the console.
* The default AJV instance skips validation for formats it does not know;
* it should do so quietly while still enforcing known formats.
*/

import { vi } from 'vitest';

import { AjvJsonSchemaValidator } from '../../src/validation/ajv-provider.js';
import type { JsonSchemaType } from '../../src/validation/types.js';

describe('AjvJsonSchemaValidator unknown formats', () => {
it('compiles custom formats without warning and skips their validation', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
try {
const schema: JsonSchemaType = {
type: 'object',
properties: {
alignmentPeriod: { type: 'string', format: 'google-duration' }
}
};
const validator = new AjvJsonSchemaValidator().getValidator(schema);

expect(warn).not.toHaveBeenCalled();
expect(validator({ alignmentPeriod: '3600s' }).valid).toBe(true);
expect(validator({ alignmentPeriod: 'bogus' }).valid).toBe(true);
} finally {
warn.mockRestore();
}
});

it('still enforces known formats', () => {
const schema: JsonSchemaType = { type: 'string', format: 'email' };
const validator = new AjvJsonSchemaValidator().getValidator(schema);

expect(validator('user@example.com').valid).toBe(true);
expect(validator('invalid-email').valid).toBe(false);
});
});
Loading