[Windows Bug] Claude in Chrome MCP fails to connect - named pipe timing/architecture issue on Windows

Resolved 💬 3 comments Opened Apr 13, 2026 by joaodeboni-max Closed Apr 16, 2026

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.bat file 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 → correct path to .bat file and correct allowed_origins
  • chrome-native-host.bat → correctly invokes cli.js --chrome-native-host
  • ✅ Extension installed and enabled in both Chrome and Edge
  • ✅ No conflicting chrome-native-host.exe processes 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