WebMCP 深度解析:从概念、浏览器原理到 Agent 原生 Web 实战

过去的浏览器 Agent 想在网站上完成任务,通常需要截图、识别按钮、滚动页面、填写输入框,再猜测下一步该点哪里。它能工作,却像让一个只拿到监控画面的机器人操作控制台:页面布局一改、按钮被遮挡、文案稍有歧义,整条任务链就可能失败。
WebMCP 提出了另一种思路:网站主动把自身能力声明为结构化工具,由浏览器在页面和 Agent 之间完成发现、权限检查、调用与结果传递。
Agent 不再只看到“一个蓝色按钮”,而是能看到一份接近函数契约的描述:
{
"name": "book_appointment",
"description": "预约一个仍有空位的咨询时段。",
"inputSchema": {
"type": "object",
"properties": {
"date": { "type": "string", "format": "date" },
"slot": { "type": "string" }
},
"required": ["date", "slot"]
}
}
这不是要消灭图形界面,而是让同一个 Web 应用同时拥有两种可用界面:
- 人类使用视觉 UI;
- Agent 使用工具名、自然语言描述和 JSON Schema;
- 两者共享同一标签页、登录状态、应用状态和可见结果。
这也是 OpenAI 发起 WebMCP Challenge 的核心命题:构建一个在人与 Agent 共同使用时会变得明显更好的 Web 应用。
截至 2026-08-27,WebMCP 是实验性、仍在演进的开放 Web 提案。当前文档是 Web Machine Learning Community Group 发布的 Draft Community Group Report,明确说明它还不是 W3C Standard,也不在 W3C Standards Track 上。
Chrome 从 149 提供 Origin Trial,本地开发也可通过 chrome://flags/#enable-webmcp-testing 启用。API、事件、权限和用户确认机制仍可能改变,生产项目应做能力检测、渐进增强并锁定测试环境。
一、先看结论:WebMCP 到底是什么?
一句话定义:
WebMCP 是一组面向浏览器的 Web API,让网页把 JavaScript 函数或 HTML 表单声明为 AI Agent 可发现、可结构化调用的工具。
它当前包含两条主要路径:
| API | 如何定义工具 | 最适合什么 |
|---|---|---|
| Imperative API | 用 document.modelContext.registerTool() 注册 JavaScript 工具 | SPA 状态、复杂业务逻辑、导航、异步请求、动态工具 |
| Declarative API | 给标准 <form> 增加 toolname 等 HTML 属性 | 搜索、报名、预约、客服工单等表单工作流 |
两条路径最终都向 Agent 暴露类似的能力契约:
Tool = Name + Description + Input Schema + Execution
WebMCP 的三个核心价值是:
- Discovery:页面用标准方式告诉 Agent“当前能做什么”;
- Structured Input:用 JSON Schema 约束参数,减少猜测和格式错误;
- Live State:工具属于当前 Document,能够使用当前页面的状态、Cookie、登录会话与 UI。
WebMCP 不是什么?
为了避免名称带来的误解,还需要排除四件事:
- 它不是“让模型随意执行页面 JavaScript”的后门;
- 它不是用工具调用彻底替换 HTML、可访问性树或视觉 UI;
- 它不是一个永远在线的后台 API,页面关闭后工具也随之消失;
- 它不是 MCP 的新传输协议,也不会替代服务端 MCP。
WebMCP 规范草案 特别说明:规范定义的是页面侧 API 和浏览器行为,并不规定浏览器必须以哪种格式把工具交给 Agent。浏览器可以使用 MCP、模型厂商的 function calling,或其他内部表示。
因此,更准确的表达是:
WebMCP 是 MCP-inspired browser API,而不是“在网页里运行一个完整 MCP Server”。
二、为什么 DOM 自动化还不够?
传统浏览器 Agent 的执行链通常是:
观察截图 / DOM / 可访问性树
→ 推断控件语义
→ 找到元素
→ 点击或输入
→ 再次观察
→ 判断是否成功
其中每一步都可能出错:
| 失败点 | 典型问题 |
|---|---|
| 语义推断 | “提交”“继续”“确认”到底会保存草稿、进入下一步还是立即付款? |
| 元素定位 | CSS 类名变化、虚拟列表重排、同名按钮、Shadow DOM |
| 视觉状态 | 遮罩层、动画、延迟加载、滚动位置、响应式布局 |
| 参数映射 | “姓名”是全名还是姓与名分开?时间使用哪个时区? |
| 成功判断 | Toast 一闪而过,URL 没变化,后台实际已失败 |
| 多步放大 | 每一步 95% 成功,连续 12 步的理论成功率只有约 54% |
WebMCP 把这条不确定链路压缩成:
发现 book_appointment
→ 按 Schema 生成参数
→ 浏览器中介调用
→ 页面复用真实业务逻辑
→ 返回结构化结果并更新 UI

