enhance JSON schema conversion to Zod schema

This commit is contained in:
samanhappy
2025-04-12 09:44:33 +08:00
parent 11c80f7469
commit 5df6dd99b7

View File

@@ -136,7 +136,7 @@ export const registerAllTools = async (server: McpServer, forceInit: boolean): P
await server.tool( await server.tool(
tool.name, tool.name,
tool.description || '', tool.description || '',
cast(tool.inputSchema.properties), json2zod(tool.inputSchema.properties, tool.inputSchema.required),
async (params: Record<string, unknown>) => { async (params: Record<string, unknown>) => {
const currentServer = getServerInfoByName(serverInfo.name)!; const currentServer = getServerInfoByName(serverInfo.name)!;
console.log(`Calling tool: ${tool.name} with params: ${JSON.stringify(params)}`); console.log(`Calling tool: ${tool.name} with params: ${JSON.stringify(params)}`);
@@ -258,28 +258,50 @@ export const createMcpServer = (name: string, version: string): McpServer => {
}; };
// Helper function: Convert JSON Schema to Zod Schema // Helper function: Convert JSON Schema to Zod Schema
function cast(inputSchema: unknown): ZodRawShape { function json2zod(inputSchema: unknown, required: unknown): ZodRawShape {
if (typeof inputSchema !== 'object' || inputSchema === null) { if (typeof inputSchema !== 'object' || inputSchema === null) {
throw new Error('Invalid input schema'); throw new Error('Invalid input schema');
} }
const properties = inputSchema as Record< const properties = inputSchema as Record<string, any>;
string,
{ type: string; description?: string; items?: { type: string } }
>;
const processedSchema: ZodRawShape = {}; const processedSchema: ZodRawShape = {};
for (const key in properties) { for (const key in properties) {
const prop = properties[key]; const prop = properties[key];
if (prop instanceof ZodType) { if (prop instanceof ZodType) {
processedSchema[key] = prop.optional(); processedSchema[key] = prop;
} else if (typeof prop === 'object' && prop !== null) { continue;
let zodType: ZodType; }
if (typeof prop !== 'object' || prop === null) {
throw new Error(`Invalid property definition for ${key}`);
}
let zodType: ZodType;
if (prop.type === 'array' && prop.items) {
if (prop.items.type === 'string') {
zodType = z.array(z.string());
} else if (prop.items.type === 'number') {
zodType = z.array(z.number());
} else if (prop.items.type === 'integer') {
zodType = z.array(z.number().int());
} else if (prop.items.type === 'boolean') {
zodType = z.array(z.boolean());
} else if (prop.items.type === 'object' && prop.items.properties) {
zodType = z.array(z.object(json2zod(prop.items.properties, prop.items.required)));
} else {
zodType = z.array(z.any());
}
} else {
switch (prop.type) { switch (prop.type) {
case 'string': case 'string':
zodType = z.string(); if (prop.enum && Array.isArray(prop.enum)) {
zodType = z.enum(prop.enum as [string, ...string[]]);
} else {
zodType = z.string();
}
break; break;
case 'number': case 'number':
zodType = z.number(); zodType = z.number();
@@ -290,32 +312,30 @@ function cast(inputSchema: unknown): ZodRawShape {
case 'integer': case 'integer':
zodType = z.number().int(); zodType = z.number().int();
break; break;
case 'array':
zodType = z.array(z.any());
break;
case 'object': case 'object':
zodType = z.record(z.any()); if (prop.properties) {
zodType = z.object(json2zod(prop.properties, prop.required));
} else {
zodType = z.record(z.any());
}
break; break;
default: default:
zodType = z.any(); zodType = z.any();
} }
}
if (prop.description) { if (prop.description) {
zodType = zodType.describe(prop.description); zodType = zodType.describe(prop.description);
} }
if (prop.items) { if (prop.default !== undefined) {
if (prop.items.type === 'string') { zodType = zodType.default(prop.default);
zodType = z.array(z.string()); }
} else if (prop.items.type === 'number') {
zodType = z.array(z.number());
} else if (prop.items.type === 'boolean') {
zodType = z.array(z.boolean());
} else {
zodType = z.array(z.any());
}
}
required = Array.isArray(required) ? required : [];
if (Array.isArray(required) && required.includes(key)) {
processedSchema[key] = zodType;
} else {
processedSchema[key] = zodType.optional(); processedSchema[key] = zodType.optional();
} }
} }