WebMCP调用接入文档.md 12 KB

WebMCP 跨网站调用接入文档

本文档说明其他网站项目如何调用当前 AX 文档编辑器中的 WebMCP 工具。

1. 功能范围

当前方案支持其他网站通过 HTTP 调用当前项目页面中的 WebMCP 工具。

调用链如下:

其他网站
  -> 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. 启动前提

启动后端:

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

然后在浏览器打开当前项目:

http://localhost:5173/

当前项目页面启动时会自动连接:

ws://localhost:8000/api/v1/webmcp/bridge/ax-editor-local

后端使用前端环境中的实际 API 地址。例如当前配置是:

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 生产配置

生产部署至少需要配置:

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 的值必须是由服务端签发、包含 subsid 的 HS256 JWT,并使用 SecureHttpOnlySameSite 属性。服务端必须验证 JWT 的用户和会话声明。Redis 用于一次性凭证、共享限流和多实例协调,未配置 Redis 时生产 WebMCP 请求会被拒绝。WEBMCP_JWT_SECRET 不能与普通 API 密钥或前端变量共用。

3. 调用接口

接口地址:

POST http://当前后端地址:8000/api/v1/webmcp/invoke

请求头:

Content-Type: application/json
X-WebMCP-Token: 当前后端配置的 Bridge Token

请求结构:

{
  "clientId": "ax-editor-local",
  "tool": "工具名称",
  "arguments": {}
}

字段说明:

字段 类型 必填 说明
clientId string 当前项目页面的客户端 ID,默认是 ax-editor-local
tool string WebMCP 工具名称
arguments object 工具参数

4. 调用示例

4.1 打开文档

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);

成功响应:

{
  "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 读取文档

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 搜索文档内容

const result = await callWebMcpTool('search_document', {
  documentId: 'doc-prod-001',
  query: 'WebMCP',
});

4.4 读取文档块

const result = await callWebMcpTool('get_block', {
  documentId: 'doc-prod-001',
  blockId: 'block-p-50',
});

4.5 获取文档目录

const result = await callWebMcpTool('get_document_toc', {
  documentId: 'doc-prod-001',
});

5. 可用工具和参数

open_document

打开当前项目右侧编辑器中的文档。

{
  "tool": "open_document",
  "arguments": {
    "documentId": "doc-prod-001"
  }
}

list_documents

获取当前用户的文档列表。

{
  "tool": "list_documents",
  "arguments": {
    "page": 1,
    "pageSize": 20,
    "sessionId": "optional-session-id"
  }
}

get_document

获取文档详情和内容块。

{
  "tool": "get_document",
  "arguments": {
    "documentId": "doc-prod-001"
  }
}

search_document

在文档中搜索内容块。

{
  "tool": "search_document",
  "arguments": {
    "documentId": "doc-prod-001",
    "query": "关键词",
    "type": "paragraph"
  }
}

get_block

获取指定文档块。

{
  "tool": "get_block",
  "arguments": {
    "documentId": "doc-prod-001",
    "blockId": "block-p-50"
  }
}

get_document_toc

获取文档目录。

{
  "tool": "get_document_toc",
  "arguments": {
    "documentId": "doc-prod-001"
  }
}

get_document_stats

获取文档统计信息。

{
  "tool": "get_document_stats",
  "arguments": {
    "documentId": "doc-prod-001"
  }
}

list_export_records

获取当前用户的导出记录。

{
  "tool": "list_export_records",
  "arguments": {
    "page": 1,
    "pageSize": 20
  }
}

6. 修改类工具

以下工具在当前 Bridge 中不会被其他网站直接执行:

  • insert_block
  • update_block
  • delete_block
  • export_document
  • download_export_record

原因是这些工具的 requiresConfirmationtrue。跨网站调用会得到失败结果:

{
  "ok": false,
  "error": "该 WebMCP 工具需要当前页面用户确认"
}

这可以防止其他网站绕过当前项目的用户确认机制,直接修改或删除文档内容。

7. 错误处理

Bridge Token 未配置

503 Service Unavailable

响应:

{
  "detail": "WebMCP Bridge 未配置访问令牌"
}

Token 错误

401 Unauthorized

响应:

{
  "detail": "WebMCP Bridge 访问令牌无效"
}

当前项目页面未打开或未连接

404 Not Found

响应:

{
  "detail": "当前 WebMCP 页面未连接"
}

工具执行超时

504 Gateway Timeout

响应:

{
  "detail": "WebMCP 工具执行超时"
}

工具执行失败

HTTP 请求可能成功返回,但 data.result.okfalse

{
  "code": 0,
  "data": {
    "result": {
      "ok": false,
      "error": "文档不存在"
    }
  }
}

调用方必须同时检查:

if (!response.ok || payload.code !== 0 || !payload.data.result.ok) {
  // 按失败处理
}

8. 其他网址项目的完整封装

建议其他项目封装一个统一函数,不要在多个页面重复拼接请求:

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. 网络环境说明

其他网站和当前项目在同一台电脑

可以调用:

http://localhost:8000/api/v1/webmcp/invoke

其他网站运行在同一局域网的另一台电脑

需要使用后端电脑的局域网地址:

http://192.168.0.195:8000/api/v1/webmcp/invoke

并确保:

  • 后端使用 --host 0.0.0.0 启动。
  • 防火墙允许访问 8000 端口。
  • 其他电脑可以访问该 IP。
  • 当前项目页面在运行后端的那台电脑上打开。

其他网站运行在公网

不能直接使用用户电脑上的 localhost。需要将当前后端或 WebMCP Gateway 部署到公网 HTTPS 地址,或者通过安全隧道暴露接口。

10. 不要这样调用

不要在其他网站中直接使用:

useUIStore.getState().openDocumentPreview(...);
executeWebMcpTool(...);

这些属于当前项目内部代码,其他网站无法直接访问,也不应依赖。

不要把 XAgent API Key 放在其他网站前端代码中。其他网站只需要使用 WebMCP Bridge Token,不需要知道 XAgent API Key。

不要让其他网站直接连接:

ws://localhost:8000/api/v1/webmcp/bridge/ax-editor-local

这个 WebSocket 是当前项目页面的内部连接。其他网站应使用 HTTP POST /invoke 接口。

11. 最小验证步骤

  1. 启动后端。
  2. 启动前端。
  3. 浏览器打开 http://localhost:5173/
  4. 确认当前项目页面保持打开。
  5. 在其他网站控制台执行:
await invokeAxWebMcp('open_document', {
  documentId: 'doc-prod-001',
});
  1. 检查当前项目右侧是否打开对应文档。

如果返回“当前 WebMCP 页面未连接”,说明当前项目页面没有成功连接后端 Bridge,需要检查前端 .env 中的:

VITE_API_BASE_URL
VITE_WEBMCP_BRIDGE_TOKEN
VITE_WEBMCP_CLIENT_ID

修改环境变量后必须重启 Vite 和 Uvicorn。