UNPKG

mcp-swagger-parser

Version:

Enterprise-grade OpenAPI/Swagger specification parser for Model Context Protocol (MCP) projects

1,039 lines 40.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAPIToMCPTransformer = void 0; exports.transformToMCPTools = transformToMCPTools; const schema_annotation_extractor_1 = require("../extractors/schema-annotation-extractor"); const bearer_auth_1 = require("../auth/bearer-auth"); const CustomHeadersManager_1 = require("../headers/CustomHeadersManager"); const axios_1 = __importDefault(require("axios")); /** * 辅助函数:创建文本内容块 */ function createTextContent(text, meta) { const content = { type: 'text', text }; if (meta) { content._meta = meta; } return content; } /** * 辅助函数:创建图像内容块 */ function createImageContent(data, mimeType, meta) { const content = { type: 'image', data, mimeType }; if (meta) { content._meta = meta; } return content; } /** * 辅助函数:创建音频内容块 */ function createAudioContent(data, mimeType, meta) { const content = { type: 'audio', data, mimeType }; if (meta) { content._meta = meta; } return content; } /** * 辅助函数:创建资源链接内容块 */ function createResourceLink(uri, name, description, mimeType, meta) { const content = { type: 'resource_link', uri }; if (name) content.name = name; if (description) content.description = description; if (mimeType) content.mimeType = mimeType; if (meta) content._meta = meta; return content; } /** * OpenAPI to MCP Tools Transformer */ class OpenAPIToMCPTransformer { constructor(spec, options = {}) { this.spec = spec; this.options = { baseUrl: options.baseUrl || this.getDefaultBaseUrl(), includeDeprecated: options.includeDeprecated ?? false, includeTags: options.includeTags ?? [], excludeTags: options.excludeTags ?? [], requestTimeout: options.requestTimeout ?? 30000, defaultHeaders: options.defaultHeaders ?? { 'Content-Type': 'application/json' }, customHandlers: options.customHandlers ?? {}, pathPrefix: options.pathPrefix ?? '', stripBasePath: options.stripBasePath ?? false, authConfig: options.authConfig ?? undefined, customHeaders: options.customHeaders ?? undefined, debugHeaders: options.debugHeaders ?? false, protectedHeaders: options.protectedHeaders ?? [], includeFieldAnnotations: options.includeFieldAnnotations ?? true, annotationOptions: { showFieldTypes: options.annotationOptions?.showFieldTypes ?? true, showRequiredMarkers: options.annotationOptions?.showRequiredMarkers ?? true, showCurrentValues: options.annotationOptions?.showCurrentValues ?? true, showExampleValues: options.annotationOptions?.showExampleValues ?? true, showEnumDescriptions: options.annotationOptions?.showEnumDescriptions ?? true, maxFieldsToShow: options.annotationOptions?.maxFieldsToShow ?? 50, maxDepth: options.annotationOptions?.maxDepth ?? 5, ...options.annotationOptions } }; // 初始化注释提取器 this.annotationExtractor = new schema_annotation_extractor_1.SchemaAnnotationExtractor(spec); // 初始化认证管理器 this.initializeAuthManager(); // 初始化自定义请求头管理器 this.initializeCustomHeadersManager(); } /** * 初始化认证管理器 */ initializeAuthManager() { const authConfig = this.options.authConfig; if (!authConfig || authConfig.type === 'none') { this.authManager = undefined; return; } switch (authConfig.type) { case 'bearer': this.authManager = new bearer_auth_1.BearerAuthManager(authConfig); break; // 后续可以添加其他认证方式 default: console.warn(`Unsupported auth type: ${authConfig.type}`); this.authManager = undefined; } } /** * 初始化自定义请求头管理器 */ initializeCustomHeadersManager() { if (this.options.customHeaders) { this.customHeadersManager = new CustomHeadersManager_1.CustomHeadersManager(this.options.customHeaders, { protectedHeaders: this.options.protectedHeaders, debugMode: this.options.debugHeaders }); } } /** * Transform OpenAPI specification to MCP Tools */ transformToMCPTools() { const tools = []; for (const [path, pathItem] of Object.entries(this.spec.paths)) { const methods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace']; for (const method of methods) { const operation = pathItem[method]; if (operation && this.shouldIncludeOperation(operation)) { const tool = this.createMCPToolFromOperation(method, path, operation); if (tool) { tools.push(tool); } } } } return tools; } /** * Get default base URL from spec */ getDefaultBaseUrl() { if (this.spec.servers && this.spec.servers.length > 0) { const serverUrl = this.spec.servers[0].url; console.log(`Using default base URL from OpenAPI spec: ${serverUrl}`); // 处理相对路径和格式化 URL return this.normalizeBaseUrl(serverUrl); } console.log('No servers found in OpenAPI spec, using default: http://localhost'); return 'http://localhost'; } /** * 标准化 Base URL */ normalizeBaseUrl(url) { if (!url) { return 'http://localhost'; } // 去除末尾的斜杠 url = url.replace(/\/+$/, ''); // 如果是相对路径,添加默认协议 if (url.startsWith('/')) { return `http://localhost${url}`; } // 如果没有协议,添加 http:// if (!url.match(/^https?:\/\//)) { // 检查是否可能是域名格式 if (url.includes('.') || url.includes('localhost') || url.includes('127.0.0.1')) { return `http://${url}`; } // 否则当作路径处理 return `http://localhost/${url.replace(/^\/+/, '')}`; } return url; } /** * Check if operation should be included based on options */ shouldIncludeOperation(operation) { // Skip deprecated operations if not included if (operation.deprecated && !this.options.includeDeprecated) { return false; } // Include/exclude by tags if (operation.tags) { // If includeTags is specified, only include operations with those tags if (this.options.includeTags.length > 0) { const hasIncludedTag = operation.tags.some(tag => this.options.includeTags.includes(tag)); if (!hasIncludedTag) { return false; } } // Exclude operations with excluded tags if (this.options.excludeTags.length > 0) { const hasExcludedTag = operation.tags.some(tag => this.options.excludeTags.includes(tag)); if (hasExcludedTag) { return false; } } } return true; } /** * Create MCP Tool from OpenAPI Operation */ createMCPToolFromOperation(method, path, operation) { try { const toolName = this.generateToolName(method, path, operation); const description = this.generateDescription(method, path, operation); const inputSchema = this.generateInputSchema(operation); const handler = this.createHandler(method, path, operation); return { name: toolName, description, inputSchema, handler, metadata: { method: method.toUpperCase(), path, tags: operation.tags, operationId: operation.operationId, deprecated: operation.deprecated } }; } catch (error) { console.warn(`Failed to create tool for ${method.toUpperCase()} ${path}:`, error); return null; } } /** * Generate tool name from operation */ generateToolName(method, path, operation) { // Use operationId if available if (operation.operationId) { return operation.operationId; } // Generate from method and path const cleanPath = path .replace(/[{}]/g, '') // Remove parameter braces .replace(/[^a-zA-Z0-9]/g, '_') // Replace non-alphanumeric with underscore .replace(/_+/g, '_') // Replace multiple underscores with single .replace(/^_|_$/g, ''); // Remove leading/trailing underscores return `${method}_${cleanPath}`; } /** * Generate description from operation */ generateDescription(method, path, operation) { if (operation.description) { return operation.description; } if (operation.summary) { return operation.summary; } // Generate default description const methodUpper = method.toUpperCase(); return `${methodUpper} request to ${path}`; } /** * Generate input schema from operation parameters and request body */ generateInputSchema(operation) { const properties = {}; const required = []; // Add parameters with enhanced example handling if (operation.parameters) { for (const param of operation.parameters) { if (!this.isReferenceObject(param)) { const paramSchema = this.convertSchemaToJsonSchema(param.schema || { type: 'string' }); // 提取所有可能的示例值 const examples = this.extractParameterExamples(param); const finalSchema = { ...paramSchema, description: param.description || `${param.in} parameter` }; // 合并示例值,优先使用参数级别的示例 if (examples.length > 0) { finalSchema.examples = examples; } properties[param.name] = finalSchema; if (param.required) { required.push(param.name); } } } } // Add request body with enhanced example handling if (operation.requestBody && !this.isReferenceObject(operation.requestBody)) { const requestBody = operation.requestBody; if (requestBody.content) { // Prefer application/json const jsonContent = requestBody.content['application/json']; if (jsonContent) { let bodySchema; if (jsonContent.schema) { bodySchema = this.convertSchemaToJsonSchema(jsonContent.schema); } else { bodySchema = { type: 'object' }; } // 处理 MediaType 级别的示例 this.enhanceSchemaWithMediaTypeExamples(bodySchema, jsonContent); if (bodySchema.type === 'object' && bodySchema.properties) { // Merge request body properties Object.assign(properties, bodySchema.properties); if (bodySchema.required) { required.push(...bodySchema.required); } } else { properties.body = bodySchema; if (requestBody.required) { required.push('body'); } } } } } // 生成完整的输入示例 const inputExamples = this.generateInputExamples(properties, operation); const inputSchema = { type: 'object', properties, required: required.length > 0 ? required : undefined, additionalProperties: false }; // 如果有完整的输入示例,添加到schema中 if (inputExamples.length > 0) { inputSchema.examples = inputExamples; } return inputSchema; } /** * Create handler function for the operation */ createHandler(method, path, operation) { return async (args) => { try { // Check for custom handler const customHandler = this.options.customHandlers[operation.operationId || `${method}_${path}`]; if (customHandler) { return await customHandler(args); } // Default HTTP request handler return await this.executeHttpRequest(method, path, args, operation); } catch (error) { console.error(`Error executing ${method.toUpperCase()} ${path}:`, error); return { content: [createTextContent(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`, { errorType: 'execution_error', method: method.toUpperCase(), path, timestamp: new Date().toISOString() })], isError: true }; } }; } /** * Execute HTTP request */ async executeHttpRequest(method, path, args, operation) { try { // 1. 构建请求 URL const { url, queryParams } = this.buildUrlWithParams(path, args, operation); // 2. 准备请求头(默认头) const headers = { ...this.options.defaultHeaders }; // 3. 添加自定义头(在认证头之前,优先级较低) if (this.customHeadersManager) { const customHeaders = await this.customHeadersManager.getHeaders({ method, path, args, operation }); Object.assign(headers, customHeaders); } // 4. 添加认证头(最高优先级,可能覆盖自定义头) if (this.authManager) { const authHeaders = await this.authManager.getAuthHeaders({ method, path, args }); Object.assign(headers, authHeaders); } // 5. 准备请求体 const requestBody = this.buildRequestBody(args, operation); console.log(JSON.stringify(requestBody, null, 2)); // 6. 调试输出最终请求头 if (this.options.debugHeaders) { console.log(`[${method.toUpperCase()} ${path}] Final headers:`, headers); } // 7. 执行 HTTP 请求 const response = await (0, axios_1.default)({ method: method.toLowerCase(), url, params: queryParams, data: requestBody, headers, timeout: this.options.requestTimeout, validateStatus: () => true, // 不要自动抛出错误,我们手动处理 maxRedirects: 5, responseType: 'json' }); // 6. 处理响应 return this.formatHttpResponse(response, method, path, operation); } catch (error) { // 7. 错误处理 return this.handleRequestError(error, method, path); } } /** * 构建带参数的完整 URL */ buildUrlWithParams(path, args, operation) { // 构建基础 URL let url = this.buildBaseUrl(path); const queryParams = {}; console.log(`Building URL - Base: ${this.options.baseUrl}, Prefix: ${this.options.pathPrefix}, Path: ${path}`); console.log(`Initial URL: ${url}`); // 处理路径参数 url = url.replace(/{([^}]+)}/g, (match, paramName) => { const value = args[paramName]; if (value !== undefined) { const encodedValue = encodeURIComponent(String(value)); console.log(`Replacing path parameter {${paramName}} with: ${encodedValue}`); return encodedValue; } console.warn(`Path parameter {${paramName}} not found in args:`, Object.keys(args)); return match; }); // 处理查询参数 if (operation.parameters) { for (const param of operation.parameters) { if (!this.isReferenceObject(param) && param.in === 'query') { const value = args[param.name]; if (value !== undefined) { queryParams[param.name] = value; console.log(`Added query parameter: ${param.name} = ${value}`); } } } } console.log(`Final URL: ${url}, Query params:`, queryParams); return { url, queryParams }; } /** * 构建基础 URL(处理 baseUrl + pathPrefix + path 的拼接) */ buildBaseUrl(path) { const baseUrl = this.options.baseUrl; const pathPrefix = this.options.pathPrefix; // 标准化各个部分 const normalizedBase = baseUrl.replace(/\/+$/, ''); // 移除末尾斜杠 const normalizedPrefix = pathPrefix ? `/${pathPrefix.replace(/^\/+|\/+$/g, '')}` : ''; // 标准化前缀 const normalizedPath = `/${path.replace(/^\/+/, '')}`; // 确保路径以斜杠开头 const fullUrl = normalizedBase + normalizedPrefix + normalizedPath; // 最后清理多余的斜杠(但保留协议后的 //) return fullUrl.replace(/([^:]\/)\/+/g, '$1'); } /** * 构建请求体 */ buildRequestBody(args, operation) { if (!operation.requestBody || this.isReferenceObject(operation.requestBody)) { return undefined; } const requestBody = operation.requestBody; // 如果有 body 参数,直接使用 if (args.body !== undefined) { return args.body; } // 否则,构建请求体对象 const bodyData = {}; let hasBodyData = false; // 收集所有非路径、非查询参数的数据作为请求体 if (operation.parameters) { const pathParams = new Set(); const queryParams = new Set(); for (const param of operation.parameters) { if (!this.isReferenceObject(param)) { if (param.in === 'path') pathParams.add(param.name); if (param.in === 'query') queryParams.add(param.name); } } for (const [key, value] of Object.entries(args)) { if (!pathParams.has(key) && !queryParams.has(key) && value !== undefined) { bodyData[key] = value; hasBodyData = true; } } } else { // 如果没有参数定义,使用所有 args 作为请求体 Object.assign(bodyData, args); hasBodyData = Object.keys(bodyData).length > 0; } return hasBodyData ? bodyData : undefined; } /** * 格式化 HTTP 响应为 MCP 格式 */ formatHttpResponse(response, method, path, operation) { const statusCode = response.status; const isSuccess = statusCode >= 200 && statusCode < 300; const url = response.config?.url || `${this.options.baseUrl}${path}`; // 构建基本响应信息 const responseInfo = { status: statusCode, statusText: response.statusText, headers: response.headers, method: method.toUpperCase(), url: url }; // 格式化响应数据 let responseText; let structuredContent; try { if (response.data) { if (typeof response.data === 'string') { responseText = response.data; } else { responseText = JSON.stringify(response.data, null, 2); structuredContent = { type: 'json', data: response.data }; } } else { responseText = `${method.toUpperCase()} ${path} completed with status ${statusCode}`; } } catch (error) { responseText = `Response received but could not be parsed: ${error}`; } // 提取响应注释(关键新增功能) let schemaAnnotations; if (isSuccess && operation.responses && this.options.includeFieldAnnotations) { const operationId = operation.operationId || `${method}_${path.replace(/[^a-zA-Z0-9]/g, '_')}`; schemaAnnotations = this.annotationExtractor.extractResponseAnnotations(operationId, method, path, operation.responses); } // 构建包含字段解释的响应文本 const enhancedResponseText = this.buildEnhancedResponseText(method, path, statusCode, response.statusText, responseText, response.data, schemaAnnotations); const mcpResponse = { content: [createTextContent(enhancedResponseText, { httpStatus: statusCode, method: method.toUpperCase(), url, timestamp: new Date().toISOString() })], isError: !isSuccess }; // 添加结构化内容 if (structuredContent) { mcpResponse.structuredContent = structuredContent; } // 添加架构注释 if (schemaAnnotations) { mcpResponse.schemaAnnotations = schemaAnnotations; } return mcpResponse; } /** * 处理请求错误 */ handleRequestError(error, method, path) { let errorMessage; let statusCode; if (axios_1.default.isAxiosError(error)) { const axiosError = error; if (axiosError.response) { // 服务器响应了错误状态码 statusCode = axiosError.response.status; const responseData = axiosError.response.data; errorMessage = [ `HTTP ${statusCode} ${axiosError.response.statusText}`, `${method.toUpperCase()} ${path}`, '', 'Error Response:', typeof responseData === 'string' ? responseData : JSON.stringify(responseData, null, 2) ].join('\n'); } else if (axiosError.request) { // 请求发出但没有收到响应 errorMessage = [ `Network Error: No response received`, `${method.toUpperCase()} ${path}`, '', 'Details:', axiosError.code || 'Unknown network error', axiosError.message ].join('\n'); } else { // 请求配置错误 errorMessage = [ `Request Configuration Error`, `${method.toUpperCase()} ${path}`, '', 'Details:', axiosError.message ].join('\n'); } } else if (error instanceof Error) { errorMessage = [ `Unexpected Error`, `${method.toUpperCase()} ${path}`, '', 'Details:', error.message, error.stack || '' ].join('\n'); } else { errorMessage = [ `Unknown Error`, `${method.toUpperCase()} ${path}`, '', 'Details:', String(error) ].join('\n'); } return { content: [createTextContent(errorMessage, { errorType: 'request_error', method: method.toUpperCase(), path, timestamp: new Date().toISOString() })], isError: true }; } /** * Build URL with path parameters */ buildUrl(path, args) { let url = this.options.baseUrl + this.options.pathPrefix + path; // Replace path parameters url = url.replace(/{([^}]+)}/g, (match, paramName) => { return args[paramName] || match; }); return url; } /** * Check if object is a reference */ isReferenceObject(obj) { return obj && typeof obj === 'object' && '$ref' in obj; } /** * 从OpenAPI参数中提取所有可能的示例值 */ extractParameterExamples(param) { const examples = []; // 1. 参数级别的 example (最高优先级) if (param.example !== undefined) { examples.push(param.example); } // 2. 参数级别的 examples 对象 if (param.examples) { Object.values(param.examples).forEach((exampleObj) => { if (!this.isReferenceObject(exampleObj) && exampleObj.value !== undefined) { examples.push(exampleObj.value); } }); } // 3. Schema 级别的示例 if (param.schema && !this.isReferenceObject(param.schema)) { const schema = param.schema; // Schema example if (schema.example !== undefined && !examples.includes(schema.example)) { examples.push(schema.example); } // 枚举值作为示例 (取第一个值) if (schema.enum && schema.enum.length > 0 && !examples.includes(schema.enum[0])) { examples.push(schema.enum[0]); } // 默认值作为示例 if (schema.default !== undefined && !examples.includes(schema.default)) { examples.push(schema.default); } } return examples; } /** * 生成完整的输入示例对象 */ generateInputExamples(properties, operation) { const examples = []; // 尝试从请求体的MediaType示例生成完整示例 if (operation.requestBody && !this.isReferenceObject(operation.requestBody)) { const requestBody = operation.requestBody; if (requestBody.content) { const jsonContent = requestBody.content['application/json']; if (jsonContent && jsonContent.example) { // 合并请求体示例和参数示例 const fullExample = { ...jsonContent.example }; // 添加路径和查询参数的示例 if (operation.parameters) { for (const param of operation.parameters) { if (!this.isReferenceObject(param)) { const paramExamples = this.extractParameterExamples(param); if (paramExamples.length > 0) { fullExample[param.name] = paramExamples[0]; } } } } examples.push(fullExample); } // 处理多个命名示例 if (jsonContent.examples) { Object.values(jsonContent.examples).forEach((exampleObj) => { if (!this.isReferenceObject(exampleObj) && exampleObj.value !== undefined) { const fullExample = { ...exampleObj.value }; // 添加参数示例 if (operation.parameters) { for (const param of operation.parameters) { if (!this.isReferenceObject(param)) { const paramExamples = this.extractParameterExamples(param); if (paramExamples.length > 0) { fullExample[param.name] = paramExamples[0]; } } } } examples.push(fullExample); } }); } } } // 如果没有请求体示例,从字段示例构建完整示例 if (examples.length === 0) { const constructedExample = {}; let hasAnyExample = false; for (const [propName, propSchema] of Object.entries(properties)) { if (propSchema.examples && propSchema.examples.length > 0) { constructedExample[propName] = propSchema.examples[0]; hasAnyExample = true; } else if (propSchema.type === 'boolean') { constructedExample[propName] = true; // 布尔类型默认示例 hasAnyExample = true; } else if (propSchema.type === 'integer' || propSchema.type === 'number') { constructedExample[propName] = propSchema.type === 'integer' ? 1 : 1.0; hasAnyExample = true; } else if (propSchema.type === 'string') { constructedExample[propName] = `example_${propName}`; hasAnyExample = true; } else if (propSchema.type === 'array') { constructedExample[propName] = []; hasAnyExample = true; } } if (hasAnyExample) { examples.push(constructedExample); } } return examples; } /** * 使用MediaType级别的示例增强schema */ enhanceSchemaWithMediaTypeExamples(schema, mediaType) { // 处理 MediaType 级别的 example if (mediaType.example !== undefined) { if (schema.type === 'object' && typeof mediaType.example === 'object' && mediaType.example !== null) { // 为对象类型的每个字段添加示例 this.mergeExamplesIntoSchemaProperties(schema, mediaType.example); } else { // 为非对象类型直接添加示例 schema.examples = schema.examples || []; if (!schema.examples.includes(mediaType.example)) { schema.examples.unshift(mediaType.example); // MediaType级别优先级较高 } } } // 处理 MediaType 级别的 examples 对象 if (mediaType.examples) { schema.examples = schema.examples || []; Object.values(mediaType.examples).forEach((exampleObj) => { if (!this.isReferenceObject(exampleObj) && exampleObj.value !== undefined) { if (!schema.examples.includes(exampleObj.value)) { schema.examples.push(exampleObj.value); } } }); } } /** * 将示例对象的值合并到schema的properties中 */ mergeExamplesIntoSchemaProperties(schema, exampleObject) { if (!schema.properties || typeof exampleObject !== 'object' || !exampleObject) { return; } for (const [key, value] of Object.entries(exampleObject)) { if (schema.properties[key] && value !== undefined) { schema.properties[key].examples = schema.properties[key].examples || []; if (!schema.properties[key].examples.includes(value)) { schema.properties[key].examples.unshift(value); } } } } /** * Convert OpenAPI schema to JSON schema */ convertSchemaToJsonSchema(schema) { if (this.isReferenceObject(schema)) { // For simplicity, return a generic object for references // In a real implementation, you would resolve the reference return { type: 'object' }; } // Basic schema conversion const jsonSchema = {}; if (schema.type) { jsonSchema.type = schema.type; } if (schema.properties) { jsonSchema.properties = {}; for (const [key, prop] of Object.entries(schema.properties)) { jsonSchema.properties[key] = this.convertSchemaToJsonSchema(prop); } } if (schema.items) { jsonSchema.items = this.convertSchemaToJsonSchema(schema.items); } if (schema.required) { jsonSchema.required = schema.required; } if (schema.description) { jsonSchema.description = schema.description + (schema.example ? ` .Example: ${JSON.stringify(schema.example, null, 2)}` : ''); } if (schema.example !== undefined) { jsonSchema.examples = [schema.example]; } // 新增:处理枚举值作为示例 if (schema.enum && schema.enum.length > 0) { jsonSchema.examples = jsonSchema.examples || []; if (!jsonSchema.examples.includes(schema.enum[0])) { jsonSchema.examples.push(schema.enum[0]); } } // 新增:处理默认值作为示例 if (schema.default !== undefined) { jsonSchema.examples = jsonSchema.examples || []; if (!jsonSchema.examples.includes(schema.default)) { jsonSchema.examples.push(schema.default); } } // 新增:处理格式化提示 (可选) if (schema.format) { jsonSchema.format = schema.format; } return jsonSchema; } /** * 构建增强的响应文本,包含字段注释 */ buildEnhancedResponseText(method, path, statusCode, statusText, responseText, responseData, schemaAnnotations) { const sections = []; // 基本信息 sections.push(`HTTP ${statusCode} ${statusText}`); sections.push(`${method.toUpperCase()} ${path}`); sections.push(''); // 添加字段注释(如果有) if (schemaAnnotations && Object.keys(schemaAnnotations.fieldAnnotations).length > 0) { sections.push('字段说明 (Field Descriptions):'); sections.push(''); const annotatedFields = this.formatFieldAnnotations(schemaAnnotations.fieldAnnotations, responseData); if (annotatedFields.length > 0) { sections.push(...annotatedFields); sections.push(''); } } // 响应数据 sections.push('响应数据 (Response Data):'); sections.push(responseText); return sections.join('\n'); } /** * 格式化字段注释为易读的文本 */ formatFieldAnnotations(fieldAnnotations, responseData) { const lines = []; // 对字段进行排序,优先显示顶级字段 const sortedFields = Object.entries(fieldAnnotations).sort(([a], [b]) => { const aDepth = a.split('.').length; const bDepth = b.split('.').length; if (aDepth !== bDepth) { return aDepth - bDepth; } return a.localeCompare(b); }); for (const [fieldPath, annotation] of sortedFields) { // 获取字段的实际值 const fieldValue = this.getFieldValue(responseData, fieldPath); const hasValue = fieldValue !== undefined; // 构建字段说明行 const parts = []; // 字段名和类型 if (annotation.type) { parts.push(`${fieldPath} (${annotation.type})`); } else { parts.push(fieldPath); } // 是否必需 if (annotation.required) { parts.push('[必需]'); } // 描述 if (annotation.description) { parts.push(`- ${annotation.description}`); } // 当前值(如果存在) if (hasValue) { const valueStr = this.formatFieldValue(fieldValue); parts.push(`= ${valueStr}`); } lines.push(` • ${parts.join(' ')}`); // 枚举值说明 if (annotation.enum && annotation.enum.length > 0) { const enumLines = annotation.enum.map((enumItem) => { let enumText = ` - ${enumItem.value}`; if (enumItem.description) { enumText += `: ${enumItem.description}`; } return enumText; }); lines.push(...enumLines); } // 示例值 if (!hasValue && annotation.example !== undefined) { const exampleStr = this.formatFieldValue(annotation.example); lines.push(` 示例: ${exampleStr}`); } } return lines; } /** * 从响应数据中获取字段值 */ getFieldValue(data, fieldPath) { if (!data || typeof data !== 'object') { return undefined; } const parts = fieldPath.split('.'); let current = data; for (const part of parts) { if (part.endsWith('[]')) { // 处理数组字段 const arrayFieldName = part.slice(0, -2); current = current[arrayFieldName]; if (Array.isArray(current)) { // 返回数组的第一个元素作为示例 current = current.length > 0 ? current[0] : undefined; } else { return undefined; } } else { current = current[part]; } if (current === undefined) { break; } } return current; } /** * 格式化字段值为可读的字符串 */ formatFieldValue(value) { if (value === null) { return 'null'; } if (value === undefined) { return 'undefined'; } if (typeof value === 'string') { return `"${value}"`; } if (typeof value === 'object') { if (Array.isArray(value)) { return `[${value.length} items]`; } return JSON.stringify(value); } return String(value); } } exports.OpenAPIToMCPTransformer = OpenAPIToMCPTransformer; /** * Convenience function to transform OpenAPI spec to MCP tools */ function transformToMCPTools(spec, options = {}) { const transformer = new OpenAPIToMCPTransformer(spec, options); return transformer.transformToMCPTools(); } //# sourceMappingURL=index.js.map