WU / 文档通用微前端
中文

MCP API:bridge、relay 与工具

浏览器 bridge、relay 的 Node exports,以及 WU 发布的 18 个 MCP 工具参考。

三种职责不同的接口

WU 集成浏览器 bridge 和 Node MCP 服务器。工具客户端通过 stdio 使用 JSON-RPC 与服务器通信,服务器通过已认证 WebSocket 请求连接页面执行操作。

接口 环境 访问
wu.mcp 浏览器 connect, disconnect, isConnected
wu-framework/mcp-server Node 配置、监听器、服务器和协议 helpers
wu_* 工具 MCP 客户端 通过 tools/list 发布的目录

导入 wu-framework/mcp-server 不启动监听器,也不接管 stdin/stdout。运行 wu-mcp-server 或调用 main(env) 才会启动服务。可运行 AI/MCP 示例用真实浏览器和无需 LLM provider 的本地 action 连接完整流程。

浏览器 bridge

import wu from 'wu-framework';

await wu.aiReady();
await wu.mcp.connect(relayUrl, { token: sessionToken });

// Consulta de estado; connect no espera el resultado de autenticación.
const connected = wu.mcp.isConnected();

// Al retirar la integración:
wu.mcp.disconnect();

relayUrl 和 sessionToken 来自可信宿主集成。Token 不应放在 URL、公开 bundle 或 store 持久状态中。

方法 参数 返回值与生命周期
connect(url?, options?) WebSocket URL;默认 ws://localhost:19100;必须提供 token,除非在 loopback 使用 { insecure: true } 加载/启动的 Promise<void>;socket 打开后开始握手
disconnect() 无 void;关闭 socket、停止重连,并释放 bridge 订阅和拦截器
isConnected() 无 boolean;检查 socket 打开及客户端已知的认证状态

4.0 bridge 通过双向 HMAC v2 握手验证 relay,且不发送 token。请同时升级 bridge 和 relay:4.0 之前的 relay 不支持 v2;新版 relay 保留 v1 以兼容旧版 bridges。缺少 token 会产生 WU_MCP_TOKEN_REQUIRED。本地模式要求 { insecure: true },且 relay 设置 WU_MCP_INSECURE=1。非 loopback 必须使用 wss://;不安全 URL 会产生 WU_MCP_INSECURE_URL。

bridge 正在连接或已连接时,不会打开另一连接。意外断开可能启动重连,disconnect() 取消该意图。关闭 MCP 不会自动卸载全部应用,也不取消已启动 handlers 的任意 Promise。

服务器配置

import { loadConfig } from 'wu-framework/mcp-server';

const config = loadConfig(process.env);

loadConfig 验证变量并返回不可变对象,不输出或向客户端暴露 token。无效值抛出错误,不静默回退默认值。

变量 默认值 行为约定
WU_MCP_TOKEN 必填 16–4096 UTF-8 字节字符串
WU_MCP_HOST 127.0.0.1 监听器 host,不含空格或 /
WU_MCP_PORT 19100 1–65535 整数
WU_MCP_TIMEOUT 30000 每个 bridge 命令超时,50–300000 ms
WU_MCP_AUTH_TIMEOUT 5000 身份验证等待时间,50–60000 ms
WU_MCP_MAX_PAYLOAD 1048576 WebSocket 上限,1024–16777216 字节
WU_MCP_ORIGINS HTTP(S) 回环地址 逗号分隔的精确 origin 列表,不含路径
WU_MCP_INSECURE 禁用 仅 1 允许省略 token;若设置 token,仍必须提供

结果包含 host、port、timeout、authTimeout、maxPayload、token、insecure 和 allowedOrigins。最后一项是 Set 或 null,不是要发送给浏览器的数组。

在 WebSocket HTTP upgrade 时检查 Origin。缺失或不允许的 Origin 收到 403。随后完成认证握手。relay 同时只允许一个已认证 bridge 处于活动状态;知道 token 也不能静默替换现有活动会话。

Puente 监听器

import { Puente, loadConfig } from 'wu-framework/mcp-server';

const puente = new Puente(loadConfig(process.env));
await puente.ready();

// Estas consultas no requieren una página autenticada.
const address = puente.address();
const connected = puente.conectado();

// Cuando el host termine su sesión:
await puente.close();

构造时启动监听器。ready() 在能够监听时解析,bind 失败时拒绝,不等待页面。构造函数第二参数可注入 { logger },必须提供 error(...args)。服务日志应写入 stderr,避免破坏 stdout 协议。

方法 返回值 失败或限制
ready() Promise<Puente> 启动失败时拒绝
address() 监听器地址 不说明是否有页面连接
conectado() boolean 即时读取;之后会话可能关闭
enviar(command, params = {}) Promise<unknown> 无 bridge、断连、超时或响应错误时拒绝
close() Promise<void> 拒绝待处理项,关闭 sockets 和监听器,不重新启动服务

enviar 接收 bridge 命令名称,例如 list_actions;对应的外部 MCP 名称是 wu_list_actions。不要混用两个层级。

各 request 保存标识符、超时和预期响应 socket,完成或失败时 relay 移除等待条目。close() 释放待处理项,并强制终止超过关闭宽限期仍未关闭的 sockets。

创建或启动 MCP 服务器

import { main } from 'wu-framework/mcp-server';

// El entorno debe contener la configuración de autenticación.
await main(process.env);

main(env) 创建监听器、等待启动、注册工具并连接 stdio 传输,安装 SIGINT/SIGTERM 处理以关闭服务器和 bridge。它完成启动后解析,不返回可管理会话的对象。外部客户端使用的对应可执行文件是 wu-mcp-server。

