Skip to main content
Glama

Status: Phases 1–3 complete (core capture, replay UI, dependency graph & session export). Phase 4 (auto-docs, performance overlays, dependency-graph UI) in progress. Active development.

🎯 What is UnderPixel?

UnderPixel is a Chrome extension + MCP server that gives AI coding assistants β€” Claude Code, Cursor, Claude Desktop, VS Code Copilot, Windsurf, or anything that speaks MCP β€” the one piece of context every other browser tool is missing: which API calls feed which UI elements.

Existing browser MCPs treat network capture and visual capture as separate, unlinked streams. UnderPixel bundles them by timestamp:

Snapshot Bundle @ T = 1712345678000
β”œβ”€β”€ screenshot        PNG
β”œβ”€β”€ dom_state         rrweb incremental snapshot
β”œβ”€β”€ api_calls         [ { url, method, status, headers, body, timing }, … ]
β”œβ”€β”€ trigger           "fetch response: GET /api/okrs"
└── correlation       "DOM #okr-table updated from GET /api/okrs"

Ask Claude "what API feeds the user table?" and get an answer grounded in actual recorded traffic β€” not guesswork from page source.

Related MCP server: Curupira

✨ Key Features

  • πŸ”— Visual–API correlation β€” every screenshot, DOM mutation, and API call indexed on a shared timeline. The core differentiator.

  • 🧠 API dependency graph β€” auto-detects call chains via value propagation (JWT β†’ request, ID β†’ URL, token β†’ header). Maps your auth flow without you writing a line.

  • 🎬 Session replay with synced timeline β€” rrweb-player on the left, event-grouped API timeline on the right. Click a request, jump to the moment it fired.

  • πŸ“‘ Full network capture via CDP β€” request and response bodies, headers, timing. Not just URLs. Powered by chrome.debugger.

  • πŸ“Έ Smart screenshot gate β€” 2-layer system (rrweb event stream + stability wait β†’ pixelmatch diff). Captures only frames where pixels actually changed.

  • 🌐 Works in your real browser β€” your cookies, your logins, your extensions. No --remote-debugging-port, no separate profile, no Playwright relaunch.

  • πŸ€– AI action audit trail β€” when Claude Code drives the browser via MCP, UnderPixel silently records everything. Replay exactly what the agent did.

  • πŸ“¦ Session export & share β€” .underpixel files (gzipped JSON). Hand a teammate a full reproduction of a bug β€” DOM, network, screenshots, all of it.

  • πŸ”Œ Client agnostic β€” Streamable HTTP or stdio MCP transport. Works with any compliant client.

  • 🎯 ~12 focused tools, not 27 β€” opinionated surface, less token overhead in tool definitions, more context for actual work.

πŸ†š How UnderPixel Compares

Capability

mcp-chrome

chrome-devtools-mcp

browser-tools-mcp

UnderPixel

Network capture w/ response bodies

βœ…

βœ…

⚠️ partial

βœ…

Screenshots

βœ…

βœ…

βœ…

βœ…

Works in your real browser

βœ…

❌ needs flags

βœ…

βœ…

Network ↔ DOM correlation

❌

❌

❌

βœ…

DOM mutation recording

❌

❌

❌

βœ… (rrweb)

Pixel-level visual change detection

❌

❌

❌

βœ… (pixelmatch)

Synced session replay

❌

❌

❌

βœ… (rrweb-player)

API dependency graph

❌

❌

❌

βœ…

AI action audit / replay

❌

❌

❌

βœ…

Session export & share

❌

❌

❌

βœ… (.underpixel)

Tool count

27

~25

~15

~12 (focused)

πŸ“ UnderPixel builds on the proven infrastructure patterns of mcp-chrome (Native Messaging bridge, CDP capture, Streamable HTTP) and uses rrweb directly as a dependency for DOM recording and replay. The novel contribution is the correlation layer β€” the thing that turns raw streams into context an LLM can reason about.

πŸš€ Quick Start

Prerequisites

  • Node.js β‰₯ 20

  • Chrome (or any Chromium browser β€” Edge, Brave, Arc work)

  • An MCP-compatible client: Claude Code, Claude Desktop, Cursor, VS Code Copilot, Windsurf…

1. Install the bridge

# npm
npm install -g underpixel-bridge

# pnpm (postinstall scripts must be enabled)
pnpm config set enable-pre-post-scripts true
pnpm install -g underpixel-bridge

# fallback: register manually if postinstall didn't run
underpixel-bridge register

The bridge auto-registers itself as a Chrome Native Messaging host. It is a thin stdio-↔-Native-Messaging translator (~200 lines) β€” all logic lives in the extension, so the bridge package rarely needs updating.

