发布日期
· 阅读约 9 分钟

Chrome WebMCP:让网页给浏览器 Agent 可调用的工具

Agent 帮用户订票、填售后单,却在自定义日期控件、多层菜单里点错、重试、烧 token——根因往往不是模型「不够聪明」,而是页面只对人类可读,没有给机器一份可调用的接口。Chrome 里的 WebMCP 要解决的就是这件事:让站点主动声明「我能做什么」,而不是让 Agent 从 DOM 里猜。

状态说明(2026-08):WebMCP 仍是 Web Machine Learning CG Draft(非 Standards Track)。Chrome 本地 flag 约自 M146Origin Trial 为 M149–M156(blink-dev Intent to Experiment);Intent 估计 Shipping M157,Stable 默认开启尚未官宣。API 可能继续变;以 Chrome 文档 为准。

先分清三个「MCP」

名字撞车很常见,先对齐:

名称干什么典型入口
WebMCP网页把客户端能力暴露给浏览器内 Agentdocument.modelContext.registerTool / HTML toolname
MCP(Model Context Protocol)Agent 连后端/外部系统的通用协议JSON-RPC + stdio / HTTP / SSE 等
Chrome DevTools MCP / DevTools for agents编码 Agent 操控、调试浏览器chrome-devtools-mcp

官方写得很直白:WebMCP 不是 MCP 的扩展,也不替代 MCP。更贴切的说法是:MCP-inspired 的浏览器 API——共享「工具发现 + 结构化调用」的哲学,但省略服务端那套 Resources / Prompts,也没有 HTTP/SSE/stdio 传输。工具绑定在当前打开的标签页上,用户离开页面,Agent 就不能再碰。

实用分工:

  1. MCP Server:核心业务、跨端数据、后台任务(随时可调用)。
  2. WebMCP:用户正在看的站点 UI、当前 session / cookie / 表单(只在访问时可用)。

为什么需要它

没有 WebMCP 时,浏览器 Agent 的路径大致是:扫可访问性树 / DOM → 猜哪个按钮 → 模拟点击 → 再猜下一步。每一步都可解释失败。

有了 WebMCP,站点可以注册例如 checkoutfilter_resultssubmit_application:带 JSON Schema 的输入输出,执行走你自己的前端逻辑,UI 仍在用户眼前更新。官方把它定位为 progressive enhancement:没 Agent 的浏览器照常用人机界面;有 Agent 时任务更准、更省步数。

在 Chrome 里怎么开

本地实验

  1. 使用具备 WebMCP 的 Chrome(flag 路径约需 ≥ 146.0.7672.0)。
  2. 打开 chrome://flags/#enable-webmcp-testingEnabled → 重启。
  3. 要在 DevTools 里调试工具列表与调用历史,再开 #devtools-webmcp-support
  4. 面向真实源、不想让用户开 flag:参加 WebMCP Origin Trial(文档写自 Chrome 149;Intent 窗口 149–156),用 <meta http-equiv="origin-trial">Origin-Trial 响应头挂 token。

环境约束(踩坑点)

  • 需要 secure context(HTTPS / localhost)与 origin-isolated 文档。若启用了会破坏源隔离的配置(例如与 document.domain / Origin-Agent-Cluster: ?0 相关),WebMCP API 会被关掉。
  • Permissions Policy 功能名是 tools,默认 self:同站可用,跨源 iframe 默认不能注册;需要时在 iframe 上写 allow="tools"
  • 工具执行依赖可见 browsing context——没有「无界面后台偷偷调网页工具」这条路径。

Imperative API:用 JS 注册工具

入口是 document.modelContext(旧的 navigator.modelContext 已走弃用路径,新代码别再用)。最小模式:

const modelContext = document.modelContext;
if (!modelContext || typeof modelContext.registerTool !== "function") {
  // 浏览器不支持或未开 flag:走无人机增强的普通 UI
  return;
}

await modelContext.registerTool({
  name: "get_order_status",
  description:
    "Search orders in a given timeframe. Returns order number, shipping status and location.",
  inputSchema: {
    type: "object",
    properties: {
      timeframe: {
        type: "string",
        enum: ["today", "yesterday", "last_7_days", "last_30_days"],
        description: "Timeframe for the order lookup.",
      },
    },
    required: ["timeframe"],
  },
  annotations: {
    readOnlyHint: true,
    untrustedContentHint: false,
  },
  execute: async ({ timeframe }) => {
    const status = await fetchOrderStatus(timeframe);
    // 返回清晰、可被模型消费的文本;过长易撞上 Agent 护栏
    return status;
  },
});

