npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-tape

v0.3.0

Published

Stdio proxy for MCP servers that logs all JSON-RPC traffic to a replayable trace file.

Readme

mcp-tape

Stdio proxy for Model Context Protocol servers. Sits between any MCP client (Claude Code, Cursor, any future host) and any MCP server, forwards JSON-RPC byte-for-byte in both directions, and writes every message to a replayable .jsonl trace file.

Pairs with the mcpreplay.dev renderer to give you time-travel debugging for agent tool calls. The trace format is open — anything can produce or consume it.

Strategic context

mcp-tape (this) and mcp-replay are the free, open-source halves of an MCP-observability product family. The JSONL trace format is deliberately open and stable — anyone can write a producer or consumer; we don't have to be the only ones. Internal strategy + team-product roadmap lives in a private companion document; the Roadmap section below tracks what's shipped and what's planned on the open side.

Install

npm i -g mcp-tape

First stable release is 0.1.0. Plain npm i -g mcp-tape installs @latest. Use -g (not npx) so the wrapped path in your config survives upgrades.

Requires Node.js 20 or newer.

Try it end-to-end (live validation)

The fastest path to "is this useful to me?" is recording and replaying a real Claude Code session in five steps.

1. Install everywhere (one command):

mcp-tape install

This walks every detected MCP client config and wraps every entry in mcpServers. Supported targets, with the file each one lives in:

| Target | Config file | |---|---| | claude-code | ~/.claude.json | | claude-desktop (per-OS — see below) | Windows: %APPDATA%\Claude\claude_desktop_config.json · macOS: ~/Library/Application Support/Claude/claude_desktop_config.json · Linux: ~/.config/Claude/claude_desktop_config.json | | antigravity (Google Antigravity IDE) | ~/.gemini/antigravity/mcp_config.json | | gemini-cli (Google Gemini CLI) | ~/.gemini/settings.json |

Pre-1.0 mcp-tape installs on Linux wrote to ~/.config/claude/ (lowercase). install and uninstall still detect that path if it exists, so older configs aren't orphaned by the upgrade.

install auto-discovers whichever of these files already exist on disk. Your config is backed up to <file>.mcp-tape.bak before any change. The command is idempotent — running it again is a no-op unless the binary path changes (after an upgrade). Add --dry-run to preview, --target=antigravity,gemini-cli to scope to specific clients, --force to refresh the backup with the current state.

On Windows, ~ is C:\Users\<you>mcp-tape install resolves it natively, no path adjustment needed. Antigravity / Gemini CLI write their MCP config lazily, so if you haven't added a server through their UI yet, the file may not exist and that target will simply be skipped.

2. Restart your MCP client (Claude Code / Claude Desktop). The wrapped servers will be invoked through mcp-tape instead of directly.

