WebMCP — 架构与原理
30 秒导读: WebMCP 是一个 W3C 草案,给浏览器加一个新 JS 接口
document.modelContext。网页用它把自己的客户端功能(一个 JS 函数,或一个<form>)登记成带自然语言描述的「工具」,浏览器里的 AI agent 就能像调用后端 MCP server 那样直接调用它们——而不是靠看截图、读 DOM、模拟鼠标点击去操作页面。
1. 这是什么(零基础也能懂)
一句话定义: WebMCP 让网页把「网页能做的事」(发起搜索、加购物车、筛选模板……)以工具的形式暴露给浏览器里的 AI agent,让 agent 直接调函数,而不是模拟人去点界面。
它解决谁的什么问题。 想象你在浏览器里对内置的 AI 助手说「把这几件衣服筛成适合婚礼的」。今天的 agent 只能:截图看页面 → 猜哪个是筛选框 → 模拟点击和输入。这套又慢又脆,页面一改版就崩。WebMCP 让网站作者主动登记一个 filter-products 工具,agent 直接调它,又快又稳。
它和「后端 MCP / API 集成」有什么不同。 这是理解 WebMCP 的关键一刀。两者都叫「工具」,但运行位置完全不同:
| 维度 | 后端集成(传统 MCP / OpenAPI) | WebMCP(本项目) |
|---|---|---|
| 工具跑在哪 | 服务方的后端服务器 | 用户浏览器里正在跑的那个页面 |
| 谁写 | 要单独写一个 MCP server | 复用页面已有的客户端 JS |
| 用户状态/登录 | 要在服务器上重新复刻一份 | 天然复用页面里的 cookie、登录态、UI 状态 |
| 网页 UI | 被绕过(disintermediation) | 仍是主角,agent 与人共享同一界面 |
这张对照表里的动机直接来自 README 的 “Backend Integrations vs. In-browser WebMCP Tools” 一节(README.md:11-23):后端集成的三大痛点是 UI 被绕过、状态/鉴权要重复搭、开发者负担重;WebMCP 用「工具就活在页面脚本里」来消除这三点。
用起来什么样。 网站作者写这么一段就登记了一个工具(这是 README 的真实示例,README.md:263-290):
await document.modelContext.registerTool({
name: "add-todo",
description: "Add a new item to the user's active todo list",
inputSchema: {
type: "object",
properties: { text: { type: "string", description: "The text content of the todo item" } },
required: ["text"]
},
async execute({ text }) {
await addTodoItemToCollection(text); // 复用页面已有的客户端逻辑
return { content: [{ type: "text", text: `Added todo item: "${text}".` }] };
}
});
注意 execute 里调的 addTodoItemToCollection 就是页面本来就有的函数——这正是 WebMCP 反复强调的「代码复用」目标(README.md:87)。
一句话直觉/类比。 把每个网页想成一个就地的 MCP server:不在云端,而在你这个标签页里;它登记的工具操作的是 DOM 和客户端逻辑,而不是远程数据库(index.bs:107-109)。
它现在处于什么阶段(重要,别误会)。 WebMCP 不是已上线的产品,而是 W3C Web Machine Learning 社区组的早期草案(index.bs:1-12,状态 CG-DRAFT)。规范里大量内容明确标着 TODO/TBD:声明式表单的 schema 合成算法只是占位(index.bs:563-570)、工具发现 API getTools()/executeTool() 还没定(README.md:344-345)。本系列文档讲的是这套设计的原理与已写下的部分,会逐处标出哪些还是空的。
2. 顶层全景(它大概怎么转)
WebMCP 由「网页一侧的登记 API」和「浏览器一侧的调用机制」两半组成,中间隔着浏览器这个中介人(mediator)。先看一次完整交互的数据流:
怎么读这张图:左边是网站作者的事(登记 + 实现),中间是浏览器替双方做的中介(存工具、给 agent 快照、转发调用),右边是 agent。网页脚本和 agent 从不直接说话——所有调用都过浏览器。
部件一句话职责:
| 部件 | 干什么 | 在哪 |
|---|---|---|
document.modelContext | 每个 Document 上的入口对象,登记/管理工具 | index.bs:283-322 |
registerTool() | 把一个工具定义写进 tool map | index.bs:336-464 |
| model context / tool map | 存「工具名 → 工具定义」的 map,每个 Document 一份 | index.bs:125-182 |
tool definition struct | 一个工具的内部表示(名/描述/schema/执行步骤/各种 hint) | index.bs:134-182 |
toolchange 事件 | 工具增删时通知关心它的文档 | index.bs:597-611 |
| observation | 浏览器 agent 看页面工具用的「快照」(含截图等) | index.bs:634-701 |
tools 权限策略 | 控制哪个源/iframe 能用这套 API | index.bs:613-617 |
主线走一遍(高层): 页面加载 → 脚本调 registerTool() 把工具写进本 Document 的 tool map(index.bs:453)→ 浏览器 agent 在某时刻对标签页「拍快照」(perform an observation),把各文档的工具收进一个 observation(index.bs:660-701)→ agent 据此决定调哪个工具,带结构化参数请求 → 浏览器调对应的 execute 步骤(index.bs:441-442)→ 结果返回 agent。
3. 阅读地图(建议顺序)
这套提案有四个相对独立的子系统,外加一份安全模型。建议按下面顺序读:
- 01-imperative-api.md — 先读这章。命令式
registerTool()是整个 API 的核心:工具定义长什么样、一次调用从注册→发现→调用→执行→响应的五步生命周期、以及registerTool规范算法逐行走读(校验、序列化、AbortSignal 注销、并行通知)。 - 02-declarative-forms.md — 声明式:不写 JS,光给
<form>加几个属性(toolname/tooldescription/toolautosubmit)就能让浏览器把表单「编译」成工具。讲清它和命令式的对应关系,以及哪些算法还是 TODO。 - 03-cross-origin-and-events.md — 跨源与事件:
tools权限策略默认只给'self'、用allow="tools"给 iframe、用exposedTo把工具授权给指定源、toolchange事件的诡异时序、以及浏览器 agent 的 observation 快照机制。 - 04-service-workers.md — 进阶场景:让 agent 调用用户没打开的网站。Service Worker 当 WebMCP provider,工具在后台跑;难点在路由(多 agent、tab+worker 共存)和会话状态(sessionId 隔离不同对话的购物车)。
- 05-security.md — 必读的安全章:为什么 agent + 自然语言 = 新攻击面。三种 prompt 注入(元数据投毒/输出注入/工具本身成靶子)、意图错配(
finalizeCart偷偷下单)、过度参数化窃取隐私,以及untrustedContentHint等缓解手段。
给 agent 的选章提示: 只关心「网页怎么登记工具」读 §01;关心「不写 JS 用表单」读 §02;关心「iframe / 跨源 agent / 事件」读 §03;关心「后台/未打开页面」读 §04;做安全审查读 §05。
4. 横向对比(同 shelf 兄弟)
WebMCP 与 MCP(Model Context Protocol) 共享词汇(tool / schema / parameter),但刻意不直接采用 MCP 规范(README.md:350-356):MCP 为 server-to-client、stdio/SSE 进程通信设计,缺少 web 原生概念(源、浏览器权限、DOM、标签页生命周期)。WebMCP 是「为 web 平台量身定做、客户端安全」的同类物,而非 MCP 的浏览器移植。
与靠截图+模拟点击的通用浏览器自动化相比:WebMCP 不取代它,而是给它一个更可靠的快车道——agent 发现没有合适工具时,仍可回退到通用 UI 自动化(README.md:73-77)。
5. 代码地图(导航索引)
| 主题 | 文件 | 符号 / 锚点 |
|---|---|---|
| 顶层动机与示例 | README.md | “Backend Integrations vs. In-browser”、registerTool 示例 |
| 规范主体(Bikeshed 源) | index.bs | 全文 |
document.modelContext 入口 | index.bs:283-322 | Document/associated ModelContext、ModelContext interface |
| 工具登记算法 | index.bs:336-464 | registerTool(tool, options) |
| 工具定义结构 | index.bs:134-182 | tool definition |
| 声明式表单(explainer) | declarative-api-explainer.md | toolname / toolparamdescription / respondWith |
| Service Worker 扩展 | docs/service-workers.md | provideContext / 路由 / sessionId |
| 安全考量 | index.bs:713-1102 | prompt-injection、misrepresentation-of-intent |