VSCode Chrome integration silently fails: 3 distinct bugs

Status Fixed / completed
Reported on v2.1.148
Maintainer reply None cached
Activity 7 comments · opened May 28, 2026 · closed Jun 15, 2026

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: fcoeoabgfenejglbffodgkkbkcdhcgfn v1.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 → spawns claude --chrome-native-host v2.1.154 (bridge process, listening on /tmp/claude-mcp-browser-bridge-$USER/<pid>.sock)
  • VSCode spawns claude --claude-in-chrome-mcp v2.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 of mcp__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:

  1. Install Claude Code in VSCode on macOS with a working chrome integration setup (bugs 1 and 2 fixed).
  2. Open Claude Code, send a message with @browser autocomplete chip.
  3. Tail ~/Library/Application Support/Code/logs/.../anthropic.claude-code/Anthropic.claude-code.Claude VSCode.log.

Observe:

  • ensure_chrome_mcp_enabled request received
  • Chrome MCP: Successfully connected to server for the extension-side client
  • No corresponding setMcpServers response or MCP 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.log from 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

View original on GitHub ↗

6 Comments

gotnull · 3 months ago

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 (setMcpServers silent no-op)

  • macOS, VS Code extension 2.1.156, Chrome ext 1.0.74, account = Claude Max.
  • Clean state: removed a stale obsolete extension version so only 2.1.156 remained, full Cmd+Q cold restart (so bugs 1 & 2 are not in play).
  • Log shows exactly your Bug 3 signature: ensure_chrome_mcp_enabled received → Chrome MCP: Successfully connected to server (host-side client) → no MCP server "claude-in-chrome": Starting connection / Successfully connected on the agent/query side (every other server - xcodebuild, firebase - logs it) → agent ToolSearchTool returns found 0 matches / select failed - none found: mcp__claude-in-chrome__tabs_context_mcp.
  • claude --chrome from 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:

// VS Code subclass:
isBrowserIntegrationSupported(){ return this.authManager.getAuthStatus()?.authMethod === "claudeai" }
// base class: return false

And getAuthStatus():

if (BEDROCK || VERTEX || FOUNDRY || SKIP_AUTH_LOGIN) return { authMethod: "3p" }
if (oauthTokens) return { authMethod: oauthTokens.scopes.includes("user:inference") ? "claudeai" : "console" }
if (ANTHROPIC_API_KEY || ANTHROPIC_AUTH_TOKEN) return { authMethod: "3p" }
if (apiKey) return { authMethod: "api-key" }

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 - @browser prose may still be injected, but ensure_chrome_mcp_enabled never 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

  • Layer 0 (gate): non-claudeai auth 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 @browser prose with no tools.
  • Bug 3 (this report): when the gate passes, setMcpServers({"claude-in-chrome"}) still silently no-ops.
gotnull · 3 months ago

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:

  1. ensureChromeMcpEnabled does await V.query.setMcpServers(K) where K = { ...mcpServers, "claude-in-chrome": { type: "stdio", command, args: ["--claude-in-chrome-mcp"], env: { USER_TYPE: "external" } } }.
  2. setMcpServers splits servers into sdk-instance vs everything-else. A stdio server like claude-in-chrome goes into the "everything-else" bucket and is forwarded to the CLI subprocess as a single IPC request: this.request({ subtype: "mcp_set_servers", servers }).
  3. The returned promise is what ensureChromeMcpEnabled awaits before setting chromeMcpState to connected (success) or error (catch).

What the log shows on a clean, gate-passing (Max/claudeai), single-version, healthy-bridge setup:

  • The webview ensure_chrome_mcp_enabled request (requestId X) is received once and never gets a response line.
  • The CLI subprocess debug output (which is otherwise very verbose: API requests, tool dispatch, MCP connections for xcodebuild/firebase, etc.) contains no mcp_set_servers / sdk_mcp_set_servers activity and no MCP server "claude-in-chrome": Starting connection.
  • chromeMcpState is therefore pushed neither as connected nor error, which is consistent with the await 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_servers IPC 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.

davidezemmi · 3 months ago

Reproducing Bug 3 on Windows (the two confirmations above are both macOS).

  • OS: Windows
  • VS Code extension: broke on 2.1.153, still broken on 2.1.156
  • Claude for Chrome extension connected ("Browser connected" banner shown)
  • Symptom matches Bug 3 exactly: webview injects the browser context, model is

