[Windows Bug] Claude in Chrome MCP fails to connect - named pipe timing/architecture issue on Windows
Environment
- OS: Windows 11 Home 10.0.26200
- Claude Code version: 2.1.9 (also reproduced on 2.1.104)
- Browsers tested: Google Chrome, Microsoft Edge
- Shell: bash (Git Bash / terminal)
Description
The claude-in-chrome MCP server fails to connect on Windows. All browser tool calls return:
"Browser extension is not connected. Please ensure the Claude browser extension is installed and running..."
This happens even when:
- The browser extension is correctly installed and enabled
- The native messaging registry keys are correctly configured (both Chrome and Edge)
- The
chrome-native-host.batfile exists and points to the correct path - The user is logged into claude.ai with the same account
Root Cause (code analysis)
After analyzing cli.js, the issue is an architectural timing problem on Windows:
The pipe name generation (zyA())
function zyA() {
if (S45() === "win32") return `\\.\pipe\${V42()}`;
return kb(x45(), V42()); // Mac/Linux: uses tmpdir with unique path
}
function V42() {
return `claude-mcp-browser-bridge-${k45()}`; // e.g. claude-mcp-browser-bridge-Admin
}
On Mac/Linux: uses os.tmpdir() which can produce unique paths per session.
On Windows: always produces a fixed pipe name: \.\pipe\claude-mcp-browser-bridge-Admin
The connection flow
Claude Code startup → zW9() → B.connect(G) [tries to connect to pipe as CLIENT]
↓
\.\pipe\claude-mcp-browser-bridge-Admin
↓ (no server exists yet)
CONNECTION FAILS
The native host (NW9() / wW9.start()) only creates the pipe SERVER when Chrome/Edge invokes it via native messaging. But zW9() tries to connect as CLIENT during Claude Code startup — before any browser interaction has occurred.
Why this doesn't affect Mac/Linux
On Mac/Linux the socket file persists on disk and the MCP client can likely detect it and retry. On Windows, named pipes are ephemeral kernel objects — if the server isn't running, the client gets an immediate connection refused with no retry.
The wW9 native host (SERVER side)
async function NW9() {
let A = new wW9, Q = new LW9;
await A.start(); // creates pipe SERVER at zyA()
while (true) {
let B = await Q.read(); // reads Chrome native messaging from stdin
if (B === null) break; // exits when stdin closes (i.e. when Chrome disconnects)
await A.handleMessage(B);
}
await A.stop(); // DESTROYS pipe server
}
The native host is designed to be short-lived — it exists only while Chrome has an active native messaging connection. The MCP client needs the server to be alive at startup, which creates a race condition.
What was verified
- ✅ Registry key
HKCU\Software\Google\Chrome\NativeMessagingHosts\com.anthropic.claude_code_browser_extension→ correct JSON path - ✅ Registry key
HKCU\Software\Microsoft\Edge\NativeMessagingHosts\com.anthropic.claude_code_browser_extension→ correct JSON path - ✅
com.anthropic.claude_code_browser_extension.json→ correctpathto.batfile and correctallowed_origins - ✅
chrome-native-host.bat→ correctly invokescli.js --chrome-native-host - ✅ Extension installed and enabled in both Chrome and Edge
- ✅ No conflicting
chrome-native-host.exeprocesses running - ✅ No Claude-related named pipes exist at connection time (confirmed via
Get-ChildItem \.\pipe\) - ✅ Works correctly from the Claude Code desktop app (which maintains its own persistent native host daemon)
Proposed Fix
The fix should make the MCP client lazy-connect or retry instead of connecting once at startup:
Option A (minimal): In zW9(), wrap B.connect(G) with retry logic — attempt to connect when a tool is actually called, retrying for a few seconds to allow the native host to start.
Option B (better): On Windows, use a different IPC mechanism that doesn't require the server to be running first (e.g., mailslots, or a persistent daemon mode).
Option C (simplest for users): Add a --chrome-native-host-daemon flag that keeps the native host running without requiring an active Chrome native messaging connection, allowing it to be started via a SessionStart hook.
The desktop app already implements something like Option C — exposing this as a CLI flag would make it work in terminal sessions too.
Additional Notes
The desktop app (Claude.ai) works because it maintains a persistent native host process. The CLI needs equivalent behavior.
This bug affects all Windows users trying to use claude-in-chrome from the terminal/CLI.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