claude-in-chrome MCP server fails to connect to native host socket

Resolved 💬 3 comments Opened Mar 22, 2026 by hihihihihiihihihihihihhhihihihhiihi Closed Mar 26, 2026

Bug Description

The built-in claude-in-chrome MCP server consistently fails to connect to the Chrome extension's native host socket, even though the socket exists and responds correctly when tested manually.

Every call to any mcp__claude-in-chrome__* tool returns:

Browser extension is not connected. Please ensure the Claude browser extension is installed and running...

Environment

  • Claude Code version: 2.1.81 (Homebrew)
  • OS: macOS Darwin 25.1.0 (Apple Silicon)
  • Chrome: 146.0.7680.80
  • Claude Chrome Extension: 1.0.63
  • Chrome Profile: Default (non-managed, non-Family Link)
  • Claude Desktop App: Installed and running

Reproduction Steps

  1. Install Claude Chrome extension (ID: fcoeoabgfenejglbffodgkkbkcdhcgfn)
  2. Start Claude Code with claude --chrome
  3. Open Chrome with the extension enabled
  4. Verify native host is running: ps aux | grep chrome-native-host
  5. Verify socket exists: ls /tmp/claude-mcp-browser-bridge-$(whoami)/
  6. Call any chrome tool — always returns "not connected"

Investigation Findings

1. Native messaging pipeline works perfectly

Manually tested in Chrome extension's service worker DevTools console:

let port = chrome.runtime.connectNative("com.anthropic.claude_browser_extension");
port.onMessage.addListener(msg => console.log("RECEIVED:", JSON.stringify(msg)));
port.postMessage({type: "ping"});
// Output: RECEIVED: {"timestamp":1774176399581,"type":"pong"}

2. Socket is functional and responds correctly

The native host creates a socket at /tmp/claude-mcp-browser-bridge-{username}/{pid}.sock. Manual connection using the length-prefixed binary protocol (4-byte LE header + JSON) works:

import socket, json, struct

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect('/tmp/claude-mcp-browser-bridge-aglitch/69616.sock')

msg = json.dumps({
    "type": "mcp_request",
    "method": "execute_tool",
    "params": {"tool": "tabs_context_mcp", "args": {"createIfEmpty": True}},
    "id": 1
}).encode()

header = struct.pack('<I', len(msg))
s.sendall(header + msg)

# Successfully returns:
# {"result":{"content":[{"type":"text","text":"{\"availableTabs\":[...]}"}]}}

3. CLI native host wrapper crashes on Chrome spawn

The wrapper script at ~/.claude/chrome/chrome-native-host points to the full 193MB CLI binary (claude --chrome-native-host). When Chrome spawns this via native messaging, it either:

  • Exits before responding to ping (Chrome reports: "Unchecked runtime.lastError: Native host has exited")
  • Or takes too long to initialize (Chrome's 10-second timeout expires)

The Desktop App's dedicated 2MB binary (/Applications/Claude.app/Contents/Helpers/chrome-native-host) works correctly and responds to ping/pong instantly.

4. Claude Code CLI never connects to the socket

Even when:

  • The correct native host is running (Desktop App binary)
  • The socket exists with correct permissions (0700 directory, 0600 socket)
  • Chrome extension is connected and functional
  • Session was started with --chrome flag
  • Multiple restart attempts with different timing

The built-in claude-in-chrome MCP server never connects to the socket.

5. Family Link / managed Chrome profiles block native messaging entirely

Chrome profiles under Google Family Link (child accounts with managed_user_id: ChildAccountSUID) silently block chrome.runtime.connectNative(). The extension loads but never establishes the native messaging connection. No error is shown to the user — it just silently fails.

Workaround

Created a custom MCP bridge server that connects to the socket using the correct length-prefixed binary protocol:

claude mcp add -s user chrome-bridge -- node ~/.claude/chrome-bridge/server.mjs

The bridge server:

  1. Scans /tmp/claude-mcp-browser-bridge-{username}/ for .sock files
  2. Sends messages using 4-byte LE length prefix + JSON (the protocol the native host expects)
  3. Exposes tools via standard MCP stdio protocol

This works — tools like tabs_context_mcp, navigate, find, read_page all function correctly through the bridge.

Suggested Fix

  1. Fix the CLI native host wrapper: Either use the Desktop App's dedicated binary, or optimize the CLI binary's --chrome-native-host mode to respond to ping within Chrome's timeout
  2. Fix socket connection in claude-in-chrome MCP server: The built-in server should scan for and connect to available sockets in the bridge directory
  3. Add Family Link detection: Warn users if their Chrome profile is managed/supervised, as native messaging will be silently blocked

🤖 Generated with Claude Code

View original on GitHub ↗

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