told it has mcp__claude-in-chrome__*, but the tools never enter the
deferred-tool pool — Claude reports they "weren't in the deferred tools list"

  • claude --chrome from the integrated terminal works fine

One 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 setMcpServers no-op is
intermittent ("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.

vpoorshab · 3 months ago

Confirming this reproduces on Windows 11 (the report is currently macOS‑only). Same end symptom: @browser injects the browser_instruction prose and <browser tabId="undefined">, but mcp__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

  • OS: Windows 11 Enterprise (build 26100)
  • Claude Code: 2.1.156 (standalone CLI at %USERPROFILE%\.local\bin\claude.exe and the VS Code‑bundled binary both 2.1.156)
  • VS Code extension: anthropic.claude-code-2.1.156-win32-x64
  • Claude in Chrome extension: fcoeoabgfenejglbffodgkkbkcdhcgfn v1.0.74 (installed in both Edge and Chrome)
  • Claude Desktop app also installed and running (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:

HKCU\Software\Google\Chrome\NativeMessagingHosts\
  com.anthropic.claude_browser_extension       -> %APPDATA%\Claude\ChromeNativeHost\com.anthropic.claude_browser_extension.json        (Claude Desktop)
  com.anthropic.claude_code_browser_extension  -> %APPDATA%\Claude Code\ChromeNativeHost\com.anthropic.claude_code_browser_extension.json (Claude Code)

HKCU\Software\Microsoft\Edge\NativeMessagingHosts\   (identical pair)

The Desktop host is the one the browser actually connects to — its process is live and bound to the extension:

PID 54052: %APPDATA%\Claude\ChromeNativeHost\chrome-native-host.exe
           chrome-extension://fcoeoabgfenejglbffodgkkbkcdhcgfn/ --parent-window=0

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:

%USERPROFILE%\.claude\chrome\chrome-native-host.bat
  -> "%USERPROFILE%\.local\bin\claude.exe" --chrome-native-host

Bug 3 (setMcpServers silent no‑op) — reproduces on Windows (root cause)

From the VS Code extension log (Claude VSCode.log):

  • Agent (SDK query) is spawned with --no-chrome; its startup MCP config does not include claude-in-chrome.
  • Chrome MCP: Successfully connected to server (extension↔bridge link is up).
  • @browser user message injects <browser_instruction>… mcp__claude-in-chrome__* …</browser_instruction> plus <browser tabId="undefined">.
  • Main agent model is claude-opus-4-8[1m] (capable; the claude-haiku-4-5 line in the log is only the session‑title generator).
  • The claude-in-chrome tools never enter the deferred‑tool pool:
  • with tool search on: ToolSearchTool: select failed — none found: mcp__claude-in-chrome__tabs_context_mcp, … and Dynamic tool loading: 0/147 deferred tools included
  • with ENABLE_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-chrome server is never registered into the agent session, exactly matching Bug 3.

Already ruled out on this machine

  • Stale extension version (removed leftover 2.1.154; everything is 2.1.156).
  • Tool search / dynamic tool loading (reproduces with ENABLE_TOOL_SEARCH=false).
  • MCP tool overload.
  • Model capability (Opus 4.8).
  • Browser pairing (bridge connects; "Browser Connected" banner shows; chromeExtension.pairedDeviceName set).

Happy to provide full logs / process trees if useful.

thomasboer-sketch · 3 months ago

Reproduced on another machine/account — adding a data point.

Env: macOS Darwin 25.5.0 (arm64) · Chrome 148.0.7778.215 · extension fcoeoabgfenejglbffodgkkbkcdhcgfn v1.0.74 (Default profile) · Claude Code VS Code ext 2.1.159 · CLI 2.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 full Cmd+Q of 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_tab yields <browser tabId="undefined"> and mcp__claude-in-chrome__* never enters the deferred-tool pool (ToolSearch … 0 matches).

Notable: on the same machine, same moment, claude --chrome from the CLI pairs and drives Chrome fine — only the VS Code extension path fails. The VS Code extension also has no /chrome command, so there's no in-extension way to force a reconnect.

tmalahie · 2 months ago

Fixed on my end 🙂 Closing the issue, will reopen it if error occurs again

Showing cached comments. Read the full discussion on GitHub ↗