console-stream-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@console-stream-mcpShow me the recent errors from the active tab"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mobius-mcp gives an AI agent a real browser it can operate and account for. It drives the Chrome you're already signed into and every action returns the requests, console errors, navigations and DOM changes it caused.
That last part is the difference. Other browser tools act, and then you ask separately what happened and correlate it yourself.
Works with any MCP client — Claude Code, Codex CLI, Cursor, Windsurf, Zed, Cline, Gemini CLI. Local-first: no cloud services, no telemetry, no external APIs.
Table of contents
Related MCP server: browser-connect-mcp
What you can do with it
Debug a broken flow end to end. Point the agent at "signup is failing" and it drives to the failure itself — no more pasting console output into chat, and no more describing which buttons to press. It comes back with the request that failed, the response body that explains why, and the console error that followed.
Catch failures that look like successes. A 200 OK carrying {"success": false}. A click swallowed by an invisible modal backdrop. An auth header that quietly stops being sent halfway through a flow. These are invisible to status codes and to element.click(), and they're what this is built to surface.
Run a QA walkthrough. Drive your key flows in one run_sequence and collect a screenshot, a HAR and the console output per step — a regression sweep before a release, without a test suite to maintain.
Reproduce and hand off a bug. Turn a confirmed repro into something filable: an ordered timeline, screenshots, and a HAR with full request/response bodies attached.
Investigate performance. Separate "the network is slow" from "the main thread is blocked" from "memory climbs every time I open this panel", using request timing alongside real CPU and memory profiles — against your actual logged-in session, not a synthetic one.
Audit what a page really sends. See every third-party request a page makes and what's in the payloads — analytics, pixels, embedded widgets — including whether anything sensitive is leaving in a request body.
Verify a fix. Re-run the same flow after the change and compare against what happened before.
Because it drives the browser you're already authenticated in, all of this works on pages behind a login — internal dashboards, admin panels, staging environments — with no credentials handled by the agent and no separate test account.
What makes it different
Actions return their consequences. Every action tool takes
observe: { windowMs, types? }and returns what the app did in that window — console, network, navigation, DOM — alongside the action's own result. One round trip, no correlation step.A blocked click says so. Every coordinate-dispatching action hit-tests first and reports
hitTest: "ok" | "blocked"with the element that will actually receive the input, and why (covered,pointer_events,offscreen).Find elements in plain language.
find({ query: "newsletter signup field" })returns ranked, clickable refs — no CSS selectors, and no paying for a full-page dump to locate one button.Your real browser, your real session. Not a fresh headless profile. Already logged in, real cookies, real extensions.
A human can watch. Driven tabs show a synthetic cursor that moves to each target before the input fires, plus a HUD logging what the agent is doing — so operating a live account isn't a black box.
Trusted input. CDP
Input.*, notelement.click(), which misses whole classes of handlers.The observability half. HAR export with full bodies, CPU/memory profiles, blocking
wait_for_*instead of polling, and rolling history that survives a server restart.
How it works
Web App
│
Browser extension
│
WebSocket
│
localhost
│
mobius-mcp
│
Claude Code / Codex / Cursor / Gemini CLIA browser client captures runtime events — console.*, uncaught errors, unhandled rejections, fetch/XHR calls, and navigation (including SPA route changes via pushState/replaceState/hash) — and streams them over a WebSocket to a local MCP server. The same connection carries commands the other way, which is why an action can return what it caused. The server keeps a rolling history (in-memory, backed by on-disk persistence — see Configuration) and exposes all of it as MCP tools.
Repo layout
Path | Description |
| Node.js MCP server; WebSocket hub + MCP tool implementations |
| Chromium extension that captures events, drives the page, and renders the cursor/HUD overlay |
|
|
| Versioned event schema/message envelope plus runtime hook patching, shared by the extension, npm client, and mcp-server (private, bundled) |
| Scenario-focused agent skills, one per major use case — see Skills |
| Example apps demonstrating integration |
Getting started
mobius-mcp is published on npm. (Contributing to this repo instead? See Contributing.)
Register the MCP server with your agent. For Claude Code:
claude mcp add mobius-mcp -- npx -y mobius-mcpOr add it directly to your MCP client's config (Claude Code, Codex CLI, Cursor, Gemini CLI, etc. all read a JSON config in this shape):
{ "mcpServers": { "mobius-mcp": { "command": "npx", "args": ["-y", "mobius-mcp"] } } }Install the browser extension. This is currently the only supported way to stream and drive a tab — see below for why.
⚠️ The Chrome Web Store build is significantly behind this repo. Store review takes time, and driving —
find,click,type_text,run_sequence, theobservewindow, hit-testing and the cursor overlay — landed after the last published release. If you want the capabilities described in this README, build the extension from this repo (steps below). The store version still works for passive capture (console, errors, network, navigation), andmobius_diagnosewill reporthandshake_rejectedif it's too old for the server you're running.Once installed, click the toolbar icon and hit "Enable tab" on the tab you want to work with — capture is opt-in per tab, nothing streams by default (see Enabling capture). An agent can also open and enable a tab itself via
open_tab/enable_capture, without the click.An npm package (
mobius-client) for direct app integration without the extension exists but development is paused — see Roadmap for why. It still works at its baseline (console/error/network/navigation capture only, no driving) if the extension truly isn't an option for your setup, but isn't the recommended path right now.Ask your agent to use it — "walk through checkout and tell me where it breaks", "check the browser console for errors", "what is this page sending to third parties".
Install the extension from source
Until the store build catches up, this is the recommended path. It takes about a minute and needs Node 18+ and Chrome.
git clone https://github.com/Topman-14/mobius-mcp.git
cd mobius-mcp
npm install
npm run buildThen load it into Chrome:
Go to
chrome://extensionsTurn on Developer mode (top right)
Click Load unpacked
Select
apps/browser-extension/distinside the cloned repo
Pin the mobius icon to your toolbar and you're done — the extension connects to the MCP server on its own.
Run the matching server too. A source-built extension speaks the current protocol, which a published npx mobius-mcp may not. Point your MCP client at the local build so both halves match:
{
"mcpServers": {
"mobius-mcp": {
"command": "node",
"args": ["/absolute/path/to/mobius-mcp/apps/mcp-server/dist/index.js"]
}
}
}If they ever drift apart, mobius_diagnose reports handshake_rejected and tells you which side to update.
To update later: git pull && npm run build, then hit the refresh icon on the extension card at chrome://extensions. Reload any tab you had capture enabled on — the in-page scripts are only re-injected on the next load. Restart your MCP client too, so it picks up the rebuilt server.
Remove the Chrome Web Store version first if you have it installed — two copies both trying to hold the WebSocket connection is the kind of thing that produces confusing symptoms.
Configuration
The server reads these environment variables on startup — set them in the env block of your MCP client's server config:
{
"mcpServers": {
"mobius-mcp": {
"command": "npx",
"args": ["-y", "mobius-mcp"],
"env": { "CONSOLE_STREAM_PERSISTENCE_TTL_MS": "7200000" }
}
}
}Variable | Default | Description |
|
| WebSocket port the browser client connects to |
|
| Event history cap per tab, both in-memory and on disk |
|
| Grace period after a tab disconnects before its buffer is purged (survives a quick page refresh) |
|
| Where per-tab event history is persisted to disk, so it survives an MCP server restart |
|
| How long persisted events are kept before being pruned from disk |
Enabling capture (extension)
The extension never captures anything by default. Click its toolbar icon and hit "Enable tab" on the tab you want to work with — that's the one opt-in. Multiple tabs can be enabled independently. For dev servers you always want captured without clicking every time, add a rule (e.g. localhost:5173) on the extension's settings page (right-click the icon → Options) — matching tabs auto-enable on navigation.
An agent can also start capture itself, without a toolbar click, via open_tab (opens a new tab) or enable_capture (an already-open tab's Chrome tab id, from list_tabs) — consent still comes from the human having installed and granted the extension its permissions, just not per tab.
An enabled tab keeps the same tabId across navigation, along with its event history, so a handle an agent obtained before a page load stays valid after it. Use clear_logs if you want a clean baseline after navigating.
Privacy defaults
Nothing is captured until a tab is enabled, and what is captured is redacted before it ever leaves the browser. Out of the box: authorization, cookie, set-cookie, proxy-authorization and x-api-key header values are replaced with [redacted] (the header name stays visible, so "was this request authenticated?" is still answerable), JSON body keys shaped like secrets (password, token, api_key, ssn, card numbers, …) are masked at any depth, and JWT-shaped strings are masked anywhere they appear. Email masking is available but off by default. All of it is configurable per-item on the extension's settings page.
Captured events are also written to disk so history survives an MCP server restart (see CONSOLE_STREAM_PERSISTENCE_DIR above). Those files hold redacted event data including request/response bodies; the directory is created 0700 and the files 0600, and everything in it is pruned after CONSOLE_STREAM_PERSISTENCE_TTL_MS (1 hour by default).
Extension permissions
Permission | Why |
| Inject the capture and driving scripts into an enabled tab |
| Settings, auto-enable rules, and per-tab capture state |
| Read tab URLs/titles for |
| Detect real page loads, to re-inject capture and emit navigation events |
| Chrome DevTools Protocol: trusted input events, screenshots, snapshots, profiling, |
| Reconnect backstop — an idle MV3 service worker can be shut down, and an alarm is the only thing that can start it again |
| Capture is opt-in per tab, but the tab could be any origin — a local dev server, a staging deploy, or production |
notifications is optional and only requested if you turn on error notifications in settings.
MCP tools
Start with mobius_diagnose — it reports whether mobius is usable right now (connection state, ever-connected history, ordered remediation), never fails, and never needs a tab. Call it first in a session and after any connection-related error. See Troubleshooting.
Find and drive
Every action below takes observe: { windowMs, types? } to return what the app did afterward, and reports hitTest so a blocked interaction is never mistaken for a working one. Targets are addressed by a ref (from find/snapshot_page) or a CSS selector. All require the extension and CDP.
find— locate elements by natural-language description ("accept cookies button"); returns ranked refs plustotalMatched. The cheap path when you know what you're looking forsnapshot_page— pruned, indexed tree of interactive/labelled/text-bearing elements, each with aref, role, accessible name and box. Narrow it withviewportOnly,rolesormaxElements. For surveying a page rather than locating one thingclick,hover,type_text,press_key,scroll_to,scroll_by,select_option,set_checkbox— real trusted CDP input events, each moving the on-page cursor overlay with its own iconrun_sequence— many steps against one tab in a single round trip, stopping at the first failure and returning what completed.find/snapshot_page/take_screenshotare eligible steps, and screenshots come back interleaved in step orderopen_tab,enable_capture— start a session without a toolbar clicknavigate_to,switch_tab,reload_tab,list_tabs,set_active_tab— browser control (extension only;list_tabssees every open tab, not just enabled ones)
Observe
get_recent_logs,get_recent_errors,get_logs_since,clear_logsget_network_requests— request/response headers plus size-capped, redacted request/response bodies for text-like content types (no CDP needed)get_capture_settings,get_connected_tabs— which categories a tab is capturing, so an empty result is distinguishable from "that category is off"start_debug_session,end_debug_session— one ordered timeline of console/network/navigation/DOM instead of correlating snapshots by hand (single-tab, doesn't survive a full-page navigation)wait_for_console_error,wait_for_navigation,wait_for_request,wait_for_element— block with a timeout instead of polling in a loopexport_har— HAR 1.2 with full request/response bodies; anything missed inline is re-fetched over CDP (binary bodies base64-encoded)get_response_body,get_request_body— CDP fallback for the rare body capture skipped (binary, oversized, non-text)
Inspect
take_screenshot,capture_full_page,capture_elementcapture_dom,capture_accessibility_tree— raw markup and the full AX tree; for markup/ARIA questions, not for finding something to clickevaluate_js— arbitrary JS in the tab, fully open (no read-only enforcement)start_cpu_profile,start_memory_profile— job-based, seeget_job_status/get_job_result/cancel_job
CDP tools make Chrome show a persistent "being debugged" banner on the tab once used — the debugger attaches on first use and stays attached rather than attaching per call. This is a Chrome-level indicator the extension cannot suppress. Profile durations are capped at 60s and best-effort beyond ~25-30s, since Chrome can terminate an idle MV3 service worker mid-profile.
Troubleshooting
If an agent reports mobius-mcp isn't working, ask it to call mobius_diagnose — it returns a state (ready, no_client_ever_connected, client_disconnected, handshake_rejected, or ws_bind_failed) plus ordered remediation steps, and never fails or requires a connected tab.
To check from outside an MCP session entirely:
npx mobius-mcp --healthPrints the same payload as JSON and exits 0 if state is "ready", 1 otherwise. This talks to whichever mobius-mcp process is already bound to the configured port (CONSOLE_STREAM_PORT, default 7331) — it doesn't start a new server, so run it while your MCP client is active.
Known limitations
Testing coverage. It works reliably across the setups it's been developed and dogfooded on, but hasn't yet been exercised across the full range of OSes, Chrome versions, and MCP clients in the wild — treat it as early-stage software, and please report anything unexpected.
The published extension lags this repo. Chrome Web Store review is slow, so the store build is currently well behind — driving in particular isn't in it yet. Build from source for the full capability set.
mobius_diagnosereports a version mismatch ashandshake_rejected.The local WebSocket is unauthenticated. Anything that can open a socket to
127.0.0.1:7331can drive the tools, includingevaluate_js— in practice, any other process running as you, and any page loaded over plainhttp(WebSocket connections aren't subject to same-origin policy; onlyhttpspages are blocked fromws://by mixed-content rules). This is the standard localhost-dev-tool trust model, but it's a real boundary, and a dedicated auth design is planned.A page can influence what it reports about itself. Capture works by patching
console.*/fetchinside the page's own JavaScript realm, which is what makes it work at all — but a hostile or compromised page can suppress events or emit fabricated ones. Treat captured output from untrusted pages as untrusted data; the server tells agents this explicitly in its MCP instructions.Actions dispatch even when the target is covered. Hit-testing reports
hitTest: "blocked"and names the element that will actually receive the input, but the event is still sent — it reports the problem rather than refusing.Screenshots need the tab in the foreground. Chrome doesn't service
captureScreenshotfor a background tab, so callswitch_tabfirst if the target isn't visible.snapshot_pagetruncates in DOM order. On a long page that means the element budget can be spent above the current viewport. UseviewportOnly, orfind, which isn't affected.The debugger banner. Any CDP-backed tool attaches
chrome.debugger, so Chrome shows its "being debugged" bar on that tab. The debugger detaches after five idle minutes.
Client capabilities
Event ingestion is identical across both browser clients — the server can't tell them apart. Command capabilities are not: driving and everything CDP-backed requires the extension. The protocol reports this via a capabilities field on connect, so commands a client can't support fail with a clear error instead of hanging.
Capability | Browser extension | npm client ( |
Console/error/network/navigation event streaming | ✅ | ✅ |
| ✅ | ✅ |
Multi-tab awareness ( | ✅ | ✅ (one entry per app instance) |
Opt-in capture (popup toggle / settings rules / agent-initiated) | ✅ | n/a — capture starts as soon as |
Browser control ( | ✅ | ❌ |
Element lookup ( | ✅ (requires CDP) | ❌ |
Instrumented actions ( | ✅ (requires CDP) | ❌ |
Cursor + HUD overlay on driven tabs | ✅ | ❌ |
Debug sessions ( | ✅ | ✅ (no DOM mutations) |
Screenshots, DOM/accessibility snapshots | ✅ (requires CDP) | ❌ |
CPU/memory profiling | ✅ (requires CDP) | ❌ |
| ✅ (requires CDP) | ❌ |
Network request/response headers + bodies | ✅ | ✅ |
Full-body HAR export, | ✅ (requires CDP for the fallback fetch) | ❌ (inline-captured bodies only) |
React/Redux/Zustand state, storage inspection | ❌ (planned) | ❌ (planned) |
See Roadmap for what "planned" maps to by stage.
Skills
mobius-mcp is agent-agnostic — it works with any MCP-speaking client, not just one. skills/<name>/SKILL.md holds one workflow per major use case. Every client gets these the portable way: each skill is also exposed as an MCP prompt of the same name — no plugin system required, works with any MCP client that supports prompts.
Claude Code users additionally get a native-feeling shortcut, since this repo doubles as an installable Claude Code plugin (.claude-plugin/plugin.json):
/plugin marketplace add Topman-14/mobius-mcp
/plugin install mobius-mcp@mobius-mcpThat's a convenience on top, not the primary path — the MCP prompts are what makes the skills available everywhere.
Skill | What it does |
| "X doesn't work" — drives to the failure itself, then separates a handler that never fired, a click eaten by an overlay, a silent API failure, a dropped session, and a response whose shape no longer matches what the frontend expects |
| Drives your key flows and reports what broke, collecting a screenshot, HAR and console output per step — a regression sweep without a test suite |
| Turns a confirmed bug into a filable artifact: ordered timeline, screenshots, and a HAR with full bodies |
| Separates "feels slow" into network-bound, CPU-bound, or a memory leak building over repeated use |
| What a page sends and exposes — third-party requests and their payloads, console noise, and controls that can't actually be reached |
Design principles
Local-first, zero cloud dependencies, zero telemetry
Framework agnostic
An action should return what it caused, not just whether it dispatched
A human should be able to watch an agent drive their browser
Extension and npm client emit an identical, versioned protocol — the server can't tell them apart
Roadmap
Staged build history and planned future work — including why the npm client is paused, and what's left for framework introspection (React/Redux/Zustand state, storage inspection) — live in ROADMAP.md.
Smoke-test app
examples/spa-smoke-test is a small React + react-router-dom SPA built to exercise every capture path at once, rather than hunting for a real app that happens to trigger all of them: a range of console.log/info/warn/error payload shapes (objects, arrays, circular refs, BigInt, long strings, PII-shaped strings for redaction), multiple ways to trigger uncaught errors and unhandled promise rejections, fetch/XHR requests covering 200/404/500/slow/network-failure/POST, route/param/search-param changes, and DOM mutations. Useful for smoke-testing changes to this repo, or just seeing what mobius-mcp captures before wiring it into a real app. Requires a clone (not part of the published npm package) — see Contributing below for setup.
cd examples/spa-smoke-test
npm install
npm run devOpen the served URL, enable capture on the tab, click through /scenarios, then ask your agent to inspect the results via the MCP tools above — try get_capture_settings first, to rule out "that category is off" before assuming a missing event is a bug. Scenarios are extensible: see examples/README.md for the full list and how to add new ones.
Contributing
Contributions are welcome — please open an issue to discuss significant changes before submitting a PR. Guidelines and PR expectations are in CONTRIBUTING.md; local setup instructions are below.
This is an npm workspaces monorepo (apps/*, packages/*). A single install at the root wires up every package — npm install inside an individual apps//packages/ folder is never necessary and will just fight the workspace symlinks in the root node_modules.
git clone https://github.com/Topman-14/mobius-mcp.git
cd mobius-mcp
npm install
npm run buildnpm run build builds every workspace in dependency order (packages/capture-core → the apps), since apps/browser-extension, apps/mcp-server, and apps/npm-client all consume the built dist/ output of the shared package, not its TypeScript source.
To run the MCP server from source instead of via npx:
npm run start --workspace=apps/mcp-serverWatch mode
For active development across the shared packages and the extension, run:
npm run watchThis does a one-time build of packages/capture-core (so nothing is resolved against a missing dist/ on a cold start), then runs three watchers in parallel with labeled output:
[packages]—tsc -b --watchforpackages/capture-core, incrementally rebuilding on save[vite]— the extension's Vite dev server, which also drives crxjs's automatic extension reload in Chrome for background/popup/options changes[content-scripts]— an esbuild watcher forcontent-script.ts/injected.ts, which are bundled as standalone IIFEs outside Vite's module graph (see the comment inapps/browser-extension/vite.config.ts)
Load the extension once via chrome://extensions → enable Developer Mode → Load unpacked → select apps/browser-extension/dist. From then on:
Edits to
packages/capture-corepropagate through to the extension's bundled output automatically.Edits to background/popup/options files trigger Vite/crxjs's automatic reload in Chrome.
Edits to
content-script.ts/injected.tsrebuild immediately, but since those are injected on demand viachrome.scripting.executeScript, the new code takes effect the next time they're injected (reload the target tab, or toggle capture off/on) rather than needing an extension reload.
If you only need the shared package rebuilding (e.g. while working on apps/npm-client or apps/mcp-server) without the extension's Vite/esbuild watchers, run npm run watch -w packages/capture-core directly instead.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityAmaintenanceEnables AI coding assistants to control and inspect a live Chrome browser through Chrome DevTools. Provides browser automation, performance analysis, debugging capabilities, and network request monitoring.Last updated1,408,23048,364Apache 2.0
- Alicense-qualityDmaintenanceEnables AI assistants to connect to browser DevTools and backend debuggers for full-stack debugging, including frontend console, network, performance, and backend log analysis.Last updated217MIT
- Alicense-qualityBmaintenanceEnables AI coding assistants to control and inspect a live Chrome browser through Chrome DevTools for automation, debugging, and performance analysis.Last updated1,408,230Apache 2.0
- Alicense-qualityCmaintenanceLets AI coding assistants control and inspect a live Chrome browser using full Chrome DevTools capabilities for browser automation, debugging, and performance analysis.Last updated1,408,230Apache 2.0
Related MCP Connectors
Live browser debugging for AI assistants — DOM, console, network via MCP.
Give AI coding agents access to your Vynix visual feedback, bug reports, and AI diagnosis.
Give your agent live data from Twitter, Reddit, the web and GitHub. No API keys, no scraping stack.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Topman-14/mobius-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server