资讯详情

用 Cloudflare Agents 的 WebMCP 适配器把 McpAgent 工具桥接到 Chrome 原生 AI:一个统一的浏览器工具箱

📅 2026/9/18 6:12:12 | 华诺云谱 👁 阅读
用 Cloudflare Agents 的 WebMCP 适配器把 McpAgent 工具桥接到 Chrome 原生 AI:一个统一的浏览器工具箱
用 Cloudflare Agents 的 WebMCP 适配器把 McpAgent 工具桥接到 Chrome 原生 AI一个统一的浏览器工具箱【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents导读本指南围绕 examples/webmcp 示例展开讲解 Cloudflare Agents 生态中实验性的 WebMCP 适配器agents/experimental/webmcp模块导出的registerWebMcp()如何把注册在McpAgent上的 MCP 工具桥接到 Chrome 原生的navigator.modelContextAPI让浏览器内置 AI 在一个注册表中同时看到页内工具与远端工具两种执行环境的工具。读完本文你将掌握如何启动并运行该示例、在 Chrome Canary 中开启 WebMCP 特性、registerWebMcp()的全部配置项、桥接的底层工作流程连接 → 发现 → 注册 → 监听 → 销毁、页内工具与远端工具的选择决策以及背后 Playwright 测试套件覆盖的行为边界。实验性警告该示例依赖agents/experimental/webmcp其 API 正处于积极开发中版本升级间可能发生破坏性变更Google 的 WebMCP APInavigator.modelContext也仍处于早期预览阶段。生产使用前务必锁定agents版本并预期升级时需要重写调用代码。源码头部packages/agents/src/experimental/webmcp.ts同样以醒目的WARNING: EXPERIMENTAL声明了这一点。示例演示了什么examples/webmcp是一个可运行的前端 Worker 演示项目核心展示 7 个能力点registerWebMcp()一行适配自动发现McpAgent暴露的工具并将它们注册到 Chrome 的 WebMCP。页内工具与远端工具并存滚动、主题切换、读取location.href这类页面专属行为直接通过navigator.modelContext.registerTool注册与桥接过来的McpAgent工具并排展示。prefix命名空间桥接工具以remote.add、remote.greet等带前缀的名字进入注册表避免与页内工具名冲突。Connect / Disconnect / Refresh 生命周期控制直观演示dispose()与refresh()的实际效果。页内 Invoke UI页内工具可直接点击 Invoke 按钮在页面里运行远端工具设计上是交给浏览器 AI 调用的因此 UI 引导到 WebMCP Chrome 扩展。特性检测当navigator.modelContext不可用时优雅降级no-op并显示可见状态条。动态同步监听 MCPtools/list_changed通知服务器端工具增删改后自动重新注册。运行示例npm install npm startpackage.json中定义了三个脚本见 examples/webmcp/package.jsonstartvite dev启动本地开发服务器deployvite build wrangler deploy构建静态资源并部署 Workertypeswrangler types env.d.ts --include-runtime false生成绑定类型声明。完整的 WebMCP 集成需要 Chrome Canary并在chrome://flags打开两个实验开关#enable-webmcp-testing#enable-experimental-web-platform-features在其他浏览器中页面依然可以正常加载适配器检测到缺少的 API 后显示状态横幅页内工具的 Invoke 按钮仍可用来直接测试工具的execute函数。client.tsx在hasWebMcp为 false 时跳过自动连接等待用户按提示启用特性后再点击 Connect 按钮见 examples/webmcp/src/client.tsx 与#L446-L456的自动连接逻辑。工作原理整个桥接分两层服务器端定义工具、客户端注册并桥接。服务器端用 McpAgent 定义工具服务器按常规方式用McpAgent定义工具。完整示例在 examples/webmcp/src/server.ts定义了add、greet、get_counter三个工具其中add会读写 Durable Object 的持久化counter状态import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { McpAgent } from agents/mcp; import { z } from zod; type State { counter: number }; export class MyMCP extends McpAgentEnv, State, {} { server new McpServer({ name: WebMCP Demo, version: 1.0.0, websiteUrl: https://github.com/cloudflare/agents }); initialState: State { counter: 0 }; async init() { this.server.registerTool( add, { description: Add a number to the counter, inputSchema: { a: z.number() } }, async ({ a }) { const next this.state.counter a; this.setState({ ...this.state, counter: next }); return { content: [{ text: Added ${a}, total is now ${next}, type: text }] }; } ); // greet、get_counter 类似此处省略 } } export default MyMCP.serve(/mcp, { binding: MyMCP });wrangler.jsonc中把MyMCP声明为 Durable Object 绑定并使用 SQLite 迁移examples/webmcp/wrangler.jsoncassets.not_found_handling: single-page-application让 SPA 页面与/mcp端点共存。客户端注册页内工具并桥接远端工具客户端从agents/experimental/webmcp导入registerWebMcpexamples/webmcp/src/client.tsx其核心调用形态如下import { registerWebMcp } from agents/experimental/webmcp; // 1. In-page tools — 只有页面才能做的事 navigator.modelContext?.registerTool({ name: page.scroll_to_top, description: Scroll the demo page back to the top, execute: async () { window.scrollTo({ top: 0, behavior: smooth }); return ok; } }); // 2. Bridge the McpAgent — 持久化存储、服务端鉴权等 const handle await registerWebMcp({ url: /mcp, prefix: remote., getHeaders: async () ({ Authorization: Bearer ${await getToken()} }) }); // 页面离开时清理 await handle.dispose();示例客户端还注册了page.set_theme切换明暗主题与page.get_url读取当前 URL两个页内工具并完整实现了连接状态指示、活动日志、Connect/Disconnect/Refresh 按钮见 examples/webmcp/src/client.tsx 与#L373-L465。完成上述注册后浏览器 AI 会在同一个navigator.modelContext注册表中同时看到page.scroll_to_top和remote.greet/remote.add/remote.get_counter。它按名称挑选工具完全不需要知道也不关心工具到底在页面里执行还是在服务器上执行。底层实现细节registerWebMcp的源码位于 packages/agents/src/experimental/webmcp.ts其内部通过McpHttpClient#L146-L269封装了modelcontextprotocol/sdk的ClientStreamableHTTPClientTransport。桥接生命周期分五步Connect连接基于传入的 URL 打开一个 MCPClient。相对 URL 会基于globalThis.location?.origin解析#L158SSE 解析、session ID 处理、重连、nextCursor分页等均由 SDK 承担。Discover发现调用tools/list通过nextCursor循环分页枚举McpAgent暴露的全部工具#L204-L226。Register注册为每个工具构建一个ModelContextTool其execute代理到client.callTool(...)并把 MCP 的content[]响应折叠成浏览器 AI 可消费的字符串#L437-L497。Watch监听订阅 MCPtools/list_changed通知#L524-L534服务器增删改工具时自动重跑第 2–3 步重新注册watch: false可关闭。Tear down销毁await handle.dispose()中止每个工具对应的AbortControllerWebMCP 规范规定的注销方式中止在途的listTools/callTool并关闭 MCP 传输#L551-L564。在navigator.modelContext缺失的浏览器上除开启#enable-webmcp-testing的近期 Chrome 外适配器自动 no-op不发任何网络请求返回一个tools为空数组的句柄并在控制台输出提示日志#L406-L424因此调用方无需自行做特性检测分支。registerWebMcp API 参考interface WebMcpOptions { url: string; // /mcp 等相对或绝对地址 headers?: Recordstring, string; // 静态鉴权头 getHeaders?: () PromiseRecordstring, string | Recordstring, string; watch?: boolean; // 默认 true prefix?: string; // 桥接工具的命名空间前缀 timeoutMs?: number; // 每次请求的超时时间 logger?: { info; warn; error }; // 默认 console quiet?: boolean; // 默认 false onSync?: (tools: McpTool[]) void; // 每次重新同步时回调 onError?: (error: Error) void; // 仅后台同步错误 } interface WebMcpHandle { readonly tools: ReadonlyArraystring; // 当前工具名含 prefix readonly disposed: boolean; refresh(): Promisevoid; // 与在途同步合并 dispose(): Promisevoid; // 幂等 }各配置项的行为细节在源码 JSDoc 中有明确说明packages/agents/src/experimental/webmcp.tsheaders与getHeaders二者可同时提供并合并getHeaders的值优先getHeaders在每次请求前被调用适合会刷新的令牌场景。动态头通过包装 transport 的fetch合并进请求#L167-L179。prefix仅作用于注册到navigator.modelContext的名字实际发往服务器的调用仍使用原始未加前缀的工具名#L439与#L451。timeoutMs作用于tools/list与tools/call的每次请求超时错误分别走onError同步场景或执行拒绝工具调用场景。onSync初始加载与tools/list_changed后都会回调收到的是服务器返回的原始未加前缀工具名。quiet等价于logger: SILENT_LOGGER。适配器所有日志默认带[webmcp-adapter]前缀#L132-L142。错误模型适配器有三类错误来源每类都有单一、可预期的暴露面来源行为初始化首次连接/listregisterWebMcp(...)的 promise reject不会调用onError后台重新同步watch 模式调用onError(err)不抛异常单个工具的execute失败executepromise reject由浏览器 AI /tools/call宿主承接onError只服务于调用方无法观察到的后台工作——即registerWebMcpresolve 之后、由服务器推送通知触发的重新同步。源码在初始化失败时会先尽力关闭传输再抛出错误#L535-L541避免泄漏连接。并发与生命周期并发refresh()与 watch 模式的通知处理器共享同一个在途 promise。若已有同步在跑再次触发refresh()或新的tools/list_changed都会返回同一个 promise 而不是另起一次同步#L503-L518从而防止unregisterAll → listTools → registerTools序列自我交错、把navigator.modelContext注册表留在不一致状态。生命周期dispose()是异步的执行顺序为标记disposed true→ 中止生命周期AbortController取消在途listTools/callTool→ 中止每个工具级AbortController从navigator.modelContext移除→ 等待在途同步收尾 → 关闭 MCP 传输。多次调用是安全的dispose 之后调用工具execute()会以WebMCP adapter has been disposed拒绝#L448-L450。组合模式页内工具 远端工具推荐的做法是自己注册页内工具让适配器负责桥接远端工具必要时加prefix让两个命名空间一目了然import { registerWebMcp } from agents/experimental/webmcp; if (modelContext in navigator) { // 1. 页内工具 — DOM、本地状态、Web API navigator.modelContext.registerTool({ name: page.scroll_to_section, description: Scroll the page to a named section, inputSchema: { type: object, properties: { id: { type: string } }, required: [id] }, async execute({ id }) { document.getElementById(String(id))?.scrollIntoView({ behavior: smooth }); return ok; } }); } // 2. 远端工具 — 持久化、鉴权、服务端逻辑 const handle await registerWebMcp({ url: /mcp, prefix: remote., getHeaders: async () ({ Authorization: Bearer ${await getToken()} }) });多次调用registerWebMcp同样合法——用不同前缀把两个 MCP 服务器桥进同一个页面const orders await registerWebMcp({ url: /orders/mcp, prefix: orders. }); const billing await registerWebMcp({ url: /billing/mcp, prefix: billing. });何时用页内工具、何时用远端工具使用场景应该放在哪里DOM 操作、滚动、主题、焦点、剪贴板页内— 直接navigator.modelContext读取本地 UI 状态Zustand、Redux、IndexedDB页内调用 Web API地理位置、文件选择器、WebRTC页内读写持久化数据KV、R2、D1、DO 状态远端— 通过registerWebMcpMcpAgent携带密钥凭据调用第三方 API远端密钥留在 Worker 里需要跨过标签页关闭仍存活的工作远端希望在多个浏览器间可用的工具远端判断基准很简单能靠 DOM 和页面本地能力完成的事放页内涉及持久化、凭据或必须在页面关闭后仍存在的事放远端。在 experimental/webmcp.md 的设计文档中有同一张决策表的扩展版本。边界情况与注意事项工具名冲突是静默的两次注册使用相同名称时后者胜出或并排出现浏览器行为未定义。用prefix与带命名空间的页内名如page.foo保持安全。有损的内容转换适配器目前把 MCP 的 content 数组折叠成字符串——text项以换行连接image项变成data:URL其余类型为尽力而为。当前 WebMCP 形态要求execute必须返回字符串更丰富的返回类型需等待规范演进源码见#L464-L484。watch 模式依赖 SSE若服务器对用于接收通知的 GET 请求返回 405适配器记录警告并继续运行无 watch——工具不会自动刷新但其余功能正常。按请求超时而非全局超时timeoutMs只作用于tools/list与tools/call没有适配器卡死的全局超时无响应的服务器会逐个影响每个调用。不支持 SSR / Worker该模块导入 MCP SDK 的 HTTP transport 并读取navigator.modelContext按设计仅限浏览器端。在 Worker 或 SSR 中导入时globalThis.location解析为undefined相对 URL 可能抛错。日志所有适配器消息带[webmcp-adapter]前缀可传quiet: true或自定义logger重定向。测试与验证适配器自带一套基于 PlaywrightChromium headless的 Vitest 测试套件位于 packages/agents/src/webmcp-tests/webmcp.test.ts约 1005 行覆盖no-op 路径无navigator.modelContext静态与动态 headers以及合并优先级工具发现、schema 保真度、description 回退、annotationsprefix——注册名带前缀、线上传输用原名工具执行、多 content 连接、图片 contenteditable="false">【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。