feat: pluggable JSON schema validator providers (#1012)

This commit is contained in:
Matt 2025-10-25 16:56:42 +01:00 • committed by GitHub
commit 5a8fb39430
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,25 +1,24 @@
import { McpServer } from './mcp.js';
import { z } from 'zod';
import { Client } from '../client/index.js';
import { InMemoryTransport } from '../inMemory.js';
import { z } from 'zod';
import { getDisplayName } from '../shared/metadataUtils.js';
import { UriTemplate } from '../shared/uriTemplate.js';
import {
ListToolsResultSchema,
CallToolResultSchema,
CompleteResultSchema,
ElicitRequestSchema,
GetPromptResultSchema,
ListPromptsResultSchema,
ListResourcesResultSchema,
ListResourceTemplatesResultSchema,
ReadResourceResultSchema,
ListPromptsResultSchema,
GetPromptResultSchema,
CompleteResultSchema,
ListToolsResultSchema,
LoggingMessageNotificationSchema,
Notification,
TextContent,
ElicitRequestSchema
type Notification,
ReadResourceResultSchema,
type TextContent
} from '../types.js';
import { ResourceTemplate } from './mcp.js';
import { completable } from './completable.js';
import { UriTemplate } from '../shared/uriTemplate.js';
import { getDisplayName } from '../shared/metadataUtils.js';
import { McpServer, ResourceTemplate } from './mcp.js';
describe('McpServer', () => {
/***
@ -112,11 +111,22 @@ describe('McpServer', () => {
}
}
return { content: [{ type: 'text' as const, text: `Operation completed with ${steps} steps` }] };
return {
content: [
{
type: 'text' as const,
text: `Operation completed with ${steps} steps`
}
]
};
}
);
const progressUpdates: Array<{ progress: number; total?: number; message?: string }> = [];
const progressUpdates: Array<{
progress: number;
total?: number;
message?: string;
}> = [];
const client = new Client({
name: 'test client',
@ -677,9 +687,15 @@ describe('tool()', () => {
expect(result.tools).toHaveLength(2);
expect(result.tools[0].name).toBe('test');
expect(result.tools[0].annotations).toEqual({ title: 'Test Tool', readOnlyHint: true });
expect(result.tools[0].annotations).toEqual({
title: 'Test Tool',
readOnlyHint: true
});
expect(result.tools[1].name).toBe('test (new api)');
expect(result.tools[1].annotations).toEqual({ title: 'Test Tool', readOnlyHint: true });
expect(result.tools[1].annotations).toEqual({
title: 'Test Tool',
readOnlyHint: true
});
});
/***
@ -722,7 +738,10 @@ describe('tool()', () => {
type: 'object',
properties: { name: { type: 'string' } }
});
expect(result.tools[0].annotations).toEqual({ title: 'Test Tool', readOnlyHint: true });
expect(result.tools[0].annotations).toEqual({
title: 'Test Tool',
readOnlyHint: true
});
expect(result.tools[1].name).toBe('test (new api)');
expect(result.tools[1].inputSchema).toEqual(result.tools[0].inputSchema);
expect(result.tools[1].annotations).toEqual(result.tools[0].annotations);
@ -756,7 +775,11 @@ describe('tool()', () => {
{
description: 'A tool with everything',
inputSchema: { name: z.string() },
annotations: { title: 'Complete Test Tool', readOnlyHint: true, openWorldHint: false }
annotations: {
title: 'Complete Test Tool',
readOnlyHint: true,
openWorldHint: false
}
},
async ({ name }) => ({
content: [{ type: 'text', text: `Hello, ${name}!` }]
@ -804,7 +827,11 @@ describe('tool()', () => {
'test',
'A tool with everything but empty params',
{},
{ title: 'Complete Test Tool with empty params', readOnlyHint: true, openWorldHint: false },
{
title: 'Complete Test Tool with empty params',
readOnlyHint: true,
openWorldHint: false
},
async () => ({
content: [{ type: 'text', text: 'Test response' }]
})
@ -815,7 +842,11 @@ describe('tool()', () => {
{
description: 'A tool with everything but empty params',
inputSchema: {},
annotations: { title: 'Complete Test Tool with empty params', readOnlyHint: true, openWorldHint: false }
annotations: {
title: 'Complete Test Tool with empty params',
readOnlyHint: true,
openWorldHint: false
}
},
async () => ({
content: [{ type: 'text' as const, text: 'Test response' }]
@ -1342,7 +1373,7 @@ describe('tool()', () => {
expect(receivedRequestId).toBeDefined();
expect(typeof receivedRequestId === 'string' || typeof receivedRequestId === 'number').toBe(true);
expect(result.content && result.content[0].text).toContain('Received request ID:');
expect(result.content?.[0].text).toContain('Received request ID:');
});
/***
@ -1370,7 +1401,10 @@ describe('tool()', () => {
});
mcpServer.tool('test-tool', async ({ sendNotification }) => {
await sendNotification({ method: 'notifications/message', params: { level: 'debug', data: loggingMessage } });
await sendNotification({
method: 'notifications/message',
params: { level: 'debug', data: loggingMessage }
});
return {
content: [
{