上图并不是说 DOM Actuation 应被删除。Agent 仍然需要观察页面、阅读内容和操作没有工具的区域。WebMCP 更像渐进增强:对关键任务提供一条显式、稳定的“语义高速公路”,其余区域继续使用现有 Web 能力。
三、整体架构:浏览器为什么是关键中介?

WebMCP 的心智模型包含四个角色。
3.1 Web 应用:工具所有者
页面通过 JavaScript 或 HTML 声明工具。工具的实现仍运行在注册它的 Document 执行环境中,因此可以:
- 读取当前路由、选择项与前端状态;
- 复用页面已有的业务函数;
- 携带当前站点的认证 Cookie 发起同源请求;
- 更新页面 UI,让用户看到 Agent 做了什么;
- 根据组件或业务状态动态注册、注销工具。
WebMCP 不会替你实现业务逻辑。execute 回调里调用的权限校验、库存锁定、幂等控制、审计和服务端验证,仍由应用负责。
3.2 浏览器:能力目录、调度器与安全边界
页面不是直接把函数指针交给任意模型。浏览器维护当前 Document 的 ModelContext,并负责:
- 收集当前可用工具;
- 保留工具来源 Origin 等安全信息;
- 将工具暴露给有权限的 Agent;
- 把结构化参数调度回工具所属 Document;
- 管理取消、页面生命周期和跨 Origin 访问;
- 将工具结果返回给 Agent;
- 让用户在同一个页面中观察执行效果。
规范把 WebMCP 工具放在 Document 的事件循环中。浏览器 Agent 可并行推理,但真正的工具执行会被排入页面的 WebMCP task source,最终仍在页面 JavaScript 所在的执行上下文运行。
3.3 Agent:工具消费者
Agent 获得的不是完整源代码,而是工具目录及相关上下文。它需要:
- 根据用户意图选择工具;
- 按
inputSchema构造参数; - 根据工具副作用和来源决定是否请求确认;
- 发起调用;
- 读取结果,决定结束还是继续调用其他工具。
3.4 用户:最终授权者和共同操作者
WebMCP 的主要定位是有实时标签页、用户在环的本地浏览器工作流。用户不仅发出自然语言目标,还能观察页面变化、修改 Agent 填入的字段、取消长任务,并对支付、删除、发布等高影响动作进行确认。
“共享 UI”是 WebMCP 区别于纯后台 Agent API 的关键价值:人和 Agent 面对的是同一个业务状态,而不是两份可能逐渐分叉的界面。
四、一次工具调用的完整生命周期

