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 and intelligent 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
specYesOpenAPI/Swagger 规范的 JSON 对象。必须包含 openapi 或 swagger 字段、info 字段、paths 字段
optionsNo导入选项(可选)

Implementation Reference

  • MCP tool handler for 'import_openapi': validates input spec, delegates to ApifoxClient.importOpenApi, formats and returns the import results with statistics, warnings, and deprecation info.
    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 the structure of spec (OpenAPI object) and optional options (overwrite behaviors, deprecation marking).
    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 MCP tools array, returned by ListToolsRequestSchema handler.
    {
      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']
      }
    },
  • Core helper method ApifoxClient.importOpenApi: implements smart deprecation handling (detects path scopes, marks removed endpoints as deprecated), calls Apifox import API, adds warnings and stats to response.
    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
      };
    }
Install Server

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