UNPKG

mcp-apifox

Version:

一个用于将 Apifox API 文档与 AI 助手集成的 Model Context Protocol (MCP) 服务器。

136 lines (132 loc) 3.48 kB
#!/usr/bin/env node // src/index.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // src/utils/apifox.ts import { request } from "undici"; async function fetchApiInfoApi(projectId, apiId, accessToken) { const response = await request(`https://api.apifox.com/v1/projects/${projectId}/export-openapi`, { method: "POST", headers: { "X-Apifox-Api-Version": "2024-03-28", "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ scope: { type: "SELECTED_ENDPOINTS", selectedEndpointIds: [apiId] }, options: { includeApifoxExtensionProperties: false, addFoldersToTags: false }, oasVersion: "3.1", exportFormat: "JSON" }) }); const result = await response.body.text(); return result; } function extractProjectIdAndApiIdFromText(text) { const urlPattern = /apifox\.com\/link\/project\/(\d+)\/apis\/api-(\d+)/; const contentPattern = /project\/(\d+).*api-(\d+)/; let projectId = ""; let apiId = ""; const lines = text.split("\n"); for (const line of lines) { const trimmedLine = line.trim(); const urlMatch = trimmedLine.match(urlPattern); if (urlMatch) { projectId = urlMatch[1]; apiId = urlMatch[2]; break; } const contentMatch = trimmedLine.match(contentPattern); if (contentMatch) { projectId = contentMatch[1]; apiId = contentMatch[2]; break; } } return { projectId, apiId }; } // src/index.ts var server = new McpServer({ name: "apifox", version: "0.0.1" }); server.tool( "get_apifox_project_id_and_api_id_from_url", "Get the project ID and API ID of Apifox from the URL.", { text: z.string().describe("The text to extract the project id and api id from") }, ({ text }) => { const { projectId, apiId } = extractProjectIdAndApiIdFromText(text); return { content: [ { type: "text", text: JSON.stringify({ projectId, apiId }) } ] }; } ); server.tool( "get_apifox_api_info", "Get the info of Apifox API.", { projectId: z.string().describe("The project ID of Apifox"), apiId: z.string().describe("The API ID of Apifox") }, async ({ projectId, apiId }) => { try { let token = process.env.APIFOX_ACCESS_TOKEN; const args = process.argv.slice(2); for (const arg of args) { const tokenArg = arg.match(/^--(?:apifox-)?token=(.+)$/); if (tokenArg) { token = tokenArg[1]; break; } } if (!token) { throw new Error("No token provided"); } const result = await fetchApiInfoApi(projectId, apiId, token); return { content: [ { type: "text", text: result } ] }; } catch (error) { return { content: [ { type: "text", text: `Error fetching API info: ${error.message}` } ], isError: true }; } } ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Apifox MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });