[BUG] Chrome Extension Native Messaging Host Conflict: Claude Desktop + Claude Code on Windows
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.25
Claude Code Version
2.1.37 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
Chrome Extension Native Messaging Host Conflict: Claude Desktop + Claude Code on Windows
Issue Summary
On Windows, Claude-in-Chrome browser tools fail with "Browser extension is not connected" even when the Chrome extension is installed, enabled, and the native messaging infrastructure is correctly configured. The root cause is a two-bug interaction between Claude Desktop's auto-updater and Claude Code's getSocketPaths() function that creates a cascade failure in the Chrome extension's native host connection logic.
Neither bug alone is sufficient to cause the failure in all configurations. Together, they make Claude-in-Chrome completely non-functional on Windows systems that have both Claude Desktop and Claude Code installed.
---
Environment
- OS: Windows 10/11
- Claude Code: v2.1.32 (standalone
.exe) - Claude Desktop: v1.1.1890 (Squirrel auto-updated from v1.1.1200)
- Chrome Extension: v1.0.47 (Claude in Chrome Beta)
- Chrome: Latest stable
---
Architecture Background
The Claude-in-Chrome system has three components:
Chrome Extension (v1.0.47)
│
│ chrome.runtime.connectNative(hostName)
▼
Native Messaging Host (launched by Chrome, communicates via stdio)
│
│ Creates named pipe: \\.\pipe\claude-mcp-browser-bridge-{username}
▼
Claude Code CLI (connects to named pipe as client)
Two native messaging hosts are registered on systems with both Claude Desktop and Claude Code:
| Registry Key | Host Name | Executable |
|---|---|---|
| com.anthropic.claude_browser_extension | Desktop | chrome-native-host.exe (Claude Desktop) |
| com.anthropic.claude_code_browser_extension | Claude Code | chrome-native-host.bat → claude.exe --chrome-native-host |
Both hosts are registered for the same Chrome extension ID (fcoeoabgfenejglbffodgkkbkcdhcgfn).
---
Bug #1: Claude Desktop Auto-Update Breaks Native Host Manifest
What happens
Claude Desktop uses Squirrel for auto-updates. Each version installs to a versioned folder:
C:\Users\{user}\AppData\Local\AnthropicClaude\app-1.1.1200\resources\chrome-native-host.exe
C:\Users\{user}\AppData\Local\AnthropicClaude\app-1.1.1520\resources\chrome-native-host.exe
C:\Users\{user}\AppData\Local\AnthropicClaude\app-1.1.1890\resources\chrome-native-host.exe
The native messaging host manifest is stored at:
C:\Users\{user}\AppData\Roaming\Claude\ChromeNativeHost\com.anthropic.claude_browser_extension.json
This manifest contains a hardcoded absolute path to chrome-native-host.exe:
{
"name": "com.anthropic.claude_browser_extension",
"path": "C:\\Users\\jason\\AppData\\Local\\AnthropicClaude\\app-1.1.1200\\resources\\chrome-native-host.exe",
"type": "stdio",
"allowed_origins": [
"chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/"
]
}
When Claude Desktop auto-updates, the old app-1.1.1200 folder is eventually cleaned up, but the manifest is never updated to point to the new version's path. The manifest still references the deleted executable.
Impact
Chrome tries to launch the native host → executable not found → native host fails to start → no named pipe is created.
Fix
Manually update the manifest path to the current version:
"path": "C:\\Users\\jason\\AppData\\Local\\AnthropicClaude\\app-1.1.1890\\resources\\chrome-native-host.exe"
Recommended permanent fix
Claude Desktop's auto-updater should update the native messaging host manifest whenever it installs a new version. Alternatively, use a stable symlink or launcher that resolves to the current version.
---
Bug #2: Chrome Extension Host Selection Order + No Fallthrough
What happens
The Chrome extension's service worker (service-worker.ts-DWAkZ3wK.js) tries to connect to native hosts in a fixed order:
const s = [
{ name: "com.anthropic.claude_browser_extension", label: "Desktop" }, // FIRST
{ name: "com.anthropic.claude_code_browser_extension", label: "Claude Code" } // SECOND
];
for (const n of s) try {
const a = chrome.runtime.connectNative(n.name);
// ... sends ping, waits for pong ...
}
Desktop is tried first. When the Desktop host's executable is missing (Bug #1), Chrome reports a native messaging error. The extension's error handling does not cleanly fall through to try the Claude Code host.
Impact
Even though Claude Code's native host (chrome-native-host.bat) is correctly registered and functional, the extension never reaches it because the Desktop host failure short-circuits the connection loop.
Evidence
With Bug #1 active (stale Desktop manifest):
- No native host process launched — no
--chrome-native-hostin any process list - No named pipe created —
\\.\pipe\claude-mcp-browser-bridge-{username}does not exist - Claude Code's
--claude-in-chrome-mcpsubprocess runs but has nothing to connect to
After fixing Bug #1 (updating Desktop manifest path):
- Native host launches successfully
- Named pipe is created
- Full protocol test succeeds (tool calls return tab data)
Recommended fix
The extension's host selection should gracefully handle missing executables and continue to the next host in the list. Consider also making the host order configurable or detecting which host application is actually running.
---
Bug #3 (Claude Code): getSocketPaths() Returns Unix Paths on Windows
What happens
This is a separate, well-documented bug in Claude Code's built-in claude-in-chrome MCP integration. The getSocketPaths() function (minified as xYI in v2.1.32) returns Unix-style socket paths on all platforms:
function getSocketPaths() {
let paths = [];
let dir = getSocketDir(); // "/tmp/claude-mcp-browser-bridge-{user}"
try {
let files = fs.readdirSync(dir); // readdir("/tmp/...") — fails on Windows
for (let f of files)
if (f.endsWith(".sock")) paths.push(path.join(dir, f));
} catch {}
let name = `claude-mcp-browser-bridge-${getUsername()}`;
let tempPath = path.join(os.tmpdir(), name); // "C:\Users\...\Temp\claude-mcp-..."
let unixPath = `/tmp/${name}`; // "/tmp/claude-mcp-..." — doesn't exist
if (!paths.includes(tempPath)) paths.push(tempPath);
if (tempPath !== unixPath && !paths.includes(unixPath)) paths.push(unixPath);
return paths; // Never includes the named pipe!
}
The companion function getSocketPath() (minified as rN$) correctly handles Windows:
function getSocketPath() {
if (os.platform() === "win32")
return `\\\\.\\pipe\\${getNamedPipeName()}`; // Correct!
return path.join(getSocketDir(), `${process.pid}.sock`);
}
But getSocketPaths() (the discovery function used by the socket pool) never calls it.
Impact
Even when the named pipe exists (Bugs #1 and #2 resolved), Claude Code's built-in tools cannot find it. The socket pool scans the wrong paths, finds no connected clients, and reports "Browser extension is not connected."
Workarounds
- Binary patch (version-specific): Add
if(os.platform()==="win32")return[getSocketPath()]togetSocketPaths(). Requires patching minified names per Claude Code version.
- External MCP bridge server (version-independent): A standalone Node.js MCP server that connects directly to the named pipe, bypassing Claude Code's broken path discovery entirely. Registered as
chrome-bridgein Claude Code's MCP config.
---
The Cascade Failure
On a Windows system with both Claude Desktop and Claude Code installed, all three bugs interact:
Bug #1: Claude Desktop updates → native host manifest points to deleted exe
↓
Bug #2: Chrome extension tries Desktop host first → exe missing → fails
Chrome extension does not fall through to Claude Code host
↓
No native messaging host launches
No named pipe is created
↓
Bug #3: Even IF the pipe existed, Claude Code's getSocketPaths()
would return Unix paths and never find the Windows named pipe
↓
"Browser extension is not connected."
Fixing Bug #1 alone resolves the pipe creation issue (Desktop host launches, pipe exists). Combined with a binary patch or MCP bridge for Bug #3, Claude-in-Chrome becomes fully functional.
Fixing Bug #2 alone (better fallthrough) would let the Claude Code host launch even when Desktop's host is broken — but Bug #3 would still prevent the built-in tools from connecting.
All three bugs must be addressed for a robust Windows experience without manual intervention.
---
Diagnostic Commands
Check if named pipe exists
// Node.js — save as test-pipe.js and run: node test-pipe.js
const net = require('net');
const os = require('os');
const pipe = '\\\\.\\pipe\\claude-mcp-browser-bridge-' + os.userInfo().username;
console.log('Testing pipe:', pipe);
const c = net.connect(pipe);
c.on('connect', () => { console.log('CONNECTED'); c.end(); });
c.on('error', (e) => { console.log('Error:', e.message); });
setTimeout(() => { console.log('Timeout'); process.exit(1); }, 5000);
Check native host registry and manifest
# PowerShell
$path = "HKCU:\Software\Google\Chrome\NativeMessagingHosts"
Get-ChildItem $path | ForEach-Object {
$val = (Get-ItemProperty $_.PSPath).'(default)'
Write-Host "$($_.Name) → $val"
if ($val -and (Test-Path $val)) {
Get-Content $val | ConvertFrom-Json | Format-List
} else {
Write-Host " *** MANIFEST FILE MISSING OR HOST EXE PATH BROKEN ***"
}
}
Check running native host processes
# PowerShell
Get-CimInstance Win32_Process |
Where-Object { $_.CommandLine -match "chrome-native-host|claude-in-chrome" } |
Select-Object ProcessId, CommandLine | Format-List
Full protocol test (proves pipe is functional)
// Node.js — tests full request/response cycle
const net = require('net');
const os = require('os');
const pipe = '\\\\.\\pipe\\claude-mcp-browser-bridge-' + os.userInfo().username;
const c = net.connect(pipe);
c.on('connect', () => {
const msg = JSON.stringify({
method: "execute_tool",
params: { client_id: "test", tool: "tabs_context_mcp", args: { createIfEmpty: true } }
});
const buf = Buffer.from(msg, 'utf-8');
const len = Buffer.allocUnsafe(4);
len.writeUInt32LE(buf.length, 0);
c.write(Buffer.concat([len, buf]));
});
let data = Buffer.alloc(0);
c.on('data', (chunk) => {
data = Buffer.concat([data, chunk]);
if (data.length >= 4) {
const len = data.readUInt32LE(0);
if (data.length >= 4 + len) {
console.log('Response:', data.slice(4, 4 + len).toString('utf-8'));
c.end();
}
}
});
c.on('error', (e) => console.log('Error:', e.message));
---
Related Issues
- #23104 — Chrome extension not connecting on Windows (getSocketPaths bug)
- #20298 — Chrome extension not connecting to Claude Code CLI
- #20375 — Claude Code and Claude Desktop native host configs conflict
- #22052 — Chrome extension connects to Claude Desktop but not Claude Code
- #23218 — Chrome extension not connecting on Windows 11
- #23539 — Chrome extension not connecting despite correct configuration
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