多数团队交付的第一个 WebMCP 工具,不会是以「工具」的名义写出来的。它会是一个本来就存在的表单,用四行代码重新声明了一遍——而它将以「此刻登录的那个人」的全部权限接受模型的调用,因为浏览器认证的是用户,而没有任何东西认证调用方。
一眼看全
WebMCP 给浏览器加了一个 API:让网页把一组结构化、可调用的工具声明给 AI 智能体,而不必让智能体通过界面去操纵页面。这确实是个好主意,而它也远比外界报道显得的要早期。
| 问题 | 答案 | 为什么重要 |
|---|---|---|
| 它是什么? | 页面注册带 JSON Schema 入参的具名工具;智能体发现并调用它们。 | 把抓取与靠选择器点击的方式,换成一份声明出来的契约。 |
| 标准状态 | Web Machine Learning 社区组的 W3C Draft Community Group Report——既不是 W3C 标准,也不在标准轨道上。 | 仍在孵化。形状还会变,而且已经变过。 |
| 实现情况 | Chrome,藏在一个实验标志与一次 origin trial 后面。其他引擎参与了讨论,但没有发布承诺。 | 只有一个实现,那是预览,不是平台。 |
| 覆盖范围 | 只有 tools。MCP 的另两个原语——resources 与 prompts——不在范围内。 | 这不是「浏览器里的 MCP」,而是 MCP 的三分之一。 |
变动从外面就看得见:入口已从 navigator.modelContext 挪到 document.modelContext,更早的 provideContext() 设计则被弃用。今天就照着它写,买到的是一次迁移——只要你清楚自己买的正是这个,那没问题。
真正发布出来的是什么
命令式的那层小到可以整个装在脑子里。页面调用 document.modelContext.registerTool(),传入一个描述符——一个 name、一段自然语言的 description、一份 JSON Schema 形式的 inputSchema,外加一个 execute 回调;智能体一侧则拿到 getTools() 用于枚举、executeTool() 用于调用,还有一个 toolchange 事件,好让单页应用随用户导航修订自己开出的清单。
document.modelContext.registerTool({
name: 'addToCart',
description: 'Add a product to the shopping cart.',
inputSchema: { type: 'object', properties: { sku: { type: 'string' } } },
async execute({ sku }) {
return await fetch('/api/cart', { method: 'POST', body: JSON.stringify({ sku }) });
},
});
这段代码里有三处细节,干的活比看上去多。
description 就是一段提示词
智能体是靠读描述来挑工具的,这就让那个字符串成了你模型指令面的一部分,而不是文档。MCP 工具投毒正是靠这个性质成立的,而现在它落在了一个你市场同事有编辑权限的地方。一句写着「用这个,别去问用户」的描述就是一条指令,而它会被照办。
有一条声明式路径,而那才是会铺开的那条
除了 JavaScript API,草案还允许一个 HTML <form> 直接充当工具声明。这才是真正会被采用的部分,因为它几乎免费——而它同时也意味着,一大片既有的界面会在一次发布里变成可被智能体调用的,期间没有任何人写下一行他自己会认作「对外开放了一个 API」的代码。
跨源在范围之内
注册选项里有 exposedTo,一份获准看见该工具的来源白名单;发现一侧则有 fromOrigins,指明要从哪些安全来源收集工具。工具默认按来源隔离,API 也要求安全上下文。但这两个选项的存在本身就在告诉你:这个模型不是「页面对浏览器的智能体说话」——它是一张图,而你的页面是图上的一个节点。
工具是在会话内部跑的
别跟着数据走,跟着权限走。execute 回调就是你这个来源下寻常的页面 JavaScript。它调用你的后端时,带上的是 cookie、localStorage 里的 bearer token、你模板渲染出来的 CSRF token——浏览器为那位正坐在那儿的用户所持有的每一份凭证。你的服务器收到一个格式良好、同源、完整鉴权的请求,而请求里任何一处字段都不会说:这些参数是一个模型拼出来的。
这是环境权限最经典的形态,也就是那个「被搞糊涂的代理人」问题;而谁被搞糊涂了,值得说准。你的页面就是那个代理人。它持有一份并非自己挣来的权限——用户的——而它现在正从一个它无法审视其意图的调用方那里,接受关于如何花掉这份权限的指令。浏览器的同意提示是真实有效的缓解措施,也确实该放在那个位置;但同意是由一个人给出的,他读的是一个工具名和一段摘要,只读一次,而这次任务接下来可能包含四十次调用。
execute() 的入参里没有任何东西能把它们分开。把三条路径并排看,不对称就一目了然。人工点击要穿过你的界面,也就意味着它穿过了你的禁用态、你的确认弹窗,以及用户身体能产出的那个速率。智能体调用按设计跳过这一切——那正是它的卖点——并以机器速率抵达处理函数。跨源调用抵达的是同一个处理函数,而它满足的那道来源检查是你的页面配置的:也许是无意间配上的,也许配的是一个开发时看着挺顺手的通配符。
而驱动这三者的指令,可能就来自你自己的页面。一个读了商品列表、读了评论、读了工单正文、或读了用户自填昵称的智能体,是在它握着你那份工具清单的同一个窗口里,读着不可信的文字。这是提示词注入,而工具调用已经预先备好了——这也正是所有正经防御都从授权层而非文本层动手的原因。
不管你管它叫什么,你都在发布一个 API
先把安全放一边,因为就算是一个登录后面没什么敏感内容的站点,运维上的这套论证照样成立。工具一经注册,你就担下了一个 API 所背负的全部义务——而且是在你平时会先搭起来的那套机器一件都没有的情况下担下的。
| 义务 | 你的 REST API 有 | 你的 WebMCP 工具有 |
|---|---|---|
| 版本管理 | 一段路径、一份弃用策略、一份变更日志。 | 一个名字字符串。改名,学过它的智能体全部作废。 |
| 限流 | 按 key 的配额、退避约定、429。 | 你会话级限额恰好是多少就是多少,而那是按人的速度定的。 |
| 授权 | scope、按客户端授予、可撤销。 | 用户的会话,全部,不加区分。 |
| 滥用处置 | 一把你能吊销的 key。 | 一个你能注销的工具——对所有人,在你下一次发布时。 |
版本那一行会最先咬人,而且咬得没声响。智能体不读你的变更日志;它在调用时读 description 与 inputSchema——这听着像是让「破坏性变更」变得不可能。并非如此。它只是让破坏变得无声:你把某个 schema 收紧,原本能成功的智能体现在校验失败,而你唯一的信号,是一条还没人搭出来的指标。在服务端,这正是工具目录生命周期那个问题,它不会因为搬进浏览器而变容易。
限流那一行会最先花钱。你的按会话限额里编码着一条关于「人有多快」的假设,而 WebMCP 是刻意来作废它的。一个在干活的智能体,十秒里调用搜索工具的次数会超过用户十分钟的量,而且它是正当地这么做——这个故事里没有攻击者,只有一个物理规律不同的调用方。
那该怎么办
以上没有一条是在反对 WebMCP。「声明出来的工具面」的替代品,是智能体用合成点击去操纵你的界面,那在每一根轴上都更糟,安全也不例外——你没法对一个你从未当作接口设计过的接口做推理。真正的论点是:采用起来太便宜,这本身就是风险;而缓解措施既乏味,又在服务端。
- 在边界上给请求打标。让
execute附上一个 header,说明这次调用来自工具,以及是哪个工具。你的服务器推断不出来,将来也永远推断不出来;这份知识唯一存在的地方,就是你正在写的那个回调。下面所有条目都依赖这一行。 - 在服务端按动作重新授权。把那个 header 当成一档更低的信任等级:同一个端点、同一个会话,但允许的操作集更窄。读操作通常没问题。任何花钱的、发消息的、难以撤回的,都该要求一次新鲜而具体的确认——这是影响半径那套论证,套用在一个上个季度还不存在的面上。
- 注册最小集,不是最大集。声明式表单那条路的诱惑,在于一次性把一切都暴露出去,因为不花钱。先从让智能体好用的只读工具起步——搜索、可用性、状态——等你有了理由、也有了限额,再加一个写工具。
- 把
exposedTo显式写出来。在一个嵌了第三方 iframe 的页面上留一个默认开放的工具,这种配置你会希望是有意做的、过了代码评审的、旁边署着一个名字的。 - 给工具路径单独限流。工具调用一旦被打上标,就能有自己的预算,而这既是滥用管控,也是成本管控。
- 把描述当成与安全相关的字符串来写。它们是提示词内容。让它们进你系统提示词的那套评审,而不是产品文案的那套。
至于节奏:既然这是一份社区组草案、只有一个带标志的实现、入口还已经挪过一次,诚实的排期是现在做原型,而先把服务端那一半交付掉。那个 header、按动作的授权、单独的限流,无论 WebMCP 是不是最后胜出的标准都用得上——它们与你为任何抵达你产品的智能体流量所需要的,是同一套控制。而那些 registerTool 调用,是你该预期要重写的部分。
常见问题
WebMCP 是 W3C 标准吗?
不是。它由 Web Machine Learning 社区组以 W3C Draft Community Group Report 形式发布,而这明确意味着:它既不是 W3C 标准,也不在 W3C 标准轨道上。社区组孵化是好点子起步的地方,也是其中一些点子止步的地方。
WebMCP 会取代 MCP 服务器吗?
不会,而且它覆盖的范围比名字暗示的要小。草案只做 tools——MCP 的 resources 与 prompts 原语不在范围内——而它针对的是「能力就住在用户已经打开、也已经登录的那个页面里」这种情形。一个远程 MCP 服务器,仍然拥有浏览器会话之外的一切。
跨源脚本能在我的页面上注册工具吗?
工具的作用域限定在注册它的那个来源,API 也要求安全上下文,所以第三方脚本无法悄悄冒充你来源下的工具。它能做的是从它自己的来源注册它自己的工具;而经由 fromOrigins 的跨源发现,加上 exposedTo 白名单,恰恰是那种该被刻意配置、而不是听凭默认值的面。
如果我的服务器分不出智能体调用和点击,最小的补救是什么?
一个 header,在 execute 内部附上,写明工具名。它不是安全边界——页面 JavaScript 想发什么都能发——但它是让一切真正的控制成为可能的那份可观测性;没有它,你甚至没法量出自己有多少流量来自智能体。
现在该不该采用?
现在做原型,并把能活下来的那部分交付掉。一个标志后面、只有一个引擎、API 还已经被改过名——对客户端那一半形成生产依赖,为时过早。服务端那一半——打了标的工具流量、按动作的授权、一份单独的配额——是无论哪份规范胜出、你都会为智能体流量而需要的活。
延伸阅读
本站:
- 什么是 MCP——WebMCP 借来词汇的那个协议。
- 环境权限——为什么「用户已登录」不是一套授权模型。
- Bot 校验与智能体访问——智能体流量问题的另一半。
- 能力发现——智能体如何得知自己能做什么。
- 提示词注入防御——为什么解法是授权,不是过滤。
- 工具目录生命周期——给客户端在调用时才发现的工具做版本管理。
来源:
- webmachinelearning/webmcp——规范、说明文档与安全说明。
- WebMCP draft community group report。