大多数 AI 平台透过 REST API 连接到外部服务。这对于结构化资料来说运作良好 — 读取 CRM 联络人、建立 Jira 工单 — 但它遗漏了浏览器内发生的所有事情。Gmail 中的电子邮件草稿、你正在阅读的 Slack 对话串、ServiceNow 中填写到一半的表单。
我们使用 Model Context Protocol (MCP) 打造了一个浏览器扩充功能来弥补这个差距。这篇文章涵盖了架构决策、我们遇到的问题,以及系统从头到尾的运作方式。
问题:浏览器状态对 API 来说是不可见的
API 给你资料库记录。它们不会给你萤幕上显示的内容。一位业务代表在 Gmail 中撰写后续追踪电子邮件时,拥有任何 API 都无法捕捉的情境 — 语气、写到一半的段落、同时开启的分页。我们希望 AI workflow 能够像坐在你旁边的人类助理一样,在这个即时的浏览器情境中运作。
架构概述
这个扩充功能基于 WXT 0.20 (Manifest V3) 以及 Svelte 5 和 TypeScript 打造。它实作了一个 MCP client,透过 WebSocket 连接到 JieGou 伺服器,公开 60 多个 AI workflow 可以呼叫的浏览器自动化工具。
讯息流程如下:
MCP Server → WebSocket → Background Service Worker → Content Script → Page
当 recipe 或 workflow 需要与浏览器互动时,它会透过 WebSocket 连线传送 JSON-RPC 2.0 工具呼叫。扩充功能的 background worker 将其路由到适当的工具执行器,该执行器会将 content script 注入到活动分页中并回传结果。
WebSocket 桥接
WebSocket proxy 处理身份验证、heartbeat、重新连线和 token 刷新。
身份验证在连线时发生 — client 传送带有 JWT token 的 authenticate 讯息。伺服器验证后开始接受工具呼叫。
Heartbeat 在应用层每 15 秒执行一次(不依赖 WebSocket 协定的 ping)。如果 pong 在 5 秒内未到达,连线会被视为中断并开始重新连线。
自动重连在断线时使用 3 秒延迟搭配指数退避。Token 刷新会在 JWT 过期前 5 分钟透过 REST endpoint 主动进行,因此连线永远不会因为凭证过期而中断。
工具执行器管道
所有工具都继承自 BaseBrowserToolExecutor 类别,该类别提供通用辅助方法:injectContentScript() 搭配 ping/pong 去重复、sendMessageToTab()、getActiveTabOrThrow() 和分页焦点管理。
工具分为几个类别:
页面互动 — click_element、fill_form_field、select_dropdown、check_box、scroll_page 和 navigate。这些透过 CSS 选择器或自动生成的参考 ID 来识别 DOM 元素进行操作。
内容读取 — read_page 解析 DOM 并为互动元素分配稳定的参考 ID。这就是 AI「看到」页面的方式 — 它获得带有可点击参考的结构化文字,而不是原始 HTML。
平台专用提取器 — web_fetcher 具有针对 Gmail、Slack、Jira、Salesforce、ServiceNow 和 HubSpot 的专门解析器。这些解析器不是通用的 DOM 抓取,而是理解每个平台的标记结构并提取干净、具型别的资料。
浏览器内部功能 — javascript 透过 Chrome DevTools Protocol Runtime.evaluate 执行任意程式码、network_capture 监控 HTTP 流量、screenshot 撷取视窗或特定元素,以及 gif_recorder 建立多步骤互动的动画录制。
注入脚本:在页面世界中执行
架构中最棘手的部分是注入脚本。Content script 在隔离的世界中执行 — 它们可以读取 DOM,但无法存取页面的 JavaScript 情境、React 元件状态或框架内部。
我们有 16 个 TypeScript 模组,透过自订 esbuild plugin 打包为 IIFE,并注入到 MAIN 世界中。这让它们能够存取 React 内部、呼叫页面层级的 API,并与单页应用程式路由器互动。
注入使用 ping/pong 去重复来避免将相同脚本注入到分页两次,结果透过 window.postMessage 流回 content script,然后再传到 background worker。
我们学到的经验
Manifest V3 service worker 是短暂的。 它们可能随时被浏览器终止。我们必须让 WebSocket 连线能够从 service worker 重启中恢复 — 在不丢失待处理工具呼叫的情况下透明地重新连线。
平台专用解析胜过通用抓取。 我们的第一版对所有内容都使用通用 DOM 提取。Gmail 的 HTML 巢状结构很深,并且在更新之间会变化。为每个平台(目前有 6 个)编写针对性的解析器,大幅提升了可靠性和资料品质。
MCP 是个很适合这个用途的协定。 基于 JSON-RPC 2.0 的基础,配合 tools/list 发现和具型别的 tools/call 呼叫,实作起来足够简单,但结构化程度足以保持可靠。我们发现它比建立自订协定更容易扩充。
接下来的计划
我们正在努力扩充平台专用处理器,改善跨单页应用程式导航的元素定位可靠性,并探索与更广泛的 MCP 生态系统共享工具定义的方法。
如果你正在打造 MCP 整合或浏览器自动化工具,我们很乐意听听你发现哪些模式有用。这个协定仍然年轻,社群正在一起摸索最佳实践。