# WebMCP 跨网站调用接入文档 本文档说明其他网站项目如何调用当前 AX 文档编辑器中的 WebMCP 工具。 ## 1. 功能范围 当前方案支持其他网站通过 HTTP 调用当前项目页面中的 WebMCP 工具。 调用链如下: ```text 其他网站 -> POST /api/v1/webmcp/invoke -> 当前项目后端 WebMCP Bridge -> 当前项目页面 WebSocket Connector -> 当前项目 WebMCP Runtime -> 执行工具 -> 返回执行结果 ``` 当前项目页面必须保持打开,因为以下工具需要操作浏览器页面状态: - `open_document` - `get_document` - `search_document` - `get_block` - `get_document_toc` - `get_document_stats` - `list_documents` - `list_export_records` ## 2. 启动前提 启动后端: ```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 ``` 然后在浏览器打开当前项目: ```text http://localhost:5173/ ``` 当前项目页面启动时会自动连接: ```text ws://localhost:8000/api/v1/webmcp/bridge/ax-editor-local ``` 后端使用前端环境中的实际 API 地址。例如当前配置是: ```text http://192.168.0.195:8000 ``` 因此其他网站如果不在同一台机器上,需要使用当前项目后端所在机器的局域网地址或公网地址,不能使用远程机器上的 `localhost`。 ## 2.1 安全边界和使用限制 当前 WebMCP 实现参考 WebMCP Community Group Draft 和 MCP Tools 安全建议,已启用以下防护: - 只允许白名单工具,工具参数会在前端和后端分别校验。 - 修改、删除、插入、导出和下载工具需要当前页面用户确认。 - Bridge 单客户端最多同时执行 8 个请求,并对调用接口进行速率限制。 - WebSocket 只接受配置的前端来源,断线会清理挂起请求。 - 文档读取类工具标记为只读和不可信内容,工具结果有大小上限。 - 自然语言转译结果会在服务端再次检查工具白名单,不能仅信任模型输出。 重要:`VITE_WEBMCP_BRIDGE_TOKEN` 会进入浏览器构建产物,不能当作长期机密凭证。生产环境不要把高权限 token 放入 `VITE_*` 变量;建议使用用户登录态、短期签名凭证或服务端代理,并在服务端增加用户身份、租户和文档权限校验。当前 Bridge 适合本机或受控内网调用,不建议直接暴露到公网。 WebMCP 仍是 Community Group Draft,不是正式 W3C 标准。工具描述和工具返回内容都可能影响 AI 判断,不能把模型生成的指令或文档内容当作可信控制信号。 ## 2.2 生产配置 生产部署至少需要配置: ```env WEBMCP_AUTH_REQUIRED=true WEBMCP_JWT_SECRET=使用独立的高熵服务端密钥 WEBMCP_SESSION_COOKIE_NAME=ax_session WEBMCP_REDIS_URL=redis://用户名:密码@redis-host:6379/0 WEBMCP_REQUIRE_SHARED_STORE=true WEBMCP_TICKET_TTL_SECONDS=60 WEBMCP_CONFIRMATION_TTL_SECONDS=120 ``` 生产环境不要配置 `VITE_WEBMCP_BRIDGE_TOKEN`。页面应通过登录会话的安全 cookie 获取短期 Bridge ticket;cookie 的值必须是由服务端签发、包含 `sub` 和 `sid` 的 HS256 JWT,并使用 `Secure`、`HttpOnly`、`SameSite` 属性。服务端必须验证 JWT 的用户和会话声明。Redis 用于一次性凭证、共享限流和多实例协调,未配置 Redis 时生产 WebMCP 请求会被拒绝。`WEBMCP_JWT_SECRET` 不能与普通 API 密钥或前端变量共用。 ## 3. 调用接口 接口地址: ```http POST http://当前后端地址:8000/api/v1/webmcp/invoke ``` 请求头: ```http Content-Type: application/json X-WebMCP-Token: 当前后端配置的 Bridge Token ``` 请求结构: ```json { "clientId": "ax-editor-local", "tool": "工具名称", "arguments": {} } ``` 字段说明: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `clientId` | `string` | 是 | 当前项目页面的客户端 ID,默认是 `ax-editor-local` | | `tool` | `string` | 是 | WebMCP 工具名称 | | `arguments` | `object` | 否 | 工具参数 | ## 4. 调用示例 ### 4.1 打开文档 ```javascript const response = await fetch( 'http://192.168.0.195:8000/api/v1/webmcp/invoke', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WebMCP-Token': 'REPLACE_WITH_WEBMCP_BRIDGE_TOKEN', }, body: JSON.stringify({ clientId: 'ax-editor-local', tool: 'open_document', arguments: { documentId: 'doc-prod-001', }, }), } ); const result = await response.json(); console.log(result); ``` 成功响应: ```json { "code": 0, "message": "Success", "data": { "requestId": "request-uuid", "tool": "open_document", "result": { "ok": true, "data": { "documentId": "doc-prod-001", "message": "文档已打开" } } } } ``` 调用成功后,当前项目右侧编辑器会打开 `doc-prod-001`。 ### 4.2 读取文档 ```javascript const result = await callWebMcpTool('get_document', { documentId: 'doc-prod-001', }); async function callWebMcpTool(tool, argumentsValue = {}) { const response = await fetch( 'http://192.168.0.195:8000/api/v1/webmcp/invoke', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WebMCP-Token': 'REPLACE_WITH_WEBMCP_BRIDGE_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 toolResult = payload.data.result; if (!toolResult.ok) { throw new Error(toolResult.error || 'WebMCP 工具执行失败'); } return toolResult.data; } ``` ### 4.3 搜索文档内容 ```javascript const result = await callWebMcpTool('search_document', { documentId: 'doc-prod-001', query: 'WebMCP', }); ``` ### 4.4 读取文档块 ```javascript const result = await callWebMcpTool('get_block', { documentId: 'doc-prod-001', blockId: 'block-p-50', }); ``` ### 4.5 获取文档目录 ```javascript const result = await callWebMcpTool('get_document_toc', { documentId: 'doc-prod-001', }); ``` ## 5. 可用工具和参数 ### `open_document` 打开当前项目右侧编辑器中的文档。 ```json { "tool": "open_document", "arguments": { "documentId": "doc-prod-001" } } ``` ### `list_documents` 获取当前用户的文档列表。 ```json { "tool": "list_documents", "arguments": { "page": 1, "pageSize": 20, "sessionId": "optional-session-id" } } ``` ### `get_document` 获取文档详情和内容块。 ```json { "tool": "get_document", "arguments": { "documentId": "doc-prod-001" } } ``` ### `search_document` 在文档中搜索内容块。 ```json { "tool": "search_document", "arguments": { "documentId": "doc-prod-001", "query": "关键词", "type": "paragraph" } } ``` ### `get_block` 获取指定文档块。 ```json { "tool": "get_block", "arguments": { "documentId": "doc-prod-001", "blockId": "block-p-50" } } ``` ### `get_document_toc` 获取文档目录。 ```json { "tool": "get_document_toc", "arguments": { "documentId": "doc-prod-001" } } ``` ### `get_document_stats` 获取文档统计信息。 ```json { "tool": "get_document_stats", "arguments": { "documentId": "doc-prod-001" } } ``` ### `list_export_records` 获取当前用户的导出记录。 ```json { "tool": "list_export_records", "arguments": { "page": 1, "pageSize": 20 } } ``` ## 6. 修改类工具 以下工具在当前 Bridge 中不会被其他网站直接执行: - `insert_block` - `update_block` - `delete_block` - `export_document` - `download_export_record` 原因是这些工具的 `requiresConfirmation` 为 `true`。跨网站调用会得到失败结果: ```json { "ok": false, "error": "该 WebMCP 工具需要当前页面用户确认" } ``` 这可以防止其他网站绕过当前项目的用户确认机制,直接修改或删除文档内容。 ## 7. 错误处理 ### Bridge Token 未配置 ```http 503 Service Unavailable ``` 响应: ```json { "detail": "WebMCP Bridge 未配置访问令牌" } ``` ### Token 错误 ```http 401 Unauthorized ``` 响应: ```json { "detail": "WebMCP Bridge 访问令牌无效" } ``` ### 当前项目页面未打开或未连接 ```http 404 Not Found ``` 响应: ```json { "detail": "当前 WebMCP 页面未连接" } ``` ### 工具执行超时 ```http 504 Gateway Timeout ``` 响应: ```json { "detail": "WebMCP 工具执行超时" } ``` ### 工具执行失败 HTTP 请求可能成功返回,但 `data.result.ok` 为 `false`: ```json { "code": 0, "data": { "result": { "ok": false, "error": "文档不存在" } } } ``` 调用方必须同时检查: ```javascript if (!response.ok || payload.code !== 0 || !payload.data.result.ok) { // 按失败处理 } ``` ## 8. 其他网址项目的完整封装 建议其他项目封装一个统一函数,不要在多个页面重复拼接请求: ```javascript const WEBMCP_API = 'http://192.168.0.195:8000/api/v1/webmcp/invoke'; const WEBMCP_TOKEN = 'REPLACE_WITH_WEBMCP_BRIDGE_TOKEN'; const WEBMCP_CLIENT_ID = 'ax-editor-local'; export async function invokeAxWebMcp(tool, argumentsValue = {}) { const response = await fetch(WEBMCP_API, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WebMCP-Token': WEBMCP_TOKEN, }, body: JSON.stringify({ clientId: WEBMCP_CLIENT_ID, tool, arguments: argumentsValue, }), }); const payload = await response.json(); if (!response.ok) { throw new Error(payload.detail || `HTTP ${response.status}`); } if (payload.code !== 0) { throw new Error(payload.message || 'WebMCP 调用失败'); } const result = payload.data?.result; if (!result?.ok) { throw new Error(result?.error || 'WebMCP 工具执行失败'); } return result.data; } // 打开当前项目中的文档 await invokeAxWebMcp('open_document', { documentId: 'doc-prod-001', }); ``` ## 9. 网络环境说明 ### 其他网站和当前项目在同一台电脑 可以调用: ```text http://localhost:8000/api/v1/webmcp/invoke ``` ### 其他网站运行在同一局域网的另一台电脑 需要使用后端电脑的局域网地址: ```text http://192.168.0.195:8000/api/v1/webmcp/invoke ``` 并确保: - 后端使用 `--host 0.0.0.0` 启动。 - 防火墙允许访问 `8000` 端口。 - 其他电脑可以访问该 IP。 - 当前项目页面在运行后端的那台电脑上打开。 ### 其他网站运行在公网 不能直接使用用户电脑上的 `localhost`。需要将当前后端或 WebMCP Gateway 部署到公网 HTTPS 地址,或者通过安全隧道暴露接口。 ## 10. 不要这样调用 不要在其他网站中直接使用: ```javascript useUIStore.getState().openDocumentPreview(...); executeWebMcpTool(...); ``` 这些属于当前项目内部代码,其他网站无法直接访问,也不应依赖。 不要把 XAgent API Key 放在其他网站前端代码中。其他网站只需要使用 WebMCP Bridge Token,不需要知道 XAgent API Key。 不要让其他网站直接连接: ```text ws://localhost:8000/api/v1/webmcp/bridge/ax-editor-local ``` 这个 WebSocket 是当前项目页面的内部连接。其他网站应使用 HTTP `POST /invoke` 接口。 ## 11. 最小验证步骤 1. 启动后端。 2. 启动前端。 3. 浏览器打开 `http://localhost:5173/`。 4. 确认当前项目页面保持打开。 5. 在其他网站控制台执行: ```javascript await invokeAxWebMcp('open_document', { documentId: 'doc-prod-001', }); ``` 6. 检查当前项目右侧是否打开对应文档。 如果返回“当前 WebMCP 页面未连接”,说明当前项目页面没有成功连接后端 Bridge,需要检查前端 `.env` 中的: ```text VITE_API_BASE_URL VITE_WEBMCP_BRIDGE_TOKEN VITE_WEBMCP_CLIENT_ID ``` 修改环境变量后必须重启 Vite 和 Uvicorn。