paperops

paperops

An observability control plane for Paper's MCP that acts as a passive proxy to meter, attribute, and live-stream every tool call with budgets and a real-time dashboard.

Category
Visit Server

README

paperops

<p align="center"> <img src="assets/og.png" alt="paperops — see everything your agent does in Paper" /> </p>

<p align="center"><code>bunx paperops</code></p>

Observability control plane for Paper's MCP. A pass-through proxy that sits between your MCP clients and Paper's local server, metering, attributing, and live-streaming every tool call. Paper bills per MCP call — and the calls are made by an agent, at a speed you were never meant to watch. paperops is where you watch them.

Features

  • Live tape — every MCP call as it happens: client, tool, the artboard or file it acted on, status, latency, size. Sort it, filter it, slice it by file tabs.
  • Call inspector — click any row: plain-language facts, a latency sparkline against recent calls of the same tool, and the raw request/response one click (and one copy button) away.
  • Budgets — weekly quotas from Paper's real plans (free/pro), per-file and per-client limits, runaway-session alerts. Declarative JSON, hot-reloaded, warn-only.
  • Timelapse — every screenshot your agent takes, as a gallery. Each one names the artboard it is of and the client that took it, in the order they happened.
  • Light and dark — follows your system until you choose; D toggles.
  • Passive by design — zero MCP calls of its own. The meter never spends what it measures.
  • Private by design — payloads and snapshots live in memory only, the on-disk ledger is metadata, the dashboard binds to localhost and makes zero external requests — fonts included.
  • Zero dependencies — one Bun process, one HTML file. bunx paperops and you're watching.

Run

bunx paperops
# paperops · proxy :29980/mcp → http://127.0.0.1:29979/mcp · dashboard http://127.0.0.1:29980/

Requires the Paper desktop app running (it serves the real MCP on 127.0.0.1:29979).

paperops --help lists the flags — --port, --target, --version. From a clone, bun dev starts the same server without the CLI wrapper.

Wire your clients through it

This repo ships a project-scoped .mcp.json: open it with Claude Code and the paperops server is already wired through the proxy — approve it once and every call appears on the tape at http://127.0.0.1:29980/ in real time.

To observe sessions in other projects, point them at the proxy too:

claude mcp add --transport http paperops http://127.0.0.1:29980/mcp

Or copy the .mcp.json entry into that project.

What gets recorded

One JSONL line per call in ~/.paperops/ledger.jsonl:

{"id":267,"ts":"2026-07-28T04:47:14.159Z","session":"8b252f7c-…","client":"claude-code","rpc":"tools/call","tool":"write_html","fileId":"01KYJQ…","fileName":"paperops","nodeId":"T5-0","nodeName":"paperops — calls (light)","status":200,"ms":40.6,"argsBytes":2333,"resultBytes":3563,"error":null}
  • Attribution comes free: the proxy reads clientInfo.name from initialize payloads and tags every subsequent call in that session, and learns artboard names from get_basic_info responses in transit — so a line says who made the call and what it acted on, without either being asked for. Clients already connected when paperops starts show as unknown, because the name only ever travels in initialize — reconnect them and it clears. Restarting paperops itself is safe: it replays the map from the ledger.
  • The 7-day meter counts tools/call requests against your weekly quota — which comes from budgets.json (week, or the plan preset). It survives restarts by replaying the ledger.
  • The ledger is an audit trail: the exact sequence of every call — names, timing, sizes, attribution. Call payloads live in memory only (privacy by design), so sessions can be audited from disk but not re-executed.

Budgets

~/.paperops/budgets.json — declarative limits, hot-reloaded on save:

{
  "plan": "pro",
  "budgets": [
    { "scope": "file", "match": "paperops", "limit": 2000, "note": "design project" },
    { "scope": "client", "match": "claude-code", "limit": 50000 }
  ]
}
  • plan — "free" or "pro"; sets the weekly quota to Paper's official number (100 or 1M calls/week, per paper.design/pricing) and a sensible session alert (50 / 200 — a heavy design session measures ≈100 calls). Defaults to free: the Free user is the one a silent meter hurts most.
  • week / sessionAlert — explicit overrides for the plan-derived values.
  • budgets — one rule per line: scope (file or client), match (exact string — a file name or id, or a client name; no regex/glob), limit (weekly calls), optional note for humans. Matching by file name reads better but detaches if the file is renamed in Paper; ids survive renames.

States: ok → warning at 80% (chrome yellow) → exceeded (red), shown on the header meter, tab counts, and the budgets rail section. v1 warns, never blocks.

Config

Env var Default Meaning
PAPEROPS_PORT 29980 Proxy + dashboard port
PAPEROPS_HOST 127.0.0.1 Listen address. Localhost-only by default — your tape, payloads and frames are your designs. Set explicitly (e.g. 0.0.0.0) to opt into network exposure.
PAPEROPS_TARGET http://127.0.0.1:29979/mcp The real Paper MCP endpoint
PAPEROPS_QUOTA 1000000 Fallback weekly quota, used only when budgets.json sets neither plan nor week. Normally the plan preset governs.

Nothing Paper-specific lives in the proxy path — point PAPEROPS_TARGET at any streamable-HTTP MCP server and it meters that instead.

Known limitation: JSON-RPC batch requests pass through untouched but meter as a single request (no per-call accounting). No supported client sends batches today, and recent MCP revisions removed batching from the protocol.


<img src="assets/dashboard.png" alt="The paperops tape: every MCP call with its client, tool, the artboard it acted on, status, latency and size — with the inspector open on one call, showing its latency against recent calls of the same tool and the raw response" />

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured