DigiDollar paywall proxy for MCP servers — plus an autonomous paying client.
v0.1 is the paywall proxy (src/server.js): it returns HTTP 402 with a
DigiDollar invoice and issues bearer tokens after payment. v0.2 is the paying
client (src/client.js): a stdio MCP server an AI agent connects to; it
detects 402, pays DigiDollar automatically (within spend caps), obtains a token,
and mirrors upstream tools — no human in the loop.
This is v0.1 research / demo software. Default
REQUIRE_TESTNET=truerefuses to run against a non-test chain. Do not use on mainnet with real funds. There is no security audit. Expect breaking changes. You run this at your own risk.
Agent dgb-tollgate Your node / upstream
| | |
|-- MCP request (no token) ----->| |
|<- 402 + fresh DD invoice ------| |
| |-- getdigidollaraddress ---------->|
| | |
|-- pay DigiDollar to payTo --------------------------------------> chain
| | |
|-- POST /token { invoiceId } -->| |
| |-- listdigidollarutxos (own node) ->|
|<- { token } -------------------|(only if address balance ≥ price) |
| | |
|-- MCP + Authorization: Bearer >| |
| |-- reverse-proxy ----------------->| upstream MCP
|<- upstream response -----------|<- streamed response --------------|
Claude / agent paying client (stdio) tollgate (v0.1) upstream MCP
| | | |
|-- MCP stdio ------------------>| | |
| |-- HTTP MCP (no token) ------>| |
| |<- 402 + DD invoice ----------| |
| |-- senddigidollar (wallet) ---> node |
| |-- POST /token -------------->| |
| |<- bearer token ---------------| |
| |-- HTTP MCP + Bearer -------->|-- proxy ------------->|
|<- tool result ------------------|<- upstream response ----------|<-----------------------|
The paying client caches the bearer token until expiry. It only pays again when
there is no valid token. Spend caps (DD_MAX_PAYMENT_USD, DD_MAX_DAILY_USD) are
enforced before any senddigidollar call.
- Unpaid request →
HTTP 402with a fresh DigiDollar address and invoice id. - Agent pays that address in DigiDollar (minimum $1.00 — consensus floor).
POST /tokenwith{ "invoiceId" }→ tollgate checks its own node (listdigidollarutxosat the invoice address). Client txids are never trusted.- On success, a short-lived HMAC-SHA256 bearer token is issued.
- Requests with a valid Bearer token are reverse-proxied to
UPSTREAM_MCP_URL(method, headers, body; streamed response).
npm install
# Configure (placeholders only in the repo — use your own secrets locally)
cp .env.example .env # then edit; do not commit .env
# Terminal A — example upstream MCP (one tool: echo)
npm run upstream
# Terminal B — tollgate (loads env from your shell / dotenv of your choice)
export $(grep -v '^#' .env | xargs) # or use your preferred env loader
npm start
# Terminal C — v0.1 walkthrough (payment step is manual)
npm run demo
# Or: v0.2 autonomous loop (payment is automatic)
npm run paid-demoPoint your MCP host at the stdio server (bin: dgb-tollgate-client):
{
"mcpServers": {
"dgb-tollgate-client": {
"command": "node",
"args": ["/path/to/dgb-tollgate/src/client.js"],
"env": {
"TOLLGATE_URL": "http://127.0.0.1:8080/mcp",
"TOLLGATE_TOKEN_URL": "http://127.0.0.1:8080/token",
"DGB_RPC_URL": "http://127.0.0.1:14023",
"DGB_RPC_USER": "rpcuser",
"DGB_RPC_PASSWORD": "…",
"DGB_WALLET": "wallet-name",
"DD_MAX_PAYMENT_USD": "5",
"DD_MAX_DAILY_USD": "25"
}
}
}
}Or: npm run client (with the same env vars exported in your shell).
| Variable | Required | Default | Description |
|---|---|---|---|
UPSTREAM_MCP_URL |
yes | — | Streamable-HTTP MCP endpoint to protect |
PRICE_USD |
yes | — | Price per token; must be ≥ 1.00 |
TOKEN_TTL_SECONDS |
no | 3600 |
Bearer token lifetime after payment |
TOLLGATE_SECRET |
yes | — | HMAC signing secret (≥ 16 chars) |
DGB_RPC_URL |
yes | — | DigiByte Core RPC URL |
DGB_RPC_USER |
yes | — | RPC username |
DGB_RPC_PASSWORD |
yes | — | RPC password |
DGB_WALLET |
yes | — | Wallet name (fresh DD addresses) |
REQUIRE_TESTNET |
no | true |
Exit unless node chain is test |
PORT |
no | 8080 |
Tollgate listen port |
INVOICE_TTL_SECONDS |
no | 900 |
How long an unpaid invoice is valid |
MIN_CONFIRMATIONS |
no | 1 |
Confirmations required for payment |
MAX_OUTSTANDING_INVOICES |
no | 1000 |
Cap on unsettled invoices; excess requests get HTTP 429 |
Startup rejects PRICE_USD < 1.00 because DigiDollar cannot create outputs
below $1.00.
| Variable | Required | Default | Description |
|---|---|---|---|
TOLLGATE_URL |
yes | — | Paywalled Streamable-HTTP MCP endpoint |
TOLLGATE_TOKEN_URL |
yes | — | Tollgate POST /token URL |
DGB_RPC_URL |
yes | — | DigiByte Core RPC (wallet that pays) |
DGB_RPC_USER |
yes | — | RPC username |
DGB_RPC_PASSWORD |
yes | — | RPC password |
DGB_WALLET |
yes | — | Wallet name used for senddigidollar |
DD_MAX_PAYMENT_USD |
no | 5 |
Per-payment spend cap |
DD_MAX_DAILY_USD |
no | 25 |
Rolling 24h spend cap |
REQUIRE_TESTNET |
no | true |
Exit unless node chain is test |
PAY_POLL_TIMEOUT_MS |
no | 90000 |
Max wait for /token after payment |
PAY_POLL_INTERVAL_MS |
no | 3000 |
Poll interval for /token |
- Payment is verified only by querying your DigiByte node for DigiDollar UTXOs at the invoice address. A client-supplied txid is never proof.
- Fresh DigiDollar address per invoice so “paid?” = address balance lookup.
- Bearer tokens are HMAC-SHA256 over
{ invoiceId, exp }; verification uses a constant-time compare. - Secrets and tokens are never logged.
- Testnet guard is on by default.
- The paying client enforces spend caps before payment (allowance, not custody).
senddigidollaralways receives integer cents (never decimal dollars).
| Method | Path | Auth | Behavior |
|---|---|---|---|
POST |
/token |
none | Body { invoiceId } → verify payment → { token, tokenType, expiresAt, invoiceId } |
* |
any other | Bearer | Valid token → proxy to upstream; else 402 + new invoice |
{
"x402Version": 1,
"error": "Payment Required",
"accepts": [
{
"scheme": "exact",
"network": "digibyte-testnet",
"asset": "DigiDollar",
"payTo": "<fresh-dd-address>",
"amountUsd": 1,
"amountCents": 100,
"invoiceId": "<uuid>",
"expiresAt": "2026-01-01T00:15:00.000Z"
}
],
"hint": "Pay the DigiDollar amount to payTo, then POST /token ..."
}src/server.js v0.1 tollgate proxy (Express)
src/client.js v0.2 paying MCP client (stdio)
src/payer.js DigiDollar payment + spend-cap policy
example/upstream-mcp.js Minimal Streamable-HTTP MCP (tool: echo)
example/demo.sh v0.1: manual payment walkthrough
example/paid-agent-demo.sh v0.2: fully autonomous payment demo
reference/ Proven modules from dgb-x402 (source of security model)
- Per-tool pricing (all-or-nothing per token)
- Digi-ID identity gating
- Batch / metered settlement
- stdio→HTTP bridging (upstream must already be HTTP)
- Multi-tenant dashboards or durable persistence
MIT