Build

AI Agent MCP Receipts: Your Logs Aren't Proof

June 29, 20265 min readAI agents · MCP · verifiable receipts · cryptography · agent security
The takeaway

An AI agent's logs are self-reported claims. A verifiable receipt is independent, signed, tamper-evident proof of what an MCP tool call actually did — checkable by anyone with a public key, no trust in the agent. We built the smallest runnable version and mapped the field.

The short version. An AI agent's logs are self-reported claims — it can rewrite them after the fact, or log a tool call that never happened. A verifiable receipt is the opposite: independent, cryptographic evidence of what an action consumed and produced, that anyone can check without trusting the agent. We built the smallest runnable version, then took it where it matters most for us — agent memory: receipts make a memory store's write-history tamper-evident, so an out-of-band edit to what your agent "remembers" is caught. Below: how it works, where we think it's most useful, the honest limits, and who's building this for real.

Why an agent's log isn't evidence

When an AI agent calls a tool over MCP — a database, a web search, a payment — what proof do you have of what actually happened? Usually a log line the agent wrote itself. That is a claim, not evidence: the agent (or a compromised proxy in the middle) can edit the log afterward, drop an embarrassing entry, or emit a confident "I queried the API and it returned X" for a call it never made. For a system that is most confident exactly when it is least grounded, a self-reported log is the weakest possible audit trail.

What a receipt is — and how it differs from a log

A receipt commits, at the moment of the action, to the SHA-256 hash of the inputs and of the output, plus the tool name, a timestamp, and a link to the previous receipt. Two properties follow:

Two layers: a hash chain, then a signature

  1. 1. Hash chain — integrity. Each receipt's prev field is the hash of the one before it, forming a chain. Edit any past receipt and the hashes after it break, so a partial edit is detectable and you can name the step that changed — no cryptography library needed. (Honest limit: the chain alone doesn't stop a thorough tamperer who recomputes it end-to-end; that's what the signature — or anchoring the head externally — is for.)
  2. 2. Ed25519 signature — authenticity. Each receipt's hash is signed with the actor's private key; verifiers check it with the public key. This proves who produced the receipt and that nothing was forged. Full zero-knowledge proofs (ZK-SNARKs) go further — proving a computation was correct while revealing nothing — and are the heavy end of this same design space.

We built the smallest runnable version — and measured it

agent-receipts is a single readable file. Its self-demo records three MCP tool calls, then attacks the trail. The results, run as published:

stepwhat we didverify() result
1an honest receipt chainTrue
2edited a past receipt's outputcaughtcontent tampered at the exact step
3re-hashed the forged receipt to look internally consistentstill caughtinvalid signature (made by the real key over the original hash) + broken chain link downstream

A self-reported log fails all three silently: edited end-to-end, it looks identical afterward. That gap — detectable tampering and third-party authenticity — is the whole point.

For MCP specifically, you don't change your tools: you wrap the dispatch. A ReceiptedDispatcher records one signed receipt per tool call, so afterwards anyone can confirm exactly which tools ran, with which argument and result hashes, in which order.

Our angle: tamper-evident memory

Receipts get most interesting where we already work — agent memory. Our open-source memory core, inspeximus, is already append-only, but the store is still a file: anyone who can touch it can rewrite a stored memory after the fact, and the agent would then recall the altered text as if it were the original. Wiring receipts in changes that — every remember() emits a signed receipt committing to the memory's content hash, so the write history becomes independently verifiable.

Measured: an honest store audits clean; an out-of-band edit (db-prod-01 → db-attacker-07, made straight in the store) is caught and named by memory id. That is tamper-evident memory — a property the broader landscape mostly applies to tool calls, not to the memory layer itself. It is the part of this we intend to keep building.

The honest limits

This is a reference proof-of-concept, and the honest scope matters more than the demo:

The landscape — who's building this

FAQ

What is a verifiable receipt for an AI agent? Cryptographic evidence — committing to the input/output hashes of an action, hash-chained and signed — that lets a third party confirm what an agent's tool call actually did, without trusting the agent's own logs.

How is a receipt different from a log? A log is self-reported and editable; a receipt is tamper-evident (hash chain) and authentic (signature), so altering it after the fact is detectable by anyone with the public key.

Do verifiable agent receipts need a blockchain? No. A hash chain plus an Ed25519 signature gives tamper-evidence and third-party verification on their own. Anchoring the chain head on-chain (as some products do) is an optional extra, not a requirement.

Does this work with MCP tool calls? Yes — wrap the tool dispatch so each call emits a receipt. The input arguments and result are committed by hash, the call is signed, and the chain orders them.

Can I actually run it? Yes — it's a single file; the hash chain works with no dependencies, signatures need the cryptography package.

The honest take. If a plain signed log already gives you everything you need, receipts are overkill — their specific value is third-party-verifiable tamper-evidence without trusting the agent. The day an agent's logs become load-bearing for billing, compliance, or safety, that gap stops being academic.

← More writing from Agora