api2mcp 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -1
- package/bin/api2mcp.js +2 -0
- package/dist/chunk-CVWZJCLP.mjs +992 -0
- package/dist/chunk-CVWZJCLP.mjs.map +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1042 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +47 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +378 -0
- package/dist/index.d.ts +378 -0
- package/dist/index.js +1049 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +41 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +72 -9
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/config/loader.ts","../src/utils/error.ts","../src/utils/logger.ts","../src/server/index.ts","../src/converter/tool-generator.ts","../src/converter/schema-converter.ts","../src/parser/swagger.ts","../src/executor/request-builder.ts","../src/executor/http-client.ts","../src/server/tool-manager.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI 入口\n */\n\nimport { Command } from 'commander';\nimport { loadConfig } from './config/loader.js';\nimport type { Config } from './config/types.js';\nimport { startServer } from './server/index.js';\nimport { ConfigurationError, OpenApiParseError } from './utils/error.js';\nimport { logger } from './utils/logger.js';\n\nconst program = new Command();\n\nprogram\n .name('api2mcp')\n .description('Convert OpenAPI specifications to MCP tools')\n .version('0.1.0')\n .option('-u, --url <url>', 'OpenAPI document URL or file path')\n .option('-b, --base-url <url>', 'API base URL (overrides OpenAPI servers)')\n .option('-t, --timeout <ms>', 'Request timeout in milliseconds', parseInt)\n .option('-h, --headers <json>', 'Custom headers as JSON string')\n .option('-p, --prefix <prefix>', 'Tool name prefix')\n .option('-d, --debug', 'Enable debug mode', false)\n .action(async (options) => {\n let config: Config | undefined;\n try {\n // 加载配置\n config = loadConfig({\n url: options.url,\n baseUrl: options.baseUrl,\n timeout: options.timeout,\n headers: options.headers,\n prefix: options.prefix,\n debug: options.debug,\n });\n\n logger.info(`Starting api2mcp...`);\n logger.info(`OpenAPI URL: ${config.openapiUrl}`);\n if (config.baseUrl) {\n logger.info(`Base URL: ${config.baseUrl}`);\n }\n\n // 启动服务器\n await startServer(config);\n } catch (error) {\n if (error instanceof ConfigurationError) {\n console.error(`Configuration error: ${error.message}`);\n process.exit(1);\n }\n\n if (error instanceof OpenApiParseError) {\n console.error(`OpenAPI parse error: ${error.message}`);\n process.exit(1);\n }\n\n console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);\n if (config?.debug && error instanceof Error && error.stack) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n });\n\n// 解析命令行参数\nprogram.parse();\n","/**\n * 配置加载器\n * 优先级: CLI 参数 > 环境变量 > 配置文件\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { ConfigurationError } from '../utils/error.js';\nimport { logger } from '../utils/logger.js';\nimport type { CliArgs, Config, ConfigFile, EnvConfig } from './types.js';\n\nconst DEFAULT_TIMEOUT = 30000;\nconst CONFIG_FILE_NAMES = ['api2mcp.json', 'api2mcp.config.json', '.api2mcp.json'];\n\n/**\n * 解析 JSON 格式的请求头字符串\n */\nfunction parseHeaders(headersStr: string | undefined): Record<string, string> | undefined {\n if (!headersStr) return undefined;\n\n try {\n const parsed = JSON.parse(headersStr);\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed as Record<string, string>;\n }\n throw new Error('Headers must be a JSON object');\n } catch (error) {\n throw new ConfigurationError(\n `Invalid headers JSON: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n}\n\n/**\n * 从环境变量加载配置\n */\nfunction loadFromEnv(env: EnvConfig): Partial<Config> {\n const config: Partial<Config> = {};\n\n if (env.OPENAPI_URL) {\n config.openapiUrl = env.OPENAPI_URL;\n }\n\n if (env.API_BASE_URL) {\n config.baseUrl = env.API_BASE_URL;\n }\n\n if (env.API_TIMEOUT) {\n const timeout = parseInt(env.API_TIMEOUT, 10);\n if (!Number.isNaN(timeout) && timeout > 0) {\n config.timeout = timeout;\n }\n }\n\n if (env.API_HEADERS) {\n config.headers = parseHeaders(env.API_HEADERS);\n }\n\n if (env.DEBUG) {\n config.debug = env.DEBUG === 'true' || env.DEBUG === '1';\n }\n\n return config;\n}\n\n/**\n * 从配置文件加载配置\n */\nfunction loadFromFile(workingDir: string = process.cwd()): Partial<Config> | null {\n for (const fileName of CONFIG_FILE_NAMES) {\n const filePath = resolve(workingDir, fileName);\n if (existsSync(filePath)) {\n try {\n const content = readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(content) as ConfigFile;\n logger.info(`Loaded configuration from ${filePath}`);\n return {\n openapiUrl: parsed.openapiUrl,\n baseUrl: parsed.baseUrl,\n timeout: parsed.timeout,\n headers: parsed.headers,\n toolPrefix: parsed.toolPrefix,\n debug: parsed.debug,\n };\n } catch (error) {\n throw new ConfigurationError(\n `Failed to load config file ${filePath}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n }\n }\n return null;\n}\n\n/**\n * 从 CLI 参数加载配置\n */\nfunction loadFromCli(args: CliArgs): Partial<Config> {\n const config: Partial<Config> = {};\n\n if (args.url) {\n config.openapiUrl = args.url;\n }\n\n if (args.baseUrl) {\n config.baseUrl = args.baseUrl;\n }\n\n if (args.timeout) {\n config.timeout = args.timeout;\n }\n\n if (args.headers) {\n config.headers = parseHeaders(args.headers);\n }\n\n if (args.prefix) {\n config.toolPrefix = args.prefix;\n }\n\n if (args.debug !== undefined) {\n config.debug = args.debug;\n }\n\n return config;\n}\n\n/**\n * 合并配置(后面的配置覆盖前面的)\n */\nfunction mergeConfigs(...configs: Array<Partial<Config>>): Config {\n const merged: Config = {\n openapiUrl: '',\n debug: false,\n };\n\n for (const config of configs) {\n if (config.openapiUrl !== undefined) merged.openapiUrl = config.openapiUrl;\n if (config.baseUrl !== undefined) merged.baseUrl = config.baseUrl;\n if (config.timeout !== undefined) merged.timeout = config.timeout;\n if (config.headers !== undefined) merged.headers = config.headers;\n if (config.toolPrefix !== undefined) merged.toolPrefix = config.toolPrefix;\n if (config.debug !== undefined) merged.debug = config.debug;\n }\n\n // 设置默认值\n if (merged.timeout === undefined) {\n merged.timeout = DEFAULT_TIMEOUT;\n }\n\n return merged;\n}\n\n/**\n * 加载配置\n * 优先级: CLI 参数 > 环境变量 > 配置文件\n */\nexport function loadConfig(cliArgs: CliArgs = {}, env: EnvConfig = process.env): Config {\n const fileConfig = loadFromFile() ?? {};\n const envConfig = loadFromEnv(env);\n const cliConfig = loadFromCli(cliArgs);\n\n const config = mergeConfigs(cliConfig, envConfig, fileConfig);\n\n // 验证必要配置\n if (!config.openapiUrl) {\n throw new ConfigurationError(\n 'OpenAPI URL is required. Provide it via --url, OPENAPI_URL env, or config file.'\n );\n }\n\n // 设置日志级别\n if (config.debug) {\n logger.setLevel('debug');\n }\n\n logger.debug('Loaded configuration:', {\n openapiUrl: config.openapiUrl,\n baseUrl: config.baseUrl,\n timeout: config.timeout,\n toolPrefix: config.toolPrefix,\n debug: config.debug,\n });\n\n return config;\n}\n\nexport default loadConfig;\n","/**\n * 错误类定义\n */\n\nexport class Api2McpError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: Error\n ) {\n super(message);\n this.name = 'Api2McpError';\n }\n}\n\nexport class ConfigurationError extends Api2McpError {\n constructor(message: string, cause?: Error) {\n super(message, 'CONFIGURATION_ERROR', cause);\n this.name = 'ConfigurationError';\n }\n}\n\nexport class OpenApiParseError extends Api2McpError {\n constructor(message: string, cause?: Error) {\n super(message, 'OPENAPI_PARSE_ERROR', cause);\n this.name = 'OpenApiParseError';\n }\n}\n\nexport class ToolExecutionError extends Api2McpError {\n constructor(\n message: string,\n public readonly toolName: string,\n cause?: Error\n ) {\n super(message, 'TOOL_EXECUTION_ERROR', cause);\n this.name = 'ToolExecutionError';\n }\n}\n\nexport class HttpError extends Api2McpError {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly responseBody?: string,\n cause?: Error\n ) {\n super(message, 'HTTP_ERROR', cause);\n this.name = 'HttpError';\n }\n}\n","/**\n * 简单日志工具\n * 所有日志输出到 stderr,避免干扰 MCP stdio 协议\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\ninterface Logger {\n debug: (message: string, ...args: unknown[]) => void;\n info: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n setLevel: (level: LogLevel) => void;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet currentLevel: LogLevel = 'info';\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\nfunction formatMessage(level: LogLevel, message: string): string {\n const timestamp = new Date().toISOString();\n return `[${timestamp}] [${level.toUpperCase()}] ${message}`;\n}\n\nexport const logger: Logger = {\n debug(message: string, ...args: unknown[]): void {\n if (shouldLog('debug')) {\n console.error(formatMessage('debug', message), ...args);\n }\n },\n\n info(message: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.error(formatMessage('info', message), ...args);\n }\n },\n\n warn(message: string, ...args: unknown[]): void {\n if (shouldLog('warn')) {\n console.error(formatMessage('warn', message), ...args);\n }\n },\n\n error(message: string, ...args: unknown[]): void {\n if (shouldLog('error')) {\n console.error(formatMessage('error', message), ...args);\n }\n },\n\n setLevel(level: LogLevel): void {\n currentLevel = level;\n },\n};\n\nexport default logger;\n","/**\n * MCP 服务器\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { Config } from '../config/types.js';\nimport { generateTools } from '../converter/tool-generator.js';\nimport { getBaseUrl, parseOpenApi } from '../parser/swagger.js';\nimport { logger } from '../utils/logger.js';\nimport { ToolManager } from './tool-manager.js';\n\n/**\n * 创建并启动 MCP 服务器\n */\nexport async function createServer(config: Config): Promise<McpServer> {\n logger.info('Creating MCP server...');\n\n // 创建 MCP 服务器实例\n const server = new McpServer({\n name: 'api2mcp',\n version: '0.1.0',\n });\n\n // 解析 OpenAPI 文档\n const openApiDoc = await parseOpenApi(config.openapiUrl);\n\n // 获取基础 URL\n let baseUrl: string;\n try {\n baseUrl = getBaseUrl(openApiDoc, config.baseUrl);\n } catch (error) {\n if (config.baseUrl) {\n baseUrl = config.baseUrl;\n } else {\n throw error;\n }\n }\n\n // 更新配置中的 baseUrl\n const effectiveConfig: Config = {\n ...config,\n baseUrl,\n };\n\n // 生成工具\n const tools = generateTools(\n openApiDoc.operations,\n openApiDoc.components?.schemas,\n config.toolPrefix\n );\n\n // 创建工具管理器并注册工具\n const toolManager = new ToolManager(server, effectiveConfig);\n toolManager.registerTools(tools);\n\n logger.info(`Server ready with ${toolManager.getToolCount()} tools`);\n\n return server;\n}\n\n/**\n * 启动服务器(使用 stdio 传输)\n */\nexport async function startServer(config: Config): Promise<void> {\n const server = await createServer(config);\n\n // 使用 stdio 传输\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n logger.info('Server started (stdio mode)');\n}\n\nexport default {\n createServer,\n startServer,\n};\n","/**\n * MCP 工具生成器\n */\n\nimport { z } from 'zod';\nimport type { OpenApiOperation, OpenApiSchema } from '../parser/types.js';\nimport { logger } from '../utils/logger.js';\nimport { convertSchema, createRefResolver } from './schema-converter.js';\n\n/**\n * 生成的工具定义\n */\nexport interface GeneratedTool {\n /** 工具名称 */\n name: string;\n /** 工具描述 */\n description: string;\n /** 输入参数 Schema */\n inputSchema: z.ZodObject<z.ZodRawShape>;\n /** 原始操作定义 */\n operation: OpenApiOperation;\n}\n\n/**\n * 生成工具名称\n */\nfunction generateToolName(operation: OpenApiOperation, prefix?: string): string {\n // 优先使用 operationId\n if (operation.operationId) {\n const name = sanitizeToolName(operation.operationId);\n return prefix ? `${prefix}_${name}` : name;\n }\n\n // 否则使用 method + path\n const pathParts = operation.path\n .split('/')\n .filter(Boolean)\n .map((part) => part.replace(/[{}]/g, ''));\n\n const name = sanitizeToolName(`${operation.method.toLowerCase()}_${pathParts.join('_')}`);\n return prefix ? `${prefix}_${name}` : name;\n}\n\n/**\n * 清理工具名称\n */\nfunction sanitizeToolName(name: string): string {\n // 替换非法字符为下划线\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '')\n .toLowerCase();\n}\n\n/**\n * 生成工具描述\n */\nfunction generateToolDescription(operation: OpenApiOperation): string {\n const parts: string[] = [];\n\n if (operation.summary) {\n parts.push(operation.summary);\n }\n\n if (operation.description) {\n parts.push(operation.description);\n }\n\n if (operation.deprecated) {\n parts.push('[DEPRECATED]');\n }\n\n // 添加方法和路径信息\n parts.push(`\\n\\nHTTP ${operation.method} ${operation.path}`);\n\n // 添加标签\n if (operation.tags && operation.tags.length > 0) {\n parts.push(`\\nTags: ${operation.tags.join(', ')}`);\n }\n\n return parts.join('\\n');\n}\n\n/**\n * 构建参数 Schema\n */\nfunction buildParametersSchema(\n operation: OpenApiOperation,\n refResolver: ReturnType<typeof createRefResolver>\n): z.ZodRawShape {\n const shape: z.ZodRawShape = {};\n\n // 处理路径参数、查询参数、头参数\n if (operation.parameters) {\n for (const param of operation.parameters) {\n const paramName = param.name;\n let paramSchema = convertSchema(param.schema, refResolver);\n\n // 添加描述\n if (param.description) {\n paramSchema = paramSchema.describe(param.description);\n }\n\n // 处理可选参数\n if (!param.required) {\n paramSchema = paramSchema.optional();\n }\n\n // 使用参数名作为键,添加位置信息\n const key = paramName;\n shape[key] = paramSchema;\n }\n }\n\n // 处理请求体\n if (operation.requestBody) {\n // 优先使用 application/json\n const jsonContent = operation.requestBody.content['application/json'];\n if (jsonContent?.schema) {\n const bodySchema = convertSchema(jsonContent.schema, refResolver);\n\n if (operation.requestBody.description) {\n shape.body = bodySchema.describe(operation.requestBody.description);\n } else {\n shape.body = bodySchema.describe('Request body');\n }\n\n if (!operation.requestBody.required) {\n shape.body = shape.body.optional();\n }\n } else {\n // 尝试其他内容类型\n const contentTypes = Object.keys(operation.requestBody.content);\n if (contentTypes.length > 0) {\n const firstContent = operation.requestBody.content[contentTypes[0]];\n if (firstContent?.schema) {\n const bodySchema = convertSchema(firstContent.schema, refResolver);\n shape.body = bodySchema.describe(`Request body (${contentTypes[0]})`);\n\n if (!operation.requestBody.required) {\n shape.body = shape.body.optional();\n }\n }\n }\n }\n }\n\n return shape;\n}\n\n/**\n * 从 OpenAPI 操作生成 MCP 工具\n */\nexport function generateTool(\n operation: OpenApiOperation,\n components?: Record<string, OpenApiSchema>,\n toolPrefix?: string\n): GeneratedTool {\n const refResolver = createRefResolver(components);\n\n const name = generateToolName(operation, toolPrefix);\n const description = generateToolDescription(operation);\n const parametersShape = buildParametersSchema(operation, refResolver);\n const inputSchema = z.object(parametersShape);\n\n logger.debug(`Generated tool: ${name}`);\n\n return {\n name,\n description,\n inputSchema,\n operation,\n };\n}\n\n/**\n * 批量生成工具\n */\nexport function generateTools(\n operations: OpenApiOperation[],\n components?: Record<string, OpenApiSchema>,\n toolPrefix?: string\n): GeneratedTool[] {\n const tools: GeneratedTool[] = [];\n const usedNames = new Set<string>();\n\n for (const operation of operations) {\n const tool = generateTool(operation, components, toolPrefix);\n\n // 处理名称冲突\n if (usedNames.has(tool.name)) {\n let counter = 1;\n let newName = `${tool.name}_${counter}`;\n while (usedNames.has(newName)) {\n counter++;\n newName = `${tool.name}_${counter}`;\n }\n logger.warn(`Tool name conflict: ${tool.name} renamed to ${newName}`);\n tool.name = newName;\n }\n\n usedNames.add(tool.name);\n tools.push(tool);\n }\n\n logger.info(`Generated ${tools.length} tools`);\n return tools;\n}\n\nexport default {\n generateTool,\n generateTools,\n};\n","/**\n * OpenAPI Schema 到 Zod Schema 转换器\n */\n\nimport { z } from 'zod';\nimport type { OpenApiSchema } from '../parser/types.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * Schema 引用解析函数类型\n */\ntype RefResolver = (ref: string) => OpenApiSchema | undefined;\n\n/**\n * 默认引用解析器(不支持 $ref)\n */\nconst defaultRefResolver: RefResolver = () => undefined;\n\n/**\n * 将 OpenAPI Schema 转换为 Zod Schema\n */\nexport function convertSchema(\n schema: OpenApiSchema | undefined,\n refResolver: RefResolver = defaultRefResolver\n): z.ZodType {\n if (!schema) {\n return z.unknown();\n }\n\n // 处理 $ref\n if (schema.$ref) {\n const resolved = refResolver(schema.$ref);\n if (resolved) {\n return convertSchema(resolved, refResolver);\n }\n logger.warn(`Unresolved $ref: ${schema.$ref}`);\n return z.unknown();\n }\n\n // 处理 allOf\n if (schema.allOf && schema.allOf.length > 0) {\n const schemas = schema.allOf.map((s) => convertSchema(s, refResolver));\n // allOf 表示所有 schema 的交集,这里用 intersection 实现\n if (schemas.length === 1) {\n return schemas[0];\n }\n return schemas.reduce((acc, s) => acc.and(s));\n }\n\n // 处理 oneOf\n if (schema.oneOf && schema.oneOf.length > 0) {\n const schemas = schema.oneOf.map((s) => convertSchema(s, refResolver));\n return z.union([schemas[0], schemas[1] || schemas[0], ...schemas.slice(2)] as [\n z.ZodType,\n z.ZodType,\n ...z.ZodType[],\n ]);\n }\n\n // 处理 anyOf\n if (schema.anyOf && schema.anyOf.length > 0) {\n const schemas = schema.anyOf.map((s) => convertSchema(s, refResolver));\n // anyOf 表示至少匹配一个,用 union 实现\n if (schemas.length === 1) {\n return schemas[0].optional();\n }\n return z.union([schemas[0], schemas[1] || schemas[0], ...schemas.slice(2)] as [\n z.ZodType,\n z.ZodType,\n ...z.ZodType[],\n ]);\n }\n\n // 处理 nullable\n const nullable = schema.nullable === true;\n\n // 根据 type 处理\n let zodSchema: z.ZodType;\n\n switch (schema.type) {\n case 'string':\n zodSchema = convertStringSchema(schema);\n break;\n\n case 'number':\n case 'integer':\n zodSchema = convertNumberSchema(schema);\n break;\n\n case 'boolean':\n zodSchema = z.boolean();\n break;\n\n case 'array':\n zodSchema = convertArraySchema(schema, refResolver);\n break;\n\n case 'object':\n zodSchema = convertObjectSchema(schema, refResolver);\n break;\n\n default:\n // 如果没有指定 type,但有 properties,当作 object 处理\n if (schema.properties) {\n zodSchema = convertObjectSchema(schema, refResolver);\n } else {\n zodSchema = z.unknown();\n }\n }\n\n // 处理 nullable\n if (nullable) {\n zodSchema = zodSchema.nullable();\n }\n\n // 处理默认值\n if (schema.default !== undefined) {\n zodSchema = zodSchema.default(schema.default);\n }\n\n // 添加描述\n if (schema.description) {\n zodSchema = zodSchema.describe(schema.description);\n }\n\n return zodSchema;\n}\n\n/**\n * 转换字符串 Schema\n */\nfunction convertStringSchema(schema: OpenApiSchema): z.ZodString {\n let zodSchema = z.string();\n\n if (schema.minLength !== undefined) {\n zodSchema = zodSchema.min(schema.minLength);\n }\n\n if (schema.maxLength !== undefined) {\n zodSchema = zodSchema.max(schema.maxLength);\n }\n\n if (schema.pattern) {\n zodSchema = zodSchema.regex(new RegExp(schema.pattern));\n }\n\n if (schema.format) {\n switch (schema.format) {\n case 'email':\n zodSchema = zodSchema.email();\n break;\n case 'uri':\n case 'url':\n zodSchema = zodSchema.url();\n break;\n case 'uuid':\n zodSchema = zodSchema.uuid();\n break;\n case 'date':\n zodSchema = zodSchema.date();\n break;\n case 'date-time':\n zodSchema = zodSchema.datetime();\n break;\n // 其他 format 不特殊处理\n }\n }\n\n if (schema.enum) {\n // 使用 const assertion 确保 TypeScript 正确推断类型\n const enumValues = schema.enum as [string, ...string[]];\n zodSchema = z.enum(enumValues) as unknown as z.ZodString;\n }\n\n return zodSchema;\n}\n\n/**\n * 转换数字 Schema\n */\nfunction convertNumberSchema(schema: OpenApiSchema): z.ZodNumber {\n let zodSchema = schema.type === 'integer' ? z.number().int() : z.number();\n\n if (schema.minimum !== undefined) {\n zodSchema = zodSchema.min(schema.minimum);\n }\n\n if (schema.maximum !== undefined) {\n zodSchema = zodSchema.max(schema.maximum);\n }\n\n if (schema.exclusiveMinimum === true && schema.minimum !== undefined) {\n zodSchema = zodSchema.min(schema.minimum + (schema.type === 'integer' ? 1 : Number.MIN_VALUE));\n } else if (typeof schema.exclusiveMinimum === 'number') {\n zodSchema = zodSchema.min(\n schema.exclusiveMinimum + (schema.type === 'integer' ? 1 : Number.MIN_VALUE)\n );\n }\n\n if (schema.exclusiveMaximum === true && schema.maximum !== undefined) {\n zodSchema = zodSchema.max(schema.maximum - (schema.type === 'integer' ? 1 : Number.MIN_VALUE));\n } else if (typeof schema.exclusiveMaximum === 'number') {\n zodSchema = zodSchema.max(\n schema.exclusiveMaximum - (schema.type === 'integer' ? 1 : Number.MIN_VALUE)\n );\n }\n\n if (schema.enum) {\n const enumValues = schema.enum as [number, ...number[]];\n zodSchema = z.enum(enumValues.map(String) as [string, ...string[]]) as unknown as z.ZodNumber;\n }\n\n return zodSchema;\n}\n\n/**\n * 转换数组 Schema\n */\nfunction convertArraySchema(\n schema: OpenApiSchema,\n refResolver: RefResolver\n): z.ZodArray<z.ZodType> {\n const itemSchema = schema.items ? convertSchema(schema.items, refResolver) : z.unknown();\n\n let zodSchema = z.array(itemSchema);\n\n if (schema.minItems !== undefined) {\n zodSchema = zodSchema.min(schema.minItems);\n }\n\n if (schema.maxItems !== undefined) {\n zodSchema = zodSchema.max(schema.maxItems);\n }\n\n return zodSchema;\n}\n\n/**\n * 转换对象 Schema\n */\nfunction convertObjectSchema(schema: OpenApiSchema, refResolver: RefResolver): z.ZodType {\n const properties = schema.properties || {};\n const required = new Set(schema.required || []);\n\n if (Object.keys(properties).length === 0) {\n // 空 object 或 additionalProperties\n if (schema.additionalProperties) {\n if (typeof schema.additionalProperties === 'boolean') {\n return z.record(z.unknown());\n }\n return z.record(convertSchema(schema.additionalProperties, refResolver));\n }\n return z.record(z.unknown());\n }\n\n const zodProperties: Record<string, z.ZodType> = {};\n\n for (const [name, prop] of Object.entries(properties)) {\n let propSchema = convertSchema(prop, refResolver);\n\n if (!required.has(name)) {\n propSchema = propSchema.optional();\n }\n\n zodProperties[name] = propSchema;\n }\n\n let zodSchema: z.ZodType = z.object(zodProperties);\n\n // 处理 additionalProperties\n if (schema.additionalProperties) {\n if (typeof schema.additionalProperties === 'boolean') {\n zodSchema = z.object(zodProperties).passthrough();\n } else {\n // Zod 不直接支持 typed additionalProperties,这里用 passthrough 并记录日志\n logger.debug('Typed additionalProperties is not fully supported, using passthrough');\n zodSchema = z.object(zodProperties).passthrough();\n }\n } else {\n zodSchema = z.object(zodProperties).strict();\n }\n\n return zodSchema;\n}\n\n/**\n * 创建引用解析器\n */\nexport function createRefResolver(\n components: Record<string, OpenApiSchema> | undefined\n): RefResolver {\n return (ref: string): OpenApiSchema | undefined => {\n // 解析 #/components/schemas/XXX 格式的引用\n const match = ref.match(/^#\\/components\\/schemas\\/(.+)$/);\n if (match && components) {\n return components[match[1]];\n }\n return undefined;\n };\n}\n\nexport default {\n convertSchema,\n createRefResolver,\n};\n","/**\n * OpenAPI 解析器\n */\n\nimport SwaggerParser from '@apidevtools/swagger-parser';\nimport type { OpenAPI, OpenAPIV3 } from 'openapi-types';\nimport { OpenApiParseError } from '../utils/error.js';\nimport { logger } from '../utils/logger.js';\nimport type {\n OpenApiOperation,\n OpenApiParameter,\n OpenApiRequestBody,\n OpenApiSchema,\n ParameterLocation,\n ParsedOpenApiDoc,\n} from './types.js';\n\n/**\n * 判断是否为 OpenAPI v3 文档\n */\nfunction isOpenAPIV3(doc: OpenAPI.Document): doc is OpenAPIV3.Document {\n return 'openapi' in doc;\n}\n\n/**\n * 转换 OpenAPI 参数\n */\nfunction convertParameter(param: OpenAPIV3.ParameterObject): OpenApiParameter {\n return {\n name: param.name,\n in: param.in as ParameterLocation,\n required: param.required,\n description: param.description,\n schema: param.schema as OpenApiSchema | undefined,\n deprecated: param.deprecated,\n };\n}\n\n/**\n * 转换 OpenAPI Schema\n */\nfunction convertSchema(schema: OpenAPIV3.SchemaObject | undefined): OpenApiSchema | undefined {\n if (!schema) return undefined;\n return schema as OpenApiSchema;\n}\n\n/**\n * 转换请求体\n */\nfunction convertRequestBody(\n requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject | undefined\n): OpenApiRequestBody | undefined {\n if (!requestBody) return undefined;\n\n // 处理 $ref\n if ('$ref' in requestBody) {\n return undefined; // $ref 将在解析后被解析\n }\n\n const content: OpenApiRequestBody['content'] = {};\n for (const [contentType, mediaType] of Object.entries(requestBody.content || {})) {\n const mt = mediaType as OpenAPIV3.MediaTypeObject;\n content[contentType] = {\n schema: convertSchema(mt.schema as OpenAPIV3.SchemaObject | undefined),\n example: mt.example,\n };\n }\n\n return {\n description: requestBody.description,\n required: requestBody.required,\n content,\n };\n}\n\n/**\n * 提取 API 操作\n */\nfunction extractOperations(doc: OpenAPIV3.Document): OpenApiOperation[] {\n const operations: OpenApiOperation[] = [];\n\n if (!doc.paths) return operations;\n\n const methods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] as const;\n\n for (const [path, pathItem] of Object.entries(doc.paths)) {\n if (!pathItem) continue;\n\n for (const method of methods) {\n const operation = pathItem[method];\n if (!operation) continue;\n\n // 收集参数(路径级 + 操作级)\n const parameters: OpenApiParameter[] = [];\n\n // 路径级参数\n if (pathItem.parameters) {\n for (const param of pathItem.parameters) {\n if (!('$ref' in param)) {\n parameters.push(convertParameter(param));\n }\n }\n }\n\n // 操作级参数\n if (operation.parameters) {\n for (const param of operation.parameters) {\n if (!('$ref' in param)) {\n parameters.push(convertParameter(param));\n }\n }\n }\n\n const op: OpenApiOperation = {\n method: method.toUpperCase(),\n path,\n operationId: operation.operationId,\n summary: operation.summary,\n description: operation.description,\n tags: operation.tags,\n parameters: parameters.length > 0 ? parameters : undefined,\n requestBody: convertRequestBody(\n operation.requestBody as\n | OpenAPIV3.RequestBodyObject\n | OpenAPIV3.ReferenceObject\n | undefined\n ),\n deprecated: operation.deprecated,\n };\n\n operations.push(op);\n }\n }\n\n return operations;\n}\n\n/**\n * 解析 OpenAPI 文档\n */\nexport async function parseOpenApi(source: string): Promise<ParsedOpenApiDoc> {\n try {\n logger.info(`Parsing OpenAPI document from: ${source}`);\n\n // 使用 SwaggerParser 解析和验证\n const api = await SwaggerParser.validate(source);\n\n // 检查版本\n if (!isOpenAPIV3(api)) {\n // 尝试转换 v2 到 v3\n if ('swagger' in api) {\n throw new OpenApiParseError(\n 'OpenAPI v2 (Swagger) is not supported. Please convert to OpenAPI v3 first.'\n );\n }\n throw new OpenApiParseError('Unsupported OpenAPI format');\n }\n\n const info: ParsedOpenApiDoc['info'] = {\n title: api.info.title,\n version: api.info.version,\n description: api.info.description,\n };\n\n const servers: ParsedOpenApiDoc['servers'] = api.servers?.map((s) => ({\n url: s.url,\n description: s.description,\n variables: s.variables,\n }));\n\n const operations = extractOperations(api);\n\n const components = api.components\n ? {\n schemas: api.components.schemas as Record<string, OpenApiSchema> | undefined,\n parameters: api.components.parameters as Record<string, OpenApiParameter> | undefined,\n requestBodies: api.components.requestBodies as\n | Record<string, OpenApiRequestBody>\n | undefined,\n }\n : undefined;\n\n logger.info(`Parsed ${operations.length} API operations`);\n\n return {\n openapi: api.openapi,\n info,\n servers,\n operations,\n components,\n };\n } catch (error) {\n if (error instanceof OpenApiParseError) {\n throw error;\n }\n throw new OpenApiParseError(\n `Failed to parse OpenAPI document: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * 获取基础 URL\n */\nexport function getBaseUrl(doc: ParsedOpenApiDoc, overrideUrl?: string): string {\n if (overrideUrl) {\n logger.debug(`Using override base URL: ${overrideUrl}`);\n return overrideUrl;\n }\n\n if (doc.servers && doc.servers.length > 0) {\n const server = doc.servers[0];\n let url = server.url;\n\n // 处理变量替换\n if (server.variables) {\n for (const [name, variable] of Object.entries(server.variables)) {\n url = url.replace(`{${name}}`, variable.default);\n }\n }\n\n logger.debug(`Using base URL from OpenAPI servers: ${url}`);\n return url;\n }\n\n throw new OpenApiParseError('No base URL found in OpenAPI document. Please specify --base-url.');\n}\n\n/**\n * 获取所有 API 操作\n */\nexport function getOperations(doc: ParsedOpenApiDoc): OpenApiOperation[] {\n return doc.operations;\n}\n\nexport default {\n parseOpenApi,\n getBaseUrl,\n getOperations,\n};\n","/**\n * HTTP 请求构建器\n */\n\nimport type { OpenApiOperation, OpenApiParameter, ParameterLocation } from '../parser/types.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * 构建后的请求参数\n */\nexport interface BuiltRequest {\n /** 请求路径(已替换路径参数) */\n path: string;\n /** 查询参数 */\n query: Record<string, string | string[]>;\n /** 请求头 */\n headers: Record<string, string>;\n /** 请求体 */\n body?: unknown;\n}\n\n/**\n * 根据参数位置分组\n */\nfunction groupParametersByLocation(\n parameters: OpenApiParameter[] | undefined\n): Record<ParameterLocation, OpenApiParameter[]> {\n const groups: Record<ParameterLocation, OpenApiParameter[]> = {\n path: [],\n query: [],\n header: [],\n cookie: [],\n };\n\n if (parameters) {\n for (const param of parameters) {\n groups[param.in].push(param);\n }\n }\n\n return groups;\n}\n\n/**\n * 构建请求\n */\nexport function buildRequest(\n operation: OpenApiOperation,\n input: Record<string, unknown>,\n defaultHeaders: Record<string, string> = {}\n): BuiltRequest {\n const groupedParams = groupParametersByLocation(operation.parameters);\n\n // 构建路径\n let path = operation.path;\n for (const param of groupedParams.path) {\n const value = input[param.name];\n if (value !== undefined) {\n path = path.replace(`{${param.name}}`, String(value));\n } else if (param.required) {\n throw new Error(`Missing required path parameter: ${param.name}`);\n }\n }\n\n // 构建查询参数\n const query: Record<string, string | string[]> = {};\n for (const param of groupedParams.query) {\n const value = input[param.name];\n if (value !== undefined) {\n if (Array.isArray(value)) {\n query[param.name] = value.map(String);\n } else {\n query[param.name] = String(value);\n }\n } else if (param.required) {\n throw new Error(`Missing required query parameter: ${param.name}`);\n }\n }\n\n // 构建请求头\n const headers: Record<string, string> = { ...defaultHeaders };\n for (const param of groupedParams.header) {\n const value = input[param.name];\n if (value !== undefined) {\n headers[param.name] = String(value);\n } else if (param.required) {\n throw new Error(`Missing required header parameter: ${param.name}`);\n }\n }\n\n // 处理请求体\n const body = input.body;\n\n // 设置 Content-Type(如果有请求体)\n if (body !== undefined && !headers['Content-Type']) {\n if (operation.requestBody?.content) {\n // 使用 OpenAPI 文档中定义的第一个内容类型\n const contentTypes = Object.keys(operation.requestBody.content);\n if (contentTypes.length > 0) {\n headers['Content-Type'] = contentTypes[0];\n }\n } else {\n headers['Content-Type'] = 'application/json';\n }\n }\n\n logger.debug(`Built request: ${operation.method} ${path}`, {\n query,\n headers,\n body: body ? '(body present)' : '(no body)',\n });\n\n return {\n path,\n query,\n headers,\n body,\n };\n}\n\n/**\n * 将查询参数追加到 URL\n */\nexport function appendQueryString(url: string, query: Record<string, string | string[]>): string {\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n params.append(key, v);\n }\n } else {\n params.append(key, value);\n }\n }\n\n const queryString = params.toString();\n if (queryString) {\n return `${url}?${queryString}`;\n }\n\n return url;\n}\n\nexport default {\n buildRequest,\n appendQueryString,\n};\n","/**\n * HTTP 客户端\n */\n\nimport type { Config } from '../config/types.js';\nimport type { OpenApiOperation } from '../parser/types.js';\nimport { HttpError, ToolExecutionError } from '../utils/error.js';\nimport { logger } from '../utils/logger.js';\nimport { appendQueryString, buildRequest } from './request-builder.js';\n\n/**\n * HTTP 响应\n */\nexport interface HttpResponse {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n body: unknown;\n}\n\n/**\n * 执行 HTTP 请求\n */\nexport async function executeRequest(\n operation: OpenApiOperation,\n input: Record<string, unknown>,\n config: Config\n): Promise<HttpResponse> {\n const baseUrl = config.baseUrl || '';\n\n try {\n // 构建请求\n const built = buildRequest(operation, input, config.headers || {});\n\n // 构建完整 URL\n let url = `${baseUrl}${built.path}`;\n url = appendQueryString(url, built.query);\n\n logger.info(`Executing: ${operation.method} ${url}`);\n\n // 构建请求选项\n const requestInit: RequestInit = {\n method: operation.method,\n headers: built.headers,\n };\n\n // 添加请求体\n if (built.body !== undefined && !['GET', 'HEAD'].includes(operation.method.toUpperCase())) {\n requestInit.body = typeof built.body === 'string' ? built.body : JSON.stringify(built.body);\n }\n\n // 创建 AbortController 用于超时控制\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), config.timeout);\n requestInit.signal = controller.signal;\n\n // 执行请求\n const response = await fetch(url, requestInit);\n clearTimeout(timeoutId);\n\n // 解析响应头\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n // 解析响应体\n let body: unknown;\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('application/json')) {\n try {\n body = await response.json();\n } catch {\n body = await response.text();\n }\n } else if (contentType.includes('text/')) {\n body = await response.text();\n } else {\n // 尝试解析为 JSON,失败则返回文本\n try {\n body = await response.json();\n } catch {\n body = await response.text();\n }\n }\n\n logger.debug(`Response status: ${response.status}`);\n\n // 检查 HTTP 错误\n if (!response.ok) {\n throw new HttpError(\n `HTTP ${response.status} ${response.statusText}`,\n response.status,\n typeof body === 'string' ? body : JSON.stringify(body)\n );\n }\n\n return {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n body,\n };\n } catch (error) {\n if (error instanceof HttpError) {\n throw error;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new ToolExecutionError(\n `Request timeout after ${config.timeout}ms`,\n operation.operationId || operation.path\n );\n }\n throw new ToolExecutionError(\n `Request failed: ${error.message}`,\n operation.operationId || operation.path,\n error\n );\n }\n\n throw new ToolExecutionError(\n 'Unknown error during request execution',\n operation.operationId || operation.path\n );\n }\n}\n\n/**\n * 格式化响应为字符串\n */\nexport function formatResponse(response: HttpResponse): string {\n const lines: string[] = [];\n\n lines.push(`Status: ${response.status} ${response.statusText}`);\n\n if (Object.keys(response.headers).length > 0) {\n lines.push('Headers:');\n for (const [key, value] of Object.entries(response.headers)) {\n lines.push(` ${key}: ${value}`);\n }\n }\n\n lines.push('Body:');\n if (typeof response.body === 'object' && response.body !== null) {\n lines.push(JSON.stringify(response.body, null, 2));\n } else {\n lines.push(String(response.body));\n }\n\n return lines.join('\\n');\n}\n\nexport default {\n executeRequest,\n formatResponse,\n};\n","/**\n * MCP 工具管理器\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Config } from '../config/types.js';\nimport type { GeneratedTool } from '../converter/tool-generator.js';\nimport { executeRequest, formatResponse } from '../executor/http-client.js';\nimport { ToolExecutionError } from '../utils/error.js';\nimport { logger } from '../utils/logger.js';\n\n/**\n * 工具管理器\n */\nexport class ToolManager {\n private tools: Map<string, GeneratedTool> = new Map();\n private config: Config;\n private server: McpServer;\n\n constructor(server: McpServer, config: Config) {\n this.server = server;\n this.config = config;\n }\n\n /**\n * 注册工具\n */\n registerTool(tool: GeneratedTool): void {\n if (this.tools.has(tool.name)) {\n logger.warn(`Tool already registered: ${tool.name}, overwriting`);\n }\n\n this.tools.set(tool.name, tool);\n\n // 使用 server.tool() 注册工具\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema.shape,\n async (args: Record<string, unknown>) => {\n return this.executeTool(tool.name, args);\n }\n );\n\n logger.debug(`Registered tool: ${tool.name}`);\n }\n\n /**\n * 批量注册工具\n */\n registerTools(tools: GeneratedTool[]): void {\n for (const tool of tools) {\n this.registerTool(tool);\n }\n logger.info(`Registered ${tools.length} tools`);\n }\n\n /**\n * 执行工具\n */\n private async executeTool(\n toolName: string,\n args: Record<string, unknown>\n ): Promise<{ content: Array<{ type: 'text'; text: string }> }> {\n const tool = this.tools.get(toolName);\n\n if (!tool) {\n return {\n content: [\n {\n type: 'text',\n text: `Error: Tool not found: ${toolName}`,\n },\n ],\n };\n }\n\n try {\n logger.debug(`Executing tool: ${toolName}`, args);\n\n const response = await executeRequest(tool.operation, args, this.config);\n const formattedResponse = formatResponse(response);\n\n return {\n content: [\n {\n type: 'text',\n text: formattedResponse,\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof ToolExecutionError\n ? `Error: ${error.message}`\n : `Error: ${error instanceof Error ? error.message : 'Unknown error'}`;\n\n logger.error(`Tool execution failed: ${toolName}`, error);\n\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n };\n }\n }\n\n /**\n * 获取所有已注册的工具名称\n */\n getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 获取工具数量\n */\n getToolCount(): number {\n return this.tools.size;\n }\n}\n\nexport default ToolManager;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,uBAAwB;;;ACDxB,qBAAyC;AACzC,uBAAwB;;;ACFjB,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,MACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAiC,aAAa;AAAA,EACnD,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,uBAAuB,KAAK;AAC3C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,oBAAN,cAAgC,aAAa;AAAA,EAClD,YAAY,SAAiB,OAAe;AAC1C,UAAM,SAAS,uBAAuB,KAAK;AAC3C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,qBAAN,cAAiC,aAAa;AAAA,EACnD,YACE,SACgB,UAChB,OACA;AACA,UAAM,SAAS,wBAAwB,KAAK;AAH5B;AAIhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,YAAN,cAAwB,aAAa;AAAA,EAC1C,YACE,SACgB,YACA,cAChB,OACA;AACA,UAAM,SAAS,cAAc,KAAK;AAJlB;AACA;AAIhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACnCA,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,IAAI,eAAyB;AAE7B,SAAS,UAAU,OAA0B;AAC3C,SAAO,WAAW,KAAK,KAAK,WAAW,YAAY;AACrD;AAEA,SAAS,cAAc,OAAiB,SAAyB;AAC/D,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAO,IAAI,SAAS,MAAM,MAAM,YAAY,CAAC,KAAK,OAAO;AAC3D;AAEO,IAAM,SAAiB;AAAA,EAC5B,MAAM,YAAoB,MAAuB;AAC/C,QAAI,UAAU,OAAO,GAAG;AACtB,cAAQ,MAAM,cAAc,SAAS,OAAO,GAAG,GAAG,IAAI;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,KAAK,YAAoB,MAAuB;AAC9C,QAAI,UAAU,MAAM,GAAG;AACrB,cAAQ,MAAM,cAAc,QAAQ,OAAO,GAAG,GAAG,IAAI;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,KAAK,YAAoB,MAAuB;AAC9C,QAAI,UAAU,MAAM,GAAG;AACrB,cAAQ,MAAM,cAAc,QAAQ,OAAO,GAAG,GAAG,IAAI;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAM,YAAoB,MAAuB;AAC/C,QAAI,UAAU,OAAO,GAAG;AACtB,cAAQ,MAAM,cAAc,SAAS,OAAO,GAAG,GAAG,IAAI;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,SAAS,OAAuB;AAC9B,mBAAe;AAAA,EACjB;AACF;;;AFlDA,IAAM,kBAAkB;AACxB,IAAM,oBAAoB,CAAC,gBAAgB,uBAAuB,eAAe;AAKjF,SAAS,aAAa,YAAoE;AACxF,MAAI,CAAC,WAAY,QAAO;AAExB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,UAAU;AACpC,QAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,aAAO;AAAA,IACT;AACA,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,yBAAyB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACnF;AAAA,EACF;AACF;AAKA,SAAS,YAAY,KAAiC;AACpD,QAAM,SAA0B,CAAC;AAEjC,MAAI,IAAI,aAAa;AACnB,WAAO,aAAa,IAAI;AAAA,EAC1B;AAEA,MAAI,IAAI,cAAc;AACpB,WAAO,UAAU,IAAI;AAAA,EACvB;AAEA,MAAI,IAAI,aAAa;AACnB,UAAM,UAAU,SAAS,IAAI,aAAa,EAAE;AAC5C,QAAI,CAAC,OAAO,MAAM,OAAO,KAAK,UAAU,GAAG;AACzC,aAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,IAAI,aAAa;AACnB,WAAO,UAAU,aAAa,IAAI,WAAW;AAAA,EAC/C;AAEA,MAAI,IAAI,OAAO;AACb,WAAO,QAAQ,IAAI,UAAU,UAAU,IAAI,UAAU;AAAA,EACvD;AAEA,SAAO;AACT;AAKA,SAAS,aAAa,aAAqB,QAAQ,IAAI,GAA2B;AAChF,aAAW,YAAY,mBAAmB;AACxC,UAAM,eAAW,0BAAQ,YAAY,QAAQ;AAC7C,YAAI,2BAAW,QAAQ,GAAG;AACxB,UAAI;AACF,cAAM,cAAU,6BAAa,UAAU,OAAO;AAC9C,cAAM,SAAS,KAAK,MAAM,OAAO;AACjC,eAAO,KAAK,6BAA6B,QAAQ,EAAE;AACnD,eAAO;AAAA,UACL,YAAY,OAAO;AAAA,UACnB,SAAS,OAAO;AAAA,UAChB,SAAS,OAAO;AAAA,UAChB,SAAS,OAAO;AAAA,UAChB,YAAY,OAAO;AAAA,UACnB,OAAO,OAAO;AAAA,QAChB;AAAA,MACF,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR,8BAA8B,QAAQ,KACpC,iBAAiB,QAAQ,MAAM,UAAU,eAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,YAAY,MAAgC;AACnD,QAAM,SAA0B,CAAC;AAEjC,MAAI,KAAK,KAAK;AACZ,WAAO,aAAa,KAAK;AAAA,EAC3B;AAEA,MAAI,KAAK,SAAS;AAChB,WAAO,UAAU,KAAK;AAAA,EACxB;AAEA,MAAI,KAAK,SAAS;AAChB,WAAO,UAAU,KAAK;AAAA,EACxB;AAEA,MAAI,KAAK,SAAS;AAChB,WAAO,UAAU,aAAa,KAAK,OAAO;AAAA,EAC5C;AAEA,MAAI,KAAK,QAAQ;AACf,WAAO,aAAa,KAAK;AAAA,EAC3B;AAEA,MAAI,KAAK,UAAU,QAAW;AAC5B,WAAO,QAAQ,KAAK;AAAA,EACtB;AAEA,SAAO;AACT;AAKA,SAAS,gBAAgB,SAAyC;AAChE,QAAM,SAAiB;AAAA,IACrB,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAEA,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,eAAe,OAAW,QAAO,aAAa,OAAO;AAChE,QAAI,OAAO,YAAY,OAAW,QAAO,UAAU,OAAO;AAC1D,QAAI,OAAO,YAAY,OAAW,QAAO,UAAU,OAAO;AAC1D,QAAI,OAAO,YAAY,OAAW,QAAO,UAAU,OAAO;AAC1D,QAAI,OAAO,eAAe,OAAW,QAAO,aAAa,OAAO;AAChE,QAAI,OAAO,UAAU,OAAW,QAAO,QAAQ,OAAO;AAAA,EACxD;AAGA,MAAI,OAAO,YAAY,QAAW;AAChC,WAAO,UAAU;AAAA,EACnB;AAEA,SAAO;AACT;AAMO,SAAS,WAAW,UAAmB,CAAC,GAAG,MAAiB,QAAQ,KAAa;AACtF,QAAM,aAAa,aAAa,KAAK,CAAC;AACtC,QAAM,YAAY,YAAY,GAAG;AACjC,QAAM,YAAY,YAAY,OAAO;AAErC,QAAM,SAAS,aAAa,WAAW,WAAW,UAAU;AAG5D,MAAI,CAAC,OAAO,YAAY;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,OAAO;AAChB,WAAO,SAAS,OAAO;AAAA,EACzB;AAEA,SAAO,MAAM,yBAAyB;AAAA,IACpC,YAAY,OAAO;AAAA,IACnB,SAAS,OAAO;AAAA,IAChB,SAAS,OAAO;AAAA,IAChB,YAAY,OAAO;AAAA,IACnB,OAAO,OAAO;AAAA,EAChB,CAAC;AAED,SAAO;AACT;;;AGvLA,iBAA0B;AAC1B,mBAAqC;;;ACDrC,IAAAA,cAAkB;;;ACAlB,iBAAkB;AAYlB,IAAM,qBAAkC,MAAM;AAKvC,SAAS,cACd,QACA,cAA2B,oBAChB;AACX,MAAI,CAAC,QAAQ;AACX,WAAO,aAAE,QAAQ;AAAA,EACnB;AAGA,MAAI,OAAO,MAAM;AACf,UAAM,WAAW,YAAY,OAAO,IAAI;AACxC,QAAI,UAAU;AACZ,aAAO,cAAc,UAAU,WAAW;AAAA,IAC5C;AACA,WAAO,KAAK,oBAAoB,OAAO,IAAI,EAAE;AAC7C,WAAO,aAAE,QAAQ;AAAA,EACnB;AAGA,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,UAAM,UAAU,OAAO,MAAM,IAAI,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAErE,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO,QAAQ,CAAC;AAAA,IAClB;AACA,WAAO,QAAQ,OAAO,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC;AAAA,EAC9C;AAGA,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,UAAM,UAAU,OAAO,MAAM,IAAI,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AACrE,WAAO,aAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,QAAQ,CAAC,GAAG,GAAG,QAAQ,MAAM,CAAC,CAAC,CAIxE;AAAA,EACH;AAGA,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,UAAM,UAAU,OAAO,MAAM,IAAI,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAErE,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO,QAAQ,CAAC,EAAE,SAAS;AAAA,IAC7B;AACA,WAAO,aAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,QAAQ,CAAC,GAAG,GAAG,QAAQ,MAAM,CAAC,CAAC,CAIxE;AAAA,EACH;AAGA,QAAM,WAAW,OAAO,aAAa;AAGrC,MAAI;AAEJ,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,kBAAY,oBAAoB,MAAM;AACtC;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AACH,kBAAY,oBAAoB,MAAM;AACtC;AAAA,IAEF,KAAK;AACH,kBAAY,aAAE,QAAQ;AACtB;AAAA,IAEF,KAAK;AACH,kBAAY,mBAAmB,QAAQ,WAAW;AAClD;AAAA,IAEF,KAAK;AACH,kBAAY,oBAAoB,QAAQ,WAAW;AACnD;AAAA,IAEF;AAEE,UAAI,OAAO,YAAY;AACrB,oBAAY,oBAAoB,QAAQ,WAAW;AAAA,MACrD,OAAO;AACL,oBAAY,aAAE,QAAQ;AAAA,MACxB;AAAA,EACJ;AAGA,MAAI,UAAU;AACZ,gBAAY,UAAU,SAAS;AAAA,EACjC;AAGA,MAAI,OAAO,YAAY,QAAW;AAChC,gBAAY,UAAU,QAAQ,OAAO,OAAO;AAAA,EAC9C;AAGA,MAAI,OAAO,aAAa;AACtB,gBAAY,UAAU,SAAS,OAAO,WAAW;AAAA,EACnD;AAEA,SAAO;AACT;AAKA,SAAS,oBAAoB,QAAoC;AAC/D,MAAI,YAAY,aAAE,OAAO;AAEzB,MAAI,OAAO,cAAc,QAAW;AAClC,gBAAY,UAAU,IAAI,OAAO,SAAS;AAAA,EAC5C;AAEA,MAAI,OAAO,cAAc,QAAW;AAClC,gBAAY,UAAU,IAAI,OAAO,SAAS;AAAA,EAC5C;AAEA,MAAI,OAAO,SAAS;AAClB,gBAAY,UAAU,MAAM,IAAI,OAAO,OAAO,OAAO,CAAC;AAAA,EACxD;AAEA,MAAI,OAAO,QAAQ;AACjB,YAAQ,OAAO,QAAQ;AAAA,MACrB,KAAK;AACH,oBAAY,UAAU,MAAM;AAC5B;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,oBAAY,UAAU,IAAI;AAC1B;AAAA,MACF,KAAK;AACH,oBAAY,UAAU,KAAK;AAC3B;AAAA,MACF,KAAK;AACH,oBAAY,UAAU,KAAK;AAC3B;AAAA,MACF,KAAK;AACH,oBAAY,UAAU,SAAS;AAC/B;AAAA,IAEJ;AAAA,EACF;AAEA,MAAI,OAAO,MAAM;AAEf,UAAM,aAAa,OAAO;AAC1B,gBAAY,aAAE,KAAK,UAAU;AAAA,EAC/B;AAEA,SAAO;AACT;AAKA,SAAS,oBAAoB,QAAoC;AAC/D,MAAI,YAAY,OAAO,SAAS,YAAY,aAAE,OAAO,EAAE,IAAI,IAAI,aAAE,OAAO;AAExE,MAAI,OAAO,YAAY,QAAW;AAChC,gBAAY,UAAU,IAAI,OAAO,OAAO;AAAA,EAC1C;AAEA,MAAI,OAAO,YAAY,QAAW;AAChC,gBAAY,UAAU,IAAI,OAAO,OAAO;AAAA,EAC1C;AAEA,MAAI,OAAO,qBAAqB,QAAQ,OAAO,YAAY,QAAW;AACpE,gBAAY,UAAU,IAAI,OAAO,WAAW,OAAO,SAAS,YAAY,IAAI,OAAO,UAAU;AAAA,EAC/F,WAAW,OAAO,OAAO,qBAAqB,UAAU;AACtD,gBAAY,UAAU;AAAA,MACpB,OAAO,oBAAoB,OAAO,SAAS,YAAY,IAAI,OAAO;AAAA,IACpE;AAAA,EACF;AAEA,MAAI,OAAO,qBAAqB,QAAQ,OAAO,YAAY,QAAW;AACpE,gBAAY,UAAU,IAAI,OAAO,WAAW,OAAO,SAAS,YAAY,IAAI,OAAO,UAAU;AAAA,EAC/F,WAAW,OAAO,OAAO,qBAAqB,UAAU;AACtD,gBAAY,UAAU;AAAA,MACpB,OAAO,oBAAoB,OAAO,SAAS,YAAY,IAAI,OAAO;AAAA,IACpE;AAAA,EACF;AAEA,MAAI,OAAO,MAAM;AACf,UAAM,aAAa,OAAO;AAC1B,gBAAY,aAAE,KAAK,WAAW,IAAI,MAAM,CAA0B;AAAA,EACpE;AAEA,SAAO;AACT;AAKA,SAAS,mBACP,QACA,aACuB;AACvB,QAAM,aAAa,OAAO,QAAQ,cAAc,OAAO,OAAO,WAAW,IAAI,aAAE,QAAQ;AAEvF,MAAI,YAAY,aAAE,MAAM,UAAU;AAElC,MAAI,OAAO,aAAa,QAAW;AACjC,gBAAY,UAAU,IAAI,OAAO,QAAQ;AAAA,EAC3C;AAEA,MAAI,OAAO,aAAa,QAAW;AACjC,gBAAY,UAAU,IAAI,OAAO,QAAQ;AAAA,EAC3C;AAEA,SAAO;AACT;AAKA,SAAS,oBAAoB,QAAuB,aAAqC;AACvF,QAAM,aAAa,OAAO,cAAc,CAAC;AACzC,QAAM,WAAW,IAAI,IAAI,OAAO,YAAY,CAAC,CAAC;AAE9C,MAAI,OAAO,KAAK,UAAU,EAAE,WAAW,GAAG;AAExC,QAAI,OAAO,sBAAsB;AAC/B,UAAI,OAAO,OAAO,yBAAyB,WAAW;AACpD,eAAO,aAAE,OAAO,aAAE,QAAQ,CAAC;AAAA,MAC7B;AACA,aAAO,aAAE,OAAO,cAAc,OAAO,sBAAsB,WAAW,CAAC;AAAA,IACzE;AACA,WAAO,aAAE,OAAO,aAAE,QAAQ,CAAC;AAAA,EAC7B;AAEA,QAAM,gBAA2C,CAAC;AAElD,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,aAAa,cAAc,MAAM,WAAW;AAEhD,QAAI,CAAC,SAAS,IAAI,IAAI,GAAG;AACvB,mBAAa,WAAW,SAAS;AAAA,IACnC;AAEA,kBAAc,IAAI,IAAI;AAAA,EACxB;AAEA,MAAI,YAAuB,aAAE,OAAO,aAAa;AAGjD,MAAI,OAAO,sBAAsB;AAC/B,QAAI,OAAO,OAAO,yBAAyB,WAAW;AACpD,kBAAY,aAAE,OAAO,aAAa,EAAE,YAAY;AAAA,IAClD,OAAO;AAEL,aAAO,MAAM,sEAAsE;AACnF,kBAAY,aAAE,OAAO,aAAa,EAAE,YAAY;AAAA,IAClD;AAAA,EACF,OAAO;AACL,gBAAY,aAAE,OAAO,aAAa,EAAE,OAAO;AAAA,EAC7C;AAEA,SAAO;AACT;AAKO,SAAS,kBACd,YACa;AACb,SAAO,CAAC,QAA2C;AAEjD,UAAM,QAAQ,IAAI,MAAM,gCAAgC;AACxD,QAAI,SAAS,YAAY;AACvB,aAAO,WAAW,MAAM,CAAC,CAAC;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AACF;;;ADjRA,SAAS,iBAAiB,WAA6B,QAAyB;AAE9E,MAAI,UAAU,aAAa;AACzB,UAAMC,QAAO,iBAAiB,UAAU,WAAW;AACnD,WAAO,SAAS,GAAG,MAAM,IAAIA,KAAI,KAAKA;AAAA,EACxC;AAGA,QAAM,YAAY,UAAU,KACzB,MAAM,GAAG,EACT,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,QAAQ,SAAS,EAAE,CAAC;AAE1C,QAAM,OAAO,iBAAiB,GAAG,UAAU,OAAO,YAAY,CAAC,IAAI,UAAU,KAAK,GAAG,CAAC,EAAE;AACxF,SAAO,SAAS,GAAG,MAAM,IAAI,IAAI,KAAK;AACxC;AAKA,SAAS,iBAAiB,MAAsB;AAE9C,SAAO,KACJ,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE,EACpB,YAAY;AACjB;AAKA,SAAS,wBAAwB,WAAqC;AACpE,QAAM,QAAkB,CAAC;AAEzB,MAAI,UAAU,SAAS;AACrB,UAAM,KAAK,UAAU,OAAO;AAAA,EAC9B;AAEA,MAAI,UAAU,aAAa;AACzB,UAAM,KAAK,UAAU,WAAW;AAAA,EAClC;AAEA,MAAI,UAAU,YAAY;AACxB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,QAAM,KAAK;AAAA;AAAA,OAAY,UAAU,MAAM,IAAI,UAAU,IAAI,EAAE;AAG3D,MAAI,UAAU,QAAQ,UAAU,KAAK,SAAS,GAAG;AAC/C,UAAM,KAAK;AAAA,QAAW,UAAU,KAAK,KAAK,IAAI,CAAC,EAAE;AAAA,EACnD;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAKA,SAAS,sBACP,WACA,aACe;AACf,QAAM,QAAuB,CAAC;AAG9B,MAAI,UAAU,YAAY;AACxB,eAAW,SAAS,UAAU,YAAY;AACxC,YAAM,YAAY,MAAM;AACxB,UAAI,cAAc,cAAc,MAAM,QAAQ,WAAW;AAGzD,UAAI,MAAM,aAAa;AACrB,sBAAc,YAAY,SAAS,MAAM,WAAW;AAAA,MACtD;AAGA,UAAI,CAAC,MAAM,UAAU;AACnB,sBAAc,YAAY,SAAS;AAAA,MACrC;AAGA,YAAM,MAAM;AACZ,YAAM,GAAG,IAAI;AAAA,IACf;AAAA,EACF;AAGA,MAAI,UAAU,aAAa;AAEzB,UAAM,cAAc,UAAU,YAAY,QAAQ,kBAAkB;AACpE,QAAI,aAAa,QAAQ;AACvB,YAAM,aAAa,cAAc,YAAY,QAAQ,WAAW;AAEhE,UAAI,UAAU,YAAY,aAAa;AACrC,cAAM,OAAO,WAAW,SAAS,UAAU,YAAY,WAAW;AAAA,MACpE,OAAO;AACL,cAAM,OAAO,WAAW,SAAS,cAAc;AAAA,MACjD;AAEA,UAAI,CAAC,UAAU,YAAY,UAAU;AACnC,cAAM,OAAO,MAAM,KAAK,SAAS;AAAA,MACnC;AAAA,IACF,OAAO;AAEL,YAAM,eAAe,OAAO,KAAK,UAAU,YAAY,OAAO;AAC9D,UAAI,aAAa,SAAS,GAAG;AAC3B,cAAM,eAAe,UAAU,YAAY,QAAQ,aAAa,CAAC,CAAC;AAClE,YAAI,cAAc,QAAQ;AACxB,gBAAM,aAAa,cAAc,aAAa,QAAQ,WAAW;AACjE,gBAAM,OAAO,WAAW,SAAS,iBAAiB,aAAa,CAAC,CAAC,GAAG;AAEpE,cAAI,CAAC,UAAU,YAAY,UAAU;AACnC,kBAAM,OAAO,MAAM,KAAK,SAAS;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aACd,WACA,YACA,YACe;AACf,QAAM,cAAc,kBAAkB,UAAU;AAEhD,QAAM,OAAO,iBAAiB,WAAW,UAAU;AACnD,QAAM,cAAc,wBAAwB,SAAS;AACrD,QAAM,kBAAkB,sBAAsB,WAAW,WAAW;AACpE,QAAM,cAAc,cAAE,OAAO,eAAe;AAE5C,SAAO,MAAM,mBAAmB,IAAI,EAAE;AAEtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,cACd,YACA,YACA,YACiB;AACjB,QAAM,QAAyB,CAAC;AAChC,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,aAAa,YAAY;AAClC,UAAM,OAAO,aAAa,WAAW,YAAY,UAAU;AAG3D,QAAI,UAAU,IAAI,KAAK,IAAI,GAAG;AAC5B,UAAI,UAAU;AACd,UAAI,UAAU,GAAG,KAAK,IAAI,IAAI,OAAO;AACrC,aAAO,UAAU,IAAI,OAAO,GAAG;AAC7B;AACA,kBAAU,GAAG,KAAK,IAAI,IAAI,OAAO;AAAA,MACnC;AACA,aAAO,KAAK,uBAAuB,KAAK,IAAI,eAAe,OAAO,EAAE;AACpE,WAAK,OAAO;AAAA,IACd;AAEA,cAAU,IAAI,KAAK,IAAI;AACvB,UAAM,KAAK,IAAI;AAAA,EACjB;AAEA,SAAO,KAAK,aAAa,MAAM,MAAM,QAAQ;AAC7C,SAAO;AACT;;;AE5MA,4BAA0B;AAgB1B,SAAS,YAAY,KAAkD;AACrE,SAAO,aAAa;AACtB;AAKA,SAAS,iBAAiB,OAAoD;AAC5E,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,IAAI,MAAM;AAAA,IACV,UAAU,MAAM;AAAA,IAChB,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM;AAAA,IACd,YAAY,MAAM;AAAA,EACpB;AACF;AAKA,SAASC,eAAc,QAAuE;AAC5F,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO;AACT;AAKA,SAAS,mBACP,aACgC;AAChC,MAAI,CAAC,YAAa,QAAO;AAGzB,MAAI,UAAU,aAAa;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,UAAyC,CAAC;AAChD,aAAW,CAAC,aAAa,SAAS,KAAK,OAAO,QAAQ,YAAY,WAAW,CAAC,CAAC,GAAG;AAChF,UAAM,KAAK;AACX,YAAQ,WAAW,IAAI;AAAA,MACrB,QAAQA,eAAc,GAAG,MAA4C;AAAA,MACrE,SAAS,GAAG;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa,YAAY;AAAA,IACzB,UAAU,YAAY;AAAA,IACtB;AAAA,EACF;AACF;AAKA,SAAS,kBAAkB,KAA6C;AACtE,QAAM,aAAiC,CAAC;AAExC,MAAI,CAAC,IAAI,MAAO,QAAO;AAEvB,QAAM,UAAU,CAAC,OAAO,QAAQ,OAAO,SAAS,UAAU,QAAQ,WAAW,OAAO;AAEpF,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,IAAI,KAAK,GAAG;AACxD,QAAI,CAAC,SAAU;AAEf,eAAW,UAAU,SAAS;AAC5B,YAAM,YAAY,SAAS,MAAM;AACjC,UAAI,CAAC,UAAW;AAGhB,YAAM,aAAiC,CAAC;AAGxC,UAAI,SAAS,YAAY;AACvB,mBAAW,SAAS,SAAS,YAAY;AACvC,cAAI,EAAE,UAAU,QAAQ;AACtB,uBAAW,KAAK,iBAAiB,KAAK,CAAC;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAGA,UAAI,UAAU,YAAY;AACxB,mBAAW,SAAS,UAAU,YAAY;AACxC,cAAI,EAAE,UAAU,QAAQ;AACtB,uBAAW,KAAK,iBAAiB,KAAK,CAAC;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,KAAuB;AAAA,QAC3B,QAAQ,OAAO,YAAY;AAAA,QAC3B;AAAA,QACA,aAAa,UAAU;AAAA,QACvB,SAAS,UAAU;AAAA,QACnB,aAAa,UAAU;AAAA,QACvB,MAAM,UAAU;AAAA,QAChB,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,QACjD,aAAa;AAAA,UACX,UAAU;AAAA,QAIZ;AAAA,QACA,YAAY,UAAU;AAAA,MACxB;AAEA,iBAAW,KAAK,EAAE;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAsB,aAAa,QAA2C;AAC5E,MAAI;AACF,WAAO,KAAK,kCAAkC,MAAM,EAAE;AAGtD,UAAM,MAAM,MAAM,sBAAAC,QAAc,SAAS,MAAM;AAG/C,QAAI,CAAC,YAAY,GAAG,GAAG;AAErB,UAAI,aAAa,KAAK;AACpB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,IAAI,kBAAkB,4BAA4B;AAAA,IAC1D;AAEA,UAAM,OAAiC;AAAA,MACrC,OAAO,IAAI,KAAK;AAAA,MAChB,SAAS,IAAI,KAAK;AAAA,MAClB,aAAa,IAAI,KAAK;AAAA,IACxB;AAEA,UAAM,UAAuC,IAAI,SAAS,IAAI,CAAC,OAAO;AAAA,MACpE,KAAK,EAAE;AAAA,MACP,aAAa,EAAE;AAAA,MACf,WAAW,EAAE;AAAA,IACf,EAAE;AAEF,UAAM,aAAa,kBAAkB,GAAG;AAExC,UAAM,aAAa,IAAI,aACnB;AAAA,MACE,SAAS,IAAI,WAAW;AAAA,MACxB,YAAY,IAAI,WAAW;AAAA,MAC3B,eAAe,IAAI,WAAW;AAAA,IAGhC,IACA;AAEJ,WAAO,KAAK,UAAU,WAAW,MAAM,iBAAiB;AAExD,WAAO;AAAA,MACL,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,mBAAmB;AACtC,YAAM;AAAA,IACR;AACA,UAAM,IAAI;AAAA,MACR,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC7F,iBAAiB,QAAQ,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;AAKO,SAAS,WAAW,KAAuB,aAA8B;AAC9E,MAAI,aAAa;AACf,WAAO,MAAM,4BAA4B,WAAW,EAAE;AACtD,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,WAAW,IAAI,QAAQ,SAAS,GAAG;AACzC,UAAM,SAAS,IAAI,QAAQ,CAAC;AAC5B,QAAI,MAAM,OAAO;AAGjB,QAAI,OAAO,WAAW;AACpB,iBAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,OAAO,SAAS,GAAG;AAC/D,cAAM,IAAI,QAAQ,IAAI,IAAI,KAAK,SAAS,OAAO;AAAA,MACjD;AAAA,IACF;AAEA,WAAO,MAAM,wCAAwC,GAAG,EAAE;AAC1D,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,kBAAkB,mEAAmE;AACjG;;;AC3MA,SAAS,0BACP,YAC+C;AAC/C,QAAM,SAAwD;AAAA,IAC5D,MAAM,CAAC;AAAA,IACP,OAAO,CAAC;AAAA,IACR,QAAQ,CAAC;AAAA,IACT,QAAQ,CAAC;AAAA,EACX;AAEA,MAAI,YAAY;AACd,eAAW,SAAS,YAAY;AAC9B,aAAO,MAAM,EAAE,EAAE,KAAK,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,aACd,WACA,OACA,iBAAyC,CAAC,GAC5B;AACd,QAAM,gBAAgB,0BAA0B,UAAU,UAAU;AAGpE,MAAI,OAAO,UAAU;AACrB,aAAW,SAAS,cAAc,MAAM;AACtC,UAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAI,UAAU,QAAW;AACvB,aAAO,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IACtD,WAAW,MAAM,UAAU;AACzB,YAAM,IAAI,MAAM,oCAAoC,MAAM,IAAI,EAAE;AAAA,IAClE;AAAA,EACF;AAGA,QAAM,QAA2C,CAAC;AAClD,aAAW,SAAS,cAAc,OAAO;AACvC,UAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAI,UAAU,QAAW;AACvB,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,cAAM,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM;AAAA,MACtC,OAAO;AACL,cAAM,MAAM,IAAI,IAAI,OAAO,KAAK;AAAA,MAClC;AAAA,IACF,WAAW,MAAM,UAAU;AACzB,YAAM,IAAI,MAAM,qCAAqC,MAAM,IAAI,EAAE;AAAA,IACnE;AAAA,EACF;AAGA,QAAM,UAAkC,EAAE,GAAG,eAAe;AAC5D,aAAW,SAAS,cAAc,QAAQ;AACxC,UAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAI,UAAU,QAAW;AACvB,cAAQ,MAAM,IAAI,IAAI,OAAO,KAAK;AAAA,IACpC,WAAW,MAAM,UAAU;AACzB,YAAM,IAAI,MAAM,sCAAsC,MAAM,IAAI,EAAE;AAAA,IACpE;AAAA,EACF;AAGA,QAAM,OAAO,MAAM;AAGnB,MAAI,SAAS,UAAa,CAAC,QAAQ,cAAc,GAAG;AAClD,QAAI,UAAU,aAAa,SAAS;AAElC,YAAM,eAAe,OAAO,KAAK,UAAU,YAAY,OAAO;AAC9D,UAAI,aAAa,SAAS,GAAG;AAC3B,gBAAQ,cAAc,IAAI,aAAa,CAAC;AAAA,MAC1C;AAAA,IACF,OAAO;AACL,cAAQ,cAAc,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO,MAAM,kBAAkB,UAAU,MAAM,IAAI,IAAI,IAAI;AAAA,IACzD;AAAA,IACA;AAAA,IACA,MAAM,OAAO,mBAAmB;AAAA,EAClC,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,kBAAkB,KAAa,OAAkD;AAC/F,QAAM,SAAS,IAAI,gBAAgB;AAEnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,KAAK,OAAO;AACrB,eAAO,OAAO,KAAK,CAAC;AAAA,MACtB;AAAA,IACF,OAAO;AACL,aAAO,OAAO,KAAK,KAAK;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,SAAS;AACpC,MAAI,aAAa;AACf,WAAO,GAAG,GAAG,IAAI,WAAW;AAAA,EAC9B;AAEA,SAAO;AACT;;;ACvHA,eAAsB,eACpB,WACA,OACA,QACuB;AACvB,QAAM,UAAU,OAAO,WAAW;AAElC,MAAI;AAEF,UAAM,QAAQ,aAAa,WAAW,OAAO,OAAO,WAAW,CAAC,CAAC;AAGjE,QAAI,MAAM,GAAG,OAAO,GAAG,MAAM,IAAI;AACjC,UAAM,kBAAkB,KAAK,MAAM,KAAK;AAExC,WAAO,KAAK,cAAc,UAAU,MAAM,IAAI,GAAG,EAAE;AAGnD,UAAM,cAA2B;AAAA,MAC/B,QAAQ,UAAU;AAAA,MAClB,SAAS,MAAM;AAAA,IACjB;AAGA,QAAI,MAAM,SAAS,UAAa,CAAC,CAAC,OAAO,MAAM,EAAE,SAAS,UAAU,OAAO,YAAY,CAAC,GAAG;AACzF,kBAAY,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAK,UAAU,MAAM,IAAI;AAAA,IAC5F;AAGA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO,OAAO;AACrE,gBAAY,SAAS,WAAW;AAGhC,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,iBAAa,SAAS;AAGtB,UAAM,kBAA0C,CAAC;AACjD,aAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,sBAAgB,GAAG,IAAI;AAAA,IACzB,CAAC;AAGD,QAAI;AACJ,UAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAE5D,QAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,UAAI;AACF,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B,QAAQ;AACN,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B;AAAA,IACF,WAAW,YAAY,SAAS,OAAO,GAAG;AACxC,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,OAAO;AAEL,UAAI;AACF,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B,QAAQ;AACN,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO,MAAM,oBAAoB,SAAS,MAAM,EAAE;AAGlD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI;AAAA,QACR,QAAQ,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,QAC9C,SAAS;AAAA,QACT,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI;AAAA,MACvD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,SAAS;AAAA,MACT;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,WAAW;AAC9B,YAAM;AAAA,IACR;AAEA,QAAI,iBAAiB,OAAO;AAC1B,UAAI,MAAM,SAAS,cAAc;AAC/B,cAAM,IAAI;AAAA,UACR,yBAAyB,OAAO,OAAO;AAAA,UACvC,UAAU,eAAe,UAAU;AAAA,QACrC;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,mBAAmB,MAAM,OAAO;AAAA,QAChC,UAAU,eAAe,UAAU;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,MACR;AAAA,MACA,UAAU,eAAe,UAAU;AAAA,IACrC;AAAA,EACF;AACF;AAKO,SAAS,eAAe,UAAgC;AAC7D,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,WAAW,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAE9D,MAAI,OAAO,KAAK,SAAS,OAAO,EAAE,SAAS,GAAG;AAC5C,UAAM,KAAK,UAAU;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,OAAO,GAAG;AAC3D,YAAM,KAAK,KAAK,GAAG,KAAK,KAAK,EAAE;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,KAAK,OAAO;AAClB,MAAI,OAAO,SAAS,SAAS,YAAY,SAAS,SAAS,MAAM;AAC/D,UAAM,KAAK,KAAK,UAAU,SAAS,MAAM,MAAM,CAAC,CAAC;AAAA,EACnD,OAAO;AACL,UAAM,KAAK,OAAO,SAAS,IAAI,CAAC;AAAA,EAClC;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC3IO,IAAM,cAAN,MAAkB;AAAA,EACf,QAAoC,oBAAI,IAAI;AAAA,EAC5C;AAAA,EACA;AAAA,EAER,YAAY,QAAmB,QAAgB;AAC7C,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAA2B;AACtC,QAAI,KAAK,MAAM,IAAI,KAAK,IAAI,GAAG;AAC7B,aAAO,KAAK,4BAA4B,KAAK,IAAI,eAAe;AAAA,IAClE;AAEA,SAAK,MAAM,IAAI,KAAK,MAAM,IAAI;AAG9B,SAAK,OAAO;AAAA,MACV,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,YAAY;AAAA,MACjB,OAAO,SAAkC;AACvC,eAAO,KAAK,YAAY,KAAK,MAAM,IAAI;AAAA,MACzC;AAAA,IACF;AAEA,WAAO,MAAM,oBAAoB,KAAK,IAAI,EAAE;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,OAA8B;AAC1C,eAAW,QAAQ,OAAO;AACxB,WAAK,aAAa,IAAI;AAAA,IACxB;AACA,WAAO,KAAK,cAAc,MAAM,MAAM,QAAQ;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YACZ,UACA,MAC6D;AAC7D,UAAM,OAAO,KAAK,MAAM,IAAI,QAAQ;AAEpC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,0BAA0B,QAAQ;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,aAAO,MAAM,mBAAmB,QAAQ,IAAI,IAAI;AAEhD,YAAM,WAAW,MAAM,eAAe,KAAK,WAAW,MAAM,KAAK,MAAM;AACvE,YAAM,oBAAoB,eAAe,QAAQ;AAEjD,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,eACJ,iBAAiB,qBACb,UAAU,MAAM,OAAO,KACvB,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAExE,aAAO,MAAM,0BAA0B,QAAQ,IAAI,KAAK;AAExD,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAyB;AACvB,WAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;;;AN5GA,eAAsB,aAAa,QAAoC;AACrE,SAAO,KAAK,wBAAwB;AAGpC,QAAM,SAAS,IAAI,qBAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAGD,QAAM,aAAa,MAAM,aAAa,OAAO,UAAU;AAGvD,MAAI;AACJ,MAAI;AACF,cAAU,WAAW,YAAY,OAAO,OAAO;AAAA,EACjD,SAAS,OAAO;AACd,QAAI,OAAO,SAAS;AAClB,gBAAU,OAAO;AAAA,IACnB,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AAGA,QAAM,kBAA0B;AAAA,IAC9B,GAAG;AAAA,IACH;AAAA,EACF;AAGA,QAAM,QAAQ;AAAA,IACZ,WAAW;AAAA,IACX,WAAW,YAAY;AAAA,IACvB,OAAO;AAAA,EACT;AAGA,QAAM,cAAc,IAAI,YAAY,QAAQ,eAAe;AAC3D,cAAY,cAAc,KAAK;AAE/B,SAAO,KAAK,qBAAqB,YAAY,aAAa,CAAC,QAAQ;AAEnE,SAAO;AACT;AAKA,eAAsB,YAAY,QAA+B;AAC/D,QAAM,SAAS,MAAM,aAAa,MAAM;AAGxC,QAAM,YAAY,IAAI,kCAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAE9B,SAAO,KAAK,6BAA6B;AAC3C;;;AJ3DA,IAAM,UAAU,IAAI,yBAAQ;AAE5B,QACG,KAAK,SAAS,EACd,YAAY,6CAA6C,EACzD,QAAQ,OAAO,EACf,OAAO,mBAAmB,mCAAmC,EAC7D,OAAO,wBAAwB,0CAA0C,EACzE,OAAO,sBAAsB,mCAAmC,QAAQ,EACxE,OAAO,wBAAwB,+BAA+B,EAC9D,OAAO,yBAAyB,kBAAkB,EAClD,OAAO,eAAe,qBAAqB,KAAK,EAChD,OAAO,OAAO,YAAY;AACzB,MAAI;AACJ,MAAI;AAEF,aAAS,WAAW;AAAA,MAClB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,IACjB,CAAC;AAED,WAAO,KAAK,qBAAqB;AACjC,WAAO,KAAK,gBAAgB,OAAO,UAAU,EAAE;AAC/C,QAAI,OAAO,SAAS;AAClB,aAAO,KAAK,aAAa,OAAO,OAAO,EAAE;AAAA,IAC3C;AAGA,UAAM,YAAY,MAAM;AAAA,EAC1B,SAAS,OAAO;AACd,QAAI,iBAAiB,oBAAoB;AACvC,cAAQ,MAAM,wBAAwB,MAAM,OAAO,EAAE;AACrD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,iBAAiB,mBAAmB;AACtC,cAAQ,MAAM,wBAAwB,MAAM,OAAO,EAAE;AACrD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AAClF,QAAI,QAAQ,SAAS,iBAAiB,SAAS,MAAM,OAAO;AAC1D,cAAQ,MAAM,MAAM,KAAK;AAAA,IAC3B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAGH,QAAQ,MAAM;","names":["import_zod","name","convertSchema","SwaggerParser"]}
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ConfigurationError,
|
|
4
|
+
OpenApiParseError,
|
|
5
|
+
loadConfig,
|
|
6
|
+
logger,
|
|
7
|
+
startServer
|
|
8
|
+
} from "./chunk-CVWZJCLP.mjs";
|
|
9
|
+
|
|
10
|
+
// src/cli.ts
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
var program = new Command();
|
|
13
|
+
program.name("api2mcp").description("Convert OpenAPI specifications to MCP tools").version("0.1.0").option("-u, --url <url>", "OpenAPI document URL or file path").option("-b, --base-url <url>", "API base URL (overrides OpenAPI servers)").option("-t, --timeout <ms>", "Request timeout in milliseconds", parseInt).option("-h, --headers <json>", "Custom headers as JSON string").option("-p, --prefix <prefix>", "Tool name prefix").option("-d, --debug", "Enable debug mode", false).action(async (options) => {
|
|
14
|
+
let config;
|
|
15
|
+
try {
|
|
16
|
+
config = loadConfig({
|
|
17
|
+
url: options.url,
|
|
18
|
+
baseUrl: options.baseUrl,
|
|
19
|
+
timeout: options.timeout,
|
|
20
|
+
headers: options.headers,
|
|
21
|
+
prefix: options.prefix,
|
|
22
|
+
debug: options.debug
|
|
23
|
+
});
|
|
24
|
+
logger.info(`Starting api2mcp...`);
|
|
25
|
+
logger.info(`OpenAPI URL: ${config.openapiUrl}`);
|
|
26
|
+
if (config.baseUrl) {
|
|
27
|
+
logger.info(`Base URL: ${config.baseUrl}`);
|
|
28
|
+
}
|
|
29
|
+
await startServer(config);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof ConfigurationError) {
|
|
32
|
+
console.error(`Configuration error: ${error.message}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (error instanceof OpenApiParseError) {
|
|
36
|
+
console.error(`OpenAPI parse error: ${error.message}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
40
|
+
if (config?.debug && error instanceof Error && error.stack) {
|
|
41
|
+
console.error(error.stack);
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
program.parse();
|
|
47
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * CLI 入口\n */\n\nimport { Command } from 'commander';\nimport { loadConfig } from './config/loader.js';\nimport type { Config } from './config/types.js';\nimport { startServer } from './server/index.js';\nimport { ConfigurationError, OpenApiParseError } from './utils/error.js';\nimport { logger } from './utils/logger.js';\n\nconst program = new Command();\n\nprogram\n .name('api2mcp')\n .description('Convert OpenAPI specifications to MCP tools')\n .version('0.1.0')\n .option('-u, --url <url>', 'OpenAPI document URL or file path')\n .option('-b, --base-url <url>', 'API base URL (overrides OpenAPI servers)')\n .option('-t, --timeout <ms>', 'Request timeout in milliseconds', parseInt)\n .option('-h, --headers <json>', 'Custom headers as JSON string')\n .option('-p, --prefix <prefix>', 'Tool name prefix')\n .option('-d, --debug', 'Enable debug mode', false)\n .action(async (options) => {\n let config: Config | undefined;\n try {\n // 加载配置\n config = loadConfig({\n url: options.url,\n baseUrl: options.baseUrl,\n timeout: options.timeout,\n headers: options.headers,\n prefix: options.prefix,\n debug: options.debug,\n });\n\n logger.info(`Starting api2mcp...`);\n logger.info(`OpenAPI URL: ${config.openapiUrl}`);\n if (config.baseUrl) {\n logger.info(`Base URL: ${config.baseUrl}`);\n }\n\n // 启动服务器\n await startServer(config);\n } catch (error) {\n if (error instanceof ConfigurationError) {\n console.error(`Configuration error: ${error.message}`);\n process.exit(1);\n }\n\n if (error instanceof OpenApiParseError) {\n console.error(`OpenAPI parse error: ${error.message}`);\n process.exit(1);\n }\n\n console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);\n if (config?.debug && error instanceof Error && error.stack) {\n console.error(error.stack);\n }\n process.exit(1);\n }\n });\n\n// 解析命令行参数\nprogram.parse();\n"],"mappings":";;;;;;;;;;AAMA,SAAS,eAAe;AAOxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,SAAS,EACd,YAAY,6CAA6C,EACzD,QAAQ,OAAO,EACf,OAAO,mBAAmB,mCAAmC,EAC7D,OAAO,wBAAwB,0CAA0C,EACzE,OAAO,sBAAsB,mCAAmC,QAAQ,EACxE,OAAO,wBAAwB,+BAA+B,EAC9D,OAAO,yBAAyB,kBAAkB,EAClD,OAAO,eAAe,qBAAqB,KAAK,EAChD,OAAO,OAAO,YAAY;AACzB,MAAI;AACJ,MAAI;AAEF,aAAS,WAAW;AAAA,MAClB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,IACjB,CAAC;AAED,WAAO,KAAK,qBAAqB;AACjC,WAAO,KAAK,gBAAgB,OAAO,UAAU,EAAE;AAC/C,QAAI,OAAO,SAAS;AAClB,aAAO,KAAK,aAAa,OAAO,OAAO,EAAE;AAAA,IAC3C;AAGA,UAAM,YAAY,MAAM;AAAA,EAC1B,SAAS,OAAO;AACd,QAAI,iBAAiB,oBAAoB;AACvC,cAAQ,MAAM,wBAAwB,MAAM,OAAO,EAAE;AACrD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,iBAAiB,mBAAmB;AACtC,cAAQ,MAAM,wBAAwB,MAAM,OAAO,EAAE;AACrD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AAClF,QAAI,QAAQ,SAAS,iBAAiB,SAAS,MAAM,OAAO;AAC1D,cAAQ,MAAM,MAAM,KAAK;AAAA,IAC3B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAGH,QAAQ,MAAM;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 配置类型定义
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* API 请求头配置
|
|
10
|
+
*/
|
|
11
|
+
type ApiHeaders = Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* 单个 API 源配置
|
|
14
|
+
*/
|
|
15
|
+
interface ApiSourceConfig {
|
|
16
|
+
/** OpenAPI 文档 URL 或本地文件路径 */
|
|
17
|
+
openapiUrl: string;
|
|
18
|
+
/** API 基础 URL(可选,默认从 OpenAPI 文档中提取) */
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/** 请求超时时间(毫秒) */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
/** 自定义请求头 */
|
|
23
|
+
headers?: ApiHeaders;
|
|
24
|
+
/** 工具名前缀 */
|
|
25
|
+
toolPrefix?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 完整配置
|
|
29
|
+
*/
|
|
30
|
+
interface Config extends ApiSourceConfig {
|
|
31
|
+
/** 调试模式 */
|
|
32
|
+
debug: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* CLI 参数 Schema
|
|
36
|
+
*/
|
|
37
|
+
declare const CliArgsSchema: z.ZodObject<{
|
|
38
|
+
url: z.ZodOptional<z.ZodString>;
|
|
39
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
40
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
41
|
+
headers: z.ZodOptional<z.ZodString>;
|
|
42
|
+
prefix: z.ZodOptional<z.ZodString>;
|
|
43
|
+
debug: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
}, "strip", z.ZodTypeAny, {
|
|
45
|
+
debug?: boolean | undefined;
|
|
46
|
+
url?: string | undefined;
|
|
47
|
+
baseUrl?: string | undefined;
|
|
48
|
+
timeout?: number | undefined;
|
|
49
|
+
headers?: string | undefined;
|
|
50
|
+
prefix?: string | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
debug?: boolean | undefined;
|
|
53
|
+
url?: string | undefined;
|
|
54
|
+
baseUrl?: string | undefined;
|
|
55
|
+
timeout?: number | undefined;
|
|
56
|
+
headers?: string | undefined;
|
|
57
|
+
prefix?: string | undefined;
|
|
58
|
+
}>;
|
|
59
|
+
type CliArgs = z.infer<typeof CliArgsSchema>;
|
|
60
|
+
/**
|
|
61
|
+
* 环境变量配置
|
|
62
|
+
*/
|
|
63
|
+
interface EnvConfig {
|
|
64
|
+
OPENAPI_URL?: string;
|
|
65
|
+
API_BASE_URL?: string;
|
|
66
|
+
API_TIMEOUT?: string;
|
|
67
|
+
API_HEADERS?: string;
|
|
68
|
+
DEBUG?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 配置加载器
|
|
73
|
+
* 优先级: CLI 参数 > 环境变量 > 配置文件
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 加载配置
|
|
78
|
+
* 优先级: CLI 参数 > 环境变量 > 配置文件
|
|
79
|
+
*/
|
|
80
|
+
declare function loadConfig(cliArgs?: CliArgs, env?: EnvConfig): Config;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* OpenAPI 类型定义
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* OpenAPI 参数位置
|
|
87
|
+
*/
|
|
88
|
+
type ParameterLocation = 'path' | 'query' | 'header' | 'cookie';
|
|
89
|
+
/**
|
|
90
|
+
* OpenAPI 参数
|
|
91
|
+
*/
|
|
92
|
+
interface OpenApiParameter {
|
|
93
|
+
name: string;
|
|
94
|
+
in: ParameterLocation;
|
|
95
|
+
required?: boolean;
|
|
96
|
+
description?: string;
|
|
97
|
+
schema?: OpenApiSchema;
|
|
98
|
+
deprecated?: boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* OpenAPI Schema
|
|
102
|
+
*/
|
|
103
|
+
interface OpenApiSchema {
|
|
104
|
+
type?: string;
|
|
105
|
+
format?: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
default?: unknown;
|
|
108
|
+
enum?: unknown[];
|
|
109
|
+
const?: unknown;
|
|
110
|
+
items?: OpenApiSchema;
|
|
111
|
+
properties?: Record<string, OpenApiSchema>;
|
|
112
|
+
additionalProperties?: boolean | OpenApiSchema;
|
|
113
|
+
required?: string[];
|
|
114
|
+
oneOf?: OpenApiSchema[];
|
|
115
|
+
anyOf?: OpenApiSchema[];
|
|
116
|
+
allOf?: OpenApiSchema[];
|
|
117
|
+
minLength?: number;
|
|
118
|
+
maxLength?: number;
|
|
119
|
+
minimum?: number;
|
|
120
|
+
maximum?: number;
|
|
121
|
+
exclusiveMinimum?: boolean | number;
|
|
122
|
+
exclusiveMaximum?: boolean | number;
|
|
123
|
+
pattern?: string;
|
|
124
|
+
minItems?: number;
|
|
125
|
+
maxItems?: number;
|
|
126
|
+
uniqueItems?: boolean;
|
|
127
|
+
nullable?: boolean;
|
|
128
|
+
deprecated?: boolean;
|
|
129
|
+
example?: unknown;
|
|
130
|
+
$ref?: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* OpenAPI 请求体
|
|
134
|
+
*/
|
|
135
|
+
interface OpenApiRequestBody {
|
|
136
|
+
description?: string;
|
|
137
|
+
required?: boolean;
|
|
138
|
+
content: Record<string, {
|
|
139
|
+
schema?: OpenApiSchema;
|
|
140
|
+
example?: unknown;
|
|
141
|
+
examples?: Record<string, unknown>;
|
|
142
|
+
}>;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* OpenAPI 响应
|
|
146
|
+
*/
|
|
147
|
+
interface OpenApiResponse {
|
|
148
|
+
description?: string;
|
|
149
|
+
content?: Record<string, {
|
|
150
|
+
schema?: OpenApiSchema;
|
|
151
|
+
example?: unknown;
|
|
152
|
+
}>;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* OpenAPI 操作
|
|
156
|
+
*/
|
|
157
|
+
interface OpenApiOperation {
|
|
158
|
+
/** HTTP 方法 */
|
|
159
|
+
method: string;
|
|
160
|
+
/** API 路径 */
|
|
161
|
+
path: string;
|
|
162
|
+
/** 操作 ID */
|
|
163
|
+
operationId?: string;
|
|
164
|
+
/** 摘要 */
|
|
165
|
+
summary?: string;
|
|
166
|
+
/** 详细描述 */
|
|
167
|
+
description?: string;
|
|
168
|
+
/** 标签 */
|
|
169
|
+
tags?: string[];
|
|
170
|
+
/** 参数列表 */
|
|
171
|
+
parameters?: OpenApiParameter[];
|
|
172
|
+
/** 请求体 */
|
|
173
|
+
requestBody?: OpenApiRequestBody;
|
|
174
|
+
/** 响应 */
|
|
175
|
+
responses?: Record<string, OpenApiResponse>;
|
|
176
|
+
/** 是否废弃 */
|
|
177
|
+
deprecated?: boolean;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* OpenAPI 文档信息
|
|
181
|
+
*/
|
|
182
|
+
interface OpenApiInfo {
|
|
183
|
+
title: string;
|
|
184
|
+
version: string;
|
|
185
|
+
description?: string;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* OpenAPI 服务器
|
|
189
|
+
*/
|
|
190
|
+
interface OpenApiServer {
|
|
191
|
+
url: string;
|
|
192
|
+
description?: string;
|
|
193
|
+
variables?: Record<string, {
|
|
194
|
+
default: string;
|
|
195
|
+
enum?: string[];
|
|
196
|
+
description?: string;
|
|
197
|
+
}>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 解析后的 OpenAPI 文档
|
|
201
|
+
*/
|
|
202
|
+
interface ParsedOpenApiDoc {
|
|
203
|
+
openapi: string;
|
|
204
|
+
info: OpenApiInfo;
|
|
205
|
+
servers?: OpenApiServer[];
|
|
206
|
+
operations: OpenApiOperation[];
|
|
207
|
+
components?: {
|
|
208
|
+
schemas?: Record<string, OpenApiSchema>;
|
|
209
|
+
parameters?: Record<string, OpenApiParameter>;
|
|
210
|
+
requestBodies?: Record<string, OpenApiRequestBody>;
|
|
211
|
+
responses?: Record<string, OpenApiResponse>;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* OpenAPI Schema 到 Zod Schema 转换器
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Schema 引用解析函数类型
|
|
221
|
+
*/
|
|
222
|
+
type RefResolver = (ref: string) => OpenApiSchema | undefined;
|
|
223
|
+
/**
|
|
224
|
+
* 将 OpenAPI Schema 转换为 Zod Schema
|
|
225
|
+
*/
|
|
226
|
+
declare function convertSchema(schema: OpenApiSchema | undefined, refResolver?: RefResolver): z.ZodType;
|
|
227
|
+
/**
|
|
228
|
+
* 创建引用解析器
|
|
229
|
+
*/
|
|
230
|
+
declare function createRefResolver(components: Record<string, OpenApiSchema> | undefined): RefResolver;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* MCP 工具生成器
|
|
234
|
+
*/
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* 生成的工具定义
|
|
238
|
+
*/
|
|
239
|
+
interface GeneratedTool {
|
|
240
|
+
/** 工具名称 */
|
|
241
|
+
name: string;
|
|
242
|
+
/** 工具描述 */
|
|
243
|
+
description: string;
|
|
244
|
+
/** 输入参数 Schema */
|
|
245
|
+
inputSchema: z.ZodObject<z.ZodRawShape>;
|
|
246
|
+
/** 原始操作定义 */
|
|
247
|
+
operation: OpenApiOperation;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 从 OpenAPI 操作生成 MCP 工具
|
|
251
|
+
*/
|
|
252
|
+
declare function generateTool(operation: OpenApiOperation, components?: Record<string, OpenApiSchema>, toolPrefix?: string): GeneratedTool;
|
|
253
|
+
/**
|
|
254
|
+
* 批量生成工具
|
|
255
|
+
*/
|
|
256
|
+
declare function generateTools(operations: OpenApiOperation[], components?: Record<string, OpenApiSchema>, toolPrefix?: string): GeneratedTool[];
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* HTTP 客户端
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* HTTP 响应
|
|
264
|
+
*/
|
|
265
|
+
interface HttpResponse {
|
|
266
|
+
status: number;
|
|
267
|
+
statusText: string;
|
|
268
|
+
headers: Record<string, string>;
|
|
269
|
+
body: unknown;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 执行 HTTP 请求
|
|
273
|
+
*/
|
|
274
|
+
declare function executeRequest(operation: OpenApiOperation, input: Record<string, unknown>, config: Config): Promise<HttpResponse>;
|
|
275
|
+
/**
|
|
276
|
+
* 格式化响应为字符串
|
|
277
|
+
*/
|
|
278
|
+
declare function formatResponse(response: HttpResponse): string;
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* OpenAPI 解析器
|
|
282
|
+
*/
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 解析 OpenAPI 文档
|
|
286
|
+
*/
|
|
287
|
+
declare function parseOpenApi(source: string): Promise<ParsedOpenApiDoc>;
|
|
288
|
+
/**
|
|
289
|
+
* 获取基础 URL
|
|
290
|
+
*/
|
|
291
|
+
declare function getBaseUrl(doc: ParsedOpenApiDoc, overrideUrl?: string): string;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* MCP 服务器
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 创建并启动 MCP 服务器
|
|
299
|
+
*/
|
|
300
|
+
declare function createServer(config: Config): Promise<McpServer>;
|
|
301
|
+
/**
|
|
302
|
+
* 启动服务器(使用 stdio 传输)
|
|
303
|
+
*/
|
|
304
|
+
declare function startServer(config: Config): Promise<void>;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* MCP 工具管理器
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 工具管理器
|
|
312
|
+
*/
|
|
313
|
+
declare class ToolManager {
|
|
314
|
+
private tools;
|
|
315
|
+
private config;
|
|
316
|
+
private server;
|
|
317
|
+
constructor(server: McpServer, config: Config);
|
|
318
|
+
/**
|
|
319
|
+
* 注册工具
|
|
320
|
+
*/
|
|
321
|
+
registerTool(tool: GeneratedTool): void;
|
|
322
|
+
/**
|
|
323
|
+
* 批量注册工具
|
|
324
|
+
*/
|
|
325
|
+
registerTools(tools: GeneratedTool[]): void;
|
|
326
|
+
/**
|
|
327
|
+
* 执行工具
|
|
328
|
+
*/
|
|
329
|
+
private executeTool;
|
|
330
|
+
/**
|
|
331
|
+
* 获取所有已注册的工具名称
|
|
332
|
+
*/
|
|
333
|
+
getToolNames(): string[];
|
|
334
|
+
/**
|
|
335
|
+
* 获取工具数量
|
|
336
|
+
*/
|
|
337
|
+
getToolCount(): number;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* 错误类定义
|
|
342
|
+
*/
|
|
343
|
+
declare class Api2McpError extends Error {
|
|
344
|
+
readonly code: string;
|
|
345
|
+
readonly cause?: Error | undefined;
|
|
346
|
+
constructor(message: string, code: string, cause?: Error | undefined);
|
|
347
|
+
}
|
|
348
|
+
declare class ConfigurationError extends Api2McpError {
|
|
349
|
+
constructor(message: string, cause?: Error);
|
|
350
|
+
}
|
|
351
|
+
declare class OpenApiParseError extends Api2McpError {
|
|
352
|
+
constructor(message: string, cause?: Error);
|
|
353
|
+
}
|
|
354
|
+
declare class ToolExecutionError extends Api2McpError {
|
|
355
|
+
readonly toolName: string;
|
|
356
|
+
constructor(message: string, toolName: string, cause?: Error);
|
|
357
|
+
}
|
|
358
|
+
declare class HttpError extends Api2McpError {
|
|
359
|
+
readonly statusCode: number;
|
|
360
|
+
readonly responseBody?: string | undefined;
|
|
361
|
+
constructor(message: string, statusCode: number, responseBody?: string | undefined, cause?: Error);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 简单日志工具
|
|
366
|
+
* 所有日志输出到 stderr,避免干扰 MCP stdio 协议
|
|
367
|
+
*/
|
|
368
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
369
|
+
interface Logger {
|
|
370
|
+
debug: (message: string, ...args: unknown[]) => void;
|
|
371
|
+
info: (message: string, ...args: unknown[]) => void;
|
|
372
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
373
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
374
|
+
setLevel: (level: LogLevel) => void;
|
|
375
|
+
}
|
|
376
|
+
declare const logger: Logger;
|
|
377
|
+
|
|
378
|
+
export { Api2McpError, type ApiHeaders, type ApiSourceConfig, type Config, ConfigurationError, type GeneratedTool, HttpError, type HttpResponse, type OpenApiOperation, type OpenApiParameter, OpenApiParseError, type OpenApiSchema, type ParsedOpenApiDoc, ToolExecutionError, ToolManager, convertSchema, createRefResolver, createServer, executeRequest, formatResponse, generateTool, generateTools, getBaseUrl, loadConfig, logger, parseOpenApi, startServer };
|