[BUG] Chrome Extension Native Messaging Host Conflict: Claude Desktop + Claude Code on Windows

Resolved 💬 2 comments Opened Feb 9, 2026 by jasonswearingen Closed Mar 10, 2026

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.batclaude.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-host in any process list
  • No named pipe created\\.\pipe\claude-mcp-browser-bridge-{username} does not exist
  • Claude Code's --claude-in-chrome-mcp subprocess 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

  1. Binary patch (version-specific): Add if(os.platform()==="win32")return[getSocketPath()] to getSocketPaths(). Requires patching minified names per Claude Code version.
  1. 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-bridge in 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

View original on GitHub ↗

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