Don't Pester Your Customer — Bitcoin Lightning micropayments for MCP servers
Project description
Tollbooth DPYC
Don't Pester Your Customer — Bitcoin Lightning micropayments for MCP servers.
The metaphors in this project are drawn with admiration from The Phantom Tollbooth by Norton Juster, illustrated by Jules Feiffer (1961). Milo, Tock, the Tollbooth, Dictionopolis, and Digitopolis are creations of Mr. Juster's extraordinary imagination. We just built the payment infrastructure.
The Problem
Thousands of developers are building MCP servers — services that let AI agents like Claude interact with the world. Knowledge graphs, financial data, code repositories, medical records. Each one is a city on the map. But the turnpike between them? Wide open. No toll collectors. No sustainable economics. Just a growing network of roads that nobody's figured out how to fund.
Every MCP operator faces the same question: how do I keep the lights on?
Traditional API keys with monthly billing? You're running a SaaS company now. The L402 protocol — Lightning-native pay-per-request? Every single API call requires a payment negotiation. Milo's toy car stops at every intersection to fumble for exact change.
The Solution
Tollbooth DPYC takes a different approach — one that respects everyone's time:
Milo drives up to the tollbooth once, buys a roll of tokens with a single Lightning invoice, and drives. No stops. No negotiations. No per-request friction. The tokens quietly decrement in the background. When the roll runs low, he buys another. The turnpike stays fast.
Prepaid credits over Bitcoin's Lightning Network, gated at the tool level, settled instantly, with no subscription management and no third-party payment processor taking a cut.
Install
pip install tollbooth-dpyc
What's in the Box
| Module | Purpose |
|---|---|
TollboothConfig |
Plain frozen dataclass — no pydantic, no env-var reading. Your host constructs it. |
UserLedger |
Per-user credit balance with debit/credit/rollback, daily usage logs, JSON serialization. |
BTCPayClient |
Async HTTP client for BTCPay Server's Greenfield API — invoices, payouts, health checks. |
VaultBackend |
Protocol for pluggable persistence — implement store_ledger, fetch_ledger, snapshot_ledger. |
LedgerCache |
In-memory LRU cache with write-behind flush. The hot path for all credit operations. |
ToolTier |
Cost tiers for tool-call metering (FREE=0, READ=1, WRITE=5, HEAVY=10 sats per call). |
tools.credits |
Ready-made tool implementations: purchase_credits, check_payment, check_balance, and more. |
Quick Start
from tollbooth import TollboothConfig, UserLedger, BTCPayClient, LedgerCache
# Configure — your host reads env vars, Tollbooth gets a plain dataclass
config = TollboothConfig(
btcpay_host="https://your-btcpay.example.com",
btcpay_store_id="your-store-id",
btcpay_api_key="your-api-key",
tollbooth_royalty_address="tollbooth@btcpay.digitalthread.link",
)
# Create a BTCPay client
async with BTCPayClient(config.btcpay_host, config.btcpay_api_key, config.btcpay_store_id) as client:
# Create an invoice for 1000 sats
invoice = await client.create_invoice(1000, metadata={"user": "milo"})
print(f"Pay here: {invoice['checkoutLink']}")
Configuration
TollboothConfig is a plain frozen dataclass. Your host application constructs it from its own settings (env vars, pydantic-settings, YAML — whatever you prefer). Tollbooth never reads environment variables directly.
| Field | Type | Default | Purpose |
|---|---|---|---|
btcpay_host |
str | None |
None |
BTCPay Server URL for creating invoices and checking payments |
btcpay_store_id |
str | None |
None |
BTCPay store ID — each operator runs their own store |
btcpay_api_key |
str | None |
None |
BTCPay API key — must have invoice + payout permissions |
btcpay_tier_config |
str | None |
None |
JSON string mapping tier names to credit multipliers |
btcpay_user_tiers |
str | None |
None |
JSON string mapping user IDs to tier names |
seed_balance_sats |
int |
0 |
Free starter balance granted to new users (0 to disable) |
tollbooth_royalty_address |
str | None |
None |
Lightning Address for the 2% royalty payout to the Tollbooth originator |
tollbooth_royalty_percent |
float |
0.02 |
Royalty percentage (0.02 = 2%) |
tollbooth_royalty_min_sats |
int |
10 |
Minimum royalty payout in sats (below this, no payout fires) |
authority_public_key |
str | None |
None |
Authority's Ed25519 PEM public key for certificate verification. When set, purchase_credits requires a valid Authority JWT. |
authority_url |
str | None |
None |
Authority MCP endpoint URL (scaffolding for future use) |
Tool Functions
The tollbooth.tools.credits module provides ready-made implementations that your MCP server wraps as tools. Each function takes infrastructure objects (BTCPayClient, LedgerCache) as parameters — you wire them up, Tollbooth handles the logic.
| Function | Purpose |
|---|---|
purchase_credits_tool |
Creates a BTCPay invoice, records it as pending, returns a checkout link. Validates Authority certificate when authority_public_key is configured. |
verify_certificate |
Verifies an Authority-signed Ed25519 JWT. Checks signature, expiry, and anti-replay (JTI). |
check_payment_tool |
Polls an invoice, credits the balance on settlement, fires the royalty payout. Idempotent. |
check_balance_tool |
Returns current balance, usage summary, tier info, and invoice history. Read-only. |
restore_credits_tool |
Recovers credits from a paid invoice lost to cache/vault issues. Checks vault first, falls back to BTCPay. |
btcpay_status_tool |
Diagnostics: BTCPay connectivity, store name, API key permissions, royalty config. |
compute_low_balance_warning |
Pure function — returns a warning dict if balance is below threshold, None if healthy. |
The Three-Party Settlement
Here's where the story takes a turn that even Milo wouldn't expect.
We didn't build Tollbooth to sell. We built it to give away — like the Massachusetts Turnpike Authority. The Authority doesn't operate every toll plaza. Independent operators run the booths. What the Authority does is simpler: it collects a small percentage of every fare that flows through infrastructure it designed.
When a user purchases credits, the settlement is three-party:
- Milo pays the operator's Lightning invoice
- The operator's BTCPay Server credits Milo's balance
- Automatically, in the background — BTCPay creates a small payout to the Tollbooth originator's Lightning Address
A royalty. Two percent of the fare. The operator sees it transparently in their BTCPay dashboard. Milo never knows it happened.
The enforcement is both technical and social. At startup, Tollbooth inspects the operator's BTCPay API key permissions. If the key lacks payout capability, Tollbooth refuses to start. Not a warning. A hard stop. The social contract, made executable.
The Economics
For Milo (the user): Nothing changes. Buy credits, use tools, drive the turnpike.
For the operator: A free, production-tested monetization framework. No license fee. The 2% royalty is a rounding error compared to the revenue you couldn't collect before. The tollbooth pays for itself on the first transaction.
For the ecosystem: Revenue scales with adoption, not effort. Every new MCP server that installs Tollbooth becomes a node in the Lightning economy. The infrastructure hums along — collecting its modest fare, maintaining the roads, and making sure the turnpike stays open for everyone.
It's the transition from mining fees to transaction fees. You stop competing on compute and start collecting on flow.
Reference Integration
thebrain-mcp — the first MCP server powered by Tollbooth. A FastMCP service that gives AI agents access to TheBrain knowledge graphs, with all 40+ tools metered via Tollbooth credits.
Architecture
Tollbooth is a three-party ecosystem:
| Repo | Role |
|---|---|
| tollbooth-authority | The institution — tax collection, EdDSA signing, purchase order certification |
| tollbooth-dpyc (this package) | The booth — operator-side credit ledger, BTCPay client, tool gating |
| thebrain-mcp | The first city — reference MCP server powered by Tollbooth |
See the Three-Party Protocol diagram for the full architecture.
tollbooth-authority tollbooth-dpyc (this package) your-mcp-server (consumer)
================================ ================================ ================================
EdDSA signing + tax ledger TollboothConfig Settings ──constructs──> TollboothConfig
certify_purchase → JWT UserLedger implements VaultBackend
Authority BTCPay BTCPayClient TOOL_COSTS maps tools to ToolTier
VaultBackend (Protocol)
LedgerCache + credit tools
Dependency flows one way: your-mcp-server --> tollbooth-dpyc. Authority is a network peer, not a code dependency. Only runtime dependency: httpx.
Development
git clone https://github.com/lonniev/tollbooth-dpyc.git
cd tollbooth-dpyc
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -q
Further Reading
The Phantom Tollbooth on the Lightning Turnpike — the full story of how we're monetizing the monetization of AI APIs, and then fading to the background.
License
Apache 2.0 — see LICENSE.
Because in the end, the tollbooth was never the destination. It was always just the beginning of the journey.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tollbooth_dpyc-0.1.2.tar.gz.
File metadata
- Download URL: tollbooth_dpyc-0.1.2.tar.gz
- Upload date:
- Size: 1.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07bc263ff754bc9da9c9a7f14b5a34e2ee8dec4ee963cefc404b6e1171cd984f
|
|
| MD5 |
5cf89a53c1a735be4d6bb7ec308fbf1d
|
|
| BLAKE2b-256 |
e10d330c5ec539d69f38bf7f7c805463d5a181bbd28c08608e5db79e94b12f9b
|
File details
Details for the file tollbooth_dpyc-0.1.2-py3-none-any.whl.
File metadata
- Download URL: tollbooth_dpyc-0.1.2-py3-none-any.whl
- Upload date:
- Size: 29.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3094c12eb587d70bdc6105a341003712c69dbc9a8eb11653a81aa30fcb9aa0e0
|
|
| MD5 |
36e12e065ef5e02e18e8104ff9e4f58d
|
|
| BLAKE2b-256 |
9c4794f5e037696add6fd789288f812dbd71cf68ef059d8e42f68c425696c404
|