2. Load the Chrome extension

  1. Download the latest extension build from GitHub Releases.

  2. Open chrome://extensions/ and enable Developer mode.

  3. Click Load unpacked and select the unzipped folder.

  4. Click the UnderPixel toolbar icon β†’ Connect to view your local MCP endpoint.

Once stable, UnderPixel will be published to the Chrome Web Store for one-click install.

3. Wire it up to your MCP client

Streamable HTTP (recommended β€” supports per-session transports, no subprocess spawn):

{
  "mcpServers": {
    "underpixel": {
      "type": "streamableHttp",
      "url": "http://127.0.0.1:PORT/mcp"
    }
  }
}

stdio (for clients that don't speak HTTP yet):

{
  "mcpServers": {
    "underpixel": {
      "command": "npx",
      "args": ["-y", "underpixel-bridge"]
    }
  }
}

The exact port number is shown in the extension popup after Connect.

4. Try it

In Claude Code (or any MCP client), ask:

"Open the Hacker News front page, capture network for 5 seconds, then tell me which API delivered the story list and what its response shape looks like."

UnderPixel will navigate, record, correlate, and hand back a structured answer with the actual endpoint URL, request method, response schema, and a timestamped DOM snapshot showing the result rendered on screen.

πŸ› οΈ MCP Tools

UnderPixel exposes ~12 tools organized by purpose. The full schemas are in packages/shared/src/tool-schemas.ts.

Tool

Description

underpixel_correlate(query)

"What API feeds the user table?" Forward (URL/body text search), reverse (DOM element β†’ APIs via rrweb snapshots), and value-level (DOM text β†’ specific JSON response field). Supports CSS selectors, attribute queries, and free text.

underpixel_timeline(startTime?, endTime?, limit?)

Chronological correlation bundles β€” API + DOM + visual state, joined on timestamp.

underpixel_snapshot_at(timestamp)

Closest screenshot + active API calls at a specific moment.

Tool

Description

underpixel_capture_start(filter?)

Start recording network + DOM + visual state. Configurable URL/domain filter.

underpixel_capture_stop()

Stop capture, return correlated summary.

underpixel_api_calls(filter?)

Query captured API calls with full headers, request and response bodies, timing.

underpixel_api_dependencies()

Auto-detected call chain β€” typed edges (bearer_token, id, session, …).

Tool

Description

underpixel_screenshot(selector?)

On-demand screenshot β€” viewport, full page, or single element.

underpixel_dom_text(selector)

Current text content of elements (TreeWalker-based, safe for any markup).

underpixel_replay(timeRange)

Open the replay tab in the browser; returns the session bundle.

Tool

Description

underpixel_navigate(url)

Open a URL (new tab or update existing).

underpixel_interact(action)

Click, fill, scroll, type, press key.

underpixel_page_read(filter?)

Accessibility tree of visible elements ('all' or 'interactive').

🧩 Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Chrome Extension (Manifest V3 Β· WXT Β· Svelte 5)             β”‚
β”‚                                                              β”‚
β”‚  Content (MAIN)                                              β”‚
β”‚    └─ rrweb.record()           β†’ DOM event stream            β”‚
β”‚    └─ PerformanceObserver      β†’ layout-shift signals        β”‚
β”‚                                                              β”‚
β”‚  Background (Service Worker)                                 β”‚
β”‚    β”œβ”€ chrome.debugger          β†’ CDP network capture         β”‚
β”‚    β”œβ”€ Correlation Engine       β†’ timestamp-window matching   β”‚
β”‚    β”œβ”€ Screenshot Gate          β†’ rrweb + stability + diff    β”‚
β”‚    β”œβ”€ IndexedDB                β†’ sessions Β· events Β· bodies  β”‚
β”‚    └─ Native Messaging         β†’ stdio to bridge             β”‚
β”‚                                                              β”‚
β”‚  Offscreen Document                                          β”‚
β”‚    └─ pixelmatch               β†’ canvas-based pixel diff     β”‚
β”‚                                                              β”‚
β”‚  Replay Page (chrome-extension://…/replay.html)              β”‚
β”‚    β”œβ”€ rrweb-player             β†’ interactive replay          β”‚
β”‚    └─ Event-grouped API timeline (synced via Svelte store)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚  Native Messaging
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  underpixel-bridge (npm package Β· Fastify Β· ~200 LOC)        β”‚
β”‚    └─ stdio ↔ Native Messaging Β· MCP transport routing       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚  MCP JSON-RPC (Streamable HTTP or stdio)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Claude Code Β· Cursor Β· Claude Desktop Β· any MCP client      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why this shape:

  • All logic in the extension. The bridge is a dumb pipe. The extension auto-updates via the Web Store; the npm package rarely changes. Single source of truth, no syncing issues.

  • Per-session MCP transports. Each MCP client gets its own StreamableHTTPServerTransport + McpServer instance β€” matches the official SDK pattern and supports concurrent clients.

  • IndexedDB everywhere. Long sessions with hundreds of API calls + rrweb events would exhaust memory. IndexedDB persists across MV3 service-worker restarts (30s idle timeout) and indexes by timestamp + URL for fast queries.

  • CDP, not webRequest. chrome.webRequest cannot read response bodies. Since "what data did this API return" is the heart of correlation, chrome.debugger is required.

πŸ“– How the correlation works

The trick isn't capturing things β€” it's joining them.

  1. Three independent streams flow into a single per-tab buffer:

    • rrweb DOM events (mutation, layout-shift, input, etc.)

    • CDP network events (Network.requestWillBeSent / responseReceived / getResponseBody)

    • Smart screenshots (gated by rrweb activity + stability + pixelmatch diff threshold)

  2. The correlation engine groups them within a configurable window (default 500 ms): an API response at T, DOM mutations at T + 20 ms, and a screenshot at T + 100 ms become a single CorrelationBundle.

  3. The dependency engine extracts trackable values from each response (JWTs, UUIDs, hex tokens, high-entropy strings, numeric IDs) and searches for them in subsequent request URLs, auth headers, and bodies β€” emitting a typed edge list.

  4. MCP tools query that bundle store. correlate(query) does forward, reverse, and value-level matching. The LLM does deeper reasoning on top of pre-joined data β€” instead of paginating through raw HAR files.

πŸ“¦ Repository Layout

underpixel/
β”œβ”€β”€ extension/                  Chrome extension (WXT, Manifest V3)
β”‚   β”œβ”€β”€ entrypoints/            background Β· content Β· popup Β· replay Β· offscreen
β”‚   └── lib/
β”‚       β”œβ”€β”€ network/            CDP capture, ref-counted debugger session
β”‚       β”œβ”€β”€ correlation/        timestamp matching, rrweb DOM walker
β”‚       β”œβ”€β”€ screenshot/         2-layer gate + pipeline
β”‚       β”œβ”€β”€ recording/          batched rrweb event persistence
β”‚       β”œβ”€β”€ storage/            IndexedDB schema (idb)
β”‚       └── tools/              MCP tool handlers
β”œβ”€β”€ bridge/                     npm: underpixel-bridge (Fastify + Native Messaging)
β”œβ”€β”€ packages/shared/            shared types, MCP tool schemas, constants
└── docs/                       high-level vision, tech design, feature specs

πŸ› οΈ Development

pnpm install        # from monorepo root
pnpm build          # build shared β†’ bridge β†’ extension
pnpm dev            # WXT dev mode with HMR (extension only)
pnpm test           # vitest across all packages
pnpm lint           # ESLint
pnpm format:check   # Prettier

See CLAUDE.md for non-obvious project conventions (e.g. rrweb runs in the MAIN world content script and is bridged via window.postMessage; response bodies > 100 KB are stored in a separate IndexedDB store).

πŸ—ΊοΈ Roadmap

  • Phase 1 β€” Core MVP: network capture, rrweb integration, correlation engine, 8 MCP tools, basic popup

  • Phase 2 β€” 2-layer screenshot gate, offscreen pixelmatch, replay page (rrweb-player + event-based API timeline), timeline / snapshot_at / replay / dom_text tools

  • Phase 3 β€” Value-propagation dependency graph, .underpixel session export/import (gzipped, with header-masking and body-stripping options)

  • Phase 4 β€” Auto-generated API docs, performance annotations on replay, visual dependency-graph UI (elkjs), advanced filters

  • Phase 5 β€” Edge / Brave / Arc support (Chromium-trivial), Firefox port (browser.devtools.network), browser-API abstraction layer

  • Future β€” Chrome Web Store listing, push-based "Explain this page" once MCP supports serverβ†’client push

πŸ™ Acknowledgments

UnderPixel stands on the shoulders of two excellent MIT-licensed projects:

  • mcp-chrome by @hangwin β€” reference implementation for the Native Messaging bridge, CDP network capture pipeline, screenshot stitching, and Streamable HTTP MCP server. UnderPixel re-implements these patterns rather than depending on the package directly (mcp-chrome is an extension, not a library), but the architectural debt is significant and gratefully acknowledged.

  • rrweb β€” DOM recording and replay. Used directly as an npm dependency. rrweb's smart mutation batching is also what made the screenshot gate simple enough to ship β€” see Design decision #5 for details.

Also leaning on pixelmatch (ISC), @modelcontextprotocol/sdk (MIT), and the WXT extension framework.

πŸ“„ License

MIT β€” same as our upstreams.


A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

–Maintainers
–Response time
–Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

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/Leluth/underpixel'

If you have feedback or need assistance with the MCP directory API, please join our Discord server