one-chrome
Drives a real, signed-in Chrome browser through an extension, giving models a full browser toolset: snapshots with stable refs, trusted mouse and keyboard input, navigation, tab groups, console/network inspection, dialogs, emulation, uploads, downloads, popups, and Core Web Vitals. Multiple clients can share the same browser concurrently, each with its own tabs, tab groups and leases.
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., "@one-chromeOpen example.com in a new tab and tell me the page heading."
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.
One Chrome
One signed-in Chrome for every model you have open.
Cursor, Claude, and OpenCode can drive the same browser at the same time. Each client gets its own tabs and its own tab group. Clicks, typing, and navigation take a lease on the tab, so two models never type into the same field at once. Reads overlap. Tabs stay in the background, so one model does not steal the window from another.
The host speaks two tool dialects:
chrome_*, a full browser toolset: snapshots with stable refs, trusted mouse and keyboard input, console, network, dialogs, emulation, and Core Web Vitals.Claude's browser toolset, all 31 members of
browser_toolset_20260801, with the same names,ref_Ntargets, error texts, and tab context. A Messages API executor turns a turn oftool_useblocks intotool_resultblocks.
Cursor / Claude / OpenCode your own Messages API app
│ stdio (starts the host) │ POST /claude/execute
▼ ▼
┌────────────────────────── One Chrome host ───────────────────────────────┐
│ /mcp chrome_* tools /mcp/claude Claude members /mcp/all both │
│ sessions · tab leases · per-tab queues · popup and download tracking │
└───────────────────────────────────┬──────────────────────────────────────┘
│ ws://127.0.0.1:12307/bridge
▼
Chrome extension, running in your profile
debugger · scripting · tab groups · downloadsInstall
Requires Node 20+ and Chrome (or Chromium) 120+.
git clone https://github.com/AbinMadathil07/one-chrome.git
cd one-chrome
npm install
npm run buildLoad the extension:
Open
chrome://extensionsand turn on Developer mode.Click Load unpacked and select the
extensionfolder inside the clone. The repo root has no manifest, and Chrome will say the manifest is missing if you select it.Open the extension popup and click Connect. It reconnects on its own after Chrome restarts.
Related MCP server: Umbra MCP Server
Add it to an MCP client
Give the client a command, not a URL. The first client starts the host. Every later client attaches to that same host, so they share one browser. You only need npm start when you want the host up before any client connects.
Replace /path/to/one-chrome with the clone path.
Cursor and Claude Code (~/.cursor/mcp.json, ~/.claude.json):
{
"mcpServers": {
"one-chrome": {
"command": "node",
"args": ["/path/to/one-chrome/dist/cli.js", "stdio"]
},
"one-chrome-claude": {
"command": "node",
"args": ["/path/to/one-chrome/dist/cli.js", "stdio", "--claude"]
}
}
}OpenCode (~/.config/opencode/opencode.jsonc), version 1.x:
{
"mcp": {
"one-chrome": {
"type": "local",
"command": ["node", "/path/to/one-chrome/dist/cli.js", "stdio"],
"enabled": true
}
}
}Command | Tools the model sees |
|
|
| Claude's 31 browser members |
| Both |
Host logs are written to ~/.chrome-mcp/host-12306.log. Check that the extension is connected with node dist/cli.js status, then try: "Open example.com and tell me the heading."
How sharing works
One shared tab | One Chrome | |
Two models click at once | They race | Each session owns its tabs. Mutations take an exclusive lease and queue per tab |
Parallel reads | Blocked behind the same lock | Shared read leases overlap |
Window focus | Every action activates the tab | Tabs open in the background. Focus emulation lets them behave as focused |
Finding a model's tabs | Guesswork | One Chrome tab group per session, titled with the client name |
A page opens a popup or a download | Easy to miss | The popup joins the opener's session. The download is reported back to it |
The client disconnects | Locks stick around | Leases drop when the connection closes. Idle sessions are swept |
A session is created for each MCP connection, so sessionId is optional. Call session_ensure with a distinct clientId when one connection drives several agents. To share a tab on purpose, attach it with session_attach_tab: reads overlap, writes wait their turn.
Claude browser toolset
stdio --claude exposes the members Claude's browser use tool defines.
Group | Members |
Navigation and capture |
|
Pointer |
|
Keyboard and timing |
|
Reading |
|
Forms and files |
|
Diagnostics |
|
Tabs |
|
Targets are {"type":"ref","ref":"ref_3"} or {"type":"coordinate","x":120,"y":340}. Refs come from read_page and find and stay valid until the page navigates. A stale ref returns Error: ref_3 is stale or not found on the current page. Re-read the page to get fresh references. Screenshots are CSS pixels, so a coordinate read off the image is the coordinate to click. Viewports wider than 1568px are scaled down, and incoming coordinates are scaled back up. Results include the tab-context footer, opened tabs, and download lines in the form Claude's API renders.
If you call the Messages API yourself, post each turn's browser tool_use blocks to the host:
curl -s http://127.0.0.1:12306/claude/execute \
-H 'content-type: application/json' \
-d '{
"session": "my-agent",
"tool_uses": [
{ "id": "toolu_1", "name": "navigate", "input": { "url": "example.com" } },
{ "id": "toolu_2", "name": "read_page", "input": { "filter": "interactive" } }
]
}'The response is { "tool_results": [...] }, one block per call, with toolset_name: "browser" and a browser_state block. Calls run in order. After a failure, the rest of the turn gets Not executed: an earlier action in this turn failed. DELETE /claude/sessions/my-agent closes that session and its tabs.
examples/claude-browser-agent.mjs is a full agent loop:
ANTHROPIC_API_KEY=sk-ant-... node examples/claude-browser-agent.mjs "Open example.com and summarize it"chrome_* toolset
Area | Tools |
Sessions |
|
Navigation |
|
Reading |
|
Input |
|
Scripting |
|
DevTools |
|
Batching |
|
Pass includeSnapshot: true on a mutating tool to get the page's interactive elements back with the result. If an action opens a JavaScript dialog, the call returns { modal } instead of hanging, and other commands wait until chrome_handle_dialog.
Configuration
Every variable is optional. Defaults are safe for a machine you control.
Variable | Default | Meaning |
|
| Bind address |
|
| MCP and executor port |
|
| Extension WebSocket port |
| empty | Shared secret. Clients send |
|
| Concurrent sessions |
|
| Tabs one session may own |
|
| Lease lifetime and wait budget |
|
| Bridge command timeout |
|
| Idle session sweep |
|
| Allow overlapping read leases |
| empty | Uploads must resolve inside this directory. Required for Claude |
| empty | Hosts navigation may reach, for example |
|
| Refuse localhost, private, and link-local hosts |
|
| Longest side of a Claude toolset screenshot |
| empty | Tools to hide, for example |
See .env.example.
Security
The browser is your real profile, with its cookies and accounts, and any page can contain text written to steer a model.
Leave the host on
127.0.0.1. SetCHROME_MCP_TOKENif other local processes can reach the ports.For untrusted sites, use a separate Chrome profile with no accounts, set
CHROME_MCP_ALLOWED_HOSTS, setCHROME_MCP_BLOCK_PRIVATE_NETWORKS=true, and pointCHROME_MCP_UPLOAD_DIRat a folder that holds only files meant for upload.javascript_exec,chrome_evaluate,chrome_fetch, and uploads run with the page's privileges. Hide the ones you do not need withCHROME_MCP_DISABLED_TOOLS.Console and network output is redacted for tokens, keys, JWTs, and credential query parameters. Treat the rest as untrusted.
Chrome shows a debugging banner while DevTools is attached.
chrome_devtools_detachremoves it for that tab.
Development
npm run dev # rebuild and serve on change
npm test # leases, sessions, Claude formatting, uploads
npm run typecheck
npm run build
npm run smoke # round trip against the running host and your Chrome
CHROME_BIN="/path/to/Google Chrome for Testing" npm run e2enpm run e2e serves a fixture page, starts its own host on ports 22306 and 22307, and launches Chrome for Testing with a copy of the extension. It does not touch a host or browser you already have open. It drives two concurrent sessions through the chrome_* tools and the full Claude toolset, both over MCP and through /claude/execute. Branded Chrome ignores --load-extension, so use Chrome for Testing or Chromium. HEADLESS=0 shows the window.
src/
cli.ts serve, stdio, status
config.ts environment variables, defaults, validation
concurrency/ sessions, tab leases, per-tab queues
bridge/ WebSocket protocol
browser/ runtime, uploads, downloads, snapshot search
claude/ Claude toolset executor
mcp/ HTTP server, both toolsets, stdio launcher
extension/ MV3 extension. Load this folder.
examples/ Messages API agent loop
scripts/ smoke and end-to-end tests
test/ unit tests and the browser fixtureCredits
The idea of driving a real Chrome profile from MCP comes from hangwin/mcp-chrome (MIT). One Chrome is an independent rewrite built around sharing that browser across models.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
On-demand cloud browser sessions; page actions need a compatible CDP client.
1Undetectable cloud browser sessions for AI agents and scrapers. Navigate, extract, click, captcha.
Run multi-step tasks in a real Chrome browser: persistent environments, live view, human takeover.
Let your AI agent operate any website through a real, logged-in browser session.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceBrowser automation for OpenCode using Chrome DevTools and a shared Chromium profile, with per-session tab isolation so concurrent agents don't interfere. Enables browser agents to use existing signed-in sessions with shared cookies and extensions.345 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to securely control a user's existing signed-in Chrome browser through isolated tab groups, with strict per-session ownership and no cookie or token exposure.1 npmISC
- AlicenseNot gradedqualityBmaintenanceEnables AI agents and clients to control a real Chromium browser through MCP tool calls, including navigation, clicking, typing, JavaScript evaluation, screenshots, and DOM snapshots. Supports multiple isolated sessions over authenticated HTTP with no disk writes.Apache 2.0
- AlicenseBqualityBmaintenanceEnables multiple AI agents to each run Google's full Chrome DevTools toolset in an isolated Chrome instance with saved logins, origin allowlists, reconnect recovery, and process cleanup. It also provides visibility into running browsers so stale sessions can be inspected or reaped.38187 npmMIT