feat: 添加 README 文档并实现 HTTP 传输模式支持
This commit is contained in:
1 parent
87878ceca1
commit
be63d49f40
3 files changed
+174
-3
No files matched your search
@@ -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
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
// 引入必要的模块
|
// 引入必要的模块
|
||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.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 { z } from "zod";
|
||||||
import { ApifoxService } from './apifox.js'
|
import { ApifoxService } from './apifox.js'
|
||||||
|
|
||||||
@@ -162,14 +165,66 @@ server.registerPrompt(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
|
||||||
|
|
||||||
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
|
// 启动服务器,使用标准输入/输出(stdio)与客户端通信
|
||||||
async function main() {
|
async function main() {
|
||||||
const transport = new StdioServerTransport();
|
const args = process.argv.slice(2);
|
||||||
await server.connect(transport);
|
const transportArgIndex = args.indexOf('--transport') !== -1 ? args.indexOf('--transport') : args.indexOf('-t');
|
||||||
console.error("Apifox MCP 服务器已通过 stdio 启动"); // 日志输出到 stderr
|
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) => {
|
main().catch((error) => {
|
||||||
console.error("服务器运行出现致命错误:", error);
|
console.error("服务器运行出现致命错误:", error);
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"zod": "^3.25.76"
|
"zod": "^3.25.76"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"apifox-mcp-server": "./index.js"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@modelcontextprotocol/inspector": "^0.17.2"
|
"@modelcontextprotocol/inspector": "^0.17.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user