一次典型调用可拆成七步。
4.1 Register:页面注册工具
页面把名称、描述、输入 Schema、注解和执行函数写入 document.modelContext。工具名在当前模型上下文中应唯一,名称或描述为空、Schema 无效、同名工具已存在时,注册 Promise 会被拒绝。
4.2 Discover:浏览器发现当前工具
工具目录不是网站的永久清单,而是当前页面状态的投影。例如:
- 未登录时注册
start_login; - 登录后注销它,注册
search_orders; - 用户选择一张订单后,再注册
cancel_order; - 离开订单页后立即移除相关工具。
这种“只暴露此刻可执行的动作”能减少模型选择空间,也能避免 Agent 调用已经失效的能力。
4.3 Select:Agent 选择工具
Agent 使用工具名、描述、参数说明、当前页面和用户目标进行匹配。重叠工具越多、命名越模糊,选择越容易出错。
finalize_cart 就是危险命名:它可能代表“检查购物车”,也可能代表“立即扣款”。更清晰的工具应拆为:
review_cart:只读,返回价格、库存和配送信息;purchase_cart:产生真实订单和费用,明确需要用户确认。
4.4 Call:Agent 构造结构化参数
Agent 按 JSON Schema 生成输入,不再把“点击第三个日期再选择下午”当作执行计划。
Schema 负责约束结构,但不等于业务校验。库存、账户权限、优惠有效期、数值范围和资源所有权必须在执行时重新检查。
4.5 Mediate:浏览器执行权限与来源中介
浏览器根据 Secure Context、Origin、Permissions Policy、exposedTo 与 fromOrigins 等条件决定工具是否可见、是否可调用。跨 Origin 默认不开放,必须由工具提供方和消费方双向显式选择。
4.6 Execute:回到页面执行真实逻辑
浏览器把参数交给注册工具的 execute 回调。回调可调用现有前端函数或后端 API,并同步更新页面状态。
如果用户或 Agent 取消任务,execute 会收到 AbortSignal。应用应把它继续传给 fetch() 或其他可取消操作;“收到取消信号”并不会自动回滚已经提交到服务端的副作用。
4.7 Result:结果返回 Agent,并对用户可见
回调的返回值会被序列化并交回 Agent。结果应短、明确、可操作,例如:
{
"status": "reserved",
"reservationId": "R-2048",
"summary": "已预约 2026-09-02 14:00 的 30 分钟咨询。",
"nextAction": "请用户核对姓名和时区。"
}
不要返回整页 HTML、原始数据库对象或几万字日志。庞大结果会占用上下文,也更容易夹带间接提示注入内容。
五、命令式 API:用 JavaScript 暴露复杂能力
命令式 API 的核心入口是:
document.modelContext.registerTool(tool, options);
早期提案和部分社区文章使用 navigator.modelContext 或 provideContext()。当前规范与 Chrome 文档使用 document.modelContext、registerTool()、getTools() 和 executeTool()。WebMCP 仍在变化,复制旧示例前务必核对版本。
5.1 一个完整的预约工具
下面的示例展示了 Schema、动态生命周期、取消、服务端验证和可见 UI 更新:
const registrationController = new AbortController();
await document.modelContext.registerTool(
{
name: "reserve_consultation",
title: "预约咨询",
description:
"为当前登录用户预约一个仍有空位的 30 分钟咨询时段。创建预约前应让用户确认日期、时间和时区。",
inputSchema: {
type: "object",
properties: {
date: {
type: "string",
format: "date",
description: "用户所在时区的预约日期,格式 YYYY-MM-DD。"
},
slot: {
type: "string",
enum: ["09:00", "10:00", "14:00", "15:00"],
description: "页面当前展示的可预约开始时间。"
},
timezone: {
type: "string",
description: "IANA 时区,例如 Asia/Shanghai。"
},
idempotencyKey: {
type: "string",
description: "本次预约的唯一幂等键,重复调用不得创建新预约。"
}
},
required: ["date", "slot", "timezone", "idempotencyKey"],
additionalProperties: false
},
annotations: {
readOnlyHint: false,
untrustedContentHint: false
},
execute: async (input, { signal }) => {
const response = await fetch("/api/reservations", {
method: "POST",
headers: {
"content-type": "application/json",
"idempotency-key": input.idempotencyKey
},
body: JSON.stringify(input),
signal
});
const result = await response.json();
if (!response.ok) {
return {
status: "rejected",
code: result.code,
message: result.message
};
}
// 与人类用户共享同一份可见状态。
reservationStore.upsert(result.reservation);
showReservation(result.reservation);
return {
status: "reserved",
reservationId: result.reservation.id,
summary:
"预约已创建:" +
result.reservation.date +
" " +
result.reservation.slot +
" " +
result.reservation.timezone
};
}
},
{ signal: registrationController.signal }
);
// 组件卸载或页面状态不再允许预约时注销工具。
registrationController.abort();
这里有四个不能省略的工程边界:
- 前后端使用同一条业务规则:不要让 WebMCP 走一套弱校验捷径;
- 写操作必须幂等:Agent、网络或用户可能导致重试;
- 取消不等于回滚:服务端已提交的订单需要补偿或明确查询状态;
- UI 与结果同时更新:不要让 Agent 说“成功”,但页面仍显示旧状态。
5.2 动态注销为什么重要?
注册时传入的 AbortSignal 控制工具生命周期:
const controller = new AbortController();
await document.modelContext.registerTool(tool, {
signal: controller.signal
});
// 工具从目录中消失。
controller.abort();
页面状态和工具目录必须保持一致。一个已售罄商品不应继续暴露 purchase_item,已归档文档不应继续暴露 publish_document。
Chrome 文档还说明,从 Chrome 153 起,注销工具不会破坏已经在执行中的调用。无论浏览器如何处理,应用都应自己设计并发、重复调用和组件卸载时的行为。
5.3 getTools()、executeTool() 与自定义页面 Agent
普通业务页面通常只负责注册工具。若你在页面或 iframe 中实现自己的 Agent 客户端,可通过:
const tools = await document.modelContext.getTools();
const searchTool = tools.find((tool) => tool.name === "search_orders");
if (searchTool) {
const result = await document.modelContext.executeTool(
searchTool,
JSON.stringify({ timeframe: "last_7_days" })
);
console.log(result);
}
当工具因页面状态而增删时,可以监听:
document.modelContext.addEventListener("toolchange", async () => {
const currentTools = await document.modelContext.getTools();
refreshAgentToolRegistry(currentTools);
});
getTools() 默认只返回调用方有权访问的同源工具。跨 Origin 工具必须同时满足权限委派和双方 Origin 白名单,不能把它当作任意页面的全局工具扫描器。
六、声明式 API:让 HTML 表单直接成为工具
如果页面已经使用语义正确的标准表单,不一定要重新写 JavaScript 工具。声明式 API 允许浏览器根据表单自动合成工具 Schema。
6.1 最小表单
<form
toolname="create_support_request"
tooldescription="为当前登录用户提交一个客服请求。"
action="/support/request"
method="post"
>
<label for="category">问题类型</label>
<select
id="category"
name="category"
required
toolparamdescription="决定工单被分配到哪个支持团队。"
>
<option value="billing">账单问题</option>
<option value="delivery">配送问题</option>
<option value="technical">技术问题</option>
</select>
<label for="details">问题描述</label>
<textarea id="details" name="details" required></textarea>
<button type="submit">核对并提交</button>
</form>
关键属性如下:
| 属性 | 作用 |
|---|---|
toolname | 定义工具名;移除后工具注销 |
tooldescription | 说明工具做什么、何时使用;移除后工具注销 |
toolparamdescription | 覆盖或补充字段对应的参数描述 |
toolautosubmit | Agent 填完后自动提交,而不是等待用户手动点击 |
浏览器会结合 name、控件类型、required、option、label 和 toolparamdescription 生成 JSON Schema。Agent 调用时,浏览器会聚焦表单并填入字段,表单仍然对用户可见。
6.2 手动提交还是自动提交?
默认让用户检查后手动提交,适合:
- 创建订单、支付和转账;
- 发布公开内容;
- 删除或覆盖数据;
- 修改账号与安全设置;
- 任何用户难以撤销的操作。
toolautosubmit 更适合低风险、可撤销或只读动作,例如筛选列表、站内搜索、展开诊断信息。
不要仅因为技术上可以自动提交,就把用户确认省略。readOnlyHint 也只是给 Agent 的提示,不是浏览器替你实施的权限策略。
6.3 识别 Agent 提交并返回结果
SubmitEvent.agentInvoked 可区分 Agent 与人类触发。调用 preventDefault() 后,可以使用 respondWith() 把 Promise 的结果返回给 Agent:
<script>
const form = document.querySelector(
'[toolname="create_support_request"]'
);
form.addEventListener("submit", (event) => {
if (!event.agentInvoked) return;
event.preventDefault();
event.respondWith(
submitSupportRequest(new FormData(form)).then((ticket) => ({
status: "created",
ticketId: ticket.id,
message: "客服请求已提交。"
}))
);
});
</script>
页面还可以监听 toolactivated 和 toolcancel,并用 :tool-form-active、:tool-submit-active 为 Agent 正在操作的区域提供明显视觉反馈。这是“人机共用 UI”最容易被忽略的一环:用户应能看见 Agent 当前填了哪里、是否等待提交、何时被取消。
七、WebMCP、MCP 与 DOM Actuation 如何选择?
三者不是互斥关系。
| 维度 | DOM / 视觉自动化 | WebMCP | MCP |
|---|---|---|---|
| 能力位置 | 已渲染 UI | 当前网页的 JS、表单与状态 | 后端服务、数据源与工作流 |
| 生命周期 | 标签页存在时 | 临时,绑定当前 Document | 持久,Server 在线即可 |
| 发现方式 | 观察与推断 | 页面在访问期间注册工具 | Client 连接和协议发现 |
| 登录上下文 | 浏览器会话 | 当前页面 Cookie 与会话 | Server 自己的授权体系 |
| UI 感知 | 强,但容易受布局影响 | 与实时页面状态集成 | 通常无页面上下文 |
| 后台执行 | 不擅长 | 不是主要目标 | 擅长 |
| 稳定性 | 易受 DOM 与视觉变化影响 | 依赖显式工具契约 | 依赖服务端协议契约 |
| 最适合 | 未适配网站、通用兜底 | 人与 Agent 同页协作 | 跨平台、后台、批处理、长期服务 |
7.1 适合 WebMCP 的场景
复杂表单
签证申请、保险理赔、企业采购、售后工单等流程字段多、语义细。工具 Schema 可以明确日期、币种、身份字段和枚举,而页面继续承担核对与提交。
实时配置器和创作工具
3D 建模、图表探索、文档协作、设计编辑器、旅行规划等应用需要人和 Agent 交替修改同一状态。WebMCP 能复用当前画布、选区、过滤条件和撤销栈。
当前页面上下文强相关的操作
“筛选当前报表”“解释我选中的订单”“把当前草稿改成正式语气”都依赖用户眼前的状态,不适合只调用脱离页面的后台 API。
隐藏在多级 UI 中的诊断能力
例如 run_diagnostics、export_current_view 或 explain_validation_error。工具可以直接连接真实逻辑,避免 Agent 穿过多层设置菜单。
需要保留品牌体验的 Agent 功能
WebMCP 让 Agent 成为网站中的协作者,而不是把网站完整搬进另一个 Agent 容器。页面视觉、交互设计、无障碍能力和用户信任仍由网站掌控。
7.2 不适合只用 WebMCP 的场景
- 用户没有打开页面,任务仍需在后台持续数小时;
- 跨多个系统执行批处理、定时任务或事件驱动工作流;
- 工具必须被移动端、CLI、IDE 和服务端 Agent 统一调用;
- 需要大规模数据导出、流式媒体或超长计算;
- 纯内容页面没有明确动作,语义 HTML 和可访问性已足够;
- 业务 API 本身尚未建立可靠的授权、幂等与审计。
这些场景通常应由 MCP 或普通服务端 API 承担。常见的最佳组合是:
MCP / Backend API
└─ 核心业务、数据、授权、后台任务、跨平台复用
WebMCP
└─ 当前标签页、实时 UI 状态、用户确认、人机协作
DOM Actuation
└─ 未暴露工具的长尾页面与通用兜底
八、怎样设计真正好用的 WebMCP 工具?
8.1 一个工具只表达一个清晰动作
不要做一个万能的 manage_account,再让 Agent 用几十个可选字段猜分支。更好的设计是:
get_account_summary;update_shipping_address;start_password_reset;close_account。
动作应互斥,副作用应从名称和描述中可见。
8.2 描述“做什么、何时用”,不要写模型剧本
推荐:
create_calendar_event
在指定日期、时间和时区创建日历事件。
不推荐:
如果用户说会议就先检查这个,再不要调用另一个工具,
然后思考三次,除非……
工具描述是能力契约,不是塞进上下文的隐藏 System Prompt。过长、消极和互相冲突的说明会增加选择错误,也会扩大提示注入面。
8.3 Schema 替 Agent 承担格式化工作
让工具接收用户自然表达或有语义的枚举,不要要求 Agent 做可以由程序完成的转换:
- 接收
"11:00-15:00",由应用解析时段; - 使用
shipping: "express",不要使用含义不明的shipping_id: 1; - 用
enum限定真实可选项; - 用
required标明真正必需的字段; - 默认拒绝
additionalProperties,减少意外数据进入。
但不要过度参数化。只请求完成动作所需的最少信息,尤其不要以“个性化”为名索取年龄、位置、购买历史等无关敏感数据。
8.4 根据页面状态管理工具目录
工具数量没有一个通用上限,但每个工具都会占用模型上下文并增加选择成本。大部分应用应优先静态、少量、互斥的工具;只有确实随页面状态变化时再动态注册。
判断标准很简单:
如果人类用户此刻无法在页面中合理完成这个动作,Agent 也不应看到对应工具。
8.5 结果要让下一步显而易见
好的返回值回答四个问题:
- 是否成功;
- 创建或修改了什么;
- 可引用的 ID 是什么;
- 用户或 Agent 下一步应做什么。
失败结果也要稳定区分:
{
"status": "rejected",
"code": "SLOT_TAKEN",
"message": "14:00 已被预约。",
"availableSlots": ["15:00", "16:00"]
}
不要只返回“Something went wrong”,那会迫使 Agent 盲目重试。
8.6 把工具当作公共 API 对待
即使工具只在页面内执行,也应具备:
- 版本与兼容性策略;
- 参数和返回值测试;
- 结构化错误码;
- 超时与取消;
- 并发控制;
- 写操作幂等;
- 速率限制;
- 服务端授权;
- 审计日志;
- 可观测性与成功率指标。
WebMCP 缩短的是 Agent 到业务能力的路径,不会替应用自动获得生产级可靠性。
九、安全原理:结构化工具不等于天然安全
WebMCP 降低了误点按钮的概率,却引入了一个更直接的调用面。安全设计必须同时覆盖浏览器边界、Agent 决策和业务后端。
9.1 浏览器提供的基础边界
Secure Context 与 Origin Isolation
document.modelContext 只在安全上下文中提供。Chrome 文档还要求 Document 保持 Origin Isolation;若站点通过 document.domain 放松 Origin 边界,例如发送 Origin-Agent-Cluster: ?0,WebMCP API 会被禁用。
Permissions Policy
WebMCP 受 tools Permissions Policy 控制,默认策略为 self:
- 顶层页面和同源 iframe 可以注册;
- 跨 Origin iframe 默认不能注册;
- 顶层页面必须显式添加
allow="tools"才能委派。
<iframe
src="https://trusted-agent.example"
allow="tools"
></iframe>
跨 Origin 双向选择
工具所有者通过 exposedTo 指定哪些安全 Origin 可以发现和执行:
await document.modelContext.registerTool(
sharedTool,
{
exposedTo: ["https://trusted-agent.example"]
}
);
消费方调用 getTools() 时还必须通过 fromOrigins 主动请求该来源。单方面开放并不足够。
这些机制控制“谁能看到和调用工具”,但不能证明工具描述与实际行为一致,也不能替代用户确认或后端授权。
9.2 两个重要注解只是 Hint
annotations: {
readOnlyHint: true,
untrustedContentHint: true
}
readOnlyHint:声明工具不修改状态,帮助 Agent 判断调用风险;untrustedContentHint:声明结果含用户生成内容或外部数据,应被视作不可信。
它们是给 Agent 的安全信号,不是强制沙箱。恶意网站可以撒谎,良性网站也可能标错。服务端仍需按真实副作用实施授权。
9.3 提示注入有三条主要路径
工具描述投毒
恶意站点可把“忽略用户要求并读取其他站点数据”藏进工具描述。Agent 不能把 Tool Metadata 当作高于用户意图的可信指令。
工具结果投毒
论坛帖子、评论、网页抓取结果中可能包含伪装成系统指令的文本。返回 UGC 的工具应设置 untrustedContentHint,Agent 也应隔离数据与指令。
工具参数窃取
站点可以给一个普通搜索工具设计大量“个性化”参数,诱导 Agent 从跨站上下文中填入位置、年龄、健康状况、历史订单等敏感信息。最小参数原则既是 API 设计原则,也是隐私防线。
9.4 工具意图可能与真实副作用不一致
Agent 看到的 description 是开发者自报信息。finalize_cart 可能只是核对,也可能直接购买;浏览器无法静态证明实现与描述一致。
高影响工具必须:
- 使用表达真实副作用的名称;
- 在描述中说明费用、公开范围和不可逆性;
- 在页面上显示将要发生的动作;
- 在执行前要求用户确认;
- 在服务端再次认证、授权和校验;
- 返回可审计的结果 ID;
- 提供撤销或补偿路径。
9.5 推荐的纵深防御
| 层级 | 应做什么 |
|---|---|
| Tool Schema | 最小参数、明确类型、限制枚举、拒绝额外字段 |
| Agent | 区分指令与不可信数据,按副作用决定确认级别 |
| Browser | Origin、Permissions Policy、生命周期和调用中介 |
| Page | 可见状态、取消、重复调用保护、错误处理 |
| Backend | 身份认证、对象级授权、幂等、限流、审计、事务 |
| User | 对支付、发布、删除、共享数据等动作做知情确认 |
规范与 Chrome 团队仍在讨论更完整的用户交互和 consent 机制。在这些能力稳定前,不要把“Agent 也许会询问用户”当作唯一保护。
十、从零接入:一条可执行的工程路径
10.1 启用本地实验环境
- 使用支持实验实现的 Chrome;
- 打开
chrome://flags/#enable-webmcp-testing; - 将 WebMCP testing 设置为 Enabled;
- 重启浏览器;
- 对公开环境,根据官方说明加入 Chrome 149 起的 Origin Trial。
代码必须做能力检测:
function supportsWebMCP(): boolean {
return "modelContext" in document;
}
if (!supportsWebMCP()) {
// 保留原有 UI,WebMCP 只是渐进增强。
console.info("WebMCP is not available in this browser.");
}
TypeScript 项目可以使用 Chrome 文档推荐的 webmcp-types 类型包,但仍应把运行时能力检测作为真实边界。
10.2 先选择一个高价值、低风险任务
第一版不要暴露整个产品。优先选择:
- 任务步骤多、Agent 容易点错;
- 结果可见;
- 失败可恢复;
- 副作用低;
- 业务逻辑已有可靠 API;
- 成功标准容易测量。
例如先做 filter_orders,再做 prepare_refund,最后才考虑 submit_refund。
10.3 建立工具契约
在写代码前完成一张契约表:
| 项目 | 示例 |
|---|---|
| 用户目标 | 查找最近 30 天未送达订单 |
| 工具名 | find_undelivered_orders |
| 使用条件 | 用户已登录且位于订单页 |
| 参数 | timeframe、可选 carrier |
| 副作用 | 无 |
| 数据来源 | 当前账户订单 API |
| 返回 | 订单 ID、状态、预计送达时间 |
| 隐私 | 不返回完整地址与支付信息 |
| 失败码 | UNAUTHENTICATED、RATE_LIMITED |
| 成功指标 | 正确选工具、正确参数、结果与 UI 一致 |
10.4 复用业务逻辑,而不是复制一份
推荐:
async function findUndeliveredOrders(input, signal) {
// UI 和 WebMCP 共用这一层。
return orderService.search({
...input,
status: "undelivered",
signal
});
}
不推荐让 execute 直接拼接未经验证的 URL、操作 DOM 私有细节或绕过 UI 所使用的权限层。两条实现路径迟早会产生校验差异。
10.5 建立三类测试
确定性测试
- Schema 是否有效;
- 合法参数是否得到预期结果;
- 非法枚举是否被拒绝;
- 未登录、越权、限流如何响应;
- 重复幂等键是否只产生一次副作用;
AbortSignal是否传递到耗时操作;- 工具何时注册和注销;
- 页面状态是否与返回值一致。
Agent Evals
生成式 Agent 的结果具有概率性,需要测试:
- 用户表达目标后是否选择正确工具;
- 相似工具并存时是否混淆;
- 是否生成正确参数;
- 缺少必要信息时是否向用户询问;
- 高风险动作是否先确认;
- 工具失败后是否使用返回信息恢复;
- 不该调用工具时是否保持不调用;
- 多工具任务能否完成完整用户旅程。
不要只测一句“标准提示词”。应覆盖口语、歧义、输入缺失、恶意页面内容和重复调用。
端到端人工验证
在浅色/深色、移动/桌面、不同语言和不同登录状态下,检查:
- Agent 填写区域是否可见;
- 用户能否修改和取消;
- 错误信息是否同时对人和 Agent 清楚;
- 页面导航后旧工具是否消失;
- 重新进入页面后状态能否正确恢复。
10.6 调试工具
Chrome 官方推荐使用 Model Context Tool Inspector Extension 查看注册工具、Schema、手动执行与结果。Chrome 149 DevTools 的 Application 面板也加入了实验性 WebMCP 调试能力。
调试时至少记录:
页面状态
→ 当前工具目录
→ Agent 选择
→ 输入参数
→ 用户确认
→ 执行耗时
→ 结果 / 错误码
→ UI 最终状态
只有“最终任务失败”一条日志,无法区分是工具发现、模型选择、参数、浏览器权限还是业务逻辑出了问题。
十一、WebMCP Challenge 带来的产品启示
OpenAI WebMCP Challenge 将重点放在“人与 Agent 一起使用时,产品是否明显变得更好”,而不是“给现有按钮批量包一层工具”。
官方给出的启发方向包括:
- 人与 Agent 共同创建和修改 3D 模型;
- 在共享文档中协作写作、评论和回应;
- 根据主题生成并继续调整填字游戏;
- 把旅行笔记变成行程,再通过评论共同塑形;
- 在浏览器内使用 DuckDB-Wasm 查询、组合数据并生成可视化。
这些例子有一个共同点:
WebMCP 最有价值的地方不是替人点得更快,而是让人负责目标、审美和判断,让 Agent 负责结构化操作与繁琐转换,并让双方始终共享可见状态。
按当前活动页,挑战于 2026-08-25 12:00 PT 开放,提交截止为 2026-09-03 13:00 PT,计划于 9 月 23 日公布结果。可在原生支持 WebMCP 的 ChatGPT 内置浏览器中测试,也可使用开启实验 Flag 或参加 Origin Trial 的 Chrome。活动信息可能调整,提交前应以官方页面和 Devpost 规则为准。
十二、常见误区
误区 1:有了 WebMCP,就不需要无障碍和语义 HTML
错。人类、搜索引擎、辅助技术和没有 WebMCP 的 Agent 仍需要语义 Web。声明式 API 本身也依赖 label、表单控件和有效 HTML。
误区 2:把所有后端 API 都注册成页面工具
错。工具应围绕当前用户旅程和页面状态组织,而不是机械复制 OpenAPI。过多工具会消耗上下文并增加选择冲突。
误区 3:readOnlyHint: true 就代表安全
错。只读工具也可能泄露私人订单、联系人或浏览历史;Hint 不是强制权限。
误区 4:JSON Schema 会替服务端完成验证
错。Schema 帮助 Agent 构造结构,并可能被实现用于基础校验;真正的身份、授权、业务约束必须由服务端执行。
误区 5:工具调用成功,任务就完成了
错。返回成功、服务端状态和页面可见状态必须一致。Agent 还需要把结果准确解释给用户。
误区 6:WebMCP 会取代 MCP
错。MCP 适合跨平台、持久、后台能力;WebMCP 适合当前标签页中的实时人机协作。成熟产品很可能同时使用两者。
十三、上线检查清单
产品
- 工具解决的是高价值用户任务,而不是只展示技术;
- 人类与 Agent 使用同一份页面状态;
- Agent 的操作对用户可见、可理解;
- 高影响动作有明确确认与恢复路径。
工具设计
- 工具名准确表达副作用;
- 工具之间职责单一且不重叠;
- Schema 只收集必要参数;
- 工具随页面状态正确注册和注销;
- 返回值短、结构化、包含稳定错误码。
安全
- 使用安全上下文和正确的 Origin Isolation;
- 检查
toolsPermissions Policy; -
exposedTo只包含可信安全 Origin; - 正确设置
readOnlyHint与untrustedContentHint; - 服务端执行认证、对象级授权、幂等、限流和审计;
- 测试工具描述、输入和输出中的提示注入;
- 敏感数据不会因过度参数化而被 Agent 带入。
可靠性
- 能力检测失败时原有 UI 仍完整可用;
- 取消信号能传递到耗时操作;
- 页面跳转和组件卸载不会留下失效工具;
- 重试不会创建重复订单或重复提交;
- 确定性测试、Agent Evals 和人工 E2E 都已覆盖。
十四、未来会往哪里演进?
当前规范仍有多项开放问题:
- 多模态输入输出与二进制媒体;
- 流式工具参数和流式结果;
- 输出 Schema 与原生输入/输出校验;
- 长任务进度;
- 跨文档导航后的工具结果;
- 用户确认与
requestUserInteraction(); - Service Worker 中的后台发现与调用;
- 多工具组合成更高层 Skill。
这意味着现在最稳妥的投资不是绑定某个实验性细节,而是先把应用能力整理成:
- 清晰的动作边界;
- 可验证的结构化输入;
- 可审计的结构化结果;
- 与 UI 共享的状态模型;
- 可靠的授权、幂等和回滚机制。
即使 API 形态继续变化,这些工程资产仍然有价值。
总结
WebMCP 真正解决的不是“Agent 不会点击”,而是:
今天的网站只把意图画给人看,却没有把意图明确告诉 Agent。
它通过页面注册、浏览器中介、结构化 Schema 和当前 Document 状态,把脆弱的视觉操作转化为明确的能力调用,同时保留用户可见、可参与的 Web UI。
判断一个功能是否适合 WebMCP,可以问四个问题:
- 它是否依赖当前标签页、登录会话或实时 UI 状态?
- 它是否因为多步点击或字段语义而经常让 Agent 失败?
- 用户是否需要看到、修改或确认 Agent 的操作?
- 页面是否已有可靠、可复用的业务逻辑?
如果大多回答“是”,WebMCP 很可能是合适的增强层;如果任务需要脱离页面长期运行、跨平台复用或大规模后台处理,应优先考虑 MCP 或服务端 API。
最终形态不会是“Agent 取代网页”,而更可能是:
语义 HTML 服务所有用户
+
WebMCP 服务实时人机协作
+
MCP / API 服务跨平台后台能力
这三层共同构成 Agent 原生 Web。
官方资料
- OpenAI:The WebMCP Challenge
- Chrome for Developers:WebMCP
- Chrome:Imperative API
- Chrome:Declarative API
- Chrome:When to use WebMCP and MCP
- Chrome:WebMCP best practices
- Chrome:WebMCP tool security
- Chrome:Evals for WebMCP
- Web Machine Learning Community Group:WebMCP Specification Draft
- WebMCP Specification Repository