Install
$ agentstack add mcp-mankhonggarden-chrome-mcp-windows-survival-guide ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Chrome MCP — Windows Survival Guide
Nine real gotchas I hit installing and operating hangwin/mcp-chrome on Windows 11 — the MCP server that drives your actual logged-in Chrome (not a fresh sandbox) so AI tools like Claude Code can act on your real accounts, cookies, sessions and bookmarks.
The official README covers the happy path. This guide covers the failure modes you'll hit on Windows 11 — each with the symptom you'll see, the root cause I traced, and the fix that actually worked. Two of them (#5 and #6) are upstream issues I opened and PR'd on 2026-05-18 — the rest are pure operator knowledge.
> Audience: anyone using chrome-mcp with Claude Code (or any MCP client) on Windows, especially with multiple Chrome profiles or alongside Anthropic's first-party Claude for Chrome extension.
Table of contents
- [Quick install](#quick-install) — the happy path that does work
- [Diagnose first](#diagnose-which-gotcha-are-you-hitting) — which gotcha are you hitting?
Install-time gotchas (Chrome + extension + bridge setup):
- [Gotcha 1 — Chrome 136+ silently drops
--remote-debugging-port](#gotcha-1--chrome-136-silently-drops---remote-debugging-port-on-the-default-profile) - [Gotcha 2 — MCP boot has no auto-retry · install bridge BEFORE Claude CLI starts](#gotcha-2--mcp-boot-has-no-auto-retry--install-the-bridge-before-claude-cli-starts)
- [Gotcha 3 — bridge ↔ extension version sync](#gotcha-3--bridge-and-extension-versions-must-match)
- [Gotcha 4 — Claude for Chrome and chrome-mcp fight over
chrome.debugger](#gotcha-4--claude-for-chrome-and-chrome-mcp-fight-over-chromedebugger-per-tab) - [Gotcha 5 — Multi-session orphaning · singleton MCP Server reassigns transport](#gotcha-5--multi-session-orphaning--singleton-mcp-server-reassigns-transport)
- [Gotcha 6 — Multi-profile port collision · Approach B workaround](#gotcha-6--multi-profile-port-collision--approach-b-workaround)
Operational gotchas (post-install · runtime · these only surface when actively driving the browser):
- [Gotcha 7 —
isTrusted=falseblocks OAuth · password · file-dialog clicks](#gotcha-7--istrustedfalse-blocks-oauth--password--file-dialog-clicks) - [Gotcha 8 — CDP redaction when a password input is in the DOM](#gotcha-8--cdp-redaction-when-a-password-input-is-in-the-dom)
- [Gotcha 9 —
chrome_keyboardtext input has surprising parser limits · useinsertTextinstead](#gotcha-9--chrome_keyboard-text-input-has-surprising-parser-limits--use-inserttext-instead) - [Cost-aware usage · token efficiency hierarchy](#cost-aware-usage--token-efficiency-hierarchy)
- [Appendix · Upstream contributions](#appendix--upstream-contributions)
- [Sponsors](#sponsors)
Quick install
The path that works on Windows 11 (Chrome 148, Node 22, Claude Code 2.1.x):
# 1. Install the bridge npm package globally
npm install -g mcp-chrome-bridge
# 2. Download the extension from hangwin's releases
# https://github.com/hangwin/mcp-chrome/releases
# Extract to a stable folder (NOT in Downloads — Chrome warns daily about unpacked extensions from temp paths)
# Example: D:\tools\chrome-extensions\mcp-chrome\
# 3. Chrome -> chrome://extensions -> Developer mode ON -> Load unpacked -> select the folder
# Note the extension ID (should be hbdgbgagpkpjffpklnamcljpakneikee if the manifest has the `key` field set)
# 4. Click the extension icon -> Connect
# Bridge process auto-spawns via Native Messaging · listens on 127.0.0.1:12306
# 5. Add the MCP entry to your client config
# For Claude Code: ~/.claude.json (or whatever CLAUDE_CONFIG_DIR points to)
# "chrome-mcp": { "type": "http", "url": "http://127.0.0.1:12306/mcp" }
# 6. Restart Claude CLI · tools should appear under mcp__chrome-mcp__*
Verify with: mcp-chrome-bridge doctor (returns OK once the extension is Connected).
Diagnose: which gotcha are you hitting?
| Symptom | Likely gotcha | |---|---| | Tried CDP attach mode (--remote-debugging-port=9222) · port never opens · DevToolsActivePort file never appears | [#1](#gotcha-1--chrome-136-silently-drops---remote-debugging-port-on-the-default-profile) | | Extension popup says "Connected" but Claude CLI reports chrome-mcp as failed/dead at startup · tool calls return "MCP server not available" | [#2](#gotcha-2--mcp-boot-has-no-auto-retry--install-the-bridge-before-claude-cli-starts) | | Extension and bridge both run · handshake fails silently · mcp-chrome-bridge doctor warns about version mismatch | [#3](#gotcha-3--bridge-and-extension-versions-must-match) | | chrome-mcp tools work until you open a tab where Anthropic's Claude for Chrome extension is active · then that tab returns "Cannot attach debugger" or silently no-ops | [#4](#gotcha-4--claude-for-chrome-and-chrome-mcp-fight-over-chromedebugger-per-tab) | | Open a second Claude Code session · the first one's chrome-mcp tools stop responding · every context switch needs Disconnect/Connect on the extension popup | [#5](#gotcha-5--multi-session-orphaning--singleton-mcp-server-reassigns-transport) | | Installed extension in multiple Chrome profiles · only one profile's tools work · the others show "Connected" but fail | [#6](#gotcha-6--multi-profile-port-collision--approach-b-workaround) | | chrome_click_element succeeds with no error but the click "did nothing" on an OAuth popup / login form / file dialog | [#7](#gotcha-7--istrustedfalse-blocks-oauth--password--file-dialog-clicks) | | chrome_javascript returns "Cannot access a chrome-extension:// URL of different extension" for every call · works on other tabs | [#8](#gotcha-8--cdp-redaction-when-a-password-input-is-in-the-dom) | | chrome_keyboard keys="some_text" returns "Invalid key string or combination" for any text with underscores · single chars work | [#9](#gotcha-9--chrome_keyboard-text-input-has-surprising-parser-limits--use-inserttext-instead) |
Gotcha 1 — Chrome 136+ silently drops --remote-debugging-port on the default profile
Symptom
You're trying to drive your real Chrome (the one with your logins) via Chrome DevTools Protocol — adding --remote-debugging-port=9222 to your Chrome shortcut so chrome-devtools-mcp --browser-url=http://127.0.0.1:9222 can attach. The Chrome process command line contains the flag, but:
Get-NetTCPConnection -LocalPort 9222 -State Listenreturns empty%LOCALAPPDATA%\Google\Chrome\User Data\DevToolsActivePortnever gets created- Direct connect to
http://127.0.0.1:9222/jsonfails
Root cause
Chrome 136+ refuses to expose the debug port when --user-data-dir resolves to the default profile location. This was a deliberate Chromium security change (~Q1 2024) to prevent credential theft via an attacker's local process spamming /json/version against your logged-in browser. Even though the flag is parsed, the listener is not started when the data-dir matches default.
Confirmed on Chrome 148 (verified 2026-05-17).
Fix · don't fight Chrome — pivot to the extension model
The clean fix is to stop using CDP attach mode entirely and use hangwin/mcp-chrome instead. It uses Chrome Native Messaging — a different transport that Chrome explicitly trusts because the bridge process is registered under HKCU and the extension manifest lists nativeMessaging permission. No debug port, no security tradeoff.
If you still need CDP attach mode for a specific tool that can't speak MCP:
# Workaround: explicit user-data-dir (NOT default · use a separate Chrome profile dir)
"chrome.exe" --remote-debugging-port=9222 --user-data-dir="D:\chrome-cdp-profile"
This works because the security rule only applies to the default profile dir. But you lose your logged-in sessions — defeating the point. The extension model wins.
Gotcha 2 — MCP boot has no auto-retry · install the bridge BEFORE Claude CLI starts
Symptom
Extension popup says "Connected" (green badge). mcp-chrome-bridge doctor reports OK. But Claude Code reports chrome-mcp as failed in the MCP list, and tool calls return "MCP server not available". Restarting the bridge doesn't help.
Root cause
Claude CLI does one MCP handshake at boot. If the bridge isn't ready exactly when the CLI fires its HTTP request to 127.0.0.1:12306/mcp, the CLI marks the server permanently dead for that session lifetime. No auto-retry. No backoff. The bridge can come up 100ms later — the CLI doesn't notice.
This is upstream MCP client behavior, not chrome-mcp specific. But chrome-mcp's bridge is lazy-launched via Native Messaging — it only spawns when the extension calls chrome.runtime.connectNative(). Race condition during CLI startup is easy to trigger.
Fix
Boot order matters:
# 1. Start Chrome FIRST
# 2. Click the chrome-mcp extension icon -> Connect -> wait for "Connected" badge
# 3. Verify the bridge is listening:
Get-NetTCPConnection -LocalPort 12306 -State Listen # should show 1 entry
# 4. THEN launch Claude Code
claude # or your wrapper
If you skip step 3 and the CLI starts before the bridge is bound, /exit and restart. There's no in-session recovery.
/mcp reconnect chrome-mcp will revive the connection IF the server was loaded at boot and just dropped. It will NOT load new MCP entries that you added to .claude.json mid-session — those require a full process restart.
Gotcha 3 — Bridge and extension versions must match
Symptom
Both processes appear healthy individually. The bridge is listening on 12306. The extension popup is green. But MCP tool calls return cryptic errors like "Invalid MCP request" or hang indefinitely.
Root cause
The npm mcp-chrome-bridge package and the Chrome extension speak a Native Messaging protocol whose message shape changes between minor versions. Mixing extension v1.0.x with bridge v1.1.x (or vice versa) sometimes works for get_windows_and_tabs but breaks chrome_get_web_content and other tools that use newer message types.
Fix
Pin both to the same release. The extension version is whatever you downloaded; the bridge version is mcp-chrome-bridge --version (or npm list -g mcp-chrome-bridge).
# Check both
npm list -g mcp-chrome-bridge # bridge version
# Extension: chrome://extensions -> Chrome MCP Server card -> version line under name
If they don't match, prefer upgrading both to the latest tagged release on hangwin/mcp-chrome/releases. The bridge installs via npm; the extension is unpacked load — replace the folder contents and click "Reload" on the extension card.
After upgrade: Disconnect/Connect on the popup, then /exit + restart Claude CLI (because of Gotcha 2).
Gotcha 4 — Claude for Chrome and chrome-mcp fight over chrome.debugger per tab
Symptom
chrome-mcp works fine on most tabs. But certain tabs — typically ones you've recently asked Anthropic's official Claude for Chrome extension to look at — return "Cannot attach debugger" on chrome_get_web_content / chrome_screenshot, or silently no-op. The bridge is fine, the extension popup is green; only one specific tab is broken.
Root cause
Both extensions use the chrome.debugger API to read DOM, take screenshots, click elements. Chrome enforces one debugger attachment per tab at a time. Whichever extension attaches first wins; the second gets Cannot attach to the target with an attached client.
The chrome-mcp extension popup shows "Connected" because the bridge ↔ extension native messaging handshake succeeded. The per-tab debugger collision is invisible to the popup state — you have to know to look.
This is distinct from the documented Claude Desktop ↔ Claude Code conflict where two Anthropic products register the same native messaging host name. That's a host-level clash. This one is two different extensions (different IDs, different vendors) fighting over a per-tab Chrome API.
Fix
Pick one of:
| Option | Trade-off | |---|---| | Disable Claude for Chrome on tabs you'll drive via chrome-mcp | Easiest · lose Claude for Chrome on those tabs | | Use a dedicated Chrome profile for chrome-mcp work (no Claude for Chrome installed in that profile) | Cleanest separation · pairs naturally with [Gotcha #6](#gotcha-6--multi-profile-port-collision--approach-b-workaround) | | Disable Claude for Chrome globally during chrome-mcp sessions | Heavy-handed · works if you don't need both at once | | Open the target page in a new tab AFTER chrome-mcp attaches first | Race-condition fragile · not recommended |
There's no Chrome-level fix — the one-debugger-per-tab rule is the API contract.
Gotcha 5 — Multi-session orphaning · singleton MCP Server reassigns transport
Symptom
You open a second Claude Code session (different terminal, same machine). The second session's chrome-mcp works. But the first session's chrome-mcp tool calls now hang or return errors. Disconnect/Connect on the extension popup brings the second session back; the cycle repeats every context switch.
Root cause
I traced this through the bridge source. The HTTP server's transportsMap already routes incoming requests by mcp-session-id header — multi-session capable at the routing layer. But every new MCP initialize request calls getMcpServer().connect(transport) on a singleton MCP Server instance:
// app/native-server/src/mcp/mcp-server.ts
export let mcpServer: Server | null = null;
export const getMcpServer = () => {
if (mcpServer) return mcpServer; // singleton — same instance for every session
mcpServer = new Server({...});
setupTools(mcpServer);
return mcpServer;
};
// server/index.ts, MCP POST init branch
await getMcpServer().connect(transport); // {
const server = new Server({...});
setupTools(server);
return server;
};
// server/index.ts, in both /mcp POST init and SSE branches
await createMcpServer().connect(transport);
Each session gets its own Server with its own transport binding. setupTools is per-instance pure. The extension-side native messaging pipe already routes by requestId UUIDs, so concurrency at the per-tab boundary stays correct.
I filed this as Issue #345 and put up PR #346 with end-to-end verification. If/when it merges, just npm install -g mcp-chrome-bridge@latest.
Until then, install the patched fork:
git clone https://github.com/MankhongGarden/mcp-chrome.git
cd mcp-chrome
git checkout fix/multi-session-mcp-server
pnpm install --filter mcp-chrome-bridge... --ignore-scripts
pnpm --filter chrome-mcp-shared build
cd app/native-server
pnpm build
npm install -g . # global mcp-chrome-bridge becomes a junction to your local clone
# In Chrome: Disconnect -> Connect on the extension popup
# Restart Claude CLI to re-establish MCP sessions
Revert at any time: npm install -g mcp-chrome-bridge@latest (removes the junction, installs stock).
After the fix is active, two Claude Code sessions can both call chrome-mcp tools without orphaning. Verified with direct HTTP POST simulating a second MCP client mid-call — session 1's tools keep responding correctly.
Gotcha 6 — Multi-profile port collision · Approach B workaround
Symptom
You want chrome-mcp available in multiple Chrome profiles (work, personal, per-project sandbox). You install the extension in each. Only one profile's tools actually work. The others show "Connected" but every tool call fails.
Root cause
Chrome Native Messaging spec: chrome.runtime.connectNative() spawns a **new bridge p
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: MankhongGarden
- Source: MankhongGarden/chrome-mcp-windows-survival-guide
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.