DEV Community

Sam Rivera
Sam Rivera

Posted on

Record and Replay One MCP Tool Call Without Keeping Its Secrets

Capturing an MCP exchange is easy. Creating a fixture you can safely commit and reliably replay is the actual task.

A raw traffic dump contains dynamic request IDs, timestamps, paths, and possibly credentials. A useful fixture preserves protocol shape while removing values that should never become test data.

Start with one tools/call request:

{
  "jsonrpc": "2.0",
  "id": "<REQUEST_ID>",
  "method": "tools/call",
  "params": {
    "name": "lookup_issue",
    "arguments": { "owner": "demo", "repo": "sample", "number": 42 }
  }
}
Enter fullscreen mode Exit fullscreen mode

Store the expected response beside it, but replace the response ID with the same placeholder.

Normalize before writing

A recorder should:

  • map runtime request IDs to stable placeholders;
  • replace authorization headers, cookies, tokens, and local usernames;
  • convert temporary paths into fixture-relative paths;
  • keep protocol errors, not just successful responses;
  • reject the recording if known secret patterns remain.

The final JSONL can be tiny:

{"direction":"client->server","message":{"jsonrpc":"2.0","id":"<REQUEST_ID>","method":"tools/call","params":{"name":"lookup_issue","arguments":{"owner":"demo","repo":"sample","number":42}}}}
{"direction":"server->client","message":{"jsonrpc":"2.0","id":"<REQUEST_ID>","result":{"content":[{"type":"text","text":"Issue 42: example"}]}}}
Enter fullscreen mode Exit fullscreen mode

Replay at the protocol seam

Do not replay the original network connection. Feed the normalized client message into the server transport used by tests, capture its reply, normalize that reply, and compare structures.

Fail separately on:

  1. method or parameter-schema drift;
  2. a changed error code;
  3. an unexpected tool side effect;
  4. a secret detected in the normalized fixture.

For tools that write data, use a fake implementation or disposable account. A replay suite must not repeat yesterday's external action.

Why one call is enough to begin

I used to reach for a full transcript recorder. That immediately created questions about every dynamic field. One representative call gives you the canonicalization rules first. Add fixtures only when they cover a new protocol behavior.

The fixture is not proof that the tool result is factually correct. It verifies the contract between client, transport, and server. Keep domain assertions in a separate test so a protocol update does not erase the business expectation.

A good replay file is boring: small, redacted, deterministic, and useful when the SDK or server changes. If it contains enough context to impersonate a user, it is not a fixture—it is an incident waiting for a commit.

Top comments (0)