claude-in-chrome: one-way channel — extension live-renders the same session that gets [] from list_connected_browsers
Summary
With both Claude.app and Claude Code installed on macOS, the Chrome extension and Claude Code end up in a one-way relationship: the extension can read and live-render a Claude Code session, but that same session gets [] from list_connected_browsers and "Browser extension is not connected" from tabs_context_mcp.
There are really two problems here. The second is the interesting one.
Bug 1 — two Anthropic native-host manifests claim the same extension id
~/Library/Application Support/Google/Chrome/NativeMessagingHosts/ contains:
| Manifest | path |
| --- | --- |
| com.anthropic.claude_browser_extension.json | /Applications/Claude.app/Contents/Helpers/chrome-native-host |
| com.anthropic.claude_code_browser_extension.json | ~/.claude/chrome/chrome-native-host |
Both list the same allowed_origins extension id (fcoeoabgfenejglbffodgkkbkcdhcgfn).
Chrome deterministically spawned the Claude.app host every time — even though Claude.app was not running at any point:
3241 /Applications/Claude.app/Contents/Helpers/chrome-native-host
3945 /Applications/Claude.app/Contents/Helpers/chrome-native-host # after full Cmd+Q relaunch
Claude Code's host never started. Renaming the desktop manifest aside and restarting Chrome fixed that much — the CLI host finally spawned and published its socket:
4880 ~/.local/bin/claude --chrome-native-host
/tmp/claude-mcp-browser-bridge-$USER/4880.sock (srw-------, correct uid)
Necessary, but not sufficient — see Bug 2.
Bug 2 — the channel is one-way between the same two processes
With everything above corrected:
- The extension's
</>("code") view lists the running Claude Code sessions and renders the current session's conversation live, updating in real time. - From inside that identical session,
list_connected_browsersreturns[], andtabs_context_mcpreturns "Browser extension is not connected" withcreateIfEmptybothtrueandfalse.
Extension → Claude Code works. Claude Code → extension does not.
Everything verified, all simultaneously true
| Precondition | State |
| --- | --- |
| Desktop manifest disabled | ✅ |
| CLI native host running (not Claude.app's) | ✅ pid 4880, 2.1.250 |
| Bridge socket published before session start | ✅ 18:10 vs 18:11:52 |
| Extension paired via pairing.html ("Connect Browser") | ✅ |
| Extension live-rendering this session | ✅ |
| Session launched with --chrome | ✅ pid 4953, 2.1.250 |
| Both ends on the same build | ✅ |
| list_connected_browsers | ❌ [] |
Environment
- macOS 24.6.0 (Intel)
- Chrome extension 1.0.85 — confirmed latest via forced update check (
chrome://extensions→ Developer mode → Update) - Claude Code 2.1.250
- Both Claude.app and Claude Code installed
Ruled out (please don't re-test these)
- Version skew — extension 1.0.85 is current, CLI 2.1.250 released same day. Both ends on 2.1.250.
- Startup ordering — hypothesised that the session only scans for the socket at startup. Tested directly: session started 18:11:52, ten minutes after the socket appeared at 18:10. No change.
- Wrong Chrome profile / account mismatch — correct profile active, single account, matches the CLI's.
- Extension disabled or sideloaded —
disable_reasons: [],from_webstore: true, service worker started. - Stale native-host wrapper —
~/.claude/chrome/chrome-native-hostexecs~/.local/bin/claude --chrome-native-host; symlink resolves to the running version.
Three misleading signals (worth fixing on their own)
- **
Claude (MCP)shows a green checkmark when the bridge is healthy, not when a session is attached.** Session attachment is a third state, behind an unlabeled</>icon. This reads as "connected" and sent this investigation down the wrong path for some time. - The error text is wrong in every particular here: "ensure the Claude browser extension is installed and running… you may need to restart Chrome." It was installed, enabled, running, and paired; restarting Chrome reproduces the same host selection. It gives no hint about native-host contention.
- Two red herrings for anyone debugging:
claude mcp listnever listsclaude-in-chrome(expected — it isn't an MCP server), andlsof -iTCPshows nothing (it's a unix domain socket). Both read as evidence of failure.
Suggested fixes
- Detect that the other Anthropic manifest is holding the channel and say so explicitly, rather than "extension is not connected".
- Disambiguate the two manifests, or have the extension prefer the host matching the product that is actually running.
- Distinguish "bridge healthy" from "session attached" in the extension UI.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