本文档说明 AX 文档编辑器如何接入外部 MCP(Model Context Protocol)服务,以及当前项目已经具备的能力和需要补充的实现。
当前项目已经实现的是 WebMCP Provider 和 Bridge:
其他网站
-> POST /api/v1/webmcp/invoke
-> AX 后端 WebMCP Bridge
-> AX 前端页面 WebSocket Connector
-> AX 前端注册的 WebMCP 工具
当前页面注册的工具包括:
open_documentlist_documentsget_documentsearch_documentget_blockget_document_tocget_document_statslist_export_recordsinsert_blockupdate_blockdelete_blockexport_documentdownload_export_record这些工具在前端 webMcpService.ts 中定义,由当前 AX 页面执行。
当前项目还不是通用 MCP Client,因此不能仅通过现有 WebMCP Bridge 自动发现或调用其他 MCP Server 的工具。要接入外部 MCP Server,需要在后端新增 MCP Client 层。
外部 MCP 服务应该由 FastAPI 后端连接,浏览器只负责展示结果和触发经过授权的操作。
用户聊天输入
-> AX 前端 Chat Agent
-> AX 后端统一工具目录
├── AX 本地 WebMCP 工具
└── 外部 MCP 工具
-> 工具路由器
├── 本地工具:通过 WebMCP Bridge 调用当前页面
└── 外部工具:通过 MCP Client 调用对应 MCP Server
-> 返回结构化结果
-> 前端展示结果
外部 MCP Server 可能使用以下连接方式:
stdio:后端启动本地 MCP Server 子进程;推荐把外部连接放在后端,原因如下:
stdio 子进程;VITE_* 环境变量;如果目标只是让其他网站调用 AX 自己的工具,不需要接入外部 MCP Server,可以直接使用现有接口。
启动后端:
cd "D:\work space\ax-shell\ax-backend-v1"
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
启动前端:
cd "D:\work space\ax-shell\ax-frontend-app"
npm run dev
然后保持 AX 页面打开:
http://localhost:5173/
页面启动时会连接 WebSocket Bridge:
ws://localhost:8000/api/v1/webmcp/bridge/{clientId}
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 等工具依赖浏览器中的编辑器状态。
先确认外部服务提供的协议和认证方式:
| 类型 | 适用场景 | 机密存放位置 |
|---|---|---|
stdio |
本机工具、文件系统工具、内部脚本 | 后端主机环境变量或密钥管理服务 |
| Streamable HTTP | 远程部署的 MCP Server | 后端服务端配置 |
| SSE | 旧版或仍提供 SSE 的 MCP Server | 后端服务端配置 |
| OAuth | 第三方 SaaS 服务 | 后端安全 Token 存储 |
不要把外部 MCP Server 的命令、Token 或 API Key 写入前端代码。
当前 requirements.txt 尚未包含 MCP Client SDK。接入时应选择与目标 Server 协议匹配的官方或可信 SDK,并固定版本。
安装依赖前应确认:
不要直接把任意用户输入拼接到 stdio 命令或参数中。
建议在后端配置中增加 Server 配置,而不是把配置硬编码到业务代码:
EXTERNAL_MCP_ENABLED=false
EXTERNAL_MCP_SERVERS_JSON={}
EXTERNAL_MCP_CONNECT_TIMEOUT=10
EXTERNAL_MCP_CALL_TIMEOUT=60
EXTERNAL_MCP_MAX_RESULT_BYTES=524288
生产环境更推荐使用单独的密钥管理系统。配置内容至少应包括:
{
"filesystem": {
"enabled": true,
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "D:/documents"],
"allowedTools": ["read_file", "list_directory"]
}
}
注意:上面的配置是接入设计示例,不代表当前项目已经支持该配置格式。
建议新增以下后端结构:
ax-backend-v1/app/mcp/
__init__.py
client.py # 单个 MCP Server 的连接和调用
manager.py # 多个 Server 的生命周期管理
registry.py # 工具目录、命名空间和白名单
schemas.py # 工具和调用结果的数据结构
单个 Client 至少应提供:
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:
"""释放连接、子进程和后台任务。"""
管理器应负责:
tools/list 结果缓存和刷新;外部工具不能直接使用裸名称,否则容易与 AX 本地工具冲突。建议统一使用:
filesystem.read_file
github.search_repositories
notion.search
内部映射可以是:
TOOL_MAPPING = {
"filesystem.read_file": {
"server": "filesystem",
"remote_name": "read_file",
},
}
对外暴露的统一工具结构建议如下:
{
"name": "filesystem.read_file",
"title": "读取文件",
"description": "读取允许目录中的文件内容",
"inputSchema": {
"type": "object",
"properties": {
"path": {"type": "string"}
},
"required": ["path"]
},
"source": "external",
"server": "filesystem",
"requiresConfirmation": false
}
推荐新增独立的外部 MCP API,而不是把外部工具直接塞进现有 AX Bridge 白名单:
GET /api/v1/mcp/tools
POST /api/v1/mcp/tools/call
获取工具:
GET /api/v1/mcp/tools
Authorization: Bearer <user-token>
调用工具:
POST /api/v1/mcp/tools/call
Authorization: Bearer <user-token>
Content-Type: application/json
{
"tool": "filesystem.read_file",
"arguments": {
"path": "D:/documents/example.txt"
}
}
返回结果建议统一成:
{
"ok": true,
"tool": "filesystem.read_file",
"server": "filesystem",
"data": {
"content": "文件内容"
}
}
外部 MCP Server 的原始结果应在后端转换成受控结构,不能无条件把任意对象、二进制数据或超大文本直接返回给浏览器。
当前聊天转译上下文主要来自前端 webMcpAgentService.ts 的本地工具列表。接入外部工具后,应将本地和外部工具合并:
本地工具:getWebMcpTools()
外部工具:GET /api/v1/mcp/tools
统一工具目录:localTools + externalTools
工具调用时按来源路由:
open_document
-> AX 前端 WebMCP Runtime
filesystem.read_file
-> AX 后端 MCP Client
自然语言转译结果必须经过服务端二次校验,不能因为模型返回了某个工具名称就直接执行。
只允许配置明确启用的 Server 和工具:
ALLOWED_EXTERNAL_TOOLS = {
"filesystem.read_file",
"filesystem.list_directory",
}
不能允许请求方任意传入 Server 地址、命令、工具名称或远程 URL。
以下类型的外部工具默认需要用户确认:
确认凭证必须绑定:
生产环境不能使用长期共享的 VITE_WEBMCP_BRIDGE_TOKEN。当前项目的生产配置应使用:
WEBMCP_AUTH_REQUIRED=true
WEBMCP_JWT_SECRET=独立的高熵服务端密钥
WEBMCP_REDIS_URL=redis://...
WEBMCP_REQUIRE_SHARED_STORE=true
外部 MCP Client 还必须校验:
如果支持 HTTP MCP Server:
如果支持 stdio MCP Server:
必须限制:
日志中不要记录:
建议记录:
先接入一个只读外部 MCP Server,例如:
只实现:
tools/list;tools/call;将外部工具目录加入聊天 Agent:
增加:
增加:
stdio Server 使用低权限进程和固定参数。本指南中的外部 MCP Client 目录、配置项和代理接口属于推荐设计。当前仓库已经实现的是 AX 自有 WebMCP 工具及 Bridge;在外部 MCP Client 代码落地前,不应把外部 Server 工具当作当前系统已支持的功能对外承诺。