chrome-in-harness
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@chrome-in-harnessopen my Gmail inbox and summarize the top 5 unread emails"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
chrome-in-harness
中文 | English
Claude-in-Chrome 风格的开源浏览器 MCP:通过 Chrome 扩展,让支持 MCP 的 AI 客户端(OpenCode / Claude Code 等)操作你真实的 Chrome profile,复用已有登录态、cookie 和插件环境,无需另起 headless 浏览器或重新登录。
便利优先,强烈建议只在测试环境使用。 本项目为降低浏览器自动化的使用成本,在安全性上做了明确取舍:操作发生在真实浏览器中,没有独立沙箱,点击、输入和提交会直接作用于已登录账号。 请使用专用测试 Chrome profile、测试账号和测试数据,避免连接生产后台、日常主力浏览器或含敏感信息的页面。域名白名单、受管标签页和脚本限制能减少误操作,但不构成完整安全隔离。
功能概览
看页面:读取可访问性树快照、元素文本和截图,使用带版本的 ref 定位元素。
操作页面:导航、点击、悬停、滚动、文本输入和快捷键;iframe / Canvas 等无法通过 ref 命中的目标可用坐标点击。
编辑代码:支持保留多行缩进的输入,以及通过页面暴露的 Monaco API 全量写入编辑器;包含键盘通路检测和编辑器塌缩恢复。
管理标签页:创建、切换、关闭标签页,或显式接管已有标签页;操作限定在 "Chrome in Harness" 受管组内。
标签页会话:
ensure_tab提供可复用的标签句柄——每个 agent 固定用自己的标签,标签被关自动补建,避免标签越开越多。批量执行:
run_actions一次调用按顺序执行多个工具(如逐字符输入、点击序列),减少 MCP 往返。等待与排查:等待文本、选择器、URL 或编辑器就绪,读取控制台消息及网络请求元数据,执行受限页面 JS 表达式。
不打扰浏览:新标签一律后台打开不抢焦点;输入通过焦点仿真在后台标签执行;需要人工操作(登录、验证码)时 agent 会提示你自行切换。
Related MCP server: chrome-bridge
架构
AI / MCP 客户端(OpenCode、Claude Code 等)
│ Streamable HTTP:工具调用 / 结果
▼
本地 Node.js server · http://127.0.0.1:12306/mcp
│ WebSocket:请求转发 / 响应关联
│ ws://127.0.0.1:8765(扩展主动连接)
▼
Chrome 扩展 · MV3 service worker / WXT
│ chrome.debugger / Chrome DevTools Protocol
▼
真实 Chrome profile 中的受管标签页四个包(每个子包都有自己的 README,含更详细的架构说明):
包 | README |
| |
| |
| |
|
扩展 service worker 作为 WS client 主动连
ws://127.0.0.1:8765(无需 Chrome 额外暴露端口,连接由扩展发起)server 在
http://127.0.0.1:12306/mcp暴露 MCP(Streamable HTTP,无状态模式);收到 tool call 后通过 WS 转发给扩展,按消息id关联等待响应,超时 30sWS 协议 v1:请求
{ v: 1, id, tool, params },响应{ v: 1, id, ok, result | error };定义与守卫集中在@chrome-in-harness/protocol,server 与扩展共用一份一次调用的路径:客户端选择工具 → server 转发 WS 请求 → 扩展解析参数并检查标签页 / 域名边界 → CDP 执行 → 结果经 server 返回客户端。浏览器操作由扩展执行,server 不另起浏览器实例。
扩展与 server 之间的桥接运行在本机;页面快照、截图、日志等工具结果会返回 MCP 客户端,是否继续发送给远程模型取决于客户端配置。
安全取舍与边界
这是面向开发、调试和测试的便利工具,不是生产环境的安全隔离方案。复用真实登录态意味着 agent 可能以当前账号权限执行操作;网页内容或模型判断也可能误导后续调用。项目没有对每次点击、输入或提交做人工审批,域名授权也不等于对站点内每个动作授权。
已有的限制包括:
WS 握手校验 Origin:只接受
chrome-extension://来源。浏览器强制写入 Origin 且页面无法伪造,因此恶意网页无法连上127.0.0.1:8765顶掉真扩展并接管 tool call。设CIC_EXTENSION_ID可进一步锁定到具体扩展 IDMCP 端点开启 DNS rebinding 防护:强制校验 Host 为
127.0.0.1:12306/localhost:12306;Origin 存在时一并校验(浏览器页面会被拒,非浏览器 MCP 客户端正常放行)标签页与域名边界:浏览器执行前检查受管组和域名白名单;新域名默认弹出确认窗口。
add_allowlist_domain可直接写入白名单,其"仅在用户明确要求时使用"依赖客户端 / agent 遵守工具说明。受限脚本:
evaluate_script使用黑名单和表达式形态检查,限制常见网络、导航和动态执行 API;这是减少误用的护栏,不是 JS 沙箱,也不保证所有页面表达式无副作用。扩展权限按需申请:
alarms(SW keepalive)、tabs+tabGroups(tab 管理 / 受管组边界 / URL 变化失效 ref)、storage(域名白名单持久化)、debugger(CDP 会话,仅在 attach 时出现「正在调试」黄条)、permissions(request_permission弹窗授权);host permission 仅 loopback127.0.0.1:8765,运行时通过optional_host_permissions白名单授权目标站
这些限制不覆盖本机恶意进程:MCP 端点没有客户端身份认证,本机进程也可伪造 Origin 连接 WS。不要将本地端点暴露到公网或不可信网络。强烈建议仅连接测试环境,并使用隔离的测试 profile 与账号。 权限与数据处理细节见 CWS_DISCLOSURE 和 PRIVACY。
工具与行为细节
工具集(24 个):ping、navigate、snapshot、click、click_at、hover、type、press_key、get_text、scroll、screenshot、tab_list、tab_new、ensure_tab、tab_select、tab_close、takeover_tab、run_actions、read_console、read_network、wait、add_allowlist_domain、evaluate_script、request_permission。
read_console / read_network:CDP 采集的 console 与网络请求元数据(响应体不采集)。缓冲从 tab 首次被工具 attach 起积累
wait:等待文本 / CSS 选择器 / URL 子串出现(页面内 Promise 轮询,默认 8s 上限 30s),超时返回
{matched:false}而非报错add_allowlist_domain:显式扩白名单(无确认窗口,直接生效)。一般无需手动调用——访问新域名会自动弹确认窗口
evaluate_script:受限
Runtime.evaluate执行页面上下文 JS。黑名单拒绝网络访问(fetch/XHR/WebSocket/sendBeacon)、eval/Function、导航(location/window.open)、document.write、debugger 与chrome.*;awaitPromise:true需 async IIFE;结果 JSON 序列化超限截断request_permission:针对域名发起
chrome.permissions.request原生授权弹窗,授予后同步写入 storage 白名单。仅当用户明确要求时调用takeover_tab:把已打开的用户 tab 收编进受管组(
tab_list标[managed:<groupId>]便于识别);仅在用户明确要求在该 tab 工作时调用,URL 必须已在白名单snapshot:
chrome.debugger+ CDPAccessibility.getFullAXTree,渲染成 Playwright ariaSnapshot 风格的缩进文本,交互元素带[ref=eN-<token>];优先用 ref 交互,减少选择器漂移。坐标点击、当前焦点输入等场景可不使用 refref 生命周期:ref 绑定 tab 的最近一次快照,格式
e<N>-<token>(token 编码 worker 代 + 快照版本);导航/关 tab/debugger 分离即失效;跨 worker 代或过期一律显式STALE_REF(拒绝静默错点);同代快照更替时交互工具按元素身份自动重试一次;SW 被杀后报NO_SNAPSHOT引导重新 snapshotclick snapshot:
click({ref, snapshot: true})点击后等两帧渲染(后台 tab 上限 300ms)再返回新快照,适合点击即重渲染、旧 ref 全部失效的页面,省一次snapshot往返;异步取数后才渲染的内容仍应先wait。点击已生效但取快照失败时只提示失败、不报错,避免误重点click_at:ref 命中不了时(iframe/Canvas/icon-only 容器)的坐标点击兜底,视口 CSS 像素,越界显式报错
press_key:单键/组合键(
ctrl/alt/shift/meta+ 键名,支持 F1-F24),可选先 focus 指定 ref;派发前有默认动作探针——临时离屏输入框验证按键真的产生字符插入(监听器探针检测不出「事件送达但默认动作被丢弃」的假活,resize/失焦后的典型死法),死了自动重开焦点仿真/激活自愈,仍死显式报KEY_PIPELINE_DEADget_text:优先读 AX value(虚拟滚动编辑器全文唯一可靠读数),innerText 兜底,上限 8KB
type:
mode="insert"(默认)/mode="verbatim"(Monaco 类编辑器逐行 insertText 还原缩进,无 trim)/mode="set"(monacosetValue原子写整个缓冲——绕开键盘/焦点/IME 通路,窗口失焦、键路死亡、编辑器塌缩都不影响;ref 可省,单编辑器页面自动选中);焦点不在可编辑元素时显式报INPUT_NOT_LANDED而非静默假成功;返回插入点概要{line, col}供模型自查wait editorRendered:Monaco 渲染完成 = 高度 > 40px 且宽度 > 200px 且有非空 view-line——resize 后塌缩成 5×5 窄条的假就绪不再放过;检测到塌缩自动按父容器尺寸强制
layout()重排救回(无参 layout 会按自身窄宽度自我维持,必须显式传维度)输入路径:常规点击与输入通过 CDP
Input.*派发浏览器事件;type mode="set"则直接调用 Monaco API,不模拟逐键输入。不保证网站将自动化操作视为人工操作域名白名单 + 运行时确认:
chrome.storage.local持久化,扩展侧在 attach 前校验,空名单 = 拒绝全部;规则example.com匹配自身与任意深度子域。访问未授权域名时自动弹出确认窗口(显示域名与来源 URL,允许/拒绝),工具即时返回DOMAIN_CONFIRMATION_REQUIRED(非阻塞),用户点「允许」后重试即通过——无需手动改配置受管组复用:
tab_new/takeover_tab优先并入本窗口既有的 "Chrome in Harness" 组(组标题带⏳/✅/❌操作状态前缀时也识别为同一组),避免每开一个 tab 就新建组代价(已接受):attach 期间 Chrome 显示「正在调试」黄条;目标 tab 打开 DevTools 会顶掉扩展会话,工具报
DEBUGGER_BUSY,关闭 DevTools 后自动恢复后台操作(自动处理,不抢前台):CDP
Input.*在后台 tab 上会被静默丢弃;输入类工具派发前开Emulation.setFocusEmulationEnabled焦点仿真(Playwright / Claude-in-Chrome 同款),让后台 tab 直接接收输入,不激活 tab、不打断用户当前视图;仿真不可用时回退激活 tab;窗口最小化时自动恢复并聚焦,恢复失败报WINDOW_NOT_INTERACTIVE
安装与运行
整体分四步:① 启动本地 server → ② 安装 Chrome 扩展 → ③ 注册 MCP 客户端 → ④ 验证。扩展没有上架 Chrome Web Store,第 ② 步需要手动加载,请仔细按流程操作。
前置要求
Node.js ≥ 20(推荐 22)
Chrome / Chromium 系浏览器
强烈建议使用专用测试 Chrome profile(Chrome → 右上角头像 → 添加新用户),与日常浏览隔离
第 ① 步:启动本地 server
npx @chrome-in-harness/launcher start这一条命令会:
检测 server 是否已在运行(已运行则直接复用)
启动本地 server(WS
127.0.0.1:8765↔ MCPhttp://127.0.0.1:12306/mcp)自动向
~/.config/opencode/opencode.json写入chrome-in-harness的 remote MCP 条目(已有同名条目会保留;配置文件无法读取或非法时会报错退出,不覆盖原文件)
start 是前台进程,关掉终端即停止。如需长期在线,见下文常驻服务。
第 ② 步:安装 Chrome 扩展(手动加载)
扩展未上架 Chrome Web Store,需以"开发者模式 + 加载已解压的扩展程序"方式安装。扩展来源二选一:
方式 A:GitHub Releases 下载 zip(推荐使用者)
到 Releases 页面 下载
chrome-in-harness-extension.zip解压到一个长期保留的固定目录(例如
~/chrome-in-harness-extension)。注意:解压目录不能删除或移动,Chrome 是"引用"这个目录加载扩展的,目录没了扩展就失效Chrome 打开
chrome://extensions打开右上角的 开发者模式 开关
点击左上角 加载已解压的扩展程序,选择上一步的解压目录(选目录本身,不是 zip)
列表出现 Chrome in Harness 即安装成功
方式 B:源码构建(开发者)
git clone https://github.com/hcfw007/chrome-in-harness.git
cd chrome-in-harness
npm ci && npm run build:extension然后同方式 A 的 3-5 步,选择目录改为 packages/extension/.output/chrome-mv3。
扩展升级方法
方式 A:下载新版本 zip → 解压覆盖同一目录 → 回到
chrome://extensions,在 Chrome in Harness 卡片上点 刷新 ↻ 图标方式 B:
git pull && npm ci && npm run build:extension→ 同样点刷新图标
首次使用提示
扩展安装后即自动连接本地 server(
ws://127.0.0.1:8765),无需配置;server 后启动也没关系,扩展会自动重连扩展的「扩展程序选项」页可维护域名白名单和访问模式
首次访问白名单外的域名时,会弹出确认窗口,点「允许」即加入白名单
第 ③ 步:注册 MCP 客户端
OpenCode:第 ① 步的
start已自动写入全局配置,重开客户端会话即可其他 MCP 客户端(Claude Code 等):手动注册 remote MCP 端点
{ "mcpServers": { "chrome-in-harness": { "type": "http", "url": "http://127.0.0.1:12306/mcp" } } }
第 ④ 步:验证全链路
npx @chrome-in-harness/launcher doctor应看到:
[✓] server 已在运行 (http://127.0.0.1:12306/mcp)
[✓] 扩展已连接(ping 通过)也可以直接在 MCP 客户端里让模型调 ping,应返回扩展版本与 userAgent。
MCP 升级后必须重启客户端会话:opencode / Claude Code 等客户端在会话启动时注册工具 schema,运行中不会热更新。服务端升级新参数/新工具后,老会话仍按旧 schema 校验并拦截新参数——重启会话即可。ref 格式同样注意:快照 ref 带 token 后缀(如
e3-a7k2),跨会话/跨 worker 重启的旧 ref 会被显式拒绝(STALE_REF),重新 snapshot 即可。
常驻服务(可选)
start 是前台进程,终端关闭或机器重启后即结束。需要长期在线可注册为用户级服务(登录自启 + 崩溃自动拉起):
npx @chrome-in-harness/launcher service install # macOS launchd / Linux systemd --user
npx @chrome-in-harness/launcher service status # 查看安装与运行状态
npx @chrome-in-harness/launcher service uninstall # 停止并移除macOS:写入
~/Library/LaunchAgents/com.chrome-in-harness.server.plist(RunAtLoad+KeepAlive),日志在~/Library/Logs/chrome-in-harness-server.logLinux:写入
~/.config/systemd/user/chrome-in-harness.service(Restart=always),日志走journalctl --user -u chrome-in-harness.serviceWindows 暂不支持,请用
start常开终端(或pm2等进程守护)已安装时再次
install会拒绝覆盖,需先uninstall;server 重启后 Chrome 扩展会自动重连
标签页使用约定
agent 应优先使用 ensure_tab,保存返回的 {tabId, url, reused},后续操作始终显式传入自己的 tabId。
再次调用 ensure_tab({tabId, url?}) 时,原标签存在且仍受管则复用,不导航、不切前台;已关闭时后台补建并返回新 ID。
url 仅用于创建,复用后需要换页面应调用 navigate;不传 url 时新标签开在 about:blank。标签被用户移出受管组会报错,不自动接管或补建。
不同 agent 各自维护标签 ID,只有明确需要多标签时才使用 tab_new;服务不提供 agent 身份识别或独占锁。
新建标签页(tab_new)默认后台打开,不抢占当前页面。需要登录、验证码或人工检查时,agent 应通知用户自行切换;仅当用户明确要求帮忙切换时才调用 tab_select。
批量执行
重复性的连续操作(如逐字符 press_key 输入)可用 run_actions 在一次调用里批量执行:
传 actions: [{tool, params}, ...],顶层 tabId 会注入未自带 tabId 的步骤。步骤按顺序执行、后续步骤能看到前序结果;
默认在首个失败处停止,continueOnError: true 则继续并保留每步错误。单次最多 50 步,禁止嵌套 run_actions,也不支持在批量里调用 screenshot。
域名访问模式
默认按域名白名单限制访问。扩展选项页提供「允许所有域名」开关,默认关闭,开启前需确认风险。 开启后允许受管标签组内所有 HTTP/HTTPS 网站,不再逐域名确认;Chrome 内部页、扩展页及本地文件仍不允许。 该设置保存在当前扩展的本地存储中,重载后保持。原白名单不会被清除,关闭开关后立即恢复生效。 此模式会使用真实登录状态,可能读取敏感内容或提交真实数据,仅建议在专用测试浏览器配置与测试账号中开启。
发布渠道
npm:
@chrome-in-harness/server(server,含chrome-in-harness-serverbin)、@chrome-in-harness/launcher(chrome-in-harnessCLI)、@chrome-in-harness/protocol(协议类型)GitHub Releases:tag
v*自动触发 npm 发布 + 扩展 zip 打包(.github/workflows/publish.yml),扩展从 Releases 的chrome-in-harness-extension.zip安装Chrome Web Store:暂未上架;权限与数据处理说明见 docs/CWS_DISCLOSURE.md 与 docs/PRIVACY.md
开发步骤
CI:push / PR 自动跑 lint → test → 扩展 typecheck → build(.github/workflows/ci.yml)。
# 1. 使用 Node 22,与 CI 保持一致;在仓库根目录安装与验证
npm ci
npm run lint # @ddyscn/lint-config(ESLint flat config)
npm test # 构建 protocol / extension,并运行四包 Vitest
npm run typecheck:extension # 构建扩展并执行独立的 TypeScript 检查
npm run build # protocol → server → extension → launcher
# 扩展产物:packages/extension/.output/chrome-mv3
# 自动修复格式 / lint:npm run lint:fix
# 2. 起本地 server
npm run dev:server
# 3. Chrome 加载扩展:见上文「第 ② 步 · 方式 B」
# 修改扩展后运行 npm run build:extension,并在 chrome://extensions 点刷新
# 4. 注册 MCP 到客户端:见上文「第 ③ 步」打包本地发版产物(三个 npm tarball + 扩展 zip,输出到 dist-release/):
npm run packRoadmap
Phase 4 — 非受限执行 / 页面交互增强:如需绕过受限
evaluate_script,再评估chrome.scripting+world: "MAIN"注入面与 CSP 兼容
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
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.
Browserless MCP — wraps the Browserless headless-Chromium REST API (browserless.io)
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients to drive your already-open Chrome browser like a human, using 45 tools for navigation, perception, capture, and trusted input that pages receive as genuinely user-generated.MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to directly operate your existing logged-in Chrome profiles, including cookies and extensions, without re-authentication or a headless browser. It provides tools for managing tabs, navigating, reading pages, clicking, typing, and launching profiles.4 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables remote AI agents to control a local, authenticated desktop browser over MCP through an outbound WebSocket bridge and Chrome extension, supporting tab management, navigation, page reading, clicking, typing, scrolling, screenshots, and JavaScript evaluation.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to see and control the user's real Chrome/Brave/Edge profile over MCP, so they can read pages, click, type, take screenshots, audit layouts, debug CSS, and scrape paginated or infinite-scroll data. Because it drives the normal browser via the DevTools protocol with real input events, it works on modern JavaScript apps and on sites where the user is logged in.12 npm1MIT