feat: 添加 README 文档并实现 HTTP 传输模式支持

This commit is contained in:
zhangguoyun committed 2025-12-16 10:32:05 +08:00
1 parent 87878ceca1
commit be63d49f40
3 files changed
+174 -3

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
# Apifox MCP Service
这是一个基于 [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) 标准实现的 Apifox 服务端。它充当 LLM (如 Claude, Gemini 等) 与 Apifox API 文档之间的桥梁,允许 AI 助手直接检索 Apifox 中的接口定义,并根据定义生成强类型的 API 请求代码。
## ✨ 功能特性
* **MCP 协议支持**: 支持标准 MCP 协议,可集成到 Claude Desktop, Cursor 等支持 MCP 的客户端。
* **多传输模式**: 支持 `stdio` (标准输入输出,默认) 和 `http` (SSE 流式传输) 两种模式。
* **接口检索**:
* `get_api_by_path`: 根据路径获取指定接口的详细定义 (Schema)。
* `get_apis_by_folder`: 获取指定目录下的所有接口定义。
* **AI 提示词 (Prompts)**:
* `gen-api-by-path`: 指导 AI 根据接口路径生成 API 代码。
* `gen-api-by-folder`: 指导 AI 根据目录批量生成 API 代码。
* **健康检查**: HTTP 模式下提供 `/health` 端点。
## 🛠️ 安装与配置
### 前置要求
* Node.js (v18 或更高版本)
* Apifox 账号及项目访问权限
### 环境变量
运行此服务需要配置以下环境变量:
| 变量名 | 描述 |
| :--- | :--- |
| `APIFOX_PROJECT_ID` | 你的 Apifox 项目 ID (数字) |
| `APIFOX_TOKEN` | 你的 Apifox 访问令牌 (Bearer Token) |
### 安装依赖
```bash
npm install
```
## 🚀 启动服务
### 1. Stdio 模式 (默认)
适用于 Claude Desktop 或作为子进程运行的场景。
```bash
# 需确保环境变量已设置
export APIFOX_PROJECT_ID=你的项目ID
export APIFOX_TOKEN=你的Token
node index.js
# 或显式指定
node index.js --transport stdio
```
### 2. HTTP (SSE) 模式
适用于远程部署或需要 HTTP 访问的场景。
```bash
node index.js --transport http --port 8889
```
* **Endpoint**: `http://localhost:8889/sse`
* **Health Check**: `http://localhost:8889/health`
## 💻 客户端集成示例
### Claude Desktop 配置
编辑 Claude Desktop 的配置文件 (通常位于 `%APPDATA%\Claude\claude_desktop_config.json` 或 `~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"apifox": {
"command": "node",
"args": [
"D:/demo/apifox-mcp-service/index.js"
],
"env": {
"APIFOX_PROJECT_ID": "123456",
"APIFOX_TOKEN": "apifox_pat_xxxxxxxx"
}
}
}
}
```
*注意:请将路径替换为你本地的实际绝对路径。*
## 📚 工具详情
### Tools
#### `get_api_by_path`
根据接口路径获取 Apifox 接口定义数据。
* 参数: `path` (string), `projectId` (number, 可选)
#### `get_apis_by_folder`
根据接口目录名称获取目录下所有接口定义。
* 参数: `folderName` (string), `projectId` (number, 可选)
### Prompts
#### `gen-api-by-path`
流程化 Prompt,引导 LLM 获取接口定义并生成符合项目规范的 API 代码。
#### `gen-api-by-folder`
流程化 Prompt,引导 LLM 批量获取目录下接口并生成代码。
## 📝 License
ISC
+58 -3
View File
@@ -1,6 +1,9 @@
#!/usr/bin/env node
// 引入必要的模块
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import http from "http";
import { z } from "zod";
import { ApifoxService } from './apifox.js'
@@ -162,14 +165,66 @@ server.registerPrompt(
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
const args = process.argv.slice(2);
const transportArgIndex = args.indexOf('--transport') !== -1 ? args.indexOf('--transport') : args.indexOf('-t');
const transportType = transportArgIndex !== -1 ? args[transportArgIndex + 1] : 'stdio';
const portArgIndex = args.indexOf('--port') !== -1 ? args.indexOf('--port') : args.indexOf('-p');
const port = portArgIndex !== -1 ? parseInt(args[portArgIndex + 1]) : 8889;
if (transportType === 'http') {
const transport = new StreamableHTTPServerTransport({});
await server.connect(transport);
const httpServer = http.createServer(async (req, res) => {
// 设置 CORS 头
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, mcp-session-id');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
if (req.method === 'GET' && req.url === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok' }));
return;
}
try {
await transport.handleRequest(req, res);
} catch (error) {
console.error("Error handling request:", error);
if (!res.headersSent) {
res.writeHead(500);
res.end("Internal Server Error");
}
}
});
httpServer.listen(port, () => {
console.error(`Apifox MCP 服务器已通过 http 启动,监听端口 ${port}`);
console.error(`MCP 服务 endpoint: http://localhost:${port}/sse`);
});
} else {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
}
}
// 运行主函数,并捕获可能的错误
main().catch((error) => {
console.error("服务器运行出现致命错误:", error);
+3
View File
@@ -20,6 +20,9 @@
"node-cache": "^5.1.2",
"zod": "^3.25.76"
},
"bin": {
"apifox-mcp-server": "./index.js"
},
"devDependencies": {
"@modelcontextprotocol/inspector": "^0.17.2"
}