UNPKG

mcp-uni

Version:

A unified gateway for managing multiple MCP servers

160 lines (159 loc) 5.73 kB
import { z } from 'zod'; /** * 将 JSON Schema 转换为 Zod Schema * @param schema JSON Schema 对象 * @returns 对应的 Zod Schema */ export function jsonSchemaToZod(schema) { if (!schema || typeof schema !== 'object') { return z.any(); } // 处理 oneOf (联合类型) if (schema.oneOf && Array.isArray(schema.oneOf)) { const schemas = schema.oneOf.map(s => jsonSchemaToZod(s)); return z.union(schemas); } // 处理 anyOf (联合类型,至少一个匹配) if (schema.anyOf && Array.isArray(schema.anyOf)) { const schemas = schema.anyOf.map(s => jsonSchemaToZod(s)); return z.union(schemas); } // 处理 allOf (交集类型) if (schema.allOf && Array.isArray(schema.allOf)) { let result = jsonSchemaToZod(schema.allOf[0]); for (let i = 1; i < schema.allOf.length; i++) { result = result.and(jsonSchemaToZod(schema.allOf[i])); } return result; } // 处理 not (否定类型) if (schema.not) { // Zod 没有直接的 not 操作,这里返回 any 作为回退 return z.any(); } // 处理枚举 if (schema.enum && Array.isArray(schema.enum)) { return z.enum(schema.enum); } // 处理常量 if (schema.const !== undefined) { return z.literal(schema.const); } // 根据 type 处理基本类型 switch (schema.type) { case 'string': { let stringSchema = z.string(); if (schema.minLength !== undefined) { stringSchema = stringSchema.min(schema.minLength); } if (schema.maxLength !== undefined) { stringSchema = stringSchema.max(schema.maxLength); } if (schema.pattern) { stringSchema = stringSchema.regex(new RegExp(schema.pattern)); } if (schema.format) { switch (schema.format) { case 'email': stringSchema = stringSchema.email(); break; case 'uri': stringSchema = stringSchema.url(); break; case 'date': stringSchema = stringSchema.date(); break; case 'date-time': stringSchema = stringSchema.datetime(); break; case 'uuid': stringSchema = stringSchema.uuid(); break; } } return stringSchema; } case 'number': case 'integer': { let numberSchema = schema.type === 'integer' ? z.number().int() : z.number(); if (schema.minimum !== undefined) { numberSchema = numberSchema.min(schema.minimum); } if (schema.maximum !== undefined) { numberSchema = numberSchema.max(schema.maximum); } return numberSchema; } case 'boolean': return z.boolean(); case 'array': { if (schema.items) { return z.array(jsonSchemaToZod(schema.items)); } return z.array(z.any()); } case 'object': { if (!schema.properties) { return z.object({}); } const shape = {}; const required = schema.required || []; for (const [key, propSchema] of Object.entries(schema.properties)) { let zodSchema = jsonSchemaToZod(propSchema); // 如果不是必需的,则设为可选 if (!required.includes(key)) { zodSchema = zodSchema.optional(); } shape[key] = zodSchema; } return z.object(shape); } case 'null': return z.null(); default: // 如果没有 type 或者 type 未知,返回 any return z.any(); } } /** * 将 MCP Tool 的 inputSchema 转换为 Zod Schema * @param inputSchema MCP Tool 的 inputSchema * @returns 对应的 Zod Schema */ export function toolInputSchemaToZod(inputSchema) { if (!inputSchema || typeof inputSchema !== 'object') { return z.object({}); } // 如果 inputSchema 已经是 Zod Schema,直接返回 if (inputSchema._def || inputSchema.parse) { return inputSchema; } // 如果是 JSON Schema,转换为 Zod Schema return jsonSchemaToZod(inputSchema); } /** * 将 MCP Tool 的 inputSchema 转换为 ZodRawShape(用于 MCP Server) * @param inputSchema MCP Tool 的 inputSchema * @returns 对应的 ZodRawShape */ export function toolInputSchemaToZodRawShape(inputSchema) { if (!inputSchema || typeof inputSchema !== 'object') { return {}; } // 如果 inputSchema 已经是 ZodRawShape,直接返回 if (inputSchema && !inputSchema.type && !inputSchema._def && !inputSchema.parse) { // 检查是否已经是 ZodRawShape 格式 const isZodRawShape = Object.values(inputSchema).every(value => value && typeof value === 'object' && (value._def || value.parse)); if (isZodRawShape) { return inputSchema; } } // 如果是 JSON Schema,转换为 Zod Schema,然后提取 shape const zodSchema = jsonSchemaToZod(inputSchema); // 如果转换后的 schema 是 object 类型,提取其 shape if (zodSchema._def && zodSchema._def.typeName === 'ZodObject') { return zodSchema._def.shape(); } // 否则返回空对象 return {}; }