claude-in-chrome: browser silently returns fabricated/cached content for localhost navigation instead of reaching the real dev server (no error surfaced)

Status Open
Reported on v2.1.222
Maintainer reply None cached
Activity 1 comment · opened Aug 6, 2026

Summary

While using the mcp__claude-in-chrome__* tools from Claude Code to test a local dev server, all browser-automation calls (navigate, get_page_text, javascript_exec, find, read_page) reported success and returned content consistent with a fully-loaded, interactive copy of my app — but the underlying HTTP requests never reached the actual local server process. No error, denial, or permission prompt was ever shown; the tab simply displayed content that could not have come from my server. The user also observed that Chrome was not running/visible in their Dock while this was happening.

This looks related to the same subsystem as #82626 and #83079 (Claude in Chrome's handling of localhost/MCP-bridge navigation), but the failure mode is different and more concerning: those report an explicit denial (Navigation to this domain is not allowed / permission-popup auto-deny). Here there was no error at all — every tool call succeeded, and the returned page content looked completely legitimate, which makes the failure much harder to notice.

Environment

  • Claude Code CLI 2.1.222, macOS 15.7.7 (24G720), arm64 (Apple Silicon)
  • claude-in-chrome MCP tools (navigate, computer, get_page_text, javascript_exec, find, read_page, read_network_requests, tabs_context_mcp, tabs_create_mcp)
  • Local dev server: Vite 8.0.16, tested on ports 8081/8082/8083, both IPv4 (127.0.0.1), IPv6 (::1), dual-stack, and via the literal hostname localhost

Reproduction / evidence

  1. Started a local HTTP server via the Bash tool (both with and without the sandbox, i.e. dangerouslyDisableSandbox: true — same result either way) that unconditionally responds to any request with a unique, unpredictable marker string (UNIQUE-DEBUG-MARKER-<timestamp>) and logs every incoming connection (method, URL, headers, remoteAddress) to a file.
  2. Confirmed via curl (both --ipv4/127.0.0.1 and -g "http://[::1]") and netstat -an that the server was genuinely listening and reachable on this machine, on both address families.
  3. Used mcp__claude-in-chrome__navigate to point a tab at this exact server (tried http://localhost:PORT/, http://127.0.0.1:PORT/, and http://[::1]:PORT/ — all three, separately, same result).
  4. navigate reported success. get_page_text / javascript_exec on the resulting tab returned a full, real, complex single-page app (the project I was working on — correct page title, menu bar, full app UI, client-side route redirect from / to a sub-path, etc.) — content this one-line debug server is structurally incapable of producing.
  5. Checked the debug server's log file: zero requests recorded from the browser session, despite the "successful" page loads above. Only my own curl verification requests appear in the log.
  6. Repeated this multiple times across fresh dev-server restarts, fresh tabs (tabs_create_mcp), and after fully quitting/relaunching Chrome. Same result every time.
  7. Ruled out (with direct evidence, not just theory):
  • HTTP/browser caching — tested with {cache: 'no-store'} and cache-busting query strings; also proved impossible once the debug-server test (step 4-5) showed a never-before-requested random path also returned fabricated content.
  • Service worker interferencenavigator.serviceWorker.getRegistrations() showed zero registrations at the time of the test; unregistering explicitly made no difference.
  • Stale/zombie server processlsof -i :PORT / ps aux / netstat confirmed only one process was ever bound to the port, matching the freshly-started debug server, with a Date response header only seconds old (when testing against the real dev server) proving live generation, not a replay.
  • IPv4/IPv6 mismatch — found and fixed a real, separate bug (Vite's --host defaults to IPv6-loopback-only on this machine; 127.0.0.1 was flatly connection-refused). Fixing this (dual-stack, then IPv6-only via explicit --host ::1, then navigating to the literal http://[::1]:PORT/ URL) made no difference to the core issue.
  • Hostname-string-based interception — tested localhost, 127.0.0.1, and the raw [::1] literal; identical behavior for all three, so it isn't specifically about the string "localhost".
  1. Separately noticed: mcp__claude-in-chrome__computer screenshot actions (Page.captureScreenshot over CDP) intermittently timed out after 30s ("renderer may be frozen or unresponsive") while lighter calls (get_page_text, javascript_exec) on the same tab succeeded normally in the same window of time.
  2. The user reported Chrome was not visible in their Dock at all while I was successfully driving "it" — no window, no icon — yet tabs_context_mcp continued to report the same tab IDs as available and interactions with them kept succeeding.

Why this matters

This is a local-dev-server testing workflow (npm run serve:python style), which the tool is explicitly meant to support. Unlike #82626/#83079's explicit-denial failure mode — annoying but obvious — this one is silent: every tool call reports success, and the content returned is plausible enough (a real, previously-cached/rendered copy of the actual target app, correctly reflecting client-side routing) that an agent (or a user skimming the transcript) could easily believe a real local-server verification passed when it didn't touch the real server at all. I only caught it because the served content stopped matching file edits I'd just made, and had to build a custom marker-response server to prove it conclusively.

Suggested investigation

Given #83079's finding that the extension has a bypassLocalhostForMcp code path and a PermissionManager that treats navigate differently from passive reads (screenshot/read_page/find are exempted from permission gating) — it seems plausible that in this session, navigate to a local origin was silently routed to some fallback/mocked/cached path instead of actually opening the real connection, without that ever surfacing as an error to either the MCP client or (per the user's report) as a visible Chrome window. If there's a cached-preview or offline-fallback rendering path in the extension that can be reached without a live, connected Chrome window, that would explain everything observed here.

What I could not determine

I don't have visibility into how/where the driven Chrome instance actually runs (local process vs. remote/managed), so I can't say definitively whether this is a routing bug (right browser, wrong network path) or a session bug (no real browser at all, content synthesized from a prior/cached session). Happy to provide full session logs/timestamps if useful for triage — this was investigated interactively via Claude Code and I can reconstruct the exact sequence of tool calls.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