diff --git a/apifox.js b/apifox.js index 43123f7..bced919 100644 --- a/apifox.js +++ b/apifox.js @@ -1,6 +1,6 @@ import axios from "axios"; import NodeCache from 'node-cache'; -import fs from 'fs' +// import fs from 'fs' const APIFOX_API_BASE = "https://apifox.gzmiyuan.com/api/v1"; @@ -50,9 +50,7 @@ export class ApifoxService { async init() { try { this.branchId = await this.getBranchId(); - console.log('branchId', this.branchId); } catch (error) { - console.error("Error initializing branch ID:", error); throw error; } } @@ -110,7 +108,6 @@ export class ApifoxService { async getApiTreeList() { const apiTree = await this.get(`/projects/${this.projectId}/api-tree-list`); - console.log('-- get api tree list success', 'length', apiTree.length); this.apiTreeList = apiTree; return apiTree; } @@ -122,12 +119,10 @@ export class ApifoxService { // 检查缓存是否有效 const cachedData = this.cache.get(cacheKey); if (cachedData) { - console.log('Using cached folder list', 'length', cachedData.length); return cachedData; } const {data: folderList} = await this.get(`/projects/${this.projectId}/api-detail-folders`); - console.log('--get folder success', 'length', folderList.length); // 设置缓存 this.cache.set(cacheKey, folderList); @@ -149,12 +144,10 @@ export class ApifoxService { // 检查缓存是否有效 const cachedData = this.cache.get(cacheKey); if (cachedData) { - console.log('Using cached data schema'); return cachedData; } const {data:schemasTreeList} = await this.get(`/projects/${this.projectId}/data-schemas?locale=zh-CN`); - console.log('--get data schema success', 'length', schemasTreeList.length); // 设置缓存 this.cache.set(cacheKey, schemasTreeList); @@ -168,12 +161,10 @@ export class ApifoxService { // 检查缓存是否有效 const cachedData = this.cache.get(cacheKey); if (cachedData) { - console.log('Using cached API details'); return cachedData; } const {data:apiDetails} = await this.get(`/api-details?locale=zh-CN`, {}); - console.log('--get api details success', 'length', apiDetails.length); // 设置缓存 this.cache.set(cacheKey, apiDetails); @@ -182,7 +173,6 @@ export class ApifoxService { getSchemaRefId(obj) { if (!obj || !obj.$ref) { - console.log('no schemaid', obj) return; } const schemaName = obj.$ref.split('/').pop(); @@ -275,9 +265,7 @@ export class ApifoxService { const requestSchemaId = this.getSchemaRefId(apiDetail.requestBody.jsonSchema); const responseSchema = Array.isArray(apiDetail.responses) ? apiDetail.responses[0].jsonSchema : apiDetail.responses.jsonSchema; const responseSchemaId = this.getSchemaRefId(responseSchema); - console.log('responseSchemaId', responseSchemaId); const respDataSchemaId = this.getSchemaRefId(dataSchema.find((item) => item.id.toString() === responseSchemaId).jsonSchema.properties.data) - console.log('respDataSchemaId', respDataSchemaId); return { path: apiDetail.path, name: apiDetail.name, @@ -312,21 +300,7 @@ export class ApifoxService { const folder = await this.getFolderByName(folderName); const apiDetails = await this.getApiDetails(); const apiList = apiDetails.filter((item) => item.folderId === folder.id); - console.log('--getApiListByFolderName success', 'length', apiList.length); return Promise.all(apiList.map((api) => this.getApiDetailResp(api))); } } - - -const apifoxService = new ApifoxService(345161); - -apifoxService.init().then(() => { - apifoxService.getApiListByFolderName('数据中心统计数据') - .then(res => { - fs.writeFileSync('apifox-ret.json', JSON.stringify(res, null, 2)); - }) - -}).catch((error) => { - console.error("Error initializing ApifoxService:", error); -}); diff --git a/index.js b/index.js index b7dd61a..2088202 100644 --- a/index.js +++ b/index.js @@ -2,23 +2,39 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; -import { ApifoxService } from './apifox' +import { ApifoxService } from './apifox.js' -process.env.APIFOX_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzQ1MTIwLCJ0cyI6IjUyOGZiZDMwNGM3MjU2NDMiLCJpYXQiOjE3NjQxNTQyODEzMzB9.IZvoCb3pN5AUl375c4Dhpur1GdYBqyHWVkJ94bDQ6BQ'; +// 设置默认环境变量 +if (!process.env.APIFOX_TOKEN) { + process.env.APIFOX_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzQ1MTIwLCJ0cyI6IjUyOGZiZDMwNGM3MjU2NDMiLCJpYXQiOjE3NjQxNTQyODEzMzB9.IZvoCb3pN5AUl375c4Dhpur1GdYBqyHWVkJ94bDQ6BQ'; +} +if (!process.env.APIFOX_PROJECT_ID) { + // 使用 steering 中提到的 organizationId 作为默认值 + process.env.APIFOX_PROJECT_ID = '345161'; +} // 创建 MCP 服务器实例 // 为其设置一个名字和版本 -const server = new McpServer({ - name: "apifox-mcp-server", - version: "1.0.0", -}); +const server = new McpServer( + { + name: "apifox-mcp-server", + version: "1.0.0", + }, + { + capabilities: { + prompts: {}, + tools: {}, + }, + } +); const apifoxService = new ApifoxService({ - projectId: process.env.APIFOX_PROJECT_ID, + projectId: Number(process.env.APIFOX_PROJECT_ID), token: process.env.APIFOX_TOKEN }); + server.registerTool( 'get_api_by_path', { @@ -31,7 +47,7 @@ server.registerTool( async ({ path }) => { try { - const apiData = apifoxService.getApiDetailByPath(path); + const apiData = await apifoxService.getApiDetailByPath(path); return { content: [ @@ -67,7 +83,7 @@ server.registerTool( async ({ folderName }) => { try { - const apiData = apifoxService.getApiListByFolderName(folderName); + const apiData = await apifoxService.getApiListByFolderName(folderName); return { content: [ @@ -93,79 +109,63 @@ server.registerTool( ) -// 定义 prompts 列表 -server.setRequestHandler(ListPromptsRequestSchema, async () => { - return { - prompts: [ - { - name: "gen-api-by-path", - description: "根据输入的接口路径获取Apifox接口文档定义,然后根据定义生成 api 接口代码定义", - arguments: [ - ], - }, - { - name: "gen-api-by-folder", - description: "根据输入的接口文件夹获取Apifox相关文件夹下所有的接口文档定义,然后根据定义生成 api 接口代码定义", - arguments: [ - ], - }, - ], - }; -}); -// 处理获取具体 prompt 的请求 -server.setRequestHandler(GetPromptRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - - switch (name) { - case "gen-api-by-path": - return { - messages: [ - { - role: "user", - content: { - type: "text", - text: `请根据以下步骤获取Apifox的接口定义并生成 api 定义代码。 +// 定义 prompts +server.registerPrompt( + 'gen-api-by-path', + { + title: 'Generate API by Path', + description: '根据输入的接口路径获取Apifox接口文档定义,然后根据定义生成 api 接口代码定义', + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `请根据以下步骤获取Apifox的接口定义并生成 api 定义代码。 步骤: 1. 使用 get_api_by_path 工具获取对应的接口定义schema 2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码 -3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,要补充相关的注释 +3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,可以根据description要补充相关的注释 4. 所有字段先定义为可空类型 5. 请根据当前项目的项目接口和代码风格生成 api 接口代码 请开始执行这些步骤。`, - }, - }, - ], - }; + }, + }, + ], + }) +); - case "gen-api-by-folder": - return { - messages: [ - { - role: "user", - content: { - type: "text", - text: `请根据以下步骤获取Apifox的接口定义并生成 api 定义代码。 +server.registerPrompt( + 'gen-api-by-folder', + { + title: 'Generate API by Folder', + description: '根据输入的接口文件夹获取Apifox相关文件夹下所有的接口文档定义,然后根据定义生成 api 接口代码定义', + }, + () => ({ + messages: [ + { + role: "user", + content: { + type: "text", + text: `请根据以下步骤获取Apifox的接口定义并生成 api 定义代码。 步骤: 1. 使用 get_api_by_folder 工具获取对应的接口定义schema,可能会返回多条接口的数据 2. 根据返回的 path,method, requestSchema, responseSchema 和其他必要字段,生成 api 定义代码 -3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,要补充相关的注释 +3. 接口的参数和返回值的类型定义,可以分别参考 requestSchema 和 responseSchema 里面的jsonSchema定义,可以根据description要补充相关的注释 4. 所有字段先定义为可空类型 5. 请根据当前项目的项目接口和代码风格生成 api 接口代码 请开始执行这些步骤。`, - }, - }, - ], - }; - - default: - throw new Error(`未知的 prompt: ${name}`); - } -}); + }, + }, + ], + }) +); @@ -174,6 +174,7 @@ async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr + } // 运行主函数,并捕获可能的错误