VSCode Chrome integration silently fails: 3 distinct bugs
Summary
Chrome browser integration in the Claude Code VSCode extension silently fails to attach the mcp__claude-in-chrome__* tools to the running CLI session. The webview shows browser context (<browser tabId="undefined"> in the prompt) and the model receives the browser_instruction prose, but the tools never appear in the deferred-tool pool, so the model is told it has chrome capabilities it does not actually have.
Investigation surfaced three distinct, independent bugs that together produce this failure. Bugs 1 and 2 are reproducible and orthogonal to my machine; bug 3 is the proximate cause I could not work around from outside the CLI binary.
Environment
- macOS 26.5 (arm64)
- Claude Code CLI: was 2.1.148, updated to 2.1.154 mid-debug
- VSCode extension: auto-updated 2.1.153 → 2.1.154 during the session
- Chrome 148.0.7778.179
- Claude Code Browser Extension:
fcoeoabgfenejglbffodgkkbkcdhcgfnv1.0.74 - Standalone Claude.app desktop also installed (whose chrome integration triggered bug 1)
---
Bug 1: Chrome extension prefers the wrong native-messaging host
The browser extension at fcoeoabgfenejglbffodgkkbkcdhcgfn iterates host candidates in this exact order (from assets/service-worker.ts-*.js):
const a = [
{name: "com.anthropic.claude_browser_extension", label: "Desktop"},
{name: "com.anthropic.claude_code_browser_extension", label: "Claude Code"}
];
for (const s of a) {
const t = chrome.runtime.connectNative(s.name);
// ping-pong handshake with 10s timeout
if (handshakeSucceeded) return; // ← Desktop wins unconditionally
}
Both manifests live in ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/ whenever both Claude.app desktop and Claude Code are installed. The Desktop manifest's chrome-native-host binary responds to the ping even when Claude.app itself isn't running — Chrome just spawns the helper fresh. So the Claude Code variant is never reached, and VSCode's bridge never receives messages from the extension.
Repro: Install both Claude.app desktop and Claude Code. Confirm /Applications/Claude.app/Contents/Helpers/chrome-native-host gets spawned by Chrome instead of ~/.claude/chrome/chrome-native-host.
Workaround I applied: Renamed com.anthropic.claude_browser_extension.json to .disabled, forcing the fallback. Trade-off: breaks Claude.app desktop's chrome integration.
Suggested fix: Reverse the preference order (Claude Code first), or have each variant identify itself in the pong so the extension picks the one matching its packaging.
---
Bug 2: claude update does not regenerate the chrome-native-host wrapper
The wrapper at ~/.claude/chrome/chrome-native-host hardcodes a specific binary path:
#!/bin/sh
# Chrome native host wrapper script
# Generated by Claude Code - do not edit manually
exec "/Users/tmalahieude/.local/share/claude/versions/2.1.148" --chrome-native-host
When the VSCode extension auto-updates to a newer Claude Code version (e.g. 2.1.154) and spawns claude --claude-in-chrome-mcp from that newer binary, the bridge end (still v2.1.148) and the MCP-server end are mismatched. Running claude update to bump the standalone CLI from 2.1.148 → 2.1.154 installed the new binary but did not rewrite the wrapper — it still pointed at the now-stale 2.1.148. The script's own comment claims "do not edit manually", implying it expects to be regenerated by the updater.
Repro: Install Claude Code, set up chrome integration so the wrapper is generated. Run claude update. Observe wrapper still points at the old version.
Workaround I applied: Manually edited the wrapper to point at 2.1.154.
Suggested fix: Either have claude update rewrite the wrapper, or change the wrapper to dereference a version-agnostic symlink like ~/.local/bin/claude.
---
Bug 3 (root cause — the one I couldn't work around): setMcpServers silently no-ops mid-session
After fixing bugs 1 and 2, the infrastructure is correct end-to-end:
- Chrome native messaging now routes to
~/.claude/chrome/chrome-native-host→ spawnsclaude --chrome-native-hostv2.1.154 (bridge process, listening on/tmp/claude-mcp-browser-bridge-$USER/<pid>.sock) - VSCode spawns
claude --claude-in-chrome-mcpv2.1.154 (MCP child) - Versions match; both processes are alive and healthy
- The MCP child responds correctly when probed directly with a JSON-RPC
initialize/tools/list— it exposes the full set ofmcp__claude-in-chrome__*tools
The remaining problem is in the SDK call that connects the MCP child to the running CLI session.
When the user sends a message with @browser, the webview emits ensure_chrome_mcp_enabled. The extension log confirms it received and dispatched the request:
2026-05-28 20:07:24.598 [info] Received message from webview: {"type":"request","channelId":"alnydhsauyw","requestId":"b487mxh6ej","request":{"type":"ensure_chrome_mcp_enabled"}}
This is supposed to call query.setMcpServers({...existing, "claude-in-chrome": <stdio config>}) on the SDK. Expected: the CLI registers the new MCP server, discovers its tools, and includes them in the deferred-tool pool on the next turn.
Actual: no response, no error, no state push ever follows. Searching the entire log for the request ID b487mxh6ej: only the inbound line. Searching for MCP server "claude-in-chrome": zero matches (compare to normal MCP server connections, e.g. MCP server "linear": Successfully connected ...). The CLI's Dynamic tool loading: N/156 deferred tools included line on the next turn shows N unchanged, total denominator unchanged — the chrome MCP server's tools never join the pool.
Repro:
- Install Claude Code in VSCode on macOS with a working chrome integration setup (bugs 1 and 2 fixed).
- Open Claude Code, send a message with
@browserautocomplete chip. - Tail
~/Library/Application Support/Code/logs/.../anthropic.claude-code/Anthropic.claude-code.Claude VSCode.log.
Observe:
ensure_chrome_mcp_enabledrequest receivedChrome MCP: Successfully connected to serverfor the extension-side client- No corresponding
setMcpServersresponse orMCP server "claude-in-chrome": ...line Dynamic tool loading: N/X deferred tools included— X is the same as before the @browser send, no new tools added
The model is then prompted with the browser_instruction block (telling it mcp__claude-in-chrome__* tools are available) but none of those tools actually exist in its tool list. It responds with confusion or ToolSearchTool: keyword search for "claude-in-chrome", found 0 matches.
Note: The same path does work occasionally — e.g. one of my sessions earlier today (0c33075e-bf8f-4845-b078-5a63a559a574) attached chrome successfully on first send, with Dynamic tool loading: 17/160 deferred tools included afterward. I could not identify what made that session succeed; subsequent attempts in fresh sessions, resumed sessions, after VSCode reloads, and after full VSCode + Chrome restarts all failed.
---
Logs / artifacts available
Happy to provide:
- Full
Anthropic.claude-code.Claude VSCode.logfrom the failing day (~19,800 lines) - Process tree showing all bridge and MCP child processes during failures
- The chrome extension's service-worker bundle showing the preference order
Showing cached comments. Read the full discussion on GitHub ↗
6 Comments
Independently reproduced Bug 3 on a second machine and want to add one upstream gating layer this report doesn't yet cover. (Filed #63482 separately before finding this thread - that one is a duplicate of this and I'm closing it; this is the canonical, more complete report.)
Confirming Bug 3 (
setMcpServerssilent no-op)Cmd+Qcold restart (so bugs 1 & 2 are not in play).ensure_chrome_mcp_enabledreceived →Chrome MCP: Successfully connected to server(host-side client) → noMCP server "claude-in-chrome": Starting connection/Successfully connectedon the agent/query side (every other server -xcodebuild,firebase- logs it) → agentToolSearchToolreturnsfound 0 matches/select failed - none found: mcp__claude-in-chrome__tabs_context_mcp.claude --chromefrom a terminal on the same machine works end-to-end. So: version-independent, bridge-health-independent - purely the dynamic registration into the running query silently no-ops. Matches your Bug 3 precisely.Additional layer: the feature is auth-gated (not in this report)
From the shipped
extension.js(2.1.156), browser integration is gated before any of the above can run:And
getAuthStatus():So browser integration is only offered when authed via a Claude.ai Pro/Max OAuth token (scope
user:inference). Console-billing OAuth, API key, Bedrock/Vertex/Foundry, and enterprise auth all disable it entirely -@browserprose may still be injected, butensure_chrome_mcp_enablednever fires and no tools register. This is a distinct failure from Bug 3: it's "feature off" rather than "registration silently fails." It likely explains reports from Console/enterprise users (and is the failure mode on my own enterprise account, separate from the Max account above where the gate passes and Bug 3 bites).Suggested framing
claudeaiauth disables browser integration silently. Either support Console/API-key/enterprise auth for browser tools, or surface a clear "browser requires a Claude.ai login" message instead of injecting@browserprose with no tools.setMcpServers({"claude-in-chrome"})still silently no-ops.One small code-level refinement of Bug 3 from the shipped
extension.js(2.1.156), in case it helps narrow the instrumentation target.The hang is in the
ensureChromeMcpEnabled->setMcpServers-> CLI IPC round-trip:ensureChromeMcpEnableddoesawait V.query.setMcpServers(K)whereK = { ...mcpServers, "claude-in-chrome": { type: "stdio", command, args: ["--claude-in-chrome-mcp"], env: { USER_TYPE: "external" } } }.setMcpServerssplits servers into sdk-instance vs everything-else. A stdio server likeclaude-in-chromegoes into the "everything-else" bucket and is forwarded to the CLI subprocess as a single IPC request:this.request({ subtype: "mcp_set_servers", servers }).ensureChromeMcpEnabledawaits before settingchromeMcpStatetoconnected(success) orerror(catch).What the log shows on a clean, gate-passing (Max/
claudeai), single-version, healthy-bridge setup:ensure_chrome_mcp_enabledrequest (requestIdX) is received once and never gets a response line.xcodebuild/firebase, etc.) contains nomcp_set_servers/sdk_mcp_set_serversactivity and noMCP server "claude-in-chrome": Starting connection.chromeMcpStateis therefore pushed neither asconnectednorerror, which is consistent with theawait this.request({ subtype: "mcp_set_servers" })promise never resolving (a silent hang rather than a thrown error). That matches the "no response, no error, no state push" behavior in the original report.So the concrete suspect is the
mcp_set_serversIPC handler in the CLI query (or the request/response correlation for that subtype) failing to ever reply when a stdio MCP server is added mid-session. Instrumenting both ends of that one IPC subtype should surface where it dies.Reproducing Bug 3 on Windows (the two confirmations above are both macOS).
told it has
mcp__claude-in-chrome__*, but the tools never enter thedeferred-tool pool — Claude reports they "weren't in the deferred tools list"
claude --chromefrom the integrated terminal works fineOne data point on the version angle: 2.1.152 happened to work for me while
2.1.153 / 2.1.156 don't. Given your note that the
setMcpServersno-op isintermittent ("the same path does work occasionally"), this may just be luck
rather than a real version boundary — flagging it in case the timing of the
2.1.153 extension change correlates with the IPC regression.
Closing my report #63696 as a duplicate of this one.
Confirming this reproduces on Windows 11 (the report is currently macOS‑only). Same end symptom:
@browserinjects thebrowser_instructionprose and<browser tabId="undefined">, butmcp__claude-in-chrome__*never enters the tool pool, so the model is told it has chrome tools it doesn't have. Bug 1 and Bug 3 both reproduce here; Bug 2 does not apply. It works fine from the Claude Code CLI; only the VS Code extension fails.Environment
%USERPROFILE%\.local\bin\claude.exeand the VS Code‑bundled binary both 2.1.156)anthropic.claude-code-2.1.156-win32-x64fcoeoabgfenejglbffodgkkbkcdhcgfnv1.0.74 (installed in both Edge and Chrome)Claude_1.9659.2.0_x64)Bug 1 (wrong native host wins) — reproduces on Windows
Both native‑messaging hosts are registered, in both Chrome and Edge:
The Desktop host is the one the browser actually connects to — its process is live and bound to the extension:
So Claude Code's host (
%APPDATA%\Claude Code\ChromeNativeHost\→%USERPROFILE%\.local\bin\claude.exe --chrome-native-host) is never reached — same Desktop‑wins behavior described in Bug 1, on Windows.Bug 2 (stale hardcoded path in wrapper) — does NOT apply here
The Claude Code wrapper already targets a version‑agnostic path, which is the fix this report suggests:
Bug 3 (
setMcpServerssilent no‑op) — reproduces on Windows (root cause)From the VS Code extension log (
Claude VSCode.log):--no-chrome; its startup MCP config does not includeclaude-in-chrome.Chrome MCP: Successfully connected to server(extension↔bridge link is up).@browseruser message injects<browser_instruction>… mcp__claude-in-chrome__* …</browser_instruction>plus<browser tabId="undefined">.claude-opus-4-8[1m](capable; theclaude-haiku-4-5line in the log is only the session‑title generator).claude-in-chrometools never enter the deferred‑tool pool:ToolSearchTool: select failed — none found: mcp__claude-in-chrome__tabs_context_mcp, …andDynamic tool loading: 0/147 deferred tools includedENABLE_TOOL_SEARCH=false(all tools loaded directly): tools still absent, agent still reports them unavailable.So it is not tool‑search‑specific, not a model issue, and not a version mismatch — the
claude-in-chromeserver is never registered into the agent session, exactly matching Bug 3.Already ruled out on this machine
ENABLE_TOOL_SEARCH=false).chromeExtension.pairedDeviceNameset).Happy to provide full logs / process trees if useful.
Reproduced on another machine/account — adding a data point.
Env: macOS
Darwin 25.5.0(arm64) · Chrome148.0.7778.215· extensionfcoeoabgfenejglbffodgkkbkcdhcgfnv1.0.74(Default profile) · Claude Code VS Code ext2.1.159· CLI2.1.114· direct OAuth (not Bedrock/Vertex) · Claude.app desktop also installed.Confirms Bug 1: the shared extension is bound to the desktop host —
PID 729 /Applications/Claude.app/Contents/Helpers/chrome-native-host chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/— and that process survives a fullCmd+Qof Claude.app (Chrome keeps the native port open), so quitting the desktop app does not free the extension. In the VS Code extension,@browser:new_tabyields<browser tabId="undefined">andmcp__claude-in-chrome__*never enters the deferred-tool pool (ToolSearch … 0 matches).Notable: on the same machine, same moment,
claude --chromefrom the CLI pairs and drives Chrome fine — only the VS Code extension path fails. The VS Code extension also has no/chromecommand, so there's no in-extension way to force a reconnect.Fixed on my end 🙂 Closing the issue, will reopen it if error occurs again