# 外部 MCP 服务接入指南 本文档说明 AX 文档编辑器如何接入外部 MCP(Model Context Protocol)服务,以及当前项目已经具备的能力和需要补充的实现。 ## 1. 先明确当前能力边界 当前项目已经实现的是 **WebMCP Provider 和 Bridge**: ```text 其他网站 -> POST /api/v1/webmcp/invoke -> AX 后端 WebMCP Bridge -> AX 前端页面 WebSocket Connector -> AX 前端注册的 WebMCP 工具 ``` 当前页面注册的工具包括: - `open_document` - `list_documents` - `get_document` - `search_document` - `get_block` - `get_document_toc` - `get_document_stats` - `list_export_records` - `insert_block` - `update_block` - `delete_block` - `export_document` - `download_export_record` 这些工具在前端 [webMcpService.ts](../src/services/webMcpService.ts) 中定义,由当前 AX 页面执行。 当前项目**还不是通用 MCP Client**,因此不能仅通过现有 WebMCP Bridge 自动发现或调用其他 MCP Server 的工具。要接入外部 MCP Server,需要在后端新增 MCP Client 层。 ## 2. 推荐的目标架构 外部 MCP 服务应该由 FastAPI 后端连接,浏览器只负责展示结果和触发经过授权的操作。 ```text 用户聊天输入 -> AX 前端 Chat Agent -> AX 后端统一工具目录 ├── AX 本地 WebMCP 工具 └── 外部 MCP 工具 -> 工具路由器 ├── 本地工具:通过 WebMCP Bridge 调用当前页面 └── 外部工具:通过 MCP Client 调用对应 MCP Server -> 返回结构化结果 -> 前端展示结果 ``` 外部 MCP Server 可能使用以下连接方式: - `stdio`:后端启动本地 MCP Server 子进程; - Streamable HTTP:后端通过 HTTP 连接远端 MCP Server; - SSE:连接支持 SSE 的 MCP Server; - 需要 API Key、OAuth 或其他服务端认证方式的远程服务。 推荐把外部连接放在后端,原因如下: - 浏览器不能安全地启动 `stdio` 子进程; - API Key、OAuth Refresh Token 等机密不能放入 `VITE_*` 环境变量; - 后端可以统一做工具白名单、用户权限、限流、审计和写操作确认; - 多个前端页面可以复用同一个 MCP Client 连接池。 ## 3. 当前项目中已经可用的 WebMCP Bridge 如果目标只是让其他网站调用 AX 自己的工具,不需要接入外部 MCP Server,可以直接使用现有接口。 ### 3.1 启动服务 启动后端: ```powershell cd "D:\work space\ax-shell\ax-backend-v1" uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` 启动前端: ```powershell cd "D:\work space\ax-shell\ax-frontend-app" npm run dev ``` 然后保持 AX 页面打开: ```text http://localhost:5173/ ``` 页面启动时会连接 WebSocket Bridge: ```text ws://localhost:8000/api/v1/webmcp/bridge/{clientId} ``` ### 3.2 调用 AX 工具 ```javascript async function invokeAxTool(tool, argumentsValue = {}) { const response = await fetch('http://localhost:8000/api/v1/webmcp/invoke', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WebMCP-Token': '从服务端安全配置中读取', }, body: JSON.stringify({ clientId: 'ax-editor-local', tool, arguments: argumentsValue, }), }); const payload = await response.json(); if (!response.ok || payload.code !== 0) { throw new Error(payload.detail || payload.message || 'WebMCP 调用失败'); } const result = payload.data.result; if (!result.ok) { throw new Error(result.error || 'AX WebMCP 工具执行失败'); } return result.data; } const documents = await invokeAxTool('list_documents', { page: 1, pageSize: 20, }); ``` 当前 AX 页面必须保持打开,因为 `open_document`、`update_block` 等工具依赖浏览器中的编辑器状态。 ## 4. 接入外部 MCP Server 的实施步骤 ### 步骤 1:选择连接方式 先确认外部服务提供的协议和认证方式: | 类型 | 适用场景 | 机密存放位置 | | --------------- | -------------------------------- | ------------------------------ | | `stdio` | 本机工具、文件系统工具、内部脚本 | 后端主机环境变量或密钥管理服务 | | Streamable HTTP | 远程部署的 MCP Server | 后端服务端配置 | | SSE | 旧版或仍提供 SSE 的 MCP Server | 后端服务端配置 | | OAuth | 第三方 SaaS 服务 | 后端安全 Token 存储 | 不要把外部 MCP Server 的命令、Token 或 API Key 写入前端代码。 ### 步骤 2:在后端增加 MCP Client 依赖 当前 [requirements.txt](../../ax-backend-v1/requirements.txt) 尚未包含 MCP Client SDK。接入时应选择与目标 Server 协议匹配的官方或可信 SDK,并固定版本。 安装依赖前应确认: - SDK 支持当前 Python 版本; - SDK 支持目标 Server 的传输方式; - SDK 的许可证和维护状态符合项目要求; - 依赖不会把不受信任的命令执行能力暴露给公网请求。 不要直接把任意用户输入拼接到 `stdio` 命令或参数中。 ### 步骤 3:增加外部 Server 配置 建议在后端配置中增加 Server 配置,而不是把配置硬编码到业务代码: ```env EXTERNAL_MCP_ENABLED=false EXTERNAL_MCP_SERVERS_JSON={} EXTERNAL_MCP_CONNECT_TIMEOUT=10 EXTERNAL_MCP_CALL_TIMEOUT=60 EXTERNAL_MCP_MAX_RESULT_BYTES=524288 ``` 生产环境更推荐使用单独的密钥管理系统。配置内容至少应包括: ```json { "filesystem": { "enabled": true, "transport": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "D:/documents"], "allowedTools": ["read_file", "list_directory"] } } ``` 注意:上面的配置是接入设计示例,不代表当前项目已经支持该配置格式。 ### 步骤 4:增加 MCP Client 管理器 建议新增以下后端结构: ```text ax-backend-v1/app/mcp/ __init__.py client.py # 单个 MCP Server 的连接和调用 manager.py # 多个 Server 的生命周期管理 registry.py # 工具目录、命名空间和白名单 schemas.py # 工具和调用结果的数据结构 ``` 单个 Client 至少应提供: ```python class ExternalMcpClient: async def connect(self) -> None: """建立连接并完成 MCP initialize。""" async def list_tools(self) -> list[dict]: """调用 tools/list 获取工具定义。""" async def call_tool(self, name: str, arguments: dict) -> dict: """调用 tools/call 执行工具。""" async def close(self) -> None: """释放连接、子进程和后台任务。""" ``` 管理器应负责: - 应用启动时连接已启用的 Server; - 应用关闭时释放连接; - 连接断开后的有限次重连; - `tools/list` 结果缓存和刷新; - 工具名称冲突处理; - 单 Server 和单用户的并发限制; - 调用超时和结果大小限制。 ### 步骤 5:为外部工具添加命名空间 外部工具不能直接使用裸名称,否则容易与 AX 本地工具冲突。建议统一使用: ```text filesystem.read_file github.search_repositories notion.search ``` 内部映射可以是: ```python TOOL_MAPPING = { "filesystem.read_file": { "server": "filesystem", "remote_name": "read_file", }, } ``` 对外暴露的统一工具结构建议如下: ```python { "name": "filesystem.read_file", "title": "读取文件", "description": "读取允许目录中的文件内容", "inputSchema": { "type": "object", "properties": { "path": {"type": "string"} }, "required": ["path"] }, "source": "external", "server": "filesystem", "requiresConfirmation": false } ``` ### 步骤 6:增加后端代理接口 推荐新增独立的外部 MCP API,而不是把外部工具直接塞进现有 AX Bridge 白名单: ```http GET /api/v1/mcp/tools POST /api/v1/mcp/tools/call ``` 获取工具: ```http GET /api/v1/mcp/tools Authorization: Bearer ``` 调用工具: ```http POST /api/v1/mcp/tools/call Authorization: Bearer Content-Type: application/json { "tool": "filesystem.read_file", "arguments": { "path": "D:/documents/example.txt" } } ``` 返回结果建议统一成: ```json { "ok": true, "tool": "filesystem.read_file", "server": "filesystem", "data": { "content": "文件内容" } } ``` 外部 MCP Server 的原始结果应在后端转换成受控结构,不能无条件把任意对象、二进制数据或超大文本直接返回给浏览器。 ### 步骤 7:接入聊天工具目录 当前聊天转译上下文主要来自前端 [webMcpAgentService.ts](../src/services/webMcpAgentService.ts) 的本地工具列表。接入外部工具后,应将本地和外部工具合并: ```text 本地工具:getWebMcpTools() 外部工具:GET /api/v1/mcp/tools 统一工具目录:localTools + externalTools ``` 工具调用时按来源路由: ```text open_document -> AX 前端 WebMCP Runtime filesystem.read_file -> AX 后端 MCP Client ``` 自然语言转译结果必须经过服务端二次校验,不能因为模型返回了某个工具名称就直接执行。 ## 5. 安全要求 ### 5.1 工具白名单 只允许配置明确启用的 Server 和工具: ```python ALLOWED_EXTERNAL_TOOLS = { "filesystem.read_file", "filesystem.list_directory", } ``` 不能允许请求方任意传入 Server 地址、命令、工具名称或远程 URL。 ### 5.2 写操作确认 以下类型的外部工具默认需要用户确认: - 写入、删除或移动文件; - 创建、修改或删除第三方平台数据; - 发送邮件、消息或通知; - 创建费用、订单或权限变更; - 执行脚本、命令或数据库写操作。 确认凭证必须绑定: - 当前用户; - 当前会话; - 工具名称; - 完整参数哈希; - 短时间有效期; - 一次性使用标识。 ### 5.3 认证和权限 生产环境不能使用长期共享的 `VITE_WEBMCP_BRIDGE_TOKEN`。当前项目的生产配置应使用: ```env WEBMCP_AUTH_REQUIRED=true WEBMCP_JWT_SECRET=独立的高熵服务端密钥 WEBMCP_REDIS_URL=redis://... WEBMCP_REQUIRE_SHARED_STORE=true ``` 外部 MCP Client 还必须校验: - 当前用户是否有权访问目标 Server; - 当前用户是否有权访问目标资源; - 文档、文件或第三方对象是否属于当前租户; - 外部工具返回内容是否可展示给当前用户。 ### 5.4 SSRF 和命令执行防护 如果支持 HTTP MCP Server: - 不允许用户直接提交任意 URL; - 只允许服务端配置的域名或地址; - 禁止访问云元数据地址、内网管理地址和本机敏感端口; - 对重定向进行重新校验; - 配置连接、读取和总调用超时。 如果支持 `stdio` MCP Server: - 命令和参数只能来自服务端配置; - 不要使用 shell 拼接执行; - 使用参数数组启动进程; - 限制工作目录和环境变量; - 使用专用低权限系统用户; - 限制子进程数量、内存和运行时间。 ### 5.5 结果和日志 必须限制: - 请求参数大小; - 工具结果大小; - 单用户并发数; - 单 Server 并发数; - 调用频率; - 连接重试次数。 日志中不要记录: - API Key; - OAuth Token; - Cookie; - 完整文件内容; - 可能包含个人信息的工具参数。 建议记录: - 用户 ID 和会话 ID; - Server 名称; - 命名空间工具名; - 调用是否需要确认; - 成功、失败或超时; - 调用耗时和结果大小。 ## 6. 推荐的分阶段落地顺序 ### 阶段一:只读工具 先接入一个只读外部 MCP Server,例如: - 文件列表; - 文件读取; - 搜索; - 查询类工具。 只实现: - Server 配置; - Client 连接; - `tools/list`; - `tools/call`; - 工具白名单; - 超时和结果限制; - 只读调用 API。 ### 阶段二:接入聊天 将外部工具目录加入聊天 Agent: - 展示工具名称和描述; - 将工具 Schema 提供给转译器; - 服务端校验工具名称和参数; - 将调用结果转换成适合聊天展示的文本或结构化卡片。 ### 阶段三:写操作和确认 增加: - 用户确认弹窗; - 一次性确认凭证; - 参数哈希绑定; - 审计日志; - 失败重试和幂等策略。 ### 阶段四:多租户和生产部署 增加: - 每个租户独立的 MCP Server 配置; - 用户级 OAuth Token; - Redis 或其他共享状态存储; - 多实例连接管理; - 监控、告警和调用成本统计。 ## 7. 上线检查清单 - [ ] 外部 MCP Client 只运行在后端。 - [ ] 外部 MCP Server 地址来自服务端配置,不来自用户输入。 - [ ] API Key 和 OAuth Token 没有进入前端构建产物。 - [ ] 所有外部工具使用命名空间。 - [ ] 工具和 Server 都有白名单。 - [ ] 只读和写操作明确区分。 - [ ] 写操作需要当前用户确认。 - [ ] 确认凭证绑定用户、会话、工具和参数哈希。 - [ ] 配置连接超时、调用超时和结果大小限制。 - [ ] 配置单用户和单 Server 并发限制。 - [ ] HTTP Server 已防护 SSRF。 - [ ] `stdio` Server 使用低权限进程和固定参数。 - [ ] 日志已脱敏。 - [ ] 已测试断线、超时、错误结果和超大结果。 - [ ] 已测试多用户和多租户权限隔离。 - [ ] 生产环境未使用长期共享 Bridge Token。 ## 8. 相关代码和文档 - [AX WebMCP 跨网站调用文档](./WebMCP调用接入文档.md) - [AX WebMCP 工具定义](../src/services/webMcpService.ts) - [AX WebMCP Bridge](../src/share/webmcp/bridge.ts) - [后端 WebMCP 路由](../../ax-backend-v1/app/api/v1/webmcp.py) - [后端配置](../../ax-backend-v1/app/config.py) - [后端依赖](../../ax-backend-v1/requirements.txt) > 本指南中的外部 MCP Client 目录、配置项和代理接口属于推荐设计。当前仓库已经实现的是 AX 自有 WebMCP 工具及 Bridge;在外部 MCP Client 代码落地前,不应把外部 Server 工具当作当前系统已支持的功能对外承诺。