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。