Witnessed
Integrates with Google Cloud KMS for Ed25519 signing, enabling production-grade key management for witness signatures.
Allows verifying email message IDs (anchor type 'email.message_id') via the Mailgun Events API, enabling proof of email sending.
Allows verifying payment transaction IDs (anchor type 'payment.txn_id') via the Stripe API, enabling proof of payment settlement.
Witnessed — verifiable action receipts for AI agents
An agent signs a claim about a consequential action with its own key; a witness service independently timestamps and countersigns it; the receipt is stored and retrievable; and anyone can verify it offline with the witness's public key.
npm i @witnessed/sdk # build it into your agent
npx @witnessed/mcp # or run a local MCP server for any agent hostLive at https://witness.medtekki.no. Design and plan in docs/superpowers/.
Live beta
Endpoint:
https://witness.medtekki.no(/healthz,/public-key,POST /receipts,GET /receipts/:id,POST /verify)Agent discovery: the service describes itself for agents at
GET /and/.well-known/receipts.json(JSON manifest),/llms.txt, and/openapi.json.Hosted MCP:
https://witness.medtekki.no/mcp(Streamable HTTP) exposesverify_receipt,get_receipt,service_info. Issuance is not hosted (it needs client-side signing) — issue with the SDK or the local MCP CLI.Local MCP CLI:
npx @witnessed/mcpruns a stdio MCP server that issues receipts signed with the agent's own key (toolsissue_receipt,verify_receipt). Point any MCP host at it.Published packages:
@witnessed/sdk,@witnessed/verifier,@witnessed/core,@witnessed/mcpon npm.Witness public key (build your trusted-key set from this to verify receipts offline):
key_id:zNo0zXMkkRwNUbNqtHj6diky8Nd9SvMZ8i7m6F99oFEpublic_key:{"kty":"OKP","crv":"Ed25519","x":"oKDkj9ODRDR8ASpYs8pKALb0AnwS6u1j7WyivK9UpM4"}
Beta caveats: receipts are free/unbilled; the signing key is host-held (not yet KMS); treat as a labelled beta, not a compliance guarantee.
Related MCP server: emilia-mcp-server
Packages
Package | Responsibility |
| Types, JCS canonicalization, Ed25519 keys/crypto, claim building & signing |
| Pure, offline receipt verification (reused client- and server-side) |
| In-memory + durable SQLite stores, signer, anchor validators, witness logic, Hono HTTP service |
|
|
| MCP server exposing |
| Production adapter: a |
What a receipt proves
Baseline (no anchor):
Agent K asserted action A over content-digest D at time T, independently witnessed at time T′, and the record is unaltered since.
With an anchor (effect-binding), the agent attaches an external reference such as an
email Message-ID, and the witness independently validates it, adding a signed
anchor_check:
...and the witness confirmed, at time T′, that the claimed external effect (Message-ID X) actually exists at the provider.
A failed or unvalidated anchor is recorded as verified: false, never rejected —
receipts never gate the underlying action. Verifiers surface anchor_check so a consumer
can choose to trust only effect-proven receipts.
Develop
Requires Node 22+ and npm (npm workspaces).
npm install
npm run typecheck # tsc --noEmit across all packages + tests
npm test # full Vitest suite
npm run check # typecheck + test (the CI gate; see .github/workflows/ci.yml)Deploy (beta)
The witness is a standard HTTP service (/healthz, /public-key, POST /receipts,
GET /receipts/:id, POST /verify).
npm run gen:witness-key # prints WITNESS_PRIVATE_JWK (keep secret) + the public key
cp .env.example .env # set WITNESS_PRIVATE_JWK (and optional store / x402 vars)
npm run start:witness # listens on :8787Container / Fly.io (a Dockerfile and fly.toml are included):
fly launch --no-deploy
fly secrets set WITNESS_PRIVATE_JWK='...' # value from gen:witness-key
fly volumes create receipts_data --size 1
fly deployPublish GET /public-key so verifiers can build their trusted-key set and check receipts
offline. Beta note: an env-held private key is acceptable for a labelled beta; move signing
to a KMS/HSM (@witnessed/gcp-kms + KmsSigner) before charging money or handling regulated data.
Trust model
The agent's private key never leaves the client; only the canonical digest and the agent signature go to the witness.
The witness signing key is pluggable via the
Signerinterface (async).LocalSignerholds a local key (dev only);KmsSignerdelegates to a KMS/HSM via an injectedKmsSignFnso the witness key never enters the process. Wire it withcreateApp({ signer, witnessPublicJwk, ... }). (Ed25519 signing required — works with GCP Cloud KMS / HSMs that support Ed25519; AWS KMS managed keys do not.)Production wiring with
@witnessed/gcp-kms(the only module touching the GCP SDK iscreateGcpKmsClient; the adapter logic is injected-client + CRC32C-verified):import { createGcpKmsClient, gcpKmsSignFn, gcpKmsPublicJwk } from "@witnessed/gcp-kms"; import { KmsSigner } from "@witnessed/witness/src/signer"; const client = createGcpKmsClient(); const keyVersion = "projects/P/locations/L/keyRings/R/cryptoKeys/witness/cryptoKeyVersions/1"; const { publicJwk, keyId } = await gcpKmsPublicJwk(keyVersion, client); const app = createApp({ signer: new KmsSigner(keyId, gcpKmsSignFn(keyVersion, client)), witnessPublicJwk: publicJwk, });The witness time is authoritative; the agent's claimed time is also retained.
Receipts carry content digests, not content — privacy by default.
Durable storage:
SqliteStorepersists receipts append-only (PRIMARY KEY onid); inject it viacreateApp({ ..., store }). Postgres can implement the sameReceiptStore.Record-keeping (
RetentionStore): aRetentionPolicy { minimumDays }(EU AI Act ≈ 180 days) sets each record'sretain_until;purgeExpired(now)deletes only records past their window and not under hold, returning both what it purged and what a legal hold kept (placeLegalHold/releaseLegalHold) — no silent deletion. Records with no policy are kept indefinitely.Article-12 export:
buildArticle12Export(receipts, keys, opts)produces an ordered, integrity-verified event log (each receipt re-verified, chain resolved) with effect/anchor, actor, timestamps, and human-oversight flags. It isformat: "...v0"and carries an explicit disclaimer that the field mapping is not legally validated — verify with counsel.x402 billing (optional):
createApp({ x402: { facilitator } })makes the witness charge per receipt. An unpaidPOST /receiptsreturns HTTP402with payment requirements (USDC, bound to the claim id so a payment can't be replayed); a paid request settles via the injectedPaymentFacilitatorand the settlement (tx_hash) is recorded as witness-signedwitness.payment— so getting paid and proving it are one on-chain-verifiable artifact. The facilitator is provider-agnostic;HttpFacilitator(@witnessed/witness/src/x402-facilitator) is a real client for a hosted x402 facilitator — it decodes theX-PAYMENTpayload, callsPOST /verifythenPOST /settle, and maps the returnedtransactionto the receipt'stx_hash(transport injected for tests; live chain settlement runs against a real facilitator).Effect-binding: agents attach an
anchor{ type, value }; the witness runs a pluggableAnchorValidator(given the anchor value + the claim'spayload_digest) and signs the result. Built in:EmailMessageIdValidator(email.message_id) — verified when the message is found.PaymentTxnIdValidator(payment.txn_id) — verified when the transaction is found and settled.EhrRecordIdValidator(ehr.record_id) — MDR-style provenance: verified when the record exists, is in an accepted status, and its content hash matches the receipt'spayload_digest(proving the agent wrote exactly the data it claimed).
Real provider lookups live in
@witnessed/witness/src/anchor-lookups:mailgunEmailLookup(Mailgun Events API, by RFC Message-ID),stripePaymentLookup(Stripe PaymentIntents/Charges), andfhirEhrLookup(FHIR REST + afhirContentHashprovenance reducer). Each takes an injectedfetchfor tests; live network/auth runs against the real provider.Evidence chains: a receipt's
prevlists predecessor receipt ids. Becauseidis a content hash, aprevlink pins the exact predecessor and is covered by the signatures, so tampering with any link breaks the chain.verifyChain()verifies every receipt and resolves every link.Human oversight: a reviewer's decision is an ordinary receipt with
action.type=human.approval/human.rejection, signed by the reviewer's own key andprev-linked to the action under review — so oversight lands in the same evidence chain. Useclient.approve(id, reason)/client.reject(id, reason). (Binding a reviewer key to a real licensed human is a separate identity layer, intentionally out of scope.)
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
Alicense-qualityDmaintenanceTamper-evident receipts for AI agent actions. The notary layer for agent-to-agent transactions.Last updated651MIT
emilia-mcp-serverofficial
AlicenseAqualityAmaintenanceThe accountability layer for AI agents — a named human's signed yes before an agent does anything irreversible (payment, record change, deploy), then an offline-verifiable Trust Receipt. Apache-2.0, formally verified.Last updated176Apache 2.0
garlofficial
Alicense-qualityCmaintenanceCryptographic verification for AI agent actions — ECDSA-secp256k1 signed Action Receipts anchored on Base, multi-dimensional trust vectors, capability tokens, and offline-verifiable on-chain proof. 29 tools.Last updated3Apache 2.0- Alicense-qualityDmaintenanceProvides cryptographic governance receipts for AI agents, enabling pre-execution evaluation and signed verdicts (EXECUTE/BLOCK/REVIEW/SHADOW) with offline-verifiable audit trails.Last updatedMIT
Related MCP Connectors
Shared, verifiable memory for AI agents and robots: signed tokens that resolve and verify offline.
Bitcoin-anchored, tamper-evident audit log for AI agents — record, disclose and verify actions.
Pre-action attestation perimeter for AI agents — 8 primitives, signed C18 receipt per call.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/medtekki/witnessed'
If you have feedback or need assistance with the MCP directory API, please join our Discord server