Claude in Chrome: CLI never contacts the native messaging host (Status stays "Disabled")
Summary
/chrome reports Status: Disabled / Extension: Installed on every session.
Every link in the chain works in isolation, except one: the CLI never opens a
connection to the native messaging host. The host's stderr stays completely
silent for the entire lifetime of a claude --chrome session, while the same
host happily serves ping and get_status from the extension seconds earlier.
Environment
|
|
| OS |
macOS (Darwin 27.0.0), Apple Silicon |
| Claude Code |
2.1.274 (Homebrew cask) |
| Browser |
Brave 153.1.95.101 (only Chromium browser installed) |
| Extension |
1.0.93, installed and signed in |
| Plan |
Claude Max (organizationType: claude_max) |
| Auth |
OAuth via /login (no API key, no setup-token) |
What works (verified)
- Extension to native host: host stderr shows
Handling Chrome message type: ping,
Responding to ping, Handling Chrome message type: get_status
- Native host: starts, creates
/tmp/claude-mcp-browser-bridge-$USER/<pid>.sock,
listens, sets mode 0600, cleans stale sockets
- Network:
wss://bridge.claudeusercontent.com returns HTTP 101 Switching Protocols
- MCP server:
claude-in-chrome connects over stdio in 3 ms, exposes its tools
(tabs_context_mcp, tabs_create_mcp, navigate, read_page)
- Host config: present at the documented Brave path,
allowed_origins matches
the extension ID
What fails
The CLI writes the wrapper script, logs the bridge URL, then stops:
[DEBUG] [Claude in Chrome] Created Chrome native host wrapper script: ~/.claude/chrome/chrome-native-host
[INFO] Bridge URL: wss://bridge.claudeusercontent.com
[DEBUG] MCP server "claude-in-chrome": Successfully connected (transport: stdio) in 3ms
[DEBUG] [closeSessionTabGroup] bridge not connected, skipping
No connection attempt to the native host is ever made. Consequence: browser tools
are rejected upstream of the permission system, even with an explicit
mcp__claude-in-chrome__* allow rule loaded:
[DEBUG] executePermissionRequestHooks called for tool: mcp__claude-in-chrome__tabs_context_mcp
[DEBUG] mcp__claude-in-chrome__tabs_context_mcp tool permission denied
~/.claude.json never gains a chromeExtension pairing entry, across many restarts.
How the native host silence was observed
The wrapper is a shell script, so stderr can be redirected to a file (the CLI
rewrites this wrapper on every startup, so it must be re-applied):
#!/bin/sh
exec 2>>/tmp/native-host.log
exec "/opt/homebrew/bin/claude" --chrome-native-host
The extension's traffic shows up immediately. A full claude --chrome session
started afterwards adds zero lines.
Things ruled out
- Conflicting native hosts from other Chromium browsers (Chrome, Edge) and their
orphaned sockets: removed, hosts disabled
- Concurrent/stale
claude --chrome sessions holding the integration: all closed
- Revoked OAuth token (
401 authentication_error: OAuth access token has been revoked): fixed via /logout + /login, error gone, symptom unchanged
- Stale
chromeExtension pairing and hasCompletedClaudeInChromeOnboarding:
removed from ~/.claude.json to force re-pairing, no effect
- Extension reinstalled from the Web Store: no effect
- Extension service worker console: empty, no errors
- macOS TCC: not involved (stdio + Unix socket, no Apple Events)
- Managed settings /
deniedMcpServers: no managed-settings.json on the machine
- Permission hooks:
PermissionRequest hook matches Bash only
Steps to reproduce
- macOS with Brave as the only Chromium browser, Claude in Chrome extension installed and signed in
claude --chrome
/chrome -> Status: Disabled, Extension: Installed
Reconnect extension -> no change; no chromeExtension entry appears in ~/.claude.json
Note
The integration also never worked while Google Chrome was the browser in use, so
this is not Brave-specific.
Claude in Chrome: CLI never contacts the native messaging host (Status stays "Disabled")
Summary
/chromereportsStatus: Disabled/Extension: Installedon every session.Every link in the chain works in isolation, except one: the CLI never opens a
connection to the native messaging host. The host's stderr stays completely
silent for the entire lifetime of a
claude --chromesession, while the samehost happily serves
pingandget_statusfrom the extension seconds earlier.Environment
organizationType: claude_max)/login(no API key, nosetup-token)What works (verified)
Handling Chrome message type: ping,Responding to ping,Handling Chrome message type: get_status/tmp/claude-mcp-browser-bridge-$USER/<pid>.sock,listens, sets mode 0600, cleans stale sockets
wss://bridge.claudeusercontent.comreturnsHTTP 101 Switching Protocolsclaude-in-chromeconnects over stdio in 3 ms, exposes its tools(
tabs_context_mcp,tabs_create_mcp,navigate,read_page)allowed_originsmatchesthe extension ID
What fails
The CLI writes the wrapper script, logs the bridge URL, then stops:
No connection attempt to the native host is ever made. Consequence: browser tools
are rejected upstream of the permission system, even with an explicit
mcp__claude-in-chrome__*allow rule loaded:~/.claude.jsonnever gains achromeExtensionpairing entry, across many restarts.How the native host silence was observed
The wrapper is a shell script, so stderr can be redirected to a file (the CLI
rewrites this wrapper on every startup, so it must be re-applied):
The extension's traffic shows up immediately. A full
claude --chromesessionstarted afterwards adds zero lines.
Things ruled out
orphaned sockets: removed, hosts disabled
claude --chromesessions holding the integration: all closed401 authentication_error: OAuth access token has been revoked): fixed via/logout+/login, error gone, symptom unchangedchromeExtensionpairing andhasCompletedClaudeInChromeOnboarding:removed from
~/.claude.jsonto force re-pairing, no effectdeniedMcpServers: no managed-settings.json on the machinePermissionRequesthook matchesBashonlySteps to reproduce
claude --chrome/chrome->Status: Disabled,Extension: InstalledReconnect extension-> no change; nochromeExtensionentry appears in~/.claude.jsonNote
The integration also never worked while Google Chrome was the browser in use, so
this is not Brave-specific.