tabularium-mcp
Officialby SQLazy
README.md
# Tabularium
Memory for AI agents that survives sessions, plus a signed ledger of what they buy. Paid per call in USDC over x402.
**Live on Base mainnet** at https://tabularium.matt-3e0.workers.dev (real USDC). Listed on the x402 Bazaar and the
MCP Registry (`io.github.SQLazy/tabularium`, npm `tabularium-mcp`).
Identity is the paying wallet: no sign-up, no API key. Every write is appended to a hash chain whose head is signed
by the server, so an agent can prove its history and walk away with it.
## Quickstart
**From Claude Code or any MCP client** (needs a wallet with a few dollars of USDC on Base, no ETH):
claude mcp add tabularium --env TABULARIUM_PRIVATE_KEY=0x... -- npx -y tabularium-mcp
Then ask your agent to remember something, or use the `load_memory` prompt. Spending is capped at $1 per session by
default (`TABULARIUM_MAX_SPEND_USD`). Use a dedicated wallet.
**From code**, with any x402 v2 client: see [examples/agent-memory.mjs](examples/agent-memory.mjs) (about 30 lines).
**For language models:** https://tabularium.matt-3e0.workers.dev/llms.txt explains when it fits, when it does not,
prices and exact formats.
**Use it for:** memory across sessions and machines, hand-offs between agents, proof of what was stored and when,
and an auditable record of what an agent spent (`tabularium_pay`). **Not for:** secrets unless encrypted first (the
operator can read values), large files (64 KB per value), or anything that must be free.
## The menu (four calls, fixed prices)
| Call | Price | What |
|---|---|---|
| `POST /write {key,value}` | $0.003 | Append a value. First write opens a 30-day workspace. |
| `GET /read?key=` | $0.002 | Latest value + its chain entry. |
| `POST /renew` | $0.25 | Extend by 30 days (from current expiry, so early renewal wastes nothing). |
| `GET /export?since=` | $0.01 | Entries + values + signed head, verifiable offline. |
Free: `GET /llms.txt` (a plain-text guide for language models: when it fits, when not, exact formats), `GET /` and `/menu` (prices, policy, public signing key), `GET /head?wallet=` (signed seq + hash, no values).
`GET /stats`: public aggregates of settled calls (paying wallets, 14-day return rate, calls, revenue). Wallets appear only
as counts; keys and values are never recorded. Every payment is public on-chain anyway.
Prices were set on 2026-10-26, before launch, to cover the Coinbase facilitator's fee ($0.001 per settled payment
after the first 1,000 a month). A typical session (10 reads, 20 writes) costs about $0.08.
Writes accept an optional `idempotency_key` (same id + same body within 7 days returns the original entry with `replayed: true`; same id + different body is 409). Use it on every retry: x402 settles after the handler runs, so a failed settlement can follow a committed write.
Policy: 30-day term, 90-day grace (reads/export/renew work, writes return 409), then purged.
64KB value cap. One signed payment buys one call: a reused payment gets 409 and is not charged. renew and export
settle before running (a free pre-check rejects a missing workspace first). See [SECURITY.md](SECURITY.md).
Keys match `^[A-Za-z0-9._:/-]{1,128}$`. 4xx/5xx responses are never charged
(the x402 middleware settles only when status < 400).
## Use it from an agent (MCP)
`mcp/` is a stdio MCP server exposing the menu as tools (the four paid calls plus menu, head, and local verify), and
`tabularium_pay` / `tabularium_ledger`: pay any x402 service and keep a signed receipt of every purchase in the
workspace, so an agent's spending is provable. The agent's wallet pays, with a per-process spend cap. See [mcp/README.md](mcp/README.md).
claude mcp add tabularium --env TABULARIUM_PRIVATE_KEY=0x... -- node /path/to/mcp/server.mjs
## Verify without trusting the server
node verifier/verify.mjs export.json <signingPubKeyHex>
Zero dependencies. Checks the chain, the values against value hashes, and the Ed25519 head signature.
Signing keys rotate. `/menu` publishes the current key and every retired one (`signing.retired`); an export
verifies against the key that was current when it was exported. Retired keys:
| Public key | Used until | Note |
|---|---|---|
| `5599f548393f2f2e1e694361a06d76d06fd3dc6cbe2d985d28f3a533025798e3` | 2026-10-26 | Testnet launch key. Its private half was exposed, so treat its signatures as testnet-only. |
## Develop
npm install
npm run keygen -- --dev # writes .dev.vars
npx wrangler dev -c wrangler.dev.jsonc --port 8787 # NO paywall, local only
node scripts/e2e.mjs # 25 checks
npm test && npm run typecheck
`src/dev-nopay.ts` removes the paywall and adds a 5ms async gap in the write path so the
concurrency test bites. It is referenced only by `wrangler.dev.jsonc`.
Caveat: wrangler hot-reload can serve stale code after a file swap; restart the server before trusting a result.
## Deploy
1. `npm run keygen`, put the public key in `SIGNING_PUBKEY_HEX` (wrangler.jsonc), then
`npx wrangler secret put SIGNING_KEY_PKCS8`. The Worker refuses to sign if the two don't match.
To rotate: move the old public key into `RETIRED_SIGNING_KEYS` (src/policy.ts), set the new one, and deploy
the new secret in the same version: `npx wrangler deploy --secrets-file <json with SIGNING_KEY_PKCS8>`.
2. Set `PAY_TO` to your receiving address.
3. `npx wrangler deploy`. `NETWORK` in wrangler.jsonc picks the chain (`base` in production, `base-sepolia` for
testing; the free `https://x402.org/facilitator` works on testnet). Local `wrangler dev` runs read `.dev.vars`,
which keeps them on base-sepolia so local tests never spend real money.
4. Mainnet: set `NETWORK=base` and use a mainnet-capable facilitator (needs its own credentials) via `FACILITATOR_URL`.
## Lessons / known limits
- `blockConcurrencyWhile` is not a mutex. Concurrent writes forked the chain
(`UNIQUE constraint failed: log.seq`). Mutations now go through an in-isolate promise-chain mutex plus
`transactionSync`. Disabling the mutex makes e2e fail; enabling it passes.
- Payments use x402 v2 (`@x402/hono` 2.28): 402s carry a `PAYMENT-REQUIRED` header, clients pay with
`PAYMENT-SIGNATURE`, receipts come back in `PAYMENT-RESPONSE`. Network ids are CAIP-2 (`eip155:84532`, `eip155:8453`);
`/menu` advertises them under `x402`.
- Payer identity is read only from `PAYMENT-SIGNATURE` (the header the middleware verifies): EVM `exact` via EIP-3009.
A legacy `X-PAYMENT` header is ignored, so nobody can pay with one wallet and claim another.
- Workers do not let one request await I/O started by another, so the paywall is initialised inside the request
that needs it and only the finished instance is shared (a shared in-flight init hung every paid call).
- Name: "Tabularium" is Rome's state archive. Earlier names (Omega, Hypomnema) collided with existing AI-memory projects. The protocol tag "omega/v1" in the hash preimage is kept as a stable domain separator.
- Success test: share of wallets that come back within 14 days.
## License
Two licenses, on purpose:
- **The service** (everything except `mcp/`, `verifier/` and `examples/`): [FSL-1.1-MIT](LICENSE.md), the Functional Source
License. Read it, audit it, run it for yourself, but do not offer it as a competing commercial service. Each version
becomes MIT two years after it is published.
- **The MCP client** (`mcp/`), **the offline verifier** (`verifier/`) and **the examples** (`examples/`): [MIT](mcp/LICENSE). The code that holds
your wallet key, and the code that checks the server, are yours to read, change and reuse freely.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues