Browser Controller
这个项目解决了什么问题
你提交了一个修复。你的智能体说"完成了,请验证。" 你切换到 Chrome,导航到页面,登录,点击各处,找到 bug。
你的智能体刚刚写了代码。它也可以验证。 你的浏览器已经为它打开着。它只是看不到。
现在它可以了。 Browser Controller 让任何兼容 MCP 的 AI 智能体(Cursor、Claude Desktop、Windsurf……)直接控制你已经打开的浏览器——你真实的会话、你的登录状态、你的 cookie。无需无头浏览器,无需全新配置文件,无需重新认证。
Related MCP server: Tabryn
核心能力
同时支持多个智能体。 Cursor 可以驱动标签页 10,而 Claude 驱动标签页 11——两者通过同一个共享守护进程,互不阻塞。
按标签页定位,而非"当前活动标签页"。 每个操作都指定一个
tabId。移动鼠标、切换标签页、看 YouTube——智能体始终在你指定的标签页上工作。它永远不会劫持你正在阅读的页面。按标签页隔离。 元素引用、控制台日志和网络缓冲区都按标签页隔离。来自标签页 10 的引用永远无法点击标签页 20 中的内容。
按标签页并发。 对同一个标签页的两个操作会串行化(无竞争);对不同标签页的操作并行执行。
标签页锁定。 智能体可以认领一个标签页,让其他智能体排队等待而不是竞争(
browser_tabs { action: "lock" })。锁在 Chrome 的 service-worker 回收后依然有效(chrome.storage.session)。智能体控制防护罩。 当智能体在某个标签页上工作时,你会看到一个半透明的蓝色内框,并且你在该标签页上的输入会被阻止(鼠标、键盘、滚轮)——徽章显示
agent <name> controlling the tab,操作完成后消失。锁定标签页会在锁的存续期间保持一个普通边框。同源 iframe 穿透。 位于 iframe 内的旧式/企业界面(例如
iframe#mainFrame中的 ONT 控制台)可以访问:所有定位工具都会搜索 iframe 文档,find/click_text会遍历每个框架。原生对话框救援。 原生的
alert/confirm/prompt会冻结页面的 JS 线程——browser_handle_dialog通过 CDP 带外解除它,无需页面 JS,这也会解除该标签页上所有其他工具的阻塞。browser_tabs close/focus始终有效,即使在冻结的标签页上也是如此。经过认证的本地连接。 令牌 + 一次性注册密钥,因此没有其他本地进程可以静默驱动你的浏览器。一切都在 localhost 上——无云端,无遥测。
无调试器横幅。
browser_evaluate通过chrome.scripting在页面的 MAIN 世界中运行——没有黄色的"此标签页正在被调试"横幅,真实值可以跨 MV3 世界边界返回。诚实的错误。 每个工具失败都会以真实的
isError结果连同完整负载到达你的智能体——不会用"成功"响应来掩盖工作流中途的失败。
工作原理
三个部分,全部在你的机器上。没有任何内容离开 localhost。
Agent (Cursor / Claude / Windsurf) ── other agents connect too ──┐
│ stdio (MCP protocol) │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────────────────┐
│ thin MCP client │ │ thin MCP client │
│ (node mcp-server/dist/ │ │ (node mcp-server/dist/ │
│ index.js) │ │ index.js) │
│ - speaks MCP over stdio │ │ - spawns daemon if not running │
│ - forwards calls to daemon │ │ - gets its own sessionId │
└──────────────┬──────────────┘ └────────────────────┬───────────────────┘
│ local IPC socket (AF_UNIX / named pipe, token-auth) │
▼ ▼
┌──────────────────────────────────────────────────────────────────────────┐
│ DAEMON (single long-running process, owns port 7225) │
│ - multiplexes N clients → 1 extension │
│ - tags every call with the client's sessionId │
│ - heartbeat eviction, per-session rate limiting │
└──────────────────────────────┬───────────────────────────────────────────┘
│ WebSocket ws://127.0.0.1:7225 (token-auth)
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ Chrome Extension (Manifest V3 service worker) │
│ - resolves the target tabId (never "the active tab" implicitly) │
│ - serializes same-tab actions, parallelizes cross-tab actions │
│ - executes click/type/snapshot/evaluate against the named tab │
└──────────────────────────────────────────────────────────────────────────┘关键思路: 任何智能体首次运行时,瘦客户端会启动一个后台守护进程,它拥有端口 7225 和扩展连接。之后每个智能体(即使来自不同的 MCP 客户端)都通过本地 IPC 套接字连接到同一个守护进程,并获得自己的 sessionId。扩展看到的是一个稳定的连接,并将每个调用路由到调用者指定的确切标签页。
快速开始
该项目不在 Chrome 网上应用店或 npm 上——你需要从这个仓库安装。两个部分:MCP 服务器(在你的机器上运行,与你的 AI 智能体通信)和 Chrome 扩展(位于你的浏览器中,执行命令)。
前置条件: Node.js ≥ 20 和 Chrome/Chromium/Edge。
1. 克隆并构建
git clone https://github.com/compnew2006/browser-controller.git
cd browser-controller
npm install
npm run build # compiles TypeScript → mcp-server/dist/2. 加载 Chrome 扩展
打开
chrome://extensions并启用开发者模式(右上角的开关)点击加载已解压的扩展程序,选择克隆仓库中的
extension/文件夹将 Browser Controller 图标固定到工具栏
灰点 = 等待守护进程。绿色 = 已连接。
3. 将 MCP 服务器添加到你的客户端
Cursor:设置 → MCP → "添加新的 MCP 服务器"。Claude Desktop:编辑 claude_desktop_config.json。Windsurf:设置 → MCP。任何兼容 MCP 的客户端都可以。
将 /path/to/browser-controller 替换为你克隆的绝对路径(Windows:使用 C:\\path\\to\\browser-controller\\mcp-server\\dist\\index.js):
{
"mcpServers": {
"browser-controller": {
"command": "node",
"args": ["/path/to/browser-controller/mcp-server/dist/index.js"]
}
}
}默认情况下,守护进程会根据其父级 IDE("Cursor"、"Claude"……)为每个连接命名。要覆盖此设置——例如当多个智能体共享一个 IDE 时,或按项目标记它们——在参数中传入 --agent <name>。它优先于所有自动检测:
{
"mcpServers": {
"browser-controller": {
"command": "node",
"args": ["/path/to/browser-controller/mcp-server/dist/index.js", "--agent", "My Project Agent"]
}
}
}该名称会出现在弹窗的已连接智能体列表中。(你也可以设置 MCP_AGENT_NAME 环境变量——效果相同。)使用相同名称重新连接会替换旧条目,因此 IDE 重启不会堆积重复项。
4. 将扩展与守护进程配对
守护进程使用两个密钥,均在首次运行时生成到 ~/.browser-controller/(Windows:%USERPROFILE%\.browser-controller\)。先让智能体"列出我的浏览器标签页"来启动它一次,然后:
读取密钥:
cat ~/.browser-controller/enrollment.json # one-time pairing secret cat ~/.browser-controller/token.json # WebSocket auth token(注册密钥在首次运行时也会打印到 MCP 客户端的日志中。)
点击扩展图标 → 设置标签页 → 粘贴注册密钥和认证令牌(除非你更改了
WS_PORT,否则端口保持7225)。
绿点 = 你已连接。你的智能体现在可以看到你的浏览器了。
这些密钥可防止任何其他本地进程打开 WebSocket 并驱动你经过认证的浏览器会话。要轮换它们,请停止你的 MCP 客户端,删除该文件夹,下次运行时会重新创建两个密钥。完整的威胁模型请参阅 SECURITY.md。
使用方法
模型是标签页优先的:智能体总是说明要对哪个标签页执行操作。它从不假设是"当前活动标签页"。
基本工作流
列出标签页以获取
tabId:browser_tabs { action: "list" } → [{ id: 15, url: "...", title: "...", active: true, lockedBy: null }, ...]快照该标签页以查看其结构并获取元素引用:
browser_snapshot { tabId: 15 } → { tree: [ { ref: "e3", role: "button", name: "Sign in" }, ... ] }引用仅对此 tabId 有效。如果你导航或 DOM 发生变化,请重新快照。自上次快照以来的新元素会被标记为
isNew: true——在操作打开覆盖层/下拉菜单后,智能体可以只关注这些元素,而无需重新读取整个树。交互,使用引用和相同的 tabId:
browser_click { tabId: 15, ref: "e3" } browser_type { tabId: 15, ref: "e5", text: "hello@example.com" } browser_press_key { tabId: 15, key: "Enter" }如果引用已过期但元素仍然存在,会通过稳健的选择器 + 文本/角色扫描自动找到它(响应携带
via: "fallback")。如果元素被完全滚动出视野(虚拟化信息流),响应会携带freshRefs: [...]及内联的新快照——在同一个步骤中用这些新引用之一重试,无需单独快照。验证——操作后再次快照或读取文本。
多智能体协调(两个智能体,两个标签页)
智能体 A 列出标签页,选择标签页 10,可选地锁定它:
browser_tabs { action: "lock", tabId: 10 }智能体 B 列出标签页,选择标签页 11,锁定它:
browser_tabs { action: "lock", tabId: 11 }两者并行工作。每个智能体的调用针对自己的标签页串行化;两个标签页互不干扰。
完成后:
browser_tabs { action: "unlock", tabId: 10 }。
弹窗就是你的控制面板
一个固定高度的标签式外壳(主体从不滚动,只有列表滚动):
标签页 — 每个打开的标签页及其锁所有者,工具栏中还有全部解锁,用于在智能体锁定中途崩溃时一键释放。
智能体 — 每个已连接的智能体及其名称、会话 ID、运行时间,以及一个 ✕ 可立即断开连接(清除心跳尚未回收的僵尸进程)。
设置 — WebSocket 端口、认证令牌、注册密钥。
活动栏 — 底部一个可折叠的条带,显示最新的工具活动;展开可查看滚动日志。
需要了解的事项
忘记
tabId了? 你会收到明确的错误:tabId is required. Call browser_tabs list first.受保护的页面(
chrome://、网上应用店、devtools)无法被脚本化——你会收到Cannot access protected page (chrome://...),而不是静默挂起。browser_navigate是唯一一个tabId可选的工具(默认为活动标签页)——但为了多智能体安全,请显式传入。仅哈希变化(例如/page→/page#section)在 URL 设置后立即解析,无需等待complete事件(SPA 在哈希变化时不会重新加载,因此该事件永远不会触发)。browser_evaluate在页面的 MAIN 世界中运行(无调试器横幅,CSP 安全)并返回真实值(跨世界边界进行 JSON 序列化)。它很强大但非幂等——超时后不会自动重试。滚动虚拟化信息流(Facebook/Instagram/Twitter):
browser_scroll返回refsMayBeStale: true,因为这些站点会回收 DOM 节点。下次交互前请重新快照。重复元素:当多个元素共享文本+角色时(例如 3 个"点赞"按钮),回退解析器按序号(
nth)选择正确的那个,而不仅仅是第一个匹配项。冻结的标签页(原生对话框阻塞)不会让你死锁:
browser_handle_dialog通过 CDP 解除它,browser_tabs { action: "close" }始终有效,是保证退出的方式。
🧠 教你的智能体
智能体开箱即可使用全部 22 个工具,但当它了解标签页优先的工作流时会表现更好。从仓库根目录:
npm run setup:cursor # or: node mcp-server/dist/index.js --setup cursor这会安装:
~/.cursor/rules/browser-controller.mdc— 标签页定位工作流、下拉菜单处理、何时锁定标签页~/.cursor/commands/check-browser.md— 为你的 Cursor 聊天添加/check-browser
之后,在任何聊天中输入 /check-browser。或者直接说"在我的浏览器中检查结果",智能体就知道该做什么。
npm run setup:claude在你的项目根目录添加一个 AGENTS.md。Claude Code 会自动发现它。
手动安装或自定义规则请参阅 agent-config/。
它能做什么
22 个工具。每个页面交互工具都接受一个 tabId(唯一的例外是 browser_navigate,其中它是可选的)。
查看
工具 | 功能 |
| 带元素引用的无障碍树。紧凑模式(默认)仅返回可交互元素。遍历 shadow DOM 和 iframe。 |
| 将标签页捕获为图像(先激活标签页再捕获) |
| 从页面或元素提取原始文本 |
| 通过自然语言查询元素——也会遍历同源 iframe |
交互
工具 | 功能 |
| 通过引用或 CSS 选择器点击——穿透同源 iframe |
| 按可见文本点击。可穿透 React portals 和覆盖层 |
| 在输入框和 contenteditable 字段中键入 |
| 按键组合(Enter、Escape、Ctrl+A) |
| 滚动页面和虚拟容器 |
| 触发工具提示和下拉菜单 |
| 从原生 |
| 等待元素出现或消失 |
| 一次调用填充多个表单字段(React/Vue 安全的 setter) |
| 元素到元素的拖拽(使用 CDP 保证可靠性) |
| 通过 |
browser_upload_file 将本地文件注入 <input type="file">,就像用户选择了它们一样:原生对话框永远不会打开,之后会触发 input/change 事件,因此 React/Vue 表单会做出响应。
browser_upload_file { tabId: 15, selector: "#resume", filePath: "/Users/me/resume.pdf" }
browser_upload_file { tabId: 15, ref: "e12", files: ["/tmp/a.png", "/tmp/b.png"] }路径是绝对的,并且位于运行浏览器的机器本地。省略 ref/selector 会自动定位页面上的第一个文件输入;一次上传多个文件需要带有 multiple 的输入。
导航
工具 | 功能 |
| 在标签页中转到 URL( |
| 列出 / 创建 / 关闭 / 聚焦 / 锁定 / 解锁 标签页 |
调试与高级
工具 | 功能 |
| 控制台输出(log、warn、error)——按标签页,上限 200 条 |
| 带状态码的 XHR/fetch 请求——按标签页,可选 |
| 在页面的 MAIN world 中运行 JavaScript(无横幅,CSP 安全) |
| 通过 CDP 关闭/接受打开的 alert/confirm/prompt(在冻结页面上也可用) |
| 通过 CDP 运行自包含的 JS action 对象 |
与其他方案对比
Browser Controller | Playwright MCP | Chrome DevTools MCP | |
使用你现有的浏览器 | 是 | 否,会启动新的 | 部分,需要调试端口 |
会话和 Cookie | 已经存在 | 全新配置文件 | 手动设置 |
支持企业 SSO 登录 | 是 | 否 | 视情况而定 |
多代理、多标签页 | 是 | 否 | 否 |
标签页定位(不会劫持活动标签页) | 是 | 不适用 | 否 |
经过身份验证的本地连接 | 是 | 不适用 | 否 |
设置 | 从源码构建 + 扩展 | 无头浏览器 | 带 |
配置
环境变量 | 默认值 | 功能 |
|
| 守护进程用于扩展连接的 WebSocket 端口 |
| (未设置) | 设置为 |
| (自动:IDE 名称) | 覆盖弹出窗口中显示的代理名称(与 |
守护进程状态文件
守护进程将所有内容保存在 ~/.browser-controller/(Windows:%USERPROFILE%\.browser-controller\):
文件 | 用途 |
| 扩展的一次性配对密钥(模式 |
| 扩展在每次 WebSocket 连接时必须提供的认证令牌(模式 |
| 瘦客户端连接的 IPC 套接字(mac/linux 上为 AF_UNIX;Windows 上为命名管道) |
| 守护进程元数据(pid、端口、启动时间)——用于检测正在运行的守护进程 |
| 客户端启动守护进程时的 stdout/stderr |
要完全重置:停止你的 MCP 客户端,删除该文件夹,下次运行时会用新的密钥重新创建。
可靠性
守护进程在任何客户端首次运行时自动启动,并保持分离运行。
连接断开时使用指数退避(1 秒 → 30 秒),每 10 秒进行 ping/pong 健康检查;错过 3 次 pong 的客户端将被驱逐。
每会话 120 次/分钟的速率限制保护守护进程免受失控的代理循环影响。
每个工具都有超时(大多数操作 5–15 秒,导航 60 秒),与每个工具的定义放在一起,因此不会与注册表脱节。
幂等读取工具(snapshot、screenshot、text、find)在超时时会重试;有副作用的工具(click、type、navigate、evaluate)——以及
console/network(在clear:true时会修改状态)——绝不重试,因此点击不会触发两次。如果另一个进程已经占用了端口 7225,守护进程会拒绝启动,而不是杀死它没有启动的进程——它会报告冲突,以便你有意识地解决它。
通过为每个客户端设置 WS_PORT,在不同的端口上运行两个守护进程:
{
"mcpServers": {
"browser-work": {
"command": "node",
"args": ["/path/to/browser-controller/mcp-server/dist/index.js"]
},
"browser-personal": {
"command": "node",
"args": ["/path/to/browser-controller/mcp-server/dist/index.js"],
"env": { "WS_PORT": "9333" }
}
}
}更新每个扩展弹出窗口中的端口以匹配。
架构
一切都在你的机器上。扩展通过 localhost 上的经过身份验证的 WebSocket 连接到守护进程;MCP 客户端通过本地 IPC 套接字连接到守护进程。没有云、没有代理,没有任何东西离开你的浏览器。
browser-controller/
├── mcp-server/ MCP server (TypeScript)
│ └── src/
│ ├── daemon.ts Single multi-client daemon (owns WS :7225)
│ ├── daemon-config.ts IPC protocol, paths, auth/enrollment tokens
│ ├── index.ts Thin stdio MCP client (spawns daemon, multiplexes)
│ ├── bridge.ts Extension WS server + cross-platform port probe
│ ├── register-tools.ts Progressive-disclosure wiring
│ └── tools/ One file per tool (22), registry pattern
├── extension/ Chrome extension (Manifest V3, plain JS, ES modules)
│ ├── background.js Wiring only (~30 lines): inject router, register events, connect
│ ├── lib/ state (buffers/locks/persistence), connection (WS lifecycle),
│ │ router (dispatch + mutex/locks + control shield), page-exec,
│ │ overlay, lock-ops, tab-concurrency (pure, unit-tested)
│ ├── handlers/ Tool implementations: navigation, interaction, inspection, tabs, cdp
│ ├── utils/ navigation + smart-selector fallback resolution
│ ├── events.js chrome.* listeners (console capture, popup, webRequest, lifecycle)
│ ├── content.js Console capture
│ └── popup/ Fixed tabbed shell (Tabs · Agents · Settings) + collapsible activity bar
├── agent-config/ Pre-built configs for Cursor + Claude Code
│ ├── cursor/ Rules and commands
│ ├── skills/ Browser automation skill
│ └── setup.mjs One-command installer
└── tests/ 15 suites / 215 tests技术栈: TypeScript(严格模式)· MCP SDK · WebSocket · Chrome 扩展 Manifest V3 · Vitest
开发
git clone https://github.com/compnew2006/browser-controller.git
cd browser-controller
npm install
npm run build
npm test命令 | 功能 |
| 将 TypeScript 编译到 |
| 监视模式 |
| 运行完整测试套件(215 个测试) |
| 仅进行类型检查,不输出 |
| 安装 Cursor 规则 + 命令 |
| 安装 Claude Code |
该套件涵盖 WebSocket 桥接(包括令牌认证拒绝和统一错误通道)、工具注册表、守护进程生命周期(心跳驱逐、速率限制、IPC 认证)、每标签页并发(同标签页串行化 + 跨标签页并行),以及通过模拟的 chrome API 测试扩展行为(路由分发、shield 语义、evaluate 往返、iframe 穿透、对话框救援)。CI 在 Node 20 和 22 上运行该套件,外加 CodeQL 和 Scorecard 扫描。
更新现有安装
git pull
npm install
npm run build然后有两个手动步骤:在 chrome://extensions 中重新加载扩展(运行中的 service worker 不会自行拾取文件更改),以及重启守护进程——它是长期运行的,也不会重新加载 dist/(杀掉它,或者直接重启你的 MCP 客户端,下次运行会在新构建上重新启动它)。
常见问题
这正是它的意义所在。扩展运行在你实际的 Chrome 中——相同的 Cookie、相同的会话、相同的本地存储。无需重新认证。
不会。MCP 客户端、守护进程和扩展都通过 localhost(IPC 套接字 + WebSocket)通信。没有任何东西离开你的机器。没有分析、没有遥测、没有云组件。有关威胁模型、认证设计和首次接触 TOFU 窗口,请参阅 SECURITY.md。
任何兼容 MCP 的客户端。Cursor、Claude Desktop、Claude Code、Windsurf、Cline,以及任何其他支持 MCP 协议的客户端。多个客户端可以同时连接同一个守护进程运行。
可以。每个代理连接到共享守护进程,获取自己的 sessionId,并针对特定的 tabId。同一标签页上的操作通过每标签页互斥锁串行化;不同标签页上的操作并行运行。代理可以选择 lock 一个标签页以声明独占访问权;其他代理会在锁后面排队,而不是失败。
它不会——不会静默发生。每个页面交互工具都需要 tabId,如果缺少,你会收到明确的 tabId is required 错误。代理永远不会意外操作你正在查看的标签页。(唯一的例外是不带 tabId 的 browser_navigate,它使用活动标签页——但在多代理场景下,你应该始终传递 tabId。)
没有它们,你机器上的任何本地进程都可以打开到端口 7225 的 WebSocket,并驱动你已认证的浏览器会话(你的银行、你的邮箱、你公司的 SSO)。enrollment 密钥将扩展与守护进程恰好配对一次(带外,在任何 WebSocket 存在之前);然后 auth token 对每个连接进行认证。两者都存放在 ~/.browser-controller/ 中,权限为 0600。
它们会从零启动一个新的浏览器实例——没有状态、没有 cookie、没有会话。你每次都必须重放完整的登录流程。而这个是连接到你已经打开的浏览器,所有内容都已加载完毕。
贡献
欢迎在问题跟踪器提交错误报告、功能请求和 PR。较大的更改请先打开一个 issue。
安全
参见 SECURITY.md——仅限 localhost 的架构、token + enrollment 设计、威胁模型和报告指南。
许可证
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables CLI coding agents to interact with your live browser tabs via MCP, using your real sessions and cookies without a sandbox.MIT
- AlicenseNot gradedqualityAmaintenanceConnects AI agents to your Chrome browser via MCP, enabling real-time control of existing tabs, sessions, and application state for development workflows.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to control your existing Chrome browser via MCP, using your logged-in sessions for automation on authenticated sites. Provides high-level browser tools plus raw CDP and Chrome API access.MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI to control a real browser through MCP tools for clicking, typing, navigation, screenshots, and more. It supports a follow mode that tracks the active tab, plus fixed mode for controlling specific tabs.18MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/compnew2006/browser-controller'
If you have feedback or need assistance with the MCP directory API, please join our Discord server