Live now: CLI on npm → npx @mdlog/agentgate · dashboard agentgate.mdloglabs.org · gateway gateway.mdloglabs.org · registry deployed on Casper Testnet.
Stripe for AI agents on Casper. Read the live on-chain service catalog with zero setup — no config, no keys:
npx @mdlog/agentgate listWrap any HTTP API into a paid, on-chain-registered service in one command — the only thing on the line besides the args is your funded wallet key:
npx @mdlog/agentgate wrap https://api.example.com/data --price 2.5 --name "My Data API" --pem ./key.pemBuy one call to any listed service the same way — the CLI pays the 402 invoice and prints the data (body → stdout, payment receipt → stderr):
npx @mdlog/agentgate buy 5 --pem ./buyer.pem --max 5wrap registers on-chain (signed by --pem) and maps your upstream on the gateway by
signing an ownership challenge — no shared admin token. --gateway defaults to the hosted
gateway; pass it to target a local/self-hosted one.
Sellers put a 402 paywall in front of their API and register it in an on-chain
registry. Buyer agents discover services from the registry, pay with a native CSPR
transfer carrying the invoice nonce as transfer_id, retry with the payment proof, and
get the data — while the gateway records an on-chain attestation that feeds each
service's trust score. No accounts, no API keys, no subscriptions: HTTP 402 + Casper.
sequenceDiagram
autonumber
participant Seller as Seller (CLI)
participant Chain as Casper (registry)
participant Gate as AgentGate gateway
participant Agent as Buyer agent
participant API as Upstream API
Seller->>Chain: register service (price, payment target, attestor)
Seller->>Gate: map upstream (owner-signed challenge → /services/:id/map)
Agent->>Chain: discover catalog + trust scores
Agent->>Gate: GET /svc/:id
Gate-->>Agent: 402 PaymentRequiredResponse (x402Version, error, accepts[])
Agent->>Chain: CSPR transfer (transfer_id = nonce)
Agent->>Gate: GET /svc/:id + X-PAYMENT: <base64 proof>
Gate->>Chain: verify transfer (target, amount, transfer_id, age)
Gate->>API: proxy (nonce burned first — single use)
API-->>Gate: data
Gate-->>Agent: 200 data
Gate--)Chain: attestation (success) → score → trust tier
Full component breakdown: docs/ARCHITECTURE.md · engineering contract: docs/SPEC.md.
Requires Node ≥ 22. No keys, no network, no chain access needed:
npm install
npm run demo # full loop: register → 402 → pay → serve → attest → score, exits 0The demo boots a mock chain + oracle + gateway in-process, wraps the oracle at 0.5 CSPR, runs the LLM buyer agent (deterministic MockLlm — no API key needed), and prints the payment deploy hash, the attestation tx hash, and the final score.
Ports: the demo binds
:4030(devnet),:4010(oracle) and:4021(gateway). If one is taken (EADDRINUSE), override:DEVNET_PORT=14030 ORACLE_PORT=14010 MIDDLEWARE_PORT=14021 npm run demo
npm run dev:seed # boots devnet+oracle+middleware AND seeds one wrapped
# service + a real paid call, then STAYS UP
npm run dev:dashboard # in a second terminal → open the URL it prints
npm run demowon't show in the dashboard — it's a self-contained one-shot that boots its own in-memory chain, runs the loop, and exits, so its data is gone by the time you open a browser. Usenpm run dev:seed(persistent + populated) to view it live. The dashboard polls the running stack every 5 s.
Port note: the dashboard defaults to
http://localhost:3000, but if 3000 is already taken Next.js silently moves to 3001 (or the next free port). Always open the URL printed in thedev:dashboardterminal, not a hard-coded 3000.
npm run dev # empty stack: devnet :4030 + oracle :4010 + middleware :4021
# paste the printed MOCK_BUYER_ACCOUNT / MOCK_SELLER_ACCOUNT export lines, then:
npm run agentgate -- wrap http://localhost:4010/feed --price 0.5 --name "RWA FX & Gold Oracle"
npm run agent -- --task "Get today's USD/IDR rate and gold price, summarize for a treasury report"
npm run agentgate -- buy 1 --mode mock # or skip the agent: pay once, print the dataSet ANTHROPIC_API_KEY to let the buyer agent use Claude instead of the MockLlm.
AGENTGATE_MODE=mock|live (default mock for the repo stack; the published CLI defaults to live) selects the chain backend behind the
ChainClient seam — everything above it is identical:
mock |
live (Casper Testnet) |
|
|---|---|---|
| Chain | in-memory devnet (@agentgate/devnet) |
casper-js-sdk v5 + CSPR.cloud REST |
| Signers | mock account strings | PEM keys |
| Payment verify | devnet transfer lookup | CSPR.cloud GET /transfers?deploy_hash= |
| Registry | devnet mirrors the Odra contract rules | deployed AgentGateRegistry contract |
| Guardrails | default admin token OK, SSRF guard off | default token refused, SSRF guard on |
All env vars are documented in .env.example. The gateway and background
services in live mode require CSPR_CLOUD_API_KEY and a non-default AGENTGATE_ADMIN_TOKEN
(enforced by config). The CLI is looser: list/status read the public node with no keys
at all; only status attestation history needs CSPR_CLOUD_API_KEY. Live wrap needs no
admin token — it maps the upstream by signing an ownership challenge with your --pem key
(verified against the on-chain owner); the admin token is only the legacy/self-hosted path.
Live buy needs only a funded buyer key (--pem or BUYER_SIGNER_PEM_PATH).
Every value can also be passed as a flag (--mode, --node-url, --registry, --pem,
--api-key, --admin-token; flag > env > default).
packages/
shared/ types · config · bigint money · trust tiers (zero runtime deps)
devnet/ in-memory mock chain HTTP server :4030
chain/ ChainClient: MockChainHttpClient + LiveCasperClient
middleware/ the product core — 402 paywall proxy + owner-signed self-map :4021
client/ agent-side fetchPaid (parse 402 → pay → retry)
oracle/ demo RWA feed: USD/IDR + gold spot + confidence :4010
buyer-agent/ LLM decision loop (AnthropicLlm / MockLlm)
cli/ agentgate wrap | buy | list | status | pause | resume | demo-accounts
dashboard/ Next.js 16 landing + catalog + live activity + docs :3000
contracts/ AgentGateRegistry (Rust/Odra) — registry, scores, attestations
e2e/ full-loop test, in-process servers on port 0
scripts/ dev.ts (stack) · demo.ts (one-shot scripted demo)
| Command | What it does |
|---|---|
npm run demo |
one-shot full loop, offline, exits 0 with both tx hashes |
npm run dev |
boots devnet + oracle + middleware, seeds demo accounts |
npm run dev:dashboard |
Next.js dashboard at :3000 |
npm run agentgate -- … |
the agentgate CLI |
npm run agent -- --task "…" |
run the buyer agent once |
npm run typecheck |
tsc --noEmit in every package + dashboard + root scripts/e2e |
npm test |
vitest: all package units + the e2e loop (341 tests) |
npm run build |
dashboard next build |
Contract tests: cd contracts/agentgate-registry && cargo odra test (20 OdraVM tests),
plus contracts/spend-guard (25 tests via cargo test).
Live on Casper Testnet (Casper 2.0, network casper-test). The full loop —
register → pay (native CSPR transfer, transfer_id = invoice nonce) → attest → score —
runs on-chain; the trust score reads (1,1) after the attestation below. Set
REGISTRY_CONTRACT_PACKAGE_HASH to the package hash for live mode.
| Artifact | Value |
|---|---|
AgentGateRegistry package hash |
hash-10f92725551941ffe5be84cd340ce0f31f9f25d1f8ed959cc1a6c3383c3e27e9 |
| Install (contract deploy) tx | 4eace325… |
register_service tx |
35d10755… |
Payment transfer tx (transfer_id = nonce) |
7cbba41d… |
record_attestation tx |
f9759829… |
Flagship service #5 register_service (2026-07-02) |
dbfdecbb… |
#5 buyer-paid transfer via agentgate buy (2.5 CSPR) |
d6cbfcab… |
#5 record_attestation |
23ddacf9… |
The registry is deployed to Casper Testnet (addresses above). The deploy runbook is in
docs/DEPLOY.md, including the wasm toolchain requirement (binaryen ≥ 123 +
wasm-strip; older binaryen leaves a bulk-memory DataCount section that makes stored
entry-point calls revert with "Sections out of order") and the verify-against-deployed-contract notes.
Hosting the services is documented in docs/HOSTING.md: dashboard →
Vercel (root vercel.json), middleware + oracle → Railway (per-package Dockerfiles +
railway.json), plus a self-contained docker-compose.hosting.yml demo stack.
Currently hosted: the live-mode gateway runs at https://gateway.mdloglabs.org and the
dashboard at https://agentgate.mdloglabs.org (cloudflared tunnels → local PM2 services;
runbook + deploy/agentgate.ecosystem.config.cjs in docs/DEPLOY-GATEWAY.md).
The CLI is published to npm as @mdlog/agentgate.
Testnet Plan B (native transfer + transfer_id) → mainnet → x402 Facilitator (Plan A)
→ CSPR.cloud streaming → MCP server for agent frameworks.
Built solo by mdlog for the Casper Agentic Buildathon 2026 (Casper Innovation Track — Agentic AI × DeFi/RWA on Casper).
