shadowmark-mcp
v2.0.0-alpha.5
Published
MCP server for Shadowmark — screen recording + annotations bridge for AI agents (SQLite-backed, dual stdio/HTTP-SSE transport)
Maintainers
Readme
🎯 shadowmark-mcp
Give your AI agent eyes, console, network & DOM — straight from the browser.
Record any web session locally; your agent reads the screen frames, console errors, network traffic, storage and DOM snapshots through MCP. No screenshots. No copy-paste. No cloud.
Quick start • Connect & record • MCP tools • HTTP API • Privacy
Turn any browser session into rich, actionable context for AI agents — local-first, MCP-native.
shadowmark-mcp is the local server half of Shadowmark. It captures what the user records in the Chrome extension — screen frames, console errors, network traffic, storage state, and DOM snapshots — into a local SQLite database, then exposes it to Claude Code / Cursor / any MCP client through 12 well-designed tools.
┌─────────────────────────────────────────────────────────────────────┐
│ Chrome Extension HTTP MCP (stdio/SSE) │
│ ───────────────── ─────────────► shadowmark-mcp ◄─────────────── Claude Code │
│ • Frame capture (2 FPS JPEG) :3141 │
│ • Console / network via CDP SQLite + JPEGs │
│ • Annotations + DOM snapshots ~/.shadowmark/ │
│ • localStorage / sessionStorage │
└─────────────────────────────────────────────────────────────────────┘All data stays on the user's machine. The server never opens an outbound connection. Sensitive headers (Authorization, Cookie, x-api-key) are auto-redacted before storage.
Why this matters — productivity in numbers
Based on the typical bug-reporting workflow when working with an AI coding agent:
| Step | Manual workflow (today) | With Shadowmark | Speedup | |---|---|---|---| | Take screenshot of the issue | 10 s | auto (every 500ms) | — | | Copy console error → paste | 20 s | auto | — | | Find related network request, copy headers + body | 60 s | auto | — | | Type selector / framework info | 60 s | auto via DOM snapshot | — | | Write description, paste into Claude | 30 s | "what's in my latest recording" | — | | Total per bug context | ~3 minutes | ~15 seconds | ~12× |
| Dimension | Manual | Shadowmark | Δ | |---|---|---|---| | Context density | ~2 KB (selector + note + 1 error line) | ~50–200 KB structured (frames, full HTML, full network trace) | 25–100× richer | | Iteration speed (bug → fix attempt) | 3–5 min round-trip | ~30 s | ~6–10× | | Frames captured per minute of session | 0–2 manual screenshots | 120 (2 FPS) | 60–120× | | Network capture | manual copy of 1–2 requests | every request + response body (≤100 KB each) | 30×+ |
For a developer who logs 5 AI-assisted debugging cycles per day:
- ~12 minutes saved per session × 5 sessions = 60 minutes saved per day.
- Across a 5-day work week that's ~5 hours of pure context-gathering reclaimed.
- Across a year, ~250 hours — roughly 6 working weeks.
These are estimates from typical workflows, not benchmarked claims. Your mileage depends on how often you hand context to an AI agent and how thoroughly you describe it today.
Client-side context — what gets captured
Per recording, Shadowmark captures and structures the following on the user's local machine:
~/.shadowmark/shadowmark.db (SQLite WAL)
├── recordings session metadata
├── frames 1 row per JPEG, with trigger reason
├── annotations ← dom_snapshot column user notes + serialized DOM
├── console_logs every console.* call + uncaught exceptions
├── network_requests ← body columns method/url/status/headers + req/res bodies
└── storage_snapshots localStorage + sessionStorage start & end
~/.shadowmark/recordings/<id>/frames/*.jpg raw screen frames at 1920×1080| Source | Captured via | Cap | Notes |
|---|---|---|---|
| Screen frame | chrome.tabCapture + canvas → JPEG q=82 | 2 FPS · ~140 KB/frame | Auto-stop at 60 s |
| Console + uncaught errors | CDP Runtime.consoleAPICalled + Runtime.exceptionThrown | unbounded rows, 4 KB / message | Levels: log/info/warn/error/debug |
| Network request | CDP Network.requestWillBeSent | unbounded rows | Headers redacted |
| Network response | CDP Network.responseReceived + Network.loadingFinished → Network.getResponseBody | 100 KB / body, text-only | Binary (images/fonts) skipped |
| Storage | chrome.scripting.executeScript snapshot of window.localStorage + sessionStorage | start + end of recording | 4 KB per key |
| DOM snapshot | content script — target outerHTML, ancestor chain, surrounding HTML | 100 KB total per annotation | Captured only when the user annotates during recording |
| Annotation note | user types into the toolbar | 4 KB plain text | Linked to a specific frame |
Every row links back to its recording_id, so the MCP tools can join across sources to build a merged timeline.
Which Chrome extension to use
shadowmark-mcp is the server. It does nothing without the companion Shadowmark Chrome extension.
| Component | Where | Distribution |
|---|---|---|
| Chrome extension | shadowmark.in | Chrome Web Store |
| MCP server (this package) | npm: shadowmark-mcp | This README |
Install the extension
Add it from the Chrome Web Store, or click Add to Chrome on shadowmark.in. That's the whole install — no cloning, no developer mode.
Quick start
1. Install + auto-configure
npm install -g shadowmark-mcp
shadowmark-mcp install # writes the MCP entry to Claude Desktop AND Claude Code configThe install command auto-detects which Claude clients you have and registers shadowmark in their MCP config. It's idempotent — safe to re-run.
2. Restart your Claude client
- Claude Code: exit the CLI and relaunch from the directory you want to work in.
- Claude Desktop: quit + reopen the app.
Connect & record (the full flow)
npm i -g shadowmark-mcp
│
▼
connect to Claude Code ──┐
(auto via stdio, or │ server reachable on :3141
SSE — see below) ├─────────────────────────────► extension shows ● Record
│ │ (a Claude Code session OR
run a recording │ `shadowmark-mcp --http`)
│
▼
"what's in my latest Shadowmark recording? suggest a fix."
│
▼
agent calls shadowmark_get_context → sees frames + console + network + DOM → edits the codeTwo roles, often one process
| Role | Who serves it |
|---|---|
| MCP reads — Claude sees your recordings | stdio: Claude Code / Claude Desktop spawn it automatically |
| Recording ingest — the extension saves frames/console/network to :3141 | the --http listener (see below) |
As of v2.0.0-alpha.3, the stdio server also opens the ingest listener on 127.0.0.1:3141 automatically while your Claude Code session is open — so recording "just works" with no extra step. The extension's Record button only appears when it can reach :3141; if it's hidden, either open a Claude Code session or start the standalone daemon.
A. Connect to Claude Code
Stdio (simplest — Claude Code launches the server):
shadowmark-mcp install # writes the config for you
# or, manually:
claude mcp add shadowmark -s user -- shadowmark-mcp --stdioSSE (one daemon serves both the extension and Claude Code):
shadowmark-mcp --http # keep running (own terminal / background)
claude mcp add shadowmark -s user --transport sse http://127.0.0.1:3141/mcpVerify with claude mcp list, then start a new Claude Code session.
B. Record + ask
- Open any
http(s)site in Chrome. - When the Shadowmark toolbar shows ● Record (server reachable), click it.
- Reproduce the issue. Optionally click elements to drop annotations — the agent gets the exact DOM for those moments. Recording auto-stops at 60 s.
- Stop (or let it auto-stop).
- In Claude Code / Claude Desktop, ask:
"What's in my latest Shadowmark recording? Suggest a fix."
Claude calls shadowmark_get_context → sees the merged timeline + key frames → reads your annotation's DOM snapshot → proposes a specific edit.
Want recording without a terminal at all?
Run it once as a background daemon so :3141 is always up:
shadowmark-mcp --http(A future release will let the extension launch the helper itself via Native Messaging — no daemon, no terminal.)
MCP tools
| Tool | Purpose |
|---|---|
| shadowmark_list_recordings | List recent recordings with ids, timestamps, frame counts |
| shadowmark_get_context | Start here — merged timeline + 4 key frames inline as images |
| shadowmark_get_annotations | User-flagged moments with frame_id + optional DOM snapshot |
| shadowmark_get_frames | Up to 8 frames inline; filter by trigger or center on a timestamp |
| shadowmark_get_console_logs | Console output (filter by level) |
| shadowmark_get_network_requests | HTTP traffic; failed_only, url_contains, include_bodies filters |
| shadowmark_get_storage | localStorage + sessionStorage snapshots |
Plus the preserved v1 annotation-task tools: get_pending_tasks, get_task, complete_task, get_page_context, clear_all_tasks.
MCP prompt
shadowmark-workflow— one-time prompt that teaches the agent how to interpret recordings and act on them. Invoke once at the start of a session for the most useful behavior.
HTTP API
The server exposes a local-only HTTP API on 127.0.0.1:3141:
| Endpoint | Method | Purpose |
|---|---|---|
| /health | GET | Liveness check (used by the Chrome extension) |
| /ingest/start | POST | Begin a recording |
| /ingest/frame | POST | Send one JPEG frame (base64) |
| /ingest/console | POST | Log a console event |
| /ingest/network | POST | Insert or upsert a network request |
| /ingest/storage | POST | Snapshot localStorage / sessionStorage |
| /ingest/annotation | POST | Save a mid-recording annotation + DOM snapshot |
| /ingest/finalize | POST | Mark the recording complete |
| /tasks | GET/POST/DELETE | Annotation-task queue (v1 surface, preserved) |
| /recordings | GET | List recordings |
| /recordings/:id | GET / DELETE | Detail or cascading delete |
| /recordings/:id/player | GET | Standalone HTML slideshow viewer |
| /recordings/:id/frames/:ts.jpg | GET | Serve a single frame |
| /recordings/:id/events.json | GET | Player data payload |
| /mcp | GET (SSE) | MCP transport for HTTP clients |
| /mcp/messages?sessionId=… | POST | MCP JSON-RPC body for SSE clients |
Configuration
| Env var | Default | Effect |
|---|---|---|
| SHADOWMARK_DB_PATH | ~/.shadowmark/shadowmark.db | Override SQLite location |
| SHADOWMARK_RECORDINGS_DIR | ~/.shadowmark/recordings/ | Override frame storage location |
| SHADOWMARK_STORE_PATH | ~/.shadowmark/tasks.json | Override annotation-task queue file. Pass none to disable persistence (tests use this). |
| SHADOWMARK_MCP_CONFIG_PATH | (auto-detected) | Override target for install subcommand (testing only). |
Privacy & security
- Local-only. The server binds to
127.0.0.1and makes no outbound calls. - Header redaction.
Authorization,Cookie,Set-Cookie,X-Api-Key,X-Auth-Token,X-Token,X-Sessionare replaced with[REDACTED]before storage. - Body capture is text-only. Binary content (images/fonts/video) is skipped — the agent can't use raw bytes anyway, and they would inflate storage.
- Size-bounded. Per-body cap 100 KB. Frame cap 60 s. Disk usage is finite per recording.
- User-controlled deletion. The extension popup has a delete button per recording. Server cascades the DB rows and removes the JPEGs from disk.
How it differs from session-replay tools
| | LogRocket / Replay.io / Sentry Session Replay | Shadowmark |
|---|---|---|
| Where data lives | Vendor cloud | User's machine (~/.shadowmark/) |
| Captured for | Product analytics, ops triage | AI-assisted development |
| Format | Proprietary playback in vendor UI | SQLite + JPEGs (open) + MCP tools |
| Per-event price | Yes (tens to thousands per month) | Free |
| Works for AI agents | No native integration | Built for it (12 MCP tools, single workflow prompt) |
| Network body capture | Optional, paid tier | On by default, 100 KB cap, text-only |
| DOM context for AI | None | Per-annotation snapshot with ancestor chain |
| Frame format | WebRTC video / DOM replay | Per-second JPEGs (model-vision friendly) |
Shadowmark is intentionally narrow: it builds context for AI agents, not for humans watching playback. The player UI exists so you can review your own sessions, but the primary consumer is your agent.
Development
git clone https://github.com/Shrikant-satpute/shadowmark-mcp
cd shadowmark-mcp
npm install
npm run build # clears dist/ and compiles
npm test # 25 tests
npm start # boot the HTTP server locallyTo regenerate the install CLI behavior:
SHADOWMARK_MCP_CONFIG_PATH=/tmp/test-mcp.json npm run start -- install --dry-runTo smoke-test the M3 tools against your real database:
node scripts/m3-smoke.mjs # uses the latest recording
node scripts/m3-smoke.mjs <recording_id> # specific oneRoadmap
- [x] Chrome Web Store listing live — shadowmark.in (v1.2.0 recording update in review)
- [ ] Cookie + IndexedDB capture (beyond localStorage)
- [ ] WebSocket frame capture
- [ ] Voice annotations via Web Speech API
- [ ] Source-map-aware stack traces
- [ ] Frame deduplication / skip-if-unchanged
- [ ] Cloud-sync option (opt-in)
- [ ] Team workspaces
Issues & feature requests: file at the GitHub repo.
License
MIT — see LICENSE.
Contact
Built by shrikant-satpute.
