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.
3 Comments
Still reproduces on 2.1.251 + extension 1.0.85, from a cold start with every variable controlled
Re-tested 2026-08-29. This run closes the variables that were still open in the original report: Chrome was fully quit and cold-started, the extension re-paired from scratch afterwards, the native host respawned from the updated install, and only one Claude Code session was running, so there is no session-picker ambiguity.
| Variable | Value |
| --- | --- |
| OS / arch | macOS 15.7.9, x86_64 |
| Chrome | 151.0.7922.174, fully quit and relaunched at 20:25; one profile opened, signed into claude.ai with the same account as Claude Code |
| extension | 1.0.85 (current on the Web Store), re-paired from
pairing.htmlafter the relaunch, browser named || native host | pid started 20:25:24,
claude --chrome-native-host, launched from the 2.1.251 CLI install || bridge socket | published 20:25, i.e. before the session existed |
| session | started 20:27:45,
claude --chrome, 2.1.251 || other sessions | none |
| desktop-app manifest | still renamed aside/disabled, so no native-messaging host contention |
Result, unchanged from the original report:
The other direction still works. The extension's
</>session list shows this session (alongside a remote-control session); selecting it live-renders that session's transcript in the side panel. So the extension can locate and read the very session that Claude Code reports has no browser attached — the one-way channel is intact on current builds.Additionally ruled out by this run, on top of what the original report ruled out:
claudelauncher" — present here, and not sufficientNeither side surfaces an error; both report themselves healthy.
Correction from the reporter: my central claim in this issue is wrong. Retracting it, and replacing it with something simpler.
Re-tested 2026-09-09. Before the new evidence, a retraction, because I sent this issue in the wrong direction and it may be why it has sat untouched.
❌ Retracted: "the extension live-renders the same session that gets
[]"That is the title of this issue and the core of both prior reports. It is false. What I was actually looking at was claude.ai open in an ordinary tab —
claude.ai/code/session_<id>, the cloud session view. That path goes through Anthropic's servers and has nothing to do with the local native-messaging bridge. The extension was never rendering the session.I confirmed this twice in earlier comments in good faith. I was reading the wrong surface both times. There is no one-way channel; there is no "same two processes, one direction only."
✅ What is actually true, restated plainly
The local native-messaging bridge never establishes. That's the whole bug:
…while every precondition on both sides is satisfied.
New evidence since the last comment
1. Both ends have advanced independently; failure is bit-for-bit identical.
| | previously tested | now |
| --- | --- | --- |
| extension | 1.0.85 | 1.0.91 (auto-updated 2026-09-08) |
| Claude Code | 2.1.251 | 2.1.266 |
1.0.85 was the version in every prior test on this issue. This should retire version skew as a candidate.
2. No permission is being withheld on either side. From Chrome's
Secure Preferencesfor the extension:nativeMessagingactive, host access<all_urls>granted and active. On the CLI side: no deny rules, no managed settings / org policy,claudeInChromeDefaultEnabled: true, onboarding completed. (Onlysystem.displayis granted-but-inactive — screenshot display metadata, unrelated.)3. Re-pairing does not restart the bridge. Re-paired from
pairing.html; the native host PID and its socket were unchanged before and after — same pid, same socket file, same mtime. Pairing state and the native-messaging channel appear fully independent. Worth stating because "try re-pairing" reads like a connection reset and it is not one.4. Preconditions for this run, all brought up minutes before the test:
| Variable | Value |
| --- | --- |
| Chrome | started 12:28:59 |
| profile |
Default, same account as Claude Code || native host | the CLI's (
claude --chrome-native-host), 12:29:26 — Claude Desktop's competing native-messaging manifest is disabled, so no host contention || bridge socket | published 12:29, 0600, correct uid — predates the session |
| session | 12:44:56, launched with
--chrome|| result |
[]|The part I think is worth a maintainer's attention
I don't think I'm unusually careless, and I burned four sessions across two weeks on this. The reason is that three separate surfaces indicate success while the bridge is dead, and none of them is actually connected to it:
✅ Claude (MCP)tab group. This is a saved Chrome tab group whose name contains a literal checkmark emoji, restored on every launch. It is static text. I had it recorded in my own notes as meaning "the bridge is healthy." It means nothing.Meanwhile the failure itself is a generic "Browser extension is not connected" and an empty array — no error code, no log, nothing naming which end failed or why.
I count ~11 open issues describing this same symptom in different words (#90013, #89913, #89780, #90385, #90469, #90153, #90306, and others), and one — #89918 — was auto-closed as
NOT_PLANNEDfor needing "a bit more information." I'd suggest the near-duplicate reports and the missing information are downstream of the same cause: there is no way for a user to tell which half is broken. Even a single log line, or havinglist_connected_browsersdistinguish "no browsers paired" from "paired but unreachable," would collapse most of that cluster.Questions
Happy to run anything specific. Environment: macOS 15.7.9 x86_64, Chrome 151, Claude Code 2.1.266, extension 1.0.91.
Follow-up to my previous comment — resolved, and the fix was a plain reinstall, not a version fix.
Removing the Claude extension from Chrome and installing it again fixed it. The version was identical on both sides: 1.0.91 before, 1.0.91 after, same
1.0.91_0folder on disk. A reload and a full Chrome restart had both already been tried in earlier attempts and did not clear it. Whatever was wedged lived in the extension's registration state, and only a clean reinstall cleared it.The transition
From a session started as
claude --chrome --debug-file /tmp/cic.log:Verified end to end immediately after: created a tab group, navigated to example.com, read the page title back, closed the tab.
Worth stressing: the CLI half authenticated and reached the bridge successfully in every failed attempt (
Connection successful,connected=true, authenticated=true, wsState=1). The failure was only ever that no extension had registered at the user-scoped rendezvous.Two suggestions
extensions_liststate anywhere in the UI — even just "0 browsers registered" — would make this self-diagnosing.The diagnostic that would have short-circuited it
Empty array means the extension is not at the bridge, so reinstall it. Everything local —
claude mcp list,lsof -iTCP, native-host pid, Chrome profile, concurrent session count — is a red herring, because the rendezvous is a cloud relay and a local-only investigation cannot see the far side of it.