Skip to main content
Glama

import_openapi

Import OpenAPI/Swagger specifications into Apifox projects to maintain API documentation. Supports OpenAPI 3.0/3.1 and Swagger 2.0 formats with options for batch imports, intelligent scope detection, and deprecation marking.

Instructions

维护 Apifox 接口文档:将 OpenAPI/Swagger 规范导入到 Apifox 项目。支持 OpenAPI 3.0/3.1 和 Swagger 2.0 格式。

⭐ 最佳实践(强烈推荐):

  1. 【分批导入】按模块分批导入(如先导入 /api/users,再导入 /api/products),而非一次性导入所有接口

  2. 【智能范围检测】每次只导入一个功能模块的完整规范,系统会自动识别范围

  3. 【启用废弃标记】设置 markDeprecatedEndpoints: true,自动保留并标记已删除的接口

分批导入的好处:更安全、更可控、支持模块独立维护、避免大规模误操作。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
optionsNo导入选项(可选)
specYesOpenAPI/Swagger 规范的 JSON 对象。必须包含 openapi 或 swagger 字段、info 字段、paths 字段

Implementation Reference

  • MCP tool handler for 'import_openapi': validates input spec, invokes ApifoxClient.importOpenApi, processes and formats the result into MCP content response.
    case 'import_openapi': { const { spec, options } = args as { spec: any; options?: any }; // 验证 OpenAPI 规范的基本结构 if (!spec || typeof spec !== 'object') { throw new Error('spec 参数必须是一个对象'); } if (!spec.openapi && !spec.swagger) { throw new Error('spec 必须包含 openapi 或 swagger 字段'); } if (!spec.info) { throw new Error('spec 必须包含 info 字段'); } if (!spec.paths) { throw new Error('spec 必须包含 paths 字段'); } const result = await apifoxClient.importOpenApi(spec, options); // 格式化导入结果 let resultText = '✅ OpenAPI 规范导入完成!\n\n'; // 显示警告信息(如果有) if (result._warnings && result._warnings.length > 0) { resultText += '⚠️ 重要提示:\n'; result._warnings.forEach((warning: string) => { resultText += ` ${warning}\n`; }); resultText += '\n'; } // 显示废弃接口统计(如果有) if (result._deprecatedInfo) { const { count, ratio, scope } = result._deprecatedInfo; resultText += '🔖 废弃接口标记:\n'; resultText += ` - 标记数量: ${count} 个\n`; resultText += ` - 废弃比例: ${ratio.toFixed(1)}%\n`; if (scope.length > 0) { resultText += ` - 影响范围: ${scope.join(', ')}\n`; } resultText += '\n'; } if (result.data && result.data.counters) { const counters = result.data.counters; // 接口统计 resultText += '📋 接口导入统计:\n'; resultText += ` - 创建: ${counters.endpointCreated || 0}\n`; resultText += ` - 更新: ${counters.endpointUpdated || 0}\n`; resultText += ` - 失败: ${counters.endpointFailed || 0}\n`; resultText += ` - 忽略: ${counters.endpointIgnored || 0}\n`; // 数据模型统计 resultText += '\n📦 数据模型导入统计:\n'; resultText += ` - 创建: ${counters.schemaCreated || 0}\n`; resultText += ` - 更新: ${counters.schemaUpdated || 0}\n`; resultText += ` - 失败: ${counters.schemaFailed || 0}\n`; resultText += ` - 忽略: ${counters.schemaIgnored || 0}\n`; // 错误信息 if (result.data.errors && result.data.errors.length > 0) { resultText += '\n⚠️ 错误信息:\n'; result.data.errors.forEach((error: any) => { resultText += ` - [${error.code}] ${error.message}\n`; }); } // 总结 const totalCreated = counters.endpointCreated + counters.schemaCreated; const totalFailed = counters.endpointFailed + counters.schemaFailed; if (totalCreated === 0 && totalFailed === 0) { resultText += '\n💡 提示:没有新增或修改任何内容,可能是因为项目中已存在相同的 API。\n'; } else if (totalFailed > 0) { resultText += `\n⚠️ 警告:有 ${totalFailed} 个项导入失败,请检查错误信息。\n`; } else { resultText += `\n🎉 成功导入 ${totalCreated} 个项!\n`; } } return { content: [ { type: 'text', text: resultText } ] }; }
  • Input schema definition for the import_openapi tool, specifying parameters like spec and options.
    inputSchema: { type: 'object', properties: { spec: { type: 'object', description: 'OpenAPI/Swagger 规范的 JSON 对象。必须包含 openapi 或 swagger 字段、info 字段、paths 字段' }, options: { type: 'object', description: '导入选项(可选)', properties: { endpointOverwriteBehavior: { type: 'string', enum: ['OVERWRITE_EXISTING', 'AUTO_MERGE', 'KEEP_EXISTING', 'CREATE_NEW'], description: '接口覆盖行为,默认为 OVERWRITE_EXISTING' }, schemaOverwriteBehavior: { type: 'string', enum: ['OVERWRITE_EXISTING', 'AUTO_MERGE', 'KEEP_EXISTING', 'CREATE_NEW'], description: '数据模型覆盖行为,默认为 OVERWRITE_EXISTING' }, markDeprecatedEndpoints: { type: 'boolean', description: '是否自动标记废弃的接口(推荐启用)。启用后会:1) 导出现有接口;2) 智能检测导入范围(如只导入 /api/marketing 模块);3) 只对比该范围内的接口;4) 标记已删除的接口为 deprecated。支持部分模块导入,不会误标记其他模块。默认为 false' }, confirmHighDeprecation: { type: 'boolean', description: '确认高比例废弃操作。当废弃比例超过 50% 时,必须设置为 true 才能继续。这是一个安全机制,防止误操作导致大量接口被标记为废弃。如果不设置此参数,操作会被阻止并返回错误信息。' } } } }, required: ['spec'] }
  • src/index.ts:75-112 (registration)
    Registration of the 'import_openapi' tool in the tools array used for MCP ListTools response.
    { name: 'import_openapi', description: '维护 Apifox 接口文档:将 OpenAPI/Swagger 规范导入到 Apifox 项目。支持 OpenAPI 3.0/3.1 和 Swagger 2.0 格式。\n\n⭐ 最佳实践(强烈推荐):\n1. 【分批导入】按模块分批导入(如先导入 /api/users,再导入 /api/products),而非一次性导入所有接口\n2. 【智能范围检测】每次只导入一个功能模块的完整规范,系统会自动识别范围\n3. 【启用废弃标记】设置 markDeprecatedEndpoints: true,自动保留并标记已删除的接口\n\n分批导入的好处:更安全、更可控、支持模块独立维护、避免大规模误操作。', inputSchema: { type: 'object', properties: { spec: { type: 'object', description: 'OpenAPI/Swagger 规范的 JSON 对象。必须包含 openapi 或 swagger 字段、info 字段、paths 字段' }, options: { type: 'object', description: '导入选项(可选)', properties: { endpointOverwriteBehavior: { type: 'string', enum: ['OVERWRITE_EXISTING', 'AUTO_MERGE', 'KEEP_EXISTING', 'CREATE_NEW'], description: '接口覆盖行为,默认为 OVERWRITE_EXISTING' }, schemaOverwriteBehavior: { type: 'string', enum: ['OVERWRITE_EXISTING', 'AUTO_MERGE', 'KEEP_EXISTING', 'CREATE_NEW'], description: '数据模型覆盖行为,默认为 OVERWRITE_EXISTING' }, markDeprecatedEndpoints: { type: 'boolean', description: '是否自动标记废弃的接口(推荐启用)。启用后会:1) 导出现有接口;2) 智能检测导入范围(如只导入 /api/marketing 模块);3) 只对比该范围内的接口;4) 标记已删除的接口为 deprecated。支持部分模块导入,不会误标记其他模块。默认为 false' }, confirmHighDeprecation: { type: 'boolean', description: '确认高比例废弃操作。当废弃比例超过 50% 时,必须设置为 true 才能继续。这是一个安全机制,防止误操作导致大量接口被标记为废弃。如果不设置此参数,操作会被阻止并返回错误信息。' } } } }, required: ['spec'] } },
  • ApifoxClient.importOpenApi method: core logic for importing OpenAPI spec, including advanced features like smart deprecated endpoint detection and marking within detected path scopes.
    async importOpenApi(spec: any, options?: { endpointOverwriteBehavior?: 'OVERWRITE_EXISTING' | 'AUTO_MERGE' | 'KEEP_EXISTING' | 'CREATE_NEW'; schemaOverwriteBehavior?: 'OVERWRITE_EXISTING' | 'AUTO_MERGE' | 'KEEP_EXISTING' | 'CREATE_NEW'; updateFolderOfChangedEndpoint?: boolean; prependBasePath?: boolean; targetBranchId?: number; markDeprecatedEndpoints?: boolean; confirmHighDeprecation?: boolean; }): Promise<any> { let finalSpec = spec; const warnings: string[] = []; // 收集警告信息 let deprecatedInfo: { count: number; ratio: number; scope: string[] } | null = null; // 如果启用了标记废弃接口功能 if (options?.markDeprecatedEndpoints) { try { // 1. 先导出现有的 OpenAPI 规范 const existingSpec = await this.exportOpenApi({ oasVersion: spec.openapi?.startsWith('3.1') ? '3.1' : '3.0', exportFormat: 'JSON' }); // 2. 智能检测路径前缀范围 const newPaths = spec.paths || {}; const newPathKeys = Object.keys(newPaths); // 安全检查:防止空 spec 导致全部标记为废弃 if (newPathKeys.length === 0) { const warning = '⚠️ 检测到空规范:新规范没有任何接口(paths 为空),已自动跳过废弃标记功能'; warnings.push(warning); warnings.push('💡 建议:只在导入包含实际接口的规范时启用 markDeprecatedEndpoints'); console.error(`\n⚠️ 警告:新规范没有任何接口(paths 为空)`); console.error(`⚠️ 启用 markDeprecatedEndpoints 时使用空规范会导致所有现有接口被标记为废弃`); console.error(`⚠️ 已自动跳过废弃标记功能,直接导入空规范`); console.error(`💡 建议:只在导入包含实际接口的规范时启用 markDeprecatedEndpoints\n`); // 跳过废弃标记逻辑,直接使用原始 spec finalSpec = spec; // 执行导入(跳到 catch 块后) const response = await this.client.post( `/v1/projects/${this.projectId}/import-openapi`, { input: JSON.stringify(finalSpec), options: { endpointOverwriteBehavior: options?.endpointOverwriteBehavior || 'OVERWRITE_EXISTING', schemaOverwriteBehavior: options?.schemaOverwriteBehavior || 'OVERWRITE_EXISTING', updateFolderOfChangedEndpoint: options?.updateFolderOfChangedEndpoint ?? false, prependBasePath: options?.prependBasePath ?? false, ...(options?.targetBranchId && { targetBranchId: options.targetBranchId }) } } ); return { ...response.data, _warnings: warnings }; } // 提取所有新路径的公共前缀 const pathPrefixes = this.detectPathPrefixes(newPathKeys); const scopeInfo = pathPrefixes.length > 0 ? pathPrefixes.join(', ') : '全部接口'; console.error(`\n🔍 检测到导入范围: ${scopeInfo}`); console.error(`📊 新规范包含 ${newPathKeys.length} 个接口路径`); // 3. 找出已删除的接口(只在相同路径前缀范围内对比) const existingPaths = existingSpec.paths || {}; const deprecatedPaths: any = {}; // 计算范围内的现有接口总数 let existingPathsInScope = 0; for (const path in existingPaths) { const isInScope = pathPrefixes.length === 0 || pathPrefixes.some(prefix => path.startsWith(prefix)); if (isInScope) { existingPathsInScope++; } } for (const path in existingPaths) { // 只对比在相同路径前缀范围内的接口 const isInScope = pathPrefixes.length === 0 || pathPrefixes.some(prefix => path.startsWith(prefix)); if (!isInScope) { // 不在导入范围内,跳过 continue; } if (!newPaths[path]) { // 整个路径被删除(在导入范围内) deprecatedPaths[path] = { ...existingPaths[path] }; // 标记所有方法为废弃 for (const method in deprecatedPaths[path]) { if (method !== 'parameters') { deprecatedPaths[path][method] = { ...deprecatedPaths[path][method], deprecated: true, summary: `[已废弃] ${deprecatedPaths[path][method].summary || ''}`, description: `⚠️ 此接口已废弃,不再维护。\n\n${deprecatedPaths[path][method].description || ''}` }; } } } else { // 路径存在,检查方法是否被删除 const existingMethods = Object.keys(existingPaths[path]).filter(m => m !== 'parameters'); const newMethods = Object.keys(newPaths[path]).filter(m => m !== 'parameters'); for (const method of existingMethods) { if (!newMethods.includes(method)) { // 方法被删除,标记为废弃 if (!deprecatedPaths[path]) { deprecatedPaths[path] = {}; } deprecatedPaths[path][method] = { ...existingPaths[path][method], deprecated: true, summary: `[已废弃] ${existingPaths[path][method].summary || ''}`, description: `⚠️ 此接口已废弃,不再维护。\n\n${existingPaths[path][method].description || ''}` }; } } } } // 4. 合并废弃接口到新规范 if (Object.keys(deprecatedPaths).length > 0) { // 计算统计信息(使用范围内的接口数计算比例) const deprecatedPathCount = Object.keys(deprecatedPaths).length; const deprecatedRatio = existingPathsInScope > 0 ? (deprecatedPathCount / existingPathsInScope) * 100 : 0; // 保存废弃信息用于返回 deprecatedInfo = { count: deprecatedPathCount, ratio: deprecatedRatio, scope: pathPrefixes }; // 安全检查:如果废弃比例过高,要求用户确认 if (deprecatedRatio > 50) { // 如果没有传递确认参数,抛出错误阻止执行 if (!options?.confirmHighDeprecation) { const errorMessage = [ `⚠️ 高比例废弃操作需要确认`, ``, `检测到即将标记 ${deprecatedPathCount} 个接口为废弃,占范围内接口的 ${deprecatedRatio.toFixed(1)}%`, `这个比例异常高,可能导致大量接口被误标记为废弃。`, ``, `📊 详细信息:`, ` - 影响范围: ${pathPrefixes.length > 0 ? pathPrefixes.join(', ') : '全部接口'}`, ` - 范围内现有接口: ${existingPathsInScope} 个`, ` - 新规范接口数量: ${newPathKeys.length} 个`, ` - 即将废弃接口: ${deprecatedPathCount} 个`, ` - 废弃比例: ${deprecatedRatio.toFixed(1)}%`, ``, `💡 可能原因:`, ` 1. 新规范的接口数量太少(当前仅 ${newPathKeys.length} 个)`, ` 2. 新规范的路径前缀与现有接口不匹配`, ` 3. 这是一次大规模重构,确实要废弃大量接口`, ``, `❌ 操作已阻止,需要用户确认后才能继续`, ``, `如需继续,请在 options 中设置 confirmHighDeprecation: true` ].join('\n'); throw new Error(errorMessage); } // 用户已确认,记录警告信息并继续执行 warnings.push(`⚠️ 高比例废弃警告:即将标记 ${deprecatedPathCount} 个接口为废弃(${deprecatedRatio.toFixed(1)}%)`); warnings.push(`✅ 用户已确认,继续执行`); console.error(`\n⚠️ 警告:即将标记 ${deprecatedPathCount} 个接口为废弃(占现有接口的 ${deprecatedRatio.toFixed(1)}%)`); console.error(`✅ 用户已确认,继续执行\n`); } // 深度合并:保留新规范的所有内容,同时添加废弃的方法 const mergedPaths: any = { ...spec.paths }; for (const path in deprecatedPaths) { if (!mergedPaths[path]) { // 整个路径被删除,添加所有废弃方法 mergedPaths[path] = deprecatedPaths[path]; } else { // 路径存在,只添加被删除的方法 mergedPaths[path] = { ...mergedPaths[path], ...deprecatedPaths[path] }; } } finalSpec = { ...spec, paths: mergedPaths }; console.error(`\n🔖 标记了 ${deprecatedPathCount} 个废弃接口路径(${deprecatedRatio.toFixed(1)}%)`); } else { console.error(`\n✅ 没有接口被删除,无需标记废弃`); } } catch (error) { // 如果获取现有规范失败(比如项目是空的),忽略错误继续导入 console.error(`⚠️ 无法获取现有规范来标记废弃接口: ${error instanceof Error ? error.message : String(error)}`); } } // 执行导入 const response = await this.client.post( `/v1/projects/${this.projectId}/import-openapi`, { input: JSON.stringify(finalSpec), options: { endpointOverwriteBehavior: options?.endpointOverwriteBehavior || 'OVERWRITE_EXISTING', schemaOverwriteBehavior: options?.schemaOverwriteBehavior || 'OVERWRITE_EXISTING', updateFolderOfChangedEndpoint: options?.updateFolderOfChangedEndpoint ?? false, prependBasePath: options?.prependBasePath ?? false, ...(options?.targetBranchId && { targetBranchId: options.targetBranchId }) } } ); // 附加警告信息和废弃统计到返回值 return { ...response.data, _warnings: warnings.length > 0 ? warnings : undefined, _deprecatedInfo: deprecatedInfo }; }

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Warren-W/apifox-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server