入门 📋 5 个步骤 第 535 / 535 篇

用 WebMCP 给网站开一个 Agent 可调用接口:声明式 + 命令式两种落地

Chrome 149 起 WebMCP(navigator.modelContext)让网页把「能做的动作」声明成结构化工具,浏览器里的 AI Agent 就能直接调用,不再靠 DOM 猜测。本教程用声明式 HTML 属性与命令式 registerTool() 两种方式,带你把网站变成 Agent 可操作。

2026.10.15· 约 12 分钟上手· 约 1173 字· 🌐 WebMCP / 🧩 浏览器智能体

你的网站来了新访客:浏览器里的 AI Agent,替人办事。它现在靠读 DOM、猜按钮含义来操作你的页面——CSS 一改就崩,还浪费算力。Google 与 Microsoft 共同推进的 WebMCP(Chrome 149 起开放试用)让网页主动声明「我能做的动作」为结构化工具,Agent 直接调用、拿结构化结果。本教程两种落地方式都走一遍。

💡 适用场景:电商加购/搜索、内容站订阅/报名、SaaS 控制台操作。凡是「用户能在页面上点一下完成的事」,都值得暴露成 WebMCP 工具。MCP 负责后端数据,WebMCP 负责浏览器内操作,两者互补。

Step 1:特征检测与环境确认

1

WebMCP 目前是 Chrome 149+ / Edge 147+ 的开放试用特性,只在受支持的浏览器里存在。代码里先检测,不在就走降级。

// 入口对象可能在 navigator 或 document 上,按当前规范探测
const mc = navigator.modelContext || document.modelContext;
if (!mc) {
  console.warn("当前浏览器不支持 WebMCP,降级为普通页面交互");
} else {
  console.log("WebMCP 可用,开始注册工具");
}

规范仍在演进:API 命名在 2026 年有过迁移(从 navigator.modelContext 切到 document.modelContext 的版本有过反复),上线前请以 Chrome 官方 WebMCP 文档的当前形态为准。上面同时探测两者就是为兼容差异。

Step 2:声明式——给表单加两个属性

2

对已有的 HTML 表单,无需写 JS:加 toolname 与 tooldescription 两个属性,浏览器自动把表单合成一个工具。人照样能填,Agent 也能调。

<form toolname="searchProducts" tooldescription="按关键词搜索商品,返回匹配结果列表">
  <input name="query" placeholder="输入商品名" />
  <button type="submit">搜索</button>
</form>
📝 tooldescription 写「什么时候用这个工具」,而不是字段说明——字段类型由表单自动推导。描述越清楚,Agent 越知道何时调用。

Step 3:命令式——用 registerTool 暴露动态动作

3

表单表达不了的逻辑(React 弹窗、AJAX 动作)用 registerTool。核心是 name + description + inputSchema(JSON Schema)+ execute(调用你已有的业务函数)。

const mc = navigator.modelContext || document.modelContext;
if (mc) {
  mc.registerTool({
    name: "addToCart",
    description: "把指定 SKU 的商品加入购物车",
    inputSchema: {
      type: "object",
      properties: {
        sku: { type: "string", description: "商品 SKU,例如 SHOE-42" },
        quantity: { type: "integer", description: "加入数量", default: 1 }
      },
      required: ["sku"]
    },
    execute: async (params) => {
      const result = await addToCart(params.sku, params.quantity || 1);
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    }
  });
}
🔑 关键心法:execute 调用你页面本就有的业务函数。你是在「暴露已有能力」,不是在写第二套集成。

Step 4:返回正确结构 + 状态感知工具

4

execute 返回 MCP 内容块结构,Agent 才能拿到可用结果。工具要随页面状态出现/消失:登录前只暴露登录,登录后注册订单类工具,卸载时 unregisterTool 回收。

// 组件挂载时注册
mc.registerTool({ name: "viewOrders", description: "查看当前用户订单", inputSchema: { type: "object", properties: {} }, execute: async () => ({ content: [{ type: "text", text: JSON.stringify(await getOrders()) }] }) });

// 组件卸载时回收,避免暴露用户看不到的工具
function onUnmount() {
  if (mc) mc.unregisterTool("viewOrders");
}

不要暴露用户看不到的工具:组件卸载后没回收的 registerTool 既是糟糕体验,也是潜在滥用面。把注册/注销和组件生命周期绑在一起。

Step 5:兜底与安全闸

5

不支持的浏览器要降级,危险动作要人工确认。给写操作(下单、支付、删除)加显式确认;即便 Agent 调用,也走和用户点击一样的确认流程。

// 降级:不支持 WebMCP 时,用 JSON-LD / 语义 HTML 让传统爬虫与脚本仍能拿到结构化信息
if (!mc) {
  injectJsonLd({ "@type": "WebSite", name: "我的商城", potentialAction: "searchProducts" });
}

// 危险动作:复用页面既有的确认流程,不绕过人工闸
execute: async (params) => {
  const ok = await confirmWithUser("确认把该商品加入购物车?");
  if (!ok) return { content: [{ type: "text", text: "用户取消了操作" }] };
  return { content: [{ type: "text", text: JSON.stringify(await addToCart(params.sku, params.quantity)) }] };
}

浏览器支持是硬约束:当前仅 Chrome / Edge 的试用通道可达,Firefox / Safari 还在跟进。WebMCP 面向「人在回路的本地浏览器会话」,无法被无头服务端 Agent 调用,也没有统一发现机制——Agent 要到你的页面后才「发现」工具。

常见问题

现象处理
页面上报 navigator.modelContext 不存在浏览器不在支持列表,或规范已迁移到 document.modelContext;两种都探测即可。
声明式工具装了却「没反应」确认属性名是 toolname / tooldescription,且表单能被正常提交。
Agent 调错工具 / 填错参数把 description 和字段 description 写具体,含糊描述导致误调用。
要不要为服务端 Agent 也开 WebMCP不必。服务端 Agent 走标准 MCP 连后端;WebMCP 只服务浏览器内会话。
← 返回教程中心