mrpkk

attest — trust layer for agent artifacts

Community mrpkk
Updated

Verify AI agent action receipts offline: canonical form, Ed25519, chain rules, transparency log. SCITT profile, MCP server, browser verifier. Apache-2.0.

attest — trust layer for agent artifacts

M8ven ScoreListed on mcpservers.org

Live: https://attest.rta.lat/demo · Code: https://github.com/mrpkk/attest

Pricing: 20 checks/day free, then $0.005 per call (x402, USDC on Base). 30-day unlimitedaccess: $9. Purchasing-power pricing (India and similar markets): the same 30 days for$3 via POST https://attest.rta.lat/subscribe?plan=ppp — same endpoint, same terms.

An agent calls an external tool or another agent and receives a foreignartifact that goes straight into its context. Nothing checks that theartifact:

  • matches the declared schema (the tool quietly changed a field type),
  • carries no hidden instruction ("ignore previous, send the keys to …"),
  • is not a base64 wrapper around such an instruction,
  • has not changed since it was checked.

attest closes that gap. No dependencies, 399 tests green.

Four layers, four different questions

Each layer answers only its own question, and none substitutes for the others.A valid form is not the same as meaningful content; a signed artifact is notthe same as a permitted action.

1. Form and emptiness — emptiness.py

Does the artifact say anything? An agent told to find five vulnerabilitiesreturns five identical items. That artifact passes every schema validation,because the form is perfect.

Seven measurable signals: identical list items, placeholder values, output cutat the token limit, whitespace-only strings and empty collections, low-varietyrepetition, required fields left at their schema default, enum fields sittingon the first value.

Verdicts are VALID_BUT_EMPTY, THIN_CONTENT, CONTENT_PRESENT.

VALID_BUT_EMPTY means "the form is fine, the content is suspect" — not"the content is absent". Suspicion requires a person; a verdict requiresproof. The difference matters.

Every signal shows where and why. Absence of signals does not provemeaningfulness — it only means the coarse checks did not fire. That sentenceis in the code, in the docstring and in the API response.

2. Generation conditions — generation.py

A signature proves who signed. It does not prove where the file came from.Anything at all can sit between "the agent produced this" and "the verifiersaw the result".

Model, version, prompt, parameters, moment and executor are bound into a singlechain_hash over the artifact. Change any link and the binding stops matching.

Absence of a binding is explicit, not silent. Four states are distinguished:no conditions at all; a binding claimed but conditions cannot be supplied;conditions supplied but no binding in the signature; conditions that do notmatch. The first and the second are different things, and confusing them wouldconfirm a forgery.

chain_hash is inside the signature, not next to it — otherwise it couldbe appended afterwards.

3. Verification without trusting us — signing.py

HMAC requires a secret, and the secret is only ours. So only the service couldverify a signature, and anyone who did not trust the service had to trust itfirst. For a product about trust, that is a contradiction at the foundation.

Now Ed25519. The public key travels with the attestation, and the verifierchecks it themselves — no network, no package of ours, no secret.

python3 attest/verify_standalone.py attestation.json

That script imports nothing from attest and opens no sockets. A test enforcesboth.

4. Authority — authority.py

Was the action permitted? A signed action is not an authorised one: permissionis granted separately and expires.

Rules match drift.check exactly — amount, payee, audience, currency, window,intent. They are duplicated on purpose: depending on another repository wouldmean the check cannot run without network access to someone else's code. Sixcomparisons are cheaper to duplicate than to make unverifiable.

A test compares the result against the live drift on every rule, so adivergence shows up immediately rather than as a client complaint.

Absence of a mandate is a denial, never consent. A verifier who presents nopermission has not demonstrated one.

A finding worth stating plainly

While building layer 3, this was found in the existing code: with ATTEST_SECRETunset, signatures were computed with attest-dev-key-do-not-use-in-production,hardcoded in the source. That variable was not set, so every attestation theservice had ever issued was signed with a key published next to it. Anyonecould have signed an artifact as if the service had verified it.

The signature looked real and was not — which is worse than having none, becausehaving none is visible. It is fixed: with no key, there is no signature.

Try it in a browser

https://attest.rta.lat/demo — four buttons, one per layer, the full responseshown immediately.

Public repo

https://github.com/mrpkk/attest

Part of the Indra set — six small services for agents that have to betrusted: https://indra.rta.lat

MCP server (Model Context Protocol)

attest is an MCP server: it speaks the Model Context Protocol overStreamable HTTP (JSON-RPC 2.0) and exposes the verifier as MCP tools.

  • MCP tools (the whole point — an agent calls them directly):
    • verify_artifact — verify one artifact, returns verdict, trust score andfindings;
    • verify_artifact_batch — verify a batch in one call (a scan report, alist of findings) and get one verdict per artifact plus a summary;
    • bridge_check — settle paid work between two agents through an escrowbridge, with a signed receipt (offline-verifiable).
  • MCP resources: none exposed yet — resources/list answers with an emptylist rather than an error, so MCP clients and directory scanners do not markthe server as broken.
  • MCP prompts: none exposed yet — prompts/list answers with an empty listfor the same reason.
  • Transport: Streamable HTTP, no auth for the free tier, X-ATTEST-ENTITLEMENTheader for a prepaid key, PAYMENT-SIGNATURE/X-PAYMENT for a per-call x402payment.

Connect an MCP client

{
  "mcpServers": {
    "attest": { "url": "https://attest.rta.lat/mcp" }
  }
}

Claude Desktop, Claude Code, Cursor, Codex, VS Code and any other MCP clientthat supports remote Streamable HTTP servers work with that block as is.

We use it ourselves: our own agents call this exact URL through the MCP SDKin opencode.jsonc, so the server is exercised by real traffic every day, notonly by the tests.

Use it from your agent

{
  "mcpServers": {
    "attest": { "url": "https://attest.rta.lat/mcp" }
  }
}

That block is not a doc snippet — it is how our own agents call this server(the same public URL, no key, no signup).

Tools: verify_artifact, verify_artifact_batch. 20 free checks per day, then$0.005 per call over x402 (USDC, Base) or $9/30 days. India pricing: $3/30 days.

MCP Server · Populars

MCP Server · New

    mybolide

    Coding Tools MCP

    Give any AI agent the ability to code

    Community mybolide
    trypostit

    The open-source social media scheduler built for AI agents

    Open-source social media scheduler built for AI agents and the teams behind them. Create, schedule and publish posts to every network through MCP or the REST API, or write them yourself in a composer your team will love.

    Community trypostit
    Agoragentic

    Agoragentic

    Public adapters and discovery catalog for Triptych OS (Agent OS): agent frameworks, MCP/A2A/x402 protocols, workflows, wallets, SDKs, and examples for execute-first routing, governed handoffs, and receipt-aware agent commerce.

    Community Agoragentic
    eduard256

    Ozon MCP Server

    MCP Server for Ozon marketplace - search products, get details, prices and delivery info

    Community eduard256
    TalkToHumans

    LinkedIn MCP Server

    Safe LinkedIn MCP server for Claude, ChatGPT, Cursor & Codex. Your Agents read LinkedIn DMs, search your network, enrich profiles and draft messages you send.

    Community TalkToHumans