Witnessed

Witnessed

Verifiable action receipts for AI agents — agents sign claims locally, an independent witness countersigns and timestamps, anyone can verify offline.

Category
访问服务器

README

Witnessed — verifiable action receipts for AI agents

CI npm @witnessed/sdk license

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 host

Live 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) exposes verify_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/mcp runs a stdio MCP server that issues receipts signed with the agent's own key (tools issue_receipt, verify_receipt). Point any MCP host at it.
  • Published packages: @witnessed/sdk, @witnessed/verifier, @witnessed/core, @witnessed/mcp on npm.
  • Witness public key (build your trusted-key set from this to verify receipts offline):
    • key_id: zNo0zXMkkRwNUbNqtHj6diky8Nd9SvMZ8i7m6F99oFE
    • public_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.

Packages

Package Responsibility
@witnessed/core Types, JCS canonicalization, Ed25519 keys/crypto, claim building & signing
@witnessed/verifier Pure, offline receipt verification (reused client- and server-side)
@witnessed/witness In-memory + durable SQLite stores, signer, anchor validators, witness logic, Hono HTTP service
@witnessed/sdk ReceiptsClient — local signing, issue via witness, offline verify
@witnessed/mcp MCP server exposing issue_receipt / verify_receipt tools
@witnessed/gcp-kms Production adapter: a KmsSignFn backed by Google Cloud KMS (Ed25519)

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 :8787

Container / 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 deploy

Publish 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 Signer interface (async). LocalSigner holds a local key (dev only); KmsSigner delegates to a KMS/HSM via an injected KmsSignFn so the witness key never enters the process. Wire it with createApp({ 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 is createGcpKmsClient; 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: SqliteStore persists receipts append-only (PRIMARY KEY on id); inject it via createApp({ ..., store }). Postgres can implement the same ReceiptStore.

  • Record-keeping (RetentionStore): a RetentionPolicy { minimumDays } (EU AI Act ≈ 180 days) sets each record's retain_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 is format: "...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 unpaid POST /receipts returns HTTP 402 with payment requirements (USDC, bound to the claim id so a payment can't be replayed); a paid request settles via the injected PaymentFacilitator and the settlement (tx_hash) is recorded as witness-signed witness.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 the X-PAYMENT payload, calls POST /verify then POST /settle, and maps the returned transaction to the receipt's tx_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 pluggable AnchorValidator (given the anchor value + the claim's payload_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's payload_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), and fhirEhrLookup (FHIR REST + a fhirContentHash provenance reducer). Each takes an injected fetch for tests; live network/auth runs against the real provider.

  • Evidence chains: a receipt's prev lists predecessor receipt ids. Because id is a content hash, a prev link 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 and prev-linked to the action under review — so oversight lands in the same evidence chain. Use client.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.)

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选