Install
$ agentstack add mcp-yyhezkel-lean-chronoscope-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
lean-chronoscope-mcp
A token-efficient browser MCP server. Headless Chrome in Docker, captures everything (console, network, exceptions, IndexedDB, snapshots) into a per-session SQLite store, and exposes 57 tools that query that store — so the model only pays for what it asks for.
Built for Claude Code, Claude Desktop, and any other MCP client. Drop-in alternative to @playwright/mcp and chrome-devtools-mcp, with a sharper focus on tokens-per-task.
[](LICENSE) [](#prerequisites) [](https://modelcontextprotocol.io)
Why?
Other browser MCP servers burn a lot of context: they re-emit the full accessibility tree on every action, list giant network logs, and inline screenshots on navigate. For a multi-step agent task that compounds fast.
This server takes a different shape:
- Capture firehose, query on read. A long-running daemon owns Chrome over CDP and writes every console message, network request, exception, and snapshot to a per-session SQLite + content-addressed blob store. Tools are queries on top — listings return summaries, detail tools fetch bodies.
- Compact, interactive-only snapshot.
[e12] button "Save"style tree — ~2.8× smaller than Playwright's full aria YAML on the same page ([measured](docs/COMPARISON.md)). - Three mount-cost modes.
full(57 tools, ~5.3k tok at mount),slim(5 core tools, ~547 tok), orgateway(3 meta-tools, ~321 tok — the model picks tools on demand and the schemas load only when asked for). - Tools other servers lack: IndexedDB read/write, network interception (abort / continue / respond), 3-mode secret redaction, FTS5 search across console + network history, snapshot diffs.
- Live MCP resources with real
listChangedand per-section change-detect memo —(unchanged since rev N)collapses repeated polling.
Quick start
Prerequisites
- Docker + Docker Compose
- Node 22+ (only if you want to run scripts/tests from the host)
Run the daemon
git clone https://github.com/yyhezkel/lean-chronoscope-mcp.git
cd lean-chronoscope-mcp
# Generate a bearer token for the HTTP bridge:
echo "LEAN_CHRONOSCOPE_HTTP_TOKEN=$(openssl rand -base64 32)" > docker/.env
docker compose -f docker/docker-compose.yml up -d --build
docker exec lean-chronoscope-mcp ls /run/lean-chronoscope/daemon.sock # should exist
curl -s http://127.0.0.1:8780/health # {"ok":true,...}
Register with an MCP client
Claude Code (HTTP transport — recommended):
claude mcp add lean-chronoscope -s user --transport http http://127.0.0.1:8780/mcp \
--header "Authorization: Bearer $(grep LEAN_CHRONOSCOPE_HTTP_TOKEN docker/.env | cut -d= -f2)"
Restart your client session — tool lists load at startup.
stdio (Claude Desktop, etc.):
{
"mcpServers": {
"lean-chronoscope": {
"command": "docker",
"args": ["exec", "-i", "lean-chronoscope-mcp", "node", "/app/dist/bin/mcp.js", "--session", "default"]
}
}
}
Tools appear in your client as mcp__lean-chronoscope__* (or whatever alias you choose). The Docker container is named lean-chronoscope-mcp by default — that's a local name only; rename it via container_name: in docker/docker-compose.yml if you prefer.
Reusing a session across reconnects (HTTP): by default the HTTP bridge mints a fresh browser session per connection. Send an x-lc-session: request header to pin a stable session id — reconnecting with the same header returns to the same daemon session (rehydrated from disk if the earlier disconnect closed it) instead of a new random one. Session ids from callers are validated (no /, \, .., NUL, empty, or >200 chars) to prevent path traversal, since an id becomes a filesystem path.
Tool surface (57 tools)
| Category | Tools | |---|---| | Session | session_list, session_new, session_attach, session_close | | Pages | page_navigate, page_list, page_new, page_select, page_close, page_back, page_forward, page_reload | | Perception | snapshot_take, snapshot_diff, screenshot_take, wait_for | | Input | click, hover, type, fill_form, key, scroll, drag, upload_file | | Console | console_list, console_get, console_search (FTS5) | | Network | network_list, network_get, network_search (FTS5), network_wait_for | | Interception | intercept_add, intercept_list, intercept_remove | | Storage | cookies_*, localStorage_*, sessionStorage_*, indexeddb_* | | Emulation | emulate_viewport, emulate_useragent, emulate_network, emulate_geolocation | | Diagnostics | performance_metrics, daemon_status, script_evaluate |
Mount-cost modes
| Mode | Flag / env | Tools advertised | tools/list payload | |---|---|---|---| | full (default) | — | 57 | ~5,350 tok | | slim | --slim / LEAN_CHRONOSCOPE_SLIM=1 | 5 core | ~547 tok | | gateway | --gateway / LEAN_CHRONOSCOPE_GATEWAY=1 | 3 meta (tools_catalog, tool_schema, tools_invoke) — the 57 stay callable by name | ~321 tok |
Gateway mode advertises a 3-tool index: the model reads tools_catalog, fetches tool_schema only for tools it needs, then calls them via tools_invoke. Useful for MCP clients that don't already defer tool schemas on the client side. Note: Claude Code already defers MCP schemas natively — gateway is mostly useful for other clients or extreme token budgets. See [docs/COMPARISON.md](docs/COMPARISON.md) for the full breakdown.
Architecture
┌─────────────────┐ Unix socket (NDJSON RPC) ┌──────────────────────────────┐
│ mcp-server │ ◀──────────────────────────▶ │ daemon (long-running) │
│ (per session, │ │ ├─ Chrome via CDP │
│ stdio / HTTP) │ │ ├─ per-session SQLite │
└─────────────────┘ │ └─ content-addressed blobs │
▲ └──────────────────────────────┘
│ MCP ▲
│ (stdio or │
│ HTTP+SSE) │ CDP
▼ ▼
MCP client Chromium
The daemon owns the browser and writes the firehose to SQLite. Each MCP client connection spawns a thin per-session mcp-server that talks to the daemon over a Unix socket. Tools are queries on the store; listings return summaries, detail tools fetch bodies, big bodies become content-addressed blobs.
See [docs/IMPLEMENTATION.md](docs/IMPLEMENTATION.md) for the deeper design rationale.
Session lifecycle & retention
Sessions are tracked in a persistent cross-session index, registry.sqlite, at /registry.sqlite (a sessions table: id, createdat, lastactivity, status open/closed, source stdio/http, pagecount, sizebytes, closedat, datadir). It survives daemon restarts and is reconciled at boot (orphaned open rows flip to closed, on-disk session dirs are re-indexed). session_list reports lastActivity, sizeBytes (db+wal+shm+blobs), status, and source, and takes an optional includeClosed to also surface closed sessions from the registry; daemon_status reports the same accounting plus a dbBytes/blobBytes breakdown.
Sessions can carry an optional human title (a column in registry.sqlite, surfaced on session_list). The session_attach tool points a connection at an existing session — by id or by title — and rehydrates a closed session's captured history from disk (the BrowserContext starts fresh; browser state isn't persisted, but all captured console/network/snapshot history is readable). A title that matches nothing starts a new session carrying it (attach-or-create).
A background reaper keeps things bounded automatically:
- Idle / size eviction — frees the browser context + memory (leaving the
on-disk DB for the age sweep) for sessions idle past LEAN_CHRONOSCOPE_IDLE_MS (default 30min) or over LEAN_CHRONOSCOPE_SIZE_CAP_BYTES (default 500MB, 0 disables).
- Row pruning — keeps the newest
LEAN_CHRONOSCOPE_MAX_CONSOLE(50k) console
rows, LEAN_CHRONOSCOPE_MAX_NETWORK (50k) network rows, and LEAN_CHRONOSCOPE_MAX_SNAPSHOTS_PER_PAGE (10) snapshots per page; FTS stays in sync via triggers and freed pages are reclaimed with incremental_vacuum. Prune now also GCs orphaned blob files right after deleting rows — a content-addressed blob (blobs/.bin) is removed only once no surviving row references its sha (dedup-safe), instead of lingering until the age sweep.
- Age sweep — session dirs older than
LEAN_CHRONOSCOPE_RETENTION_DAYS
(default 7) are removed ~hourly (not just at boot) and the registry stays in sync.
Reaper cadence is LEAN_CHRONOSCOPE_REAPER_INTERVAL_MS (default 60000, 0 disables the reaper). Sessions checkpoint (wal_checkpoint(TRUNCATE)) before closing so the persisted db.sqlite is complete and compact.
> Env vars use the LEAN_CHRONOSCOPE_* prefix; the legacy BROWSER_MCP_* names > are still honored as a fallback for backward compatibility.
vs Playwright MCP / Chrome DevTools MCP
| | lean-chronoscope-mcp | @playwright/mcp | chrome-devtools-mcp | |---|---|---|---| | Snapshot format | compact, interactive-only | full aria YAML | aria + extras | | Snapshot cost (HN, ~tok) | ~5,343 | ~14,756 | similar to Playwright | | 5-step task cost (~tok) | ~5.6k | ~24k | similar to Playwright | | Mount overhead | 57 tools, ~5.3k tok (or 321 in gateway) | 20 tools, ~2k | ~30 tools | | IndexedDB tools | ✅ | ❌ | ❌ | | Network interception | ✅ abort / continue / respond | ❌ | ❌ | | Secret redaction | ✅ 3-mode | ❌ | ❌ | | FTS5 search (console / network) | ✅ | ❌ | ❌ | | Persistence | per-session SQLite | in-memory | in-memory |
Full numbers + methodology in [docs/COMPARISON.md](docs/COMPARISON.md). Token estimate = chars/4; the ratio is tokenizer-independent.
Documentation
- [
CLAUDE.md](CLAUDE.md) — guide for working inside the repo (also useful for any agent-driven contribution). - [
docs/IMPLEMENTATION.md](docs/IMPLEMENTATION.md) — full architecture + rationale. - [
docs/SECURITY.md](docs/SECURITY.md) — trust model + redaction options. - [
docs/COMPARISON.md](docs/COMPARISON.md) — measured token comparison vs Playwright MCP. - [
docs/TESTS.md](docs/TESTS.md) + [docs/TOOL_TESTS.md](docs/TOOL_TESTS.md) — what each test covers; per-tool checklist. - [
docs/FOLLOWUPS.md](docs/FOLLOWUPS.md) — known deferrals, deployment notes, MCP-client integration tips. - [
CHANGELOG.md](CHANGELOG.md) — release notes.
Development
pnpm install
pnpm typecheck
pnpm build
docker compose -f docker/docker-compose.yml up -d --build
node scripts/test-all-tools.mjs # 57-tool e2e suite (must pass 57/57)
node scripts/bench-tokens.mjs # measure mount + per-call cost
node scripts/smoke-test-gateway.mjs # gateway-mode smoke
See [CONTRIBUTING.md](CONTRIBUTING.md).
License
[MIT](LICENSE) © Yossi Yehezkel
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: yyhezkel
- Source: yyhezkel/lean-chronoscope-mcp
- License: MIT
- Homepage: https://github.com/yyhezkel/lean-chronoscope-mcp#readme
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.