mcp-uni
Version:
A unified gateway for managing multiple MCP servers
160 lines (159 loc) • 5.73 kB
JavaScript
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 {};
}