fix: reject plain JSON Schema objects passed as inputSchema (#1596)
Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
This commit is contained in:
parent
4cbcec0edb
commit
93640d33ab
2 changed files with 40 additions and 4 deletions
|
|
@ -1024,9 +1024,10 @@ export class McpServer {
|
|||
annotations = rest.shift() as ToolAnnotations;
|
||||
}
|
||||
} else if (typeof firstArg === 'object' && firstArg !== null) {
|
||||
// Not a ZodRawShapeCompat, so must be annotations in this position
|
||||
// Case: tool(name, annotations, cb)
|
||||
// Or: tool(name, description, annotations, cb)
|
||||
// ToolAnnotations values are primitives. Nested objects indicate a misplaced schema
|
||||
if (Object.values(firstArg).some(v => typeof v === 'object' && v !== null)) {
|
||||
throw new Error(`Tool ${name} expected a Zod schema or ToolAnnotations, but received an unrecognized object`);
|
||||
}
|
||||
annotations = rest.shift() as ToolAnnotations;
|
||||
}
|
||||
}
|
||||
|
|
@ -1386,7 +1387,7 @@ function isZodRawShapeCompat(obj: unknown): obj is ZodRawShapeCompat {
|
|||
|
||||
/**
|
||||
* Converts a provided Zod schema to a Zod object if it is a ZodRawShapeCompat,
|
||||
* otherwise returns the schema as is.
|
||||
* otherwise returns the schema as is. Throws if the value is not a valid Zod schema.
|
||||
*/
|
||||
function getZodSchemaObject(schema: ZodRawShapeCompat | AnySchema | undefined): AnySchema | undefined {
|
||||
if (!schema) {
|
||||
|
|
@ -1397,6 +1398,10 @@ function getZodSchemaObject(schema: ZodRawShapeCompat | AnySchema | undefined):
|
|||
return objectFromShape(schema);
|
||||
}
|
||||
|
||||
if (!isZodSchemaInstance(schema as object)) {
|
||||
throw new Error('inputSchema must be a Zod schema or raw shape, received an unrecognized object');
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2050,6 +2050,37 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
|
|||
// Clean up spies
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
test('should reject plain JSON Schema objects passed as inputSchema', () => {
|
||||
const mcpServer = new McpServer({
|
||||
name: 'test server',
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
const jsonSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
directory_id: {
|
||||
type: 'string',
|
||||
format: 'uuid',
|
||||
description: 'The UUID of the directory'
|
||||
}
|
||||
},
|
||||
required: ['directory_id']
|
||||
} as any;
|
||||
|
||||
const cb = async ({ directory_id }: any) => ({
|
||||
content: [{ type: 'text' as const, text: `Got: ${directory_id}` }]
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
mcpServer.tool('test', 'A tool', jsonSchema, cb);
|
||||
}).toThrow(/unrecognized object/);
|
||||
|
||||
expect(() => {
|
||||
mcpServer.registerTool('test', { description: 'A tool', inputSchema: jsonSchema }, cb);
|
||||
}).toThrow(/unrecognized object/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resource()', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue