apifox-mcp
Apifox MCP 服务器(改造版 · 支持按模块动态读取)
让 AI 助手通过 MCP 协议管理 Apifox 项目的接口文档:创建/更新/审计 API、管理数据模型、检查命名与响应一致性。 本仓库是 iwen-conf/apifox-mcp 的改造版: 原版 Python MCP 包不支持按模块读取,本版新增
APIFOX_MODULE_ID支持(按模块动态导出/导入),并修复了导入写操作落错模块的问题。⚠️ 安全:凡涉及 API Token 处均为占位符,真实 Token 只存在于本机
.zcode/config.json的环境变量中,严禁写入任何将要上传 git 的文件。
目录结构
apifox-mcp/
├── src/ # MCP 服务器源码(唯一需要部署的包)
│ ├── config.py utils.py main.py __init__.py
│ └── tools/ # 8 个工具模块(22 个 MCP 工具)
├── scripts/ # 本地开发脚本(不上生产)
│ └── send_mcp.py # JSON-RPC 验证脚本(token 从环境变量读取)
├── requirements.txt # 依赖(锁定 mcp[cli]==1.29.0)
├── README.md # 本文件
├── venv/ # 虚拟环境(.gitignore 已忽略,不上传)
└── src/*.old # 上游原版文件对照(.gitignore 已忽略,仅本地参考)
.old后缀文件是上游原版(config.py.old、utils.py.old、tools/*.old等), 与改造版同目录存放,便于 diff 对照;它们不会被 Python 加载,也不会上传 git。
快速开始
1. 安装依赖(必须锁定 mcp 1.x)
python -m venv venv
venv/Scripts/pip install -r requirements.txt # Windows
venv/bin/pip install -r requirements.txt # Linux/macOS不能装 mcp 2.x——它移除了 FastMCP API,本包会启动失败。
Python ≥ 3.10(mcp 1.x 要求)。
⚠️ Windows 下系统 PATH 里的
python可能是 Microsoft Store 占位符(WindowsApps),不可用,务必用 venv 内的解释器。
2. 配置环境变量(四件套)
变量 | 说明 |
| Apifox 开放 API Token(登录 Apifox 后获取) |
| 项目 ID |
| 目标模块 ID(配置后按模块动态读取/写入) |
| 指向本仓库根目录的绝对路径(clone 后所在目录,不限定盘符,如 |
3. 注册 MCP 服务器
服务器名 = 探测出的模块名 + " API 文档"(如"管理侧接口 API 文档")。
探测模块名:调一次导出接口,响应 info.title 即模块名:
POST https://api.apifox.com/v1/projects/{项目ID}/export-openapi?locale=zh-CN
Header: Authorization: Bearer {Token} + X-Apifox-Api-Version: 2024-03-28
Body: {"scope":{"type":"ALL"},"oasVersion":"3.1","exportFormat":"JSON","moduleId":{模块ID}}注册方式(命令指向 venv python,args ["-m","src.main"]):
Claude Code:
claude mcp add <名称> -- <venv python> -m src.main(用--env传四件套)Codex / Gemini CLI:
codex mcp add .../gemini mcp add ...Cursor / Windsurf / WorkBuddy:写入对应
mcp.json/mcp_config.json(mcpServers条目)项目下
.mcp.json:合并写入zcode(本机客户端):写 workspace 级
<repo>/.zcode/config.json:
{
"mcp": {
"servers": {
"管理侧接口 API 文档": {
"command": "<venv python 绝对路径>",
"args": ["-m", "src.main"],
"env": {
"APIFOX_TOKEN": "<Token>",
"APIFOX_PROJECT_ID": "<你的项目ID>",
"APIFOX_MODULE_ID": "<你的模块ID>",
"PYTHONPATH": "<仓库根目录绝对路径>"
}
}
}
}
}zcode 对 workspace 级 MCP 默认信任并自动连接,配置后需重启会话生效。
⚠️ .zcode/ 含明文 token,务必加入 .gitignore。
4. 验证
向 MCP 进程 stdin 发 JSON-RPC(或直接跑 scripts/send_mcp.py):
initialize(protocolVersion2024-11-05)notifications/initializedtools/list→ 应含list_api_endpoints等 22 个工具tools/call调list_api_endpoints→ 能返回接口列表
⚠️ Windows 下不要用 select 读子进程 stdout(用线程+队列);手写测试脚本时子进程要继承完整系统环境 (
env = dict(os.environ)再叠加),否则 Python 的_overlapped(Winsock)加载失败报WinError 10106。 zcode 客户端本身会继承父进程环境,不受此影响。
改造记录(相对上游)
改动文件清单
文件 | 改动 |
| 新增 |
| 新增 |
| 重写:create/update/delete 全部基于统一封装;更新走全量快照覆盖, |
| 重写:新增 |
| 统一 export/import helper,去 emoji/序号/装饰线,统一注释与命名 |
| 清理入口日志与注释 |
|
|
核心改造点
① 按模块动态读取(config.py)
APIFOX_MODULE_ID = os.getenv("APIFOX_MODULE_ID") # 可选,指定模块 ID 实现按模块动态读取② 统一导出请求体(utils.py)
def _build_export_payload(scope_type: str = "ALL") -> Dict[str, Any]:
"""构建导出 OpenAPI 的请求体。配置了 APIFOX_MODULE_ID 时自动带上 moduleId,实现按模块动态导出。"""
payload: Dict[str, Any] = {
"scope": {"type": scope_type},
"options": {"includeApifoxExtensionProperties": True, "addFoldersToTags": False},
"oasVersion": "3.1",
"exportFormat": "JSON"
}
if APIFOX_MODULE_ID:
try:
payload["moduleId"] = int(APIFOX_MODULE_ID)
except ValueError:
pass
return payload③ 导入写操作带 moduleId(api_tools / crud_tools)
# 配置了 APIFOX_MODULE_ID 时导入到指定模块,否则保持原逻辑落到默认模块
if APIFOX_MODULE_ID:
import_payload["options"]["moduleId"] = APIFOX_MODULE_ID⚠️
moduleId必须放在options对象内——放在请求体顶层会被 Apifox 忽略, 接口会落进项目默认模块(默认模块与目标模块是两套独立实体,客户端看不到变化)。 这是曾污染默认模块的根因,务必遵守。
能力边界与踩坑记录
导入不写 moduleId → 全落默认模块:见上文改造点③,本仓库曾因此污染默认模块。
参数名:
targetEndpointFolderId/targetSchemaFolderId是正确参数名(与上游 Go CLI 一致),endpointFolderId也能用,二者皆可。security(鉴权)写不进 token 值:import 对
security只做方案关联(schemeGroups引用bearerAuth),authConfigs.token的具体值写不进去(合并保留旧值/置空)。token 值请在客户端用「继承」+ 环境变量({{bearerToken}}/{{refreshToken}})实现。注意:刷新 token 类接口用{{refreshToken}},其余用{{bearerToken}};登录类接口无需鉴权。删除/改名能力(v2 新增,基于"全量快照 + deleteUnmatchedResources"):官方开放 API 无独立删除端点,但 import-openapi 支持
deleteUnmatchedResources: true(删除导入源中不存在的接口/模型)。本版据此实现了真实删除与改名:delete_api_endpoint:导出全量快照 → 移除目标接口 → 全量回导(其余接口原样保留)update_api_endpoint传new_path/new_method:导出全量 → 删旧建新 → 全量回导(即"改名")delete_schema/update_schema传new_name:同样基于全量快照⚠️ 安全红线:这类操作必须基于
export_openapi的全量结果修改,严禁手工拼一个残缺快照再 delete——那会连带删除快照里没有的接口与模型。所有删除/改名工具都带confirm=True二次确认。⚠️ 模块范围:
deleteUnmatchedResources的作用范围与导出/导入一致;配置了APIFOX_MODULE_ID时只影响该模块,未配置时作用于整个项目,多模块项目务必先确认作用域。
update 不再有"改路径即新建"陷阱(v2 已修复):旧版
update_api_endpoint传new_path会被当成新端点新建、旧端点残留(公开 API 无删除能力时只能客户端清理)。v2 起:只传
path+method(不含new_path/new_method)→ 全量快照 + 原位覆盖(保留目录位置)传了
new_path/new_method→ 全量快照 + 改名(旧端点删除,创建新端点)改名后如需改路径模板参数名(如
{taskId} → {taskCode}),直接体现在new_path字符串里即可生效,不再产生副本。
客户端看到旧数据:MCP 摘要/详情接口导出时带
moduleId,Apifox 服务端对该参数组合有导出缓存;不带 moduleId 的导出是准的。客户端刷新(Cmd/Ctrl+R)可强制更新。数据模型 id 分段:目标模块与默认模块的数据模型 id 段不同,清理时认 id 段,别误删。
上游能力边界(源自上游 README / AGENTS / SKILL)
上游官方主推 Go CLI(
cmd/apifox-cli),Python MCP 包为 legacy 兼容层;本仓库专注 Python 版。上游
import-openapi的 options 参数名:targetEndpointFolderId/targetSchemaFolderId。
收尾自查清单
服务器名(探测出的模块名 + " API 文档")
配置写入位置(哪个工具/文件)与是否需重启/信任
导入类工具带
options.moduleId仓库无明文 token(
grep -r "afxp_" .应无命中)
License
MIT(上游同源)。