Claude-in-Chrome Windows & WSL working fixes
Bug Description
Claude-in-Chrome is completely broken on Windows due to two independent bugs:
- Bun stdin crash:
claude.exe --chrome-native-hostcrashes withpanic: Internal assertion failure(Bun v1.3.5 standalone can't handle stdin in native messaging mode) - Socket path discovery bug:
getSocketPaths()(minified asGc4in v2.1.34) never includes Windows named pipe paths — only returnsos.tmpdir()filesystem paths that can't connect to named pipes
Even after fixing bug #1 (using Node.js instead of Bun for the native host), bug #2 prevents the MCP server from finding the native host's socket because Windows named pipes (\.\pipe\NAME) and filesystem paths (C:\Users\...\AppData\Local\Temp\NAME) are in completely separate OS namespaces.
Root Cause Analysis
Bug 1: Bun stdin crash
claude.exe is a Bun v1.3.5 standalone binary. When invoked as --chrome-native-host, it panics on stdin initialization:
panic(main thread): Internal assertion failure
oh no: Bun has crashed. This indicates a bug in Bun, not your code.
Bug 2: Socket discovery (the deeper issue)
The getSocketPaths() function returns:
C:\Users\...\AppData\Local\Temp\claude-mcp-browser-bridge-{user} ← filesystem path
/tmp/claude-mcp-browser-bridge-{user} ← Unix path
The native host listens on:
\.\pipe\claude-mcp-browser-bridge-{user} ← Windows named pipe
These are different Windows namespaces:
- Filesystem paths → NTFS, accessed via
CreateFileWin the filesystem namespace - Named pipes → Object Manager, accessed via
CreateFileWin the\.\pipe\namespace
net.createConnection(tmpdir_path) calls libuv's uv_pipe_connect → CreateFileW → looks in NTFS → ENOENT (pipe not found in filesystem).
The getSocketPath() (singular, uW6 in v2.1.34) correctly returns \.\pipe\... on Windows, but the bridge connector (Qzq) prefers getSocketPaths() (plural, Gc4) over socketPath, so the correct path is never tried.
Why .mcp.json override doesn't work
We tried overriding the built-in claude-in-chrome MCP via .mcp.json to use node.exe + patched cli.js:
{
"mcpServers": {
"claude-in-chrome": {
"command": "node.exe",
"args": ["path/to/patched/cli.js", "--claude-in-chrome-mcp"]
}
}
}
Result: Name is reserved — claude mcp add rejects it, and the .mcp.json entry is silently ignored at runtime. The built-in always spawns claude.exe (unpatched Bun binary). Adding a different name (e.g., chrome-browser) causes tool name deduplication — its tools are hidden.
Working Fix (verified)
We have a complete working fix, but it can only be applied to the native host — not to the MCP server process:
1. Native host: Node.js instead of Bun
Replace chrome-native-host.bat to use node.exe + cli.js from an isolated npm install:
@echo off
"path\to\node.exe" "path\to\node_host\node_modules\@anthropic-ai\claude-code\cli.js" --chrome-native-host
2. Patch getSocketPaths() in cli.js
Add Windows named pipe to discovery before return:
// In the getSocketPaths function (Gc4 in minified v2.1.34), before 'return A}':
if (process.platform === "win32") {
const pipePath = `\\.\pipe\${baseName}`;
if (!paths.includes(pipePath)) paths.push(pipePath);
}
3. Self-healing hook
A Python hook that runs on session start:
- Rewrites
.batif Claude Code overwrites it to useclaude.exe - Syncs cli.js version when
claude.exeupdates - Re-applies the Gc4 patch after version syncs
Verification
Manual test spawning the MCP server via node.exe + patched cli.js:
$ node cli.js --claude-in-chrome-mcp
# Send initialize → OK (server name: "Claude in Chrome")
# Send tools/call tabs_context_mcp → "No MCP tab groups found" (SUCCESS - bridge connected!)
The fix works. But the built-in MCP server still uses claude.exe with unpatched getSocketPaths(), so the actual mcp__claude-in-chrome__* tools remain broken.
Suggested Fix (for Anthropic)
Option A: Patch getSocketPaths() (minimal, 3 lines)
// In getSocketPaths(), before return:
if (process.platform === "win32") {
const pipePath = `\\.\pipe\${baseName}`;
if (!paths.includes(pipePath)) paths.push(pipePath);
}
Option B: Fix bridge connector priority
Make the bridge connector also check socketPath (from getSocketPath() singular) alongside getSocketPaths() (plural), especially on Windows where the singular version returns the correct \.\pipe\ path.
Option C: Allow .mcp.json to override reserved names
This would let users apply their own fixes without waiting for releases.
Environment
- Claude Code: 2.1.34
- OS: Windows 11 (NT 10.0.26100)
- Node.js: v25.5.0
- Chrome extension: Claude v1.0.45
Related Issues
- #23526 — Same root cause (getSocketPaths missing pipe path), has community patch for npm installs
- #23739 — Bun crash on
--chrome-native-host(high-priority) - #22890 — "not connected despite native host running"
- #23082 — "extension executes but CLI receives not connected"
- #23218, #22025, #21300 — Various reports of Windows connection failure
- #22416, #21935 — Bun named pipe crash reports
26 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
this github-actions won't let anyone help!
Update: Complete User-Side Fix Found (including VS Code IDE)
We discovered
claudeCode.claudeProcessWrapper— a VS Code setting in the extension'spackage.jsonthat overrides the executable used to launch Claude processes. This enables a complete fix for both Terminal CLI and VS Code IDE contexts.Fix Architecture
| Context | Solution |
|---------|----------|
| Native Host |
.batwrapper usesnode.exe + patched cli.jsinstead ofclaude.exe|| Terminal CLI |
npm install -g @anthropic-ai/claude-code, then launch viaclaude.cmd(npm) || VS Code IDE | Set
claudeCode.claudeProcessWrapperto a.cmdwrapper that intercepts--claude-in-chrome-mcp|VS Code Fix Details
The wrapper script intercepts
--claude-in-chrome-mcpand delegates tonode.exe + patched cli.js. All other invocations pass through to the original binary.VS Code settings.json:
How
getClaudeBinary()works (from extension.js)When
claudeProcessWrapperis set:pathToClaudeCodeExecutable= wrapper pathexecutableArgs= [original_binary_path]getChromeMcpServerConfig()only usespathToClaudeCodeExecutable, so it calls:wrapper.cmd --claude-in-chrome-mcpwrapper.cmd original_binary [args...]Verification
{"name": "Claude in Chrome", "version": "1.0.0"}mcp__ide__*) unaffectedThe upstream fix (patching
getSocketPaths()/Gc4()) is still the right long-term solution. This workaround requires npm install, Gc4 patching, wrapper scripts, and a self-healing hook — far too complex for end users.Multi-Session Architecture (Multiple Chrome-enabled Claude sessions)
Multiple Claude sessions can simultaneously use Chrome-in-Chrome without conflict. The architecture supports this natively:
How it works
chrome-native-host.bat\.\pipe\claude-mcp-browser-bridge-{user}tabs_create_mcp. Sessions see only their own tabs.Notes
--no-chromeflagstabs_context_mcpreturns only its own tab group--no-chrometo save resourcesVS Code + Terminal coexistence
With the
claudeProcessWrapperfix from the parent issue:node.exe + patched cli.jsfor Chrome MCPclaude.cmd(npm) →node.exe + patched cli.jsUpdate for Issue #23828: Third Independent Bug Discovered
Summary
After extensive testing, I've discovered a third independent bug affecting Windows users with spaces in their usernames. This bug is orthogonal to the two bugs already documented in this issue (Bun crash + getSocketPaths() missing Windows pipes).
---
The Username Space Bug
Root Cause
When a Windows username contains spaces (e.g., "Dennis Bosma", "John Smith"), the native host and MCP client use different pipe names:
This pipe name mismatch causes MCP tools to fail with "Browser extension is not connected" even when the extension is working correctly.
Why This Happens
The native host uses
os.userInfo().usernamedirectly (returns OS username with spaces), but somewhere in the MCP client connection logic, the username gets sanitized (spaces removed). These two paths create pipes with different names.Critical Insight
This bug persists EVEN AFTER fixing bugs #1 and #2:
\\.\\pipe\\paths → Fixes discoveryThis is why some users report success with the Node.js + getSocketPaths() patch, but others still fail — it depends on whether they have spaces in their Windows username.
---
Test Evidence
Test 1: Pipe Existence Verification
Result:
The pipe with space exists, but the MCP client searches for the sanitized version.
Test 2: Native Host Logs
With diagnostic logging in
chrome-native-host.bat:Output:
The batch file sanitization doesn't work because
claude.cmdusesos.userInfo().username(OS API) which ignores environment variables.---
Proposed Fix
Option A: Sanitize in BOTH Locations (Recommended)
Add
.replace(/\s+/g, '')to username in:--chrome-native-host)getSocketPaths())One-line fix, applies everywhere username is used for pipe names.
Option B: Try Both Variants (Backward Compatible)
Modify
getSocketPaths()to return BOTH sanitized and unsanitized pipe names:More robust, handles both old and new native host versions.
---
Affected Users
This bug affects:
Estimated impact: 30-50% of Windows users (default Windows setup creates usernames with spaces).
Why It's Confusing
Users see:
/chromestatus: "Enabled, Extension: Installed"The extension IS working (Chrome native messaging uses stdin/stdout, not named pipes), but MCP tools can't connect to the native host's pipe because of the name mismatch.
---
Relationship to Existing Bugs
| Bug | Affects | Workaround Impact | Username Space Impact |
|-----|---------|-------------------|----------------------|
| #1: Bun crash | All Windows users | Node.js fixes → users still fail | ❌ Not fixed |
| #2: getSocketPaths() | All Windows users | Patch fixes → users still fail | ❌ Not fixed |
| #3: Username spaces | ~40% Windows users | Neither workaround helps | ✅ INDEPENDENT BUG |
Critical: Fixing bugs #1 and #2 does NOT fix bug #3. Users with spaces in usernames need this additional fix.
---
Priority Justification
Impact: Medium-High
Difficulty: Trivial
.replace(/\s+/g, '')User Experience: Critical
---
Environment
---
Sources
I believe this is also an issue with this feature, similar to the spaces in usernames bug.
https://github.com/anthropics/claude-code/issues/24366
My recommendation is one of two things:
A) Get the user's folder name on the system, and substring everything from the last (or second to last of there is a trailing one) slash character.
```
const os = require('os');
const path = require('path');
var sanitizedUserName = path.basename(os.homedir());
Update: ESM Compatibility Bug & Confirmed Working Fix (v2.1.37)
New Bug Found: ESM Module System
After updating from v2.1.34 → v2.1.37, our previous fix broke for two reasons:
Gc4()→cc4()— any name-based patch breaks on updates"type": "module"(ESM), sorequire("os")throwsReferenceError: require is not definedat runtimeOur original patch used
require("os").userInfo().usernamewhich worked under v2.1.34 but fails in v2.1.37. The fix: useprocess.env.USERNAME(always available on Windows, no imports needed).Working Patch (ESM-safe, version-resilient)
Injected before
return A}in thegetSocketPathsfunction:Key design decisions:
process.platforminstead of minified helper (e.g.,qCY()) — survives minification changesprocess.env.USERNAMEinstead ofrequire("os").userInfo().username— ESM compatibleclaude-mcp-browser-bridgeanchor string, scan backwards for nearestfunction NAME(){, brace-count for boundaries. Works regardless of minified name.Important:
claude.exevsclaude.cmdThe Bun standalone binary (
claude.exeat~/.local/bin/) embeds compressed JS that cannot be patched. Any cli.js patch only works when launching via the npm global wrapper (claude.cmd) which usesnode.exe + cli.js.When Claude spawns the MCP server (
--claude-in-chrome-mcp), it usesprocess.execPath— if that'sclaude.exe, the MCP server also runs unpatched Bun. Users must launch viaclaude.cmd(or addnode.exe cli.jsto PATH ahead ofclaude.exe).Response to @robertmclaws on
path.basename(os.homedir())Good suggestion — it avoids the sanitization problem entirely since Windows already sanitizes the folder name. However, in ESM context (
"type": "module"), neitherrequire('os')norrequire('path')are available without animport. The ESM-safe equivalent would beprocess.env.USERPROFILE+ manual basename extraction, butprocess.env.USERNAMEis simpler and directly matches what the native host uses for pipe creation (after our.batappliesSET "USERNAME=%USERNAME: =%").Verification
Successfully tested end-to-end on Windows with v2.1.37:
tabs_context_mcp→ returns active Chrome tabstabs_create_mcp→ creates new tabsnavigate→ navigates to URLsread_page→ reads page accessibility tree@bosmadev Great debug, would love if that is merged soon
@bcherny Could you please take a look at this conglomeration of issues that are preventing Claude Chrome from working on Windows?
Additional findings: Bridge (wss://bridge.claudeusercontent.com) is also broken on Windows
We spent 6 debugging sessions investigating the bridge path (new architecture in v2.1.39+) separately from the named pipe/native host issues documented above. Summary of bridge-specific findings:
Bridge pairing never succeeds
Both sides connect to the bridge successfully, but
addinCountalways remains0:wss://bridge.claudeusercontent.com/chrome/{accountUuid}, receives{"type":"waiting"}--chrome) → establishes 3+ TCP connections to the bridge server{"type":"stats","desktopConnected":true,"addinCount":0}— Chrome side never counted as valid addinTested with:
fcoeoabgfenejglbffodgkkbkcdhcgfn) via manifestkey/api/oauth/profile)client_type: "chrome-extension",oauth_tokenin connect messageoauthAccount.accountUuidnever populatedB$().oauthAccount?.accountUuid(used asuser_idin bridge connect) is only populated duringZn$()which runs during token refresh (IML()). If the token hasn't expired,getUserId()returnsundefined. SettingexpiresAt: 0forces refresh but the new session enters a reconnect loop (25+ bridge connections) without pairing.Extension startup race condition
The extension's bridge init
ir()callsisFeatureEnabledAsync("chrome_ext_bridge_enabled")on startup, but the feature cache inchrome.storage.localis empty and no token exists yet → silently returns false →ir()bails with no retry.Conclusion
The bridge architecture (
wss://bridge.claudeusercontent.com) appears non-functional on Windows as of v2.1.39. The named pipe fix documented in the parent issue is the correct approach. The bridge issues are in addition to bugs #1 (Bun crash), #2 (getSocketPaths), and #3 (username spaces).To reproduce the bridge debugging: load the extension as unpacked with debug logging added to
mcpPermissions-DXLzMLpD.js(18[BRIDGE-DBG]markers inir(),nr(),lr()) andservice-worker.ts-C7wbHtdg.js(11[SW-DBG]markers). Pre-populatechrome.storage.localwith the feature flag cache and a valid OAuth token, then reload the extension to observe the fullir()flow.(Closed our duplicate #25091 in favor of this issue.)
It would be a good thing to have Claude Desktop and Claude CLI both being able to navigate the browser simultaneously.. @bcherny how about you make a contest and pick a couple people that would voluntarily contribute, presenting you PRs to cherrypick.
Published: Self-healing SessionStart hook — fixes all 3 Windows Chrome bugs automatically
I've open-sourced the complete fix as part of my Claude Code configuration repo:
Repository: bosmadev/claude
Fix script:
scripts/fix-chrome-native-host.pyDocumentation: README.md > Chrome MCP Fix
What it fixes (3 independent bugs)
| Bug | Root Cause | Fix Applied |
|-----|-----------|-------------|
| Bun stdin crash |
claude.exe(Bun standalone) panics on--chrome-native-hoststdin | Rewrites.batto usenode.exe+ isolatedcli.jsinstall || Socket path discovery |
getSocketPaths()never returns\.\pipe\paths on Windows | Patches function in cli.js to add named pipe path || Bridge exclusive mode |
tengu_copper_bridgeGrowthBook flag forces broken WSS bridge path | Disables flag in.claude.jsoncached features |How it works
Runs as a SessionStart hook — checks and auto-repairs on every Claude Code launch:
.batreferencesclaude.exeor Bun → rewrites tonode.exe + cli.js~/.claude/chrome/node_host/install synced to npm global versiongetSocketPaths()in both isolated and npm globalcli.jsusing content-based pattern matching (survives minification name changes across versions)tengu_copper_bridgeflag (WSS bridge broken on Windows —accountUuidnever populated, pairing never succeeds)Setup
See the README for full hook registration and troubleshooting.
Still needed as of v2.1.39
All three bugs remain unfixed upstream. The fix is still required and has been tested across v2.1.33 → v2.1.39.
Resolution: Environment variable override was the root cause
After 6 sessions of deep investigation (bridge protocol, native host crashes, WebSocket pairing), the actual fix turned out to be much simpler:
A
CLAUDE_CODE_TOKENenvironment variable was being injected into my terminal session, silently overriding the normal OAuth authentication flow. This prevented the bridge from pairing the Chrome extension with the desktop client.Fix: Remove the token environment variable from the terminal session. Once removed, Claude in Chrome connected immediately — bridge pairing, native messaging, everything works.
Lesson for other Windows users: If you're seeing bridge pairing failures despite all prerequisites being met (valid OAuth tokens, feature flags enabled, WebSocket connects), check for auth-related environment variables (
CLAUDE_CODE_TOKEN,ANTHROPIC_API_KEY, etc.) that may be overriding the expected auth flow.That's fine for @NotMyself, but the issues I pointed out have nothing to do with environment variables as those variables are not set on my machine.
@robertmclaws we we’re all looking for solutions to this issue. I posted what fixed it for me in case it helps someone else. Your mileage may vary.
@NotMyself No worries! I just didn't want Anthropic to see that and go "ok problem solved" and close the ticket. 🤜🏻
Update: v2.1.42 Status — Bug #2 Fixed Upstream, Bug #1 Still Present
getSocketPaths (Bug #2): FIXED in 2.1.42
The
getSocketPathsfunction (minified askc7()in 2.1.42) now has native Windows pipe support via an early return:This means the manual patch documented above (
process.env.USERNAMEinjection beforereturn A}) is no longer needed on 2.1.42+. The native code usesos.userInfo().usernamewith proper fallback chain.Bun Crash (Bug #1): STILL BROKEN in 2.1.42
The native binary (
claude.exe) still ships with Bun 1.3.9-canary.62 and panics on--chrome-native-host:The
.bat→node.exe+cli.jsworkaround is still required for the Chrome native host.Bridge (tengu_copper_bridge): STILL BROKEN
tengu_copper_bridge: falsein.claude.jsoncachedGrowthBookFeatures is still required. The WSS bridge path remains non-functional on Windows.Important: PowerShell vs Git Bash Resolution
Windows users may unknowingly run different binaries depending on their shell:
| Shell | Resolves to | Why |
|-------|------------|-----|
| PowerShell |
C:\Users\{user}\.local\bin\claude.exe(native) | PS has aclaudefunction wrapper that explicitly callsclaude.exe|| Git Bash |
D:\nvm4w\nodejs\claude(npm shim) | Extensionless shell script wins in Unix-like PATH resolution |This can cause version mismatches if only one install is updated. Users seeing an older version in their banner should check
which claude/Get-Command claudeto determine which binary is active.Summary for 2.1.42
| Bug | Status | Workaround Still Needed? |
|-----|--------|--------------------------|
| #1: Bun stdin crash | NOT FIXED | Yes —
.batmust usenode.exe + cli.js|| #2: getSocketPaths | FIXED upstream | No — native pipe support built in |
| #3: Username spaces | Untested (no spaces in my username) | Unknown — native uses
os.userInfo()not env var || #4: Bridge (WSS) | NOT FIXED | Yes —
tengu_copper_bridge: falserequired |The self-healing hook still detects native pipe support (2.1.41+) and skips patching, but continues to manage the
.batrewrite and bridge flag — both still necessary.Update: Bug #4 —
claudeInChromeDefaultEnabledsilently disabled (v2.1.56)Summary
Discovered a fourth independent bug that prevents Chrome MCP from working even after fixing bugs #1-3. The
claudeInChromeDefaultEnabledflag in.claude.jsongets silently set tofalse, causing Claude Code to never spawn the--claude-in-chrome-mcpserver process.---
Root Cause
When
claudeInChromeDefaultEnabled: false, Claude Code's built-in Chrome MCP initialization is completely skipped — no--claude-in-chrome-mcpsubprocess is spawned, no socket connection is attempted, and Chrome tools return "Browser extension is not connected."How the flag gets reset
tengu_chrome_auto_enable: false(GrowthBook feature flag) — prevents auto-enabling Chrome on session start/chromecommand toggles the flag — accidental disable persists across sessionsWhy it's hard to detect
/statusshows Chrome extension as "Installed" (registry + manifest correct)cachedChromeExtensionInstalled: truein.claude.json.batis correct (node.exe + cli.js)wmic process where "commandline like '%claude-in-chrome-mcp%'"returns emptyDiagnosis
---
Fix
Manual fix
Then restart Claude Code.
Self-healing hook (automatic)
Added
ensure_chrome_enabled()to the fix-chrome-native-host.py SessionStart hook. It now checks and re-enables the flag on every session start.---
Connection Flow Analysis (v2.1.56)
The Chrome MCP connection path in v2.1.56:
Key insight:
tengu_ccr_bridgevstengu_copper_bridgeThese are two different flags that share similar names:
| Flag | Controls | Default | Effect |
|------|----------|---------|--------|
|
tengu_ccr_bridge| Remote Control / REPL bridge (/remote-controlcommand) | false | Unrelated to Chrome MCP ||
tengu_copper_bridge| Chrome MCP WebSocket bridge (wss://bridge.claudeusercontent.com) | false | When true, EXCLUSIVELY uses broken WSS bridge |---
Updated Bug Summary for v2.1.56
| Bug | Status Upstream | Workaround | Self-Healing Hook |
|-----|----------------|------------|-------------------|
| #1: Bun stdin crash | NOT FIXED (Bun 1.3.9-canary.62) |
.batusesnode.exe + cli.js| ✅ Auto-fixes .bat || #2: getSocketPaths | FIXED in 2.1.42+ | N/A (native support) | ✅ Auto-detects, patches pre-2.1.41 |
| #3: Bridge (WSS) | NOT FIXED |
tengu_copper_bridge: false| ✅ Auto-disables flag || #4: Chrome disabled | NOT FIXED |
claudeInChromeDefaultEnabled: true| ✅ Auto-enables flag |Critical ordering: Bug #4 must be fixed FIRST — if the MCP server never spawns, bugs #1-3 are irrelevant.
---
Suggested Upstream Fix
Option A: Don't gate on
claudeInChromeDefaultEnabledwhen extension is installedIf
cachedChromeExtensionInstalled: trueANDhasCompletedClaudeInChromeOnboarding: true, always spawn the MCP server regardless ofclaudeInChromeDefaultEnabled.Option B: Make
tengu_chrome_auto_enablerespect onboarding stateWhen the user has completed Chrome onboarding,
tengu_chrome_auto_enableshould default totrueeven if GrowthBook sendsfalse.Option C: Respect custom MCP entries for reserved names
If
mcpServers["claude-in-chrome"]exists in.claude.json, use it instead of the built-in. This lets users override the built-in without the name being "reserved."---
Environment
Bug #5: Stale socket prevents reconnection after Chrome starts late (v2.1.58)
When Claude Code starts before Chrome, the in-process Chrome MCP pipe client exhausts its reconnection budget (100 attempts with exponential backoff) and enters a permanently broken state.
Proof the pipe works
Direct test with correct length-prefixed binary framing:
Pipe is alive, Chrome extension responds, native host works. But
tabs_context_mcpreturns "Browser extension is not connected."Root Cause
In
O6A(single socket client), after connection errors the socket object is not nulled:Fix suggestion
Add
this.closeSocket()when giving up after max reconnects:Or fix
ensureConnected()to detect stale sockets:Workaround
Start Chrome before Claude Code, or restart Claude Code while Chrome is running.
Environment
WSL2 (Linux) Fix — Native Host Registration Missing
The issue described here also affects WSL2 users running Chrome natively in Linux. While the Windows-specific bugs (Bun crash, named pipe discovery) don't apply, Claude Code fails to auto-register the Chrome native messaging host on WSL/Linux, leaving the bridge completely non-functional.
Root Cause (WSL)
Claude Code detects the Chrome extension (
cachedChromeExtensionInstalled: true) but never creates:~/.claude/chrome/chrome-native-host~/.config/google-chrome/NativeMessagingHosts/com.anthropic.claude_code_browser_extension.jsonclaudeInChromeDefaultEnabledflag in~/.claude.jsonWithout these, Chrome has no way to launch the native host, so the bridge socket is never created and the MCP server reports "Browser extension is not connected."
Working Fix (WSL2 / Native Linux Chrome)
Step 1 — Create the native host wrapper:
Step 2 — Register the native messaging host manifest:
Step 3 — Enable the Chrome flag:
Step 4 — Restart Chrome and Claude Code:
chrome://extensions)Verification
Environment
fcoeoabgfenejglbffodgkkbkcdhcgfnNote
After the first successful connection, Claude Code rewrites the native host wrapper to use its own versioned binary path directly (e.g.,
~/.local/share/claude/versions/2.1.58). This is expected behavior — future version updates may require re-running Step 1 or pointing the wrapper at the new version.@bosmadev I was able to make the Chrome work on WSL2. I have to apply this script and also fork your script to only fix the
tengu_copper_bridge(I did not apply the other fixes)Updated workaround for v2.1.76 (bridge feature flag issue)
The socket path bug from the original report is fixed in v2.1.76, but a new issue has replaced it: the
tengu_copper_bridgeserver-side feature flag forcesBridgeClient(WebSocket towss://bridge.claudeusercontent.com) over local sockets, with no fallback. The bridge fails to connect → "Browser extension is not connected".Root cause trace
_Oz()returns bridge URL when flag enabled →bridgeConfigset in chrome context →Xd1()picksL61(A)(BridgeClient/y61) instead ofQzA(A)(local socket pool/pzA) → bridge auth fails → no fallback → "not connected"Confirmed by instrumenting
dzA— client type isy61(BridgeClient), notpzA(local pool).Fix (PowerShell — run after every update)
Then restart Chrome and run via
%APPDATA%\npm\claude.cmd.Full script with version checks and uninstall
PR with
scripts/fix-windows-chrome.ps1: https://github.com/anthropics/claude-code/pull/34789Branch:
cruzlauroiii/claude-code@fix/windows-chrome-bridge-fallbackTested on: cli.js v2.1.76, Chrome extension v1.0.61, Windows 11 Pro, Node.js v25.8.1
Updated PR #34789 now includes:
patches/cli.js.patch— exact diff with original/patched SHA-256 hashespatches/chrome-native-host.bat— patched native host wrapperpatches/README.md— full version/hash table for cli.js v2.1.76 and Chrome extension v1.0.61scripts/fix-windows-chrome.ps1— automated patch script with-UninstallsupportPR: https://github.com/anthropics/claude-code/pull/34789
Bug still present in cli.js 2.1.96 — different target strings needed
Confirming the bridge-fallback bug @cruzlauroiii documented for 2.1.76 is alive in cli.js 2.1.96 (
cc_version=2.1.96.f1e). Same root cause —bridgeConfigis set unconditionally on the chrome context, the connector factory picks the cloud WebSocket bridge,queryBridgeExtensionsagainstwss://bridge.claudeusercontent.comreturns empty for the account, and there's no fallback to the local socket pool — so allmcp__claude-in-chrome__*calls fail with "Browser extension is not connected" even when\\.\pipe\claude-mcp-browser-bridge-<user>is healthy and the extension is signed in on the same account.⚠️ cruzlauroiii's PowerShell script silently no-ops against 2.1.96
Their script targets
function _Oz(){if(!w8("tengu_copper_bridge",!1))return;— but in 2.1.96:_Oznow names an HTML tree-adapter helper (function _Oz(q,K){let _=q.treeAdapter.getNamespaceURI(K.element)...}), nothing to do with Chrome.tengu_copper_bridgestring no longer appears anywhere in the bundle (0 matches).PowerShell's
.Replace()on a non-matching target returns the original text unchanged, so the script "succeeds" without error and users believe they're patched. I only caught it because theOy7/RO8-era minified names in my build didn't line up with cruzlauroiii's.Alternative fix target — patch the connector factory directly
In 2.1.96 the factory is:
where
RO8is the cloudBridgeClientandOy7is the local socket pool. The one-line Windows fix:Non-Windows behavior is unchanged. This targets the factory instead of the feature-flag function, which I've found more stable across minified builds — the factory keeps the same shape (
bridgeConfig ? X : getSocketPaths ? Y : Z) even when symbol names churn.Verified:
tabs_context_mcp+tabs_create_mcpboth return clean results through the local named pipe after the patch.cli.jspost-patch sha256 starts withaa85a104; pre-patch was62ad81e3.Note on auto-updates
cli.jsis replaced wholesale on every Claude Code update, so any textual patch is ephemeral. ASessionStarthook that re-applies the replacement when the marker is missing (silent no-op when present, logsneeds-manual-interventionwhen the target string has drifted so you know to re-derive) takes care of it without needing to re-run a script manually.Packaged as a plugin
I've wrapped all of the above into a Claude Code plugin that installs the hook, re-applies the patch on every session start, and is a no-op on non-Windows platforms:
https://github.com/robertmonroe/claude-in-chrome-windows-fix
Restart Claude Code after install. Check
~/.claude/cache/claude-in-chrome-patch.jsonto see the hook's status (already-patchedis the steady state). When a future Claude Code release inevitably reshuffles the minified symbol names again, the hook recordsneeds-manual-interventioninstead of corruptingcli.js— so you'll know to update the patch constants rather than finding out because Chrome tools silently broke.Upstream fix request
The cleanest upstream fix is probably to restore a fallback in the factory — try
bridgeConfigfirst, catch failure, fall back togetSocketPathsif available. Or gatebridgeConfigon a platform/env check. Either way the current "cloud-or-bust" branch is losing a lot of same-machine users whose local pipe is perfectly healthy.Closing for now — inactive for too long. Please open a new issue if this is still relevant.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.