3. Use the client normally. Every MCP server you talk to writes a JSONL trace to ./mcp-traces/ (relative to wherever the server's working dir is). One file per session per server, named like 2026-05-13T15-30-00-000Z-<label>.jsonl.

4. Open a trace: go to mcpreplay.dev, click Open local trace… and pick the .jsonl file. (Or drag-and-drop it onto the page.) The trace never leaves your browser. Drag multiple .jsonl files at once to merge sessions across servers (e.g. robot-md-gateway + robot-md-mcp interleaved by timestamp).

5. Share a trace: send the .jsonl file to a collaborator. They drag it into mcpreplay.dev. Done — no public URL, no server staging.

When to consider Tier 1 validated: you've recorded ≥3 real multi-hour sessions, shared at least one trace with a collaborator, and neither of you had to hand-edit ~/.claude.json or hand-scrub secrets. When that lands, the daily-driver loop works.

Roll back when done:

mcp-tape uninstall

Per-entry, in place. Any unwrapped entries you added manually after install are preserved. The .mcp-tape.bak is removed after a successful restore.

Usage (single server, no auto-install)

If you don't want to wrap your whole config — for one-off experiments or non-Claude clients — call mcp-tape directly with -- separating its flags from the server command:

mcp-tape -- npx -y @modelcontextprotocol/server-filesystem /home/me
mcp-tape --out ~/.mcp-traces --label fs -- node my-server.js

The proxy is transparent — JSON-RPC traffic is forwarded byte-for-byte. The trace file is the only side-effect.

Long sessions: rotation + size caps

Trace files rotate when they exceed --max-bytes (default 50 MB). The newest is <name>.jsonl, then .1, .2, … up to --max-files (default 4). Oldest is evicted. A multi-hour session caps at roughly 200 MB total.

mcp-tape --max-bytes 104857600 --max-files 8 -- node my-server.js   # 100 MB × 8

Env vars MCP_TAPE_MAX_BYTES and MCP_TAPE_MAX_FILES work the same way; the CLI flag overrides the env var. To merge rotated files in the viewer, drag the active file plus its .1/.2/… companions onto mcpreplay.dev together.

Live mode (Tier 2)

Stream a session to mcpreplay.dev while it's still running:

mcp-tape --serve -- npx -y @modelcontextprotocol/server-filesystem /home/me

This starts a localhost websocket on port 7777 (override with --serve 9001 or MCP_TAPE_SERVE=9001). In POSIX shells the -- separates mcp-tape's flags from the server command; PowerShell's native-command shim strips -- from argv, so on Windows you can drop it (mcp-tape --serve npx -y …) — mcp-tape will see the bare npx and start the wrapped command from there.

Open the URL printed on stderr:

mcp-tape: live mode on ws://127.0.0.1:7777/  (open https://mcpreplay.dev/?live=ws://127.0.0.1:7777)

If the requested port is already in use — a previous Claude session that didn't shut down cleanly, another wrapped server holding it — mcp-tape scans a small range above the requested port and then asks the OS for any free port. The stderr line tells you which port it actually bound:

mcp-tape: port 7777 was unavailable — bound 7778 instead
mcp-tape: live mode on ws://127.0.0.1:7778/  (open https://mcpreplay.dev/?live=ws://127.0.0.1:7778)

New subscribers get a snapshot of everything-so-far on connect, then live appends as each frame is written. Reconnect-resume is automatic via ?since=<lastSeq> so a flaky network or refreshed browser tab doesn't lose frames.

The websocket is bound to 127.0.0.1 only — there is no auth, no TLS, and no remote-access path. mcp-replay refuses to connect to any host other than localhost / 127.0.0.1.

--no-file: serve-only mode

For short debug sessions where you don't want a .jsonl file to clean up afterwards, add --no-file:

mcp-tape --serve --no-file -- node my-server.js

This streams every frame to the websocket but writes nothing to disk. --no-file requires --serve. If the websocket fails to bind entirely (extremely rare), mcp-tape automatically reverts to writing a .jsonl so the session isn't silently lost.

Full live-mode walkthrough lives in the renderer repo at mcp-replay/docs/live-mode.md.

Secret redaction

mcp-tape redacts common secret shapes from the logged trace by default. It does not alter messages forwarded between client and server. Even with redaction on, treat traces as sensitive — no regex is exhaustive.

Default field-name redaction (case-insensitive substring match on the JSON key): password, secret, token, apiKey / api_key, authorization, bearer, privateKey / private_key, accessKey / access_key.

Default value patterns:

  • AWS access key id (AKIA…)
  • sk-* API keys (OpenAI/Anthropic shape)
  • GitHub tokens (ghp_, gho_, ghu_, ghs_, ghr_)
  • JWTs (three base64url segments separated by .)
  • Authorization: / Bearer … header values appearing in any string
  • File paths matching id_rsa, id_ed25519, id_ecdsa, id_dsa, or .env*

Inspect or add to these:

mcp-tape --redact-defaults                                # print the built-in list
mcp-tape --redact 'MYCO_[A-Z0-9]{20}' -- node my-server.js
mcp-tape --no-redact-defaults --redact '...' -- node my-server.js

Custom redaction config

For project-specific rules — especially nested fields — create ~/.config/mcp-tape/redact.json:

{
  "extends": "default",
  "rules": [
    { "type": "path", "path": "$.params.arguments.api_key" },
    { "type": "path", "path": "$..customer_id" },
    { "type": "regex", "pattern": "MYCO-[A-Z0-9]{20}" }
  ]
}

The file is auto-loaded at startup. extends: "default" merges with built-in rules; set it to null to replace them entirely. Path rules use a JSONPath subset ($, .field, [i], [*], ..field). Override the path with --redact-file PATH or env MCP_TAPE_REDACT.

Trace format

One JSON object per line. First line is a meta header, last line is an end marker, everything in between is one protocol message per line.

{"v":1,"type":"meta","startedAt":"2026-05-12T23:00:00.000Z","label":"fs","command":["npx","-y","@modelcontextprotocol/server-filesystem","/home/me"],"mcpTapVersion":"0.1.0"}
{"t":"2026-05-12T23:00:00.123Z","dir":"in","raw":{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}}
{"t":"2026-05-12T23:00:00.245Z","dir":"out","raw":{"jsonrpc":"2.0","id":1,"result":{}}}
{"t":"2026-05-12T23:00:30.000Z","type":"end","exitCode":0,"durationMs":30000}
  • dir: "in" — client → server (data the proxy received on stdin)
  • dir: "out" — server → client (data the proxy received from the server's stdout)
  • raw — verbatim JSON-RPC message, post-redaction
  • t — ISO-8601 with millisecond precision

The full spec lives at mcpreplay.dev/docs/format.

Roadmap

Shipped (v0.2.0):

  • PlatAtlas upload — mcp-tape login --subdomain <slug> runs a GitHub device-flow auth against PlatAtlas, mcp-tape upload <file> posts a trace to <subdomain>.platatlas.com/api/traces, and --upload-on-exit auto-uploads the final trace after the wrapped server exits. Session stored XDG-style at ~/.config/mcp-tape/session.json.

Shipped (v0.3.0):

  • mcp-tape upload --public and --upload-on-exit --public flag the uploaded trace as world-readable by UUID. The CLI echoes a ready-to-paste mcpreplay.dev/?trace=… URL so you can hand the link to anyone with the UUID. Private remains the default. See --help for the full caveat.

Shipped (v0.1.0 — stable):

  • Stdio proxy + JSONL trace + signal forwarding
  • install / uninstall subcommands for Claude Code, Claude Desktop, Antigravity, and Gemini CLI configs (per-OS path resolution for Claude Desktop)
  • Trace rotation with --max-bytes / --max-files (and MCP_TAPE_MAX_* env vars)
  • File-based redaction config at ~/.config/mcp-tape/redact.json with JSONPath + regex rules, layered on the legacy defaults
  • Live mode — mcp-tape --serve <port> exposes a localhost websocket with snapshot + append + reconnect-resume; renderer connects via ?live=ws://127.0.0.1:7777. Port-conflict fallback if 7777 is busy. --no-file for serve-only sessions.
  • In-trace search by tool-call name + argument pattern (in the renderer)
  • Trace diff view in the renderer (mcpreplay.dev/?diff=a.jsonl;b.jsonl)

Planned:

  • HTTP / SSE transport (currently stdio-only)
  • Frame drop-count surfaced to subscribers when the broadcaster's ring buffer evicts

License

MIT