要点:

  • name / description / inputSchema / execute 是注册核心。
  • AbortSignal 注销(没有单独的 unregisterTool):SPA 换路由时在离开页面 abort。
  • annotations.readOnlyHint:只读工具,方便 Agent 决定要不要二次确认。
  • annotations.untrustedContentHint:返回 UGC / 外部数据时标上,降低间接 prompt injection 风险。

跨源共享时双闸:注册侧 exposedTo: ['https://trusted.example'],发现侧 getTools({ fromOrigins: ['https://partner.org'] })。只暴露给你愿意代用户行动的源。

框架侧已有实验封装:React 的 usewebmcp、Angular 也对 Signal Forms 做了 WebMCP 对接——仍属实验,跟 Chrome 版本一起看。

Declarative API:给表单贴注解

表单本来就是「结构化输入」。声明式 API 让浏览器把 <form> 合成工具:

<form
  toolname="createSupportRequest"
  tooldescription="Submits a request for customer support."
  action="/submit"
>
  <label for="firstName">First Name</label>
  <input type="text" name="firstName" id="firstName" />

  <label for="topic">Topic</label>
  <select
    name="topic"
    required
    toolparamdescription="Determines what team this request is routed to."
  >
    <option value="returns">Return my purchase.</option>
    <option value="shipping">Check where my package is.</option>
  </select>

  <button type="submit">Submit</button>
</form>

行为差异:

  • 没有 toolautosubmit:Agent 填完字段后,通常还要用户点提交——适合付款、发帖等敏感动作。
  • toolautosubmit:调用时可触发提交/导航。
  • 提交事件上有 agentInvoked;需要把结果回给模型时,先 preventDefault(),再 respondWith(promise)
  • 样式钩子::tool-form-active:tool-submit-active,让用户看见「Agent 正在操作这块」。

去掉 toolnametooldescription 即注销该声明式工具。

怎么验:Inspector 与 DevTools

  1. Model Context Tool Inspector 扩展:看已注册工具、手搓参数调用、用自然语言试 Agent(文档默认示例模型为 gemini-3-flash-preview)。
  2. DevTools → Application → WebMCP(Chrome 149+,需开调试 flag):Available Tools / Invoked Tools、schema 校验、手动 Run。
  3. 若用 Chrome DevTools for agents 自动化联调,需额外打开 WebMCP 相关 category(如 --category-experimental-webmcp),与「站点实现 WebMCP」是两条线。

官方 demo 可对照:WebMCP zaMaker、Travel(React)、Le Petit Bistro(声明式),源码在 GoogleChromeLabs/webmcp-tools

工具设计:少而准

抄官方 best practices 里最容易落地的几条:

  • 一个工具一件事;重叠工具会让模型选错。
  • 名称用动词表结果create-event vs start-event-creation-process(后者只是导航到表单)。
  • 描述用正向能力,少写「不要用于某某」。
  • Schema 宽松、代码里严格校验;错误信息写清楚,方便模型改参重试。
  • 字符预算(安全文档建议量级):描述约 500、参数描述约 150、名称约 30、单次输出约 1.5K——具体 Agent 会有差异。

安全:默认别给跨源、别信模型护栏

WebMCP 把能力交给 Agent,等价于多了一条「可编程操作面」。至少做到:

  • 跨源默认不暴露;exposedTo 白名单要短。
  • 写操作要用户可见、可取消;敏感流优先声明式 + 人手确认。
  • 返回不可信内容时打 untrustedContentHint
  • 假定 LLM 护栏挡不住间接 prompt injection——业务侧校验、鉴权、审计不能省。

什么时候还不该上

  • 需要无 UI / 纯后台的长期自动化 → 业务仍应走后端 MCP 或正规 API。
  • 工具要被未打开你网站的 Agent 随时调用 → WebMCP 发现不了。
  • 浏览器未开 flag / 未进 Origin Trial → 只能当增强,不能当唯一路径。

最小落地清单

  1. #enable-webmcp-testing(或 Origin Trial)。
  2. Feature detect 后注册 1~3 个高价值工具(搜索、填表、查状态)。
  3. 用 Inspector / Application → WebMCP 手测 schema 与错误返回。
  4. 敏感工具强制用户确认;只读工具标 readOnlyHint
  5. 后端能力继续放 MCP Server;页面上下文交互再叠 WebMCP。

一句话:WebMCP 让「当前打开的网页」成为浏览器 Agent 的可靠工具源;MCP 负责随时可达的业务后端。 两者一起用,而不是互相取代。

参考