宿主需要显式管理生命周期时:

Export 行为约定
createMcpServer(puente, config) 返回带 connect(transport) 和 close() 的服务器,并注册 18 个工具
createCommandRunner(puente) 返回 (commandName, params?) => Promise<WuMcpToolResult> 函数,适配 bridge 响应

宿主向 connect 提供兼容 MCP 传输。关闭嵌入式集成时,MCP 服务器和 Puente 都需关闭,一方不能替代另一方生命周期。下载示例使用打包可执行文件和最小 stdio 客户端,无需导入 bundle 内 SDK 私有类。

工具目录

以下为服务器注册的目录。工具参数经过 relay schemas,执行权限在 bridge 或 wu.ai.execute 再次检查。

工具 参数 主要结果 页面权限
wu_conexion {} { puerto, host, requiere_token, app_conectada } 无需连接页面
wu_list_actions {} { actions, count } 已认证 bridge;列出不授予执行权
wu_execute_action { action, params? } { action, success, result?, reason? } executeActions 和 action 权限
wu_status {} Framework、应用、根键、actions/events 数量 已认证 bridge;根键需要 readStore
wu_list_apps {} 应用描述与状态 已认证 bridge
wu_list_events { limit? } 已脱敏的最近事件 readDiagnostics
wu_get_state { path? } { path, value } readStore
wu_set_state { path, value } { path, value, updated: true } writeStore
wu_emit_event { event, data? } { emitted, data } emitEvents;禁止内部命名空间
wu_navigate { route } { navigated: route } emitEvents;更新 currentPath 还需 writeStore
wu_snapshot { appName? } 应用、可访问树与 timestamp readDOM
wu_screenshot { selector?, quality? } DOM 捕获、元数据或错误 readDOM
wu_click { selector?, text? } 已激活元素或错误 modifyDOM
wu_type { selector, text, clear?, submit? } 写入结果或错误 modifyDOM
wu_console { level?, limit? } 已脱敏控制台条目 readDiagnostics
wu_network { method?, status?, limit? } 已过滤网络元数据 readDiagnostics
wu_mount_app { appName, container? } 已挂载应用 modifyDOM 和正常挂载契约
wu_unmount_app { appName } 已卸载应用 modifyDOM

参数详情:

  • 事件 limit 为 1–200 整数,默认 20;ring 最多保留 200 条。
  • 控制台和网络 limit 为 1–500 整数,默认 50。控制台接受 level: 'all' | 'log' | 'warn' | 'error',默认 all;网络接受 100 至 599 的 status。
  • quality 为 0–1,bridge 默认 0.8。helper 默认使用 DOM/foreignObject 捕获和 PNG;quality 不改变 PNG 压缩,也不保证特权截图级别的还原度。
  • clear 和 submit 默认 false。写入可能触发控件事件,submit: true 可能提交表单。
  • event 为 1–200 字符字符串。relay 和 bridge 都拒绝 wu:、system: 和 app: 前缀。
  • 读取时空 path 选择根,写入要求非空路径。诊断数据离开 bridge 前会脱敏。

wu_navigate 发出 shell:navigate,shell 必须处理该事件。仅凭结果无法证明页面已改变,使用的 gate 是 emitEvents,而非 AI 的 navigate flag。禁用 readStore 时,wu_status 返回 storeKeys: []。

JSON-RPC 与失败结果

初始化 MCP 会话后,action 调用形式如下:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "wu_execute_action",
    "arguments": { "action": "sum_local", "params": { "a": 2, "b": 3 } }
  }
}

服务器在 content[0].text 中返回文本。bridge 返回 error 字段或传输失败时,createCommandRunner 标记 isError。success: false 的 action 结果可能仍处于 isError: false 的 envelope 内。

分别检查 MCP 层和 action 层。HTTP 正常、socket 打开或 envelope 没有 isError,都不能证明 handler 获得授权并成功完成。

tools/list 列出安装版本的工具;wu_list_actions 列出另一目录,即页面在 AI 子系统注册的 handlers。执行 action 需要两层注册和对应权限。

身份验证与名称 helpers

Export 签名 行为
isOriginAllowed (origin, allowedOrigins = null) => boolean 为 null 时,仅允许精确的 HTTP(S) 回环 origin
tokenMatches (candidate, expectedDigest) => boolean 使用 timingSafeEqual 比较候选值 SHA-256 与预期的 32 字节 digest
isReservedEvent (eventName) => boolean 检测三个保留内部命名空间

tokenMatches 的第二参数要求 digest,不是明文 token。digest 大小不正确可能导致比较错误。这些 helpers 不打开 socket,也不授予领域权限。

取消、安全与测试

此实现协议不会将 MCP 取消传播到 wu.ai.execute handler。示例取消等待,并观察已开始的计算继续完成。disconnect 和 close 释放传输及待处理项,但不实现副作用补偿。

特权操作请使用范围受限的自定义 actions 和已认证服务。浏览器 AI 标志是页面技术控制,不能替代业务授权、幂等性或持久操作记录。

node examples/mcp/local-relay.mjs
node scripts/verify-server-examples.mjs --mcp

测试涵盖握手、错误 token、真实工具/actions、求和、无效 schema、权限拒绝、保留事件、可观察取消和 cleanup。token 在内存生成,所有 listeners 都是本地,无需 LLM provider。可下载完整示例,或查看可运行 AI actions 与 MCP。

一起完善 WU

发现了问题?有新的想法?

你的使用体验能让 WU 变得更好。告诉我们遇到的问题,或支持项目的持续开发。