更新于 2026-10-11。工具注解在代理调用前描述行为。它是提示,不是权限机制;回调和服务端仍需校验输入、身份与授权。
当前 WebMCP 有哪些注解?
当前草案定义四个布尔字段。本站较早文章混用了 MCP 与 WebMCP 的字段,本次修订将两者分开。
| 字段 | 描述的行为 |
|---|---|
readOnlyHint | 是否只读取数据、不改变状态 |
untrustedContentHint | 返回内容是否从工具作者的角度看属于不可信内容 |
consequentialHint | 操作是否具有重大的现实影响或不可逆后果 |
debugging | 工具是否面向调试或开发者用途 |
不能把 MCP 示例中的 destructiveHint、idempotentHint、openWorldHint 直接说成当前 WebMCP 字段。同一应用若还提供 MCP 服务,应在那里遵循对应协议定义。
先准确判断工具行为
只读取自己控制页面的标题,可以声明只读。如果标题含不可信的第三方或用户内容,应重新评估内容提示。创建记录、消耗配额、改变购物车的函数,即使没有收费,也并非纯只读。
async function registerPageTools() {
const context = document.modelContext;
if (!context) return; // Keep the normal page available.
const registration = new AbortController();
await context.registerTool({
name: "getPageHeading",
description: "Read the first h1 or h2 heading on this page. No data is changed.",
inputSchema: {
type: "object",
properties: {
level: { type: "string", enum: ["h1", "h2"], description: "Heading level to read" }
},
additionalProperties: false
},
annotations: { readOnlyHint: true, untrustedContentHint: false, consequentialHint: false },
execute: async ({ level = "h1" }) => {
if (!["h1", "h2"].includes(level)) throw new Error("Invalid heading level");
return { heading: document.querySelector(level)?.textContent?.trim() || "" };
}
}, { signal: registration.signal });
window.addEventListener("pagehide", () => registration.abort(), { once: true });
}
void registerPageTools();
回调校验允许的标题级别,使用 execute,离开页面时通过 AbortSignal 清理注册。应在真实支持此 API 的浏览器测试。
三个实际场景
查询商品目录
工具只返回公开目录信息时,可以考虑只读提示。说明数据来源;搜索结果若包含第三方文字,应评估不可信内容,而不是把所有读取结果都视为可信。
预订或付款
创建预订或转账需要明确处理现实后果。注解不提供确认页面、授权检查或回滚能力,应在应用中实现,并同时测试普通界面和工具路径。
开发诊断
开发者诊断可以使用调试提示。不能为减少用户操作阻力,把购买、账户修改工具伪装为调试工具。给工具添加注解,也不意味着可以公开特权诊断能力。
WebMCP Verify 怎样检测?
在 2026-10-05 规则下,D4 的标称权重为 2。它检查每个被捕获的当前命令式工具是否声明了至少一个已识别的布尔注解。false 也是布尔值;空对象、"true" 字符串或无关属性不满足此检测。
只有部分工具符合时会得到 partial。没有当前命令式工具时,这项被跳过。只用声明式方案,不需要为了这两分虚构命令式注册,详见评分计算。
扫描器只能观察声明,不能调用工具验证实际行为是否一致。因此注解通过不是安全认证。
发布前核对
检查实际副作用、输入校验和返回数据,确认注解值符合事实,再在支持环境中测试发现与调用。保留正常界面。
