* feat(record): capture MCP call streams to NDJSON and replay deterministically mcporter record <session> wraps the runtime transport and appends every JSON-RPC request, response, and notification to a per-session NDJSON file under ~/.mcporter/recordings/. mcporter replay <session> reconstructs an in-memory transport from the recording and matches requests by method + deep-equal params, returning the recorded response without contacting the live server. Use cases: - Reproduce MCP-backed agent bugs offline (no live Linear quota, no Vercel API rate limits) - Build test fixtures from real call sequences - Share a session for a postmortem without sharing credentials The format is plain JSON-RPC over NDJSON with a small _meta field (direction, server, timestamp). No proprietary blob. Env-var passthrough (MCPORTER_RECORD=<name>, MCPORTER_REPLAY=<name>) lets the existing runtime constructor wrap any transport when set. * fix(replay): attach cause to wrapped errors to satisfy preserve-caught-error lint * fix(replay): rewrite response ids during replay * fix(replay): harden record replay modes Clear conflicting record/replay env vars when spawning wrapped commands, force those commands off the daemon fast path, truncate each recording file at session start, and fail replay close when recorded requests remain unused. * fix(cli): preserve wrapped command flags Stop global flag extraction at -- so record/replay wrappers do not consume child command flags, and drop the release-owned changelog entry from the PR diff. * fix(replay): propagate cleanup failures through cli Ensure replay-mode transport close failures escape normal runtime and CLI cleanup after best-effort shutdown has completed. Add runtime and CLI regressions for partial recordings that leave requests unreplayed. * fix: harden record replay runtime paths * test: align replay fixtures with windows home --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
2.6 KiB
| summary | read_when | |
|---|---|---|
| How to record MCP JSON-RPC traffic to NDJSON and replay it deterministically for offline debugging. |
|
Record and replay MCP calls
mcporter record captures the JSON-RPC traffic between the runtime and configured MCP servers. mcporter replay reads the captured stream and serves the recorded responses back to the same requests without contacting the live MCP server.
Recordings live under ~/.mcporter/recordings/ as newline-delimited JSON:
mcporter record demo-session -- mcporter call linear.list_issues limit:5
mcporter replay demo-session -- mcporter call linear.list_issues limit:5
Recordings contain raw JSON-RPC params and responses. Review and redact them before sharing, attaching to bug reports, or committing them to a repository because tool arguments and results can include credentials, private content, or customer data.
To record or replay a later command, create the session configuration and export the matching environment variable:
mcporter record demo-session
MCPORTER_RECORD=demo-session mcporter call linear.list_issues limit:5
mcporter replay demo-session
MCPORTER_REPLAY=demo-session mcporter call linear.list_issues limit:5
Use --server when you only want one server's traffic:
mcporter record demo-session --server linear -- mcporter call linear.list_issues limit:5
mcporter replay demo-session --server linear -- mcporter call linear.list_issues limit:5
File format
Each line is one JSON-RPC envelope with an added _meta object:
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_issues","arguments":{"limit":5}},"_meta":{"dir":"send","server":"linear","ts":"2026-05-16T12:00:00.000Z"}}
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"..."}]},"_meta":{"dir":"recv","server":"linear","ts":"2026-05-16T12:00:00.100Z"}}
_meta.dir is send, recv, or lifecycle. Replay strips _meta before delivering a response. Lifecycle events such as transport start and close are recorded for diagnostics but ignored during replay.
Deterministic matching
Replay is strict. For each server, mcporter expects requests to arrive in the same order with the same JSON-RPC method and deeply equal params. If the next request differs, replay fails with an error that names the incoming request and the next recorded request it expected.
This makes recordings useful as reproducible bug fixtures: a replay either follows the captured MCP exchange exactly or fails at the first point where the workflow diverges.