loading…
Search for a command to run...
loading…
Minimal MCP server demonstrating L402 pay-per-call with Depth-of-Identity reputation gating, providing a bitcoin data tool that fetches BTC price and mempool fe
Minimal MCP server demonstrating L402 pay-per-call with Depth-of-Identity reputation gating, providing a bitcoin data tool that fetches BTC price and mempool fees.
Minimal MCP server showing @powforge/mcp-l402-gate in action.
One tool, bitcoin_data, fetches current BTC/USD price plus recommended mempool fees from mempool.space. Each call is gated by:
L402 alone proves a caller paid. L402 + DoI proves they paid and carry a per-pubkey reputation that survives across sessions and costs irreversible work to fake. That second half is the part most MCP billing kits skip.
git clone https://github.com/zekebuilds-lab/mcp-l402-gate-example
cd mcp-l402-gate-example
cp .env.example .env # fill in GATE_HMAC_SECRET and LNBits creds
npm install
npm start
Server logs the tool URL and oracle on boot. Default port is 3100.
First call has no auth, so the gate returns a 402 with an invoice:
curl -i -X POST http://localhost:3100/tools/bitcoin_data \
-H 'Content-Type: application/json' \
-H 'X-Caller-Pubkey: 02a1b2c3...your-hex-pubkey' \
-d '{}'
Expected response:
HTTP/1.1 402 Payment Required
WWW-Authenticate: L402 macaroon="...", invoice="lnbc1..."
Content-Type: application/json
{
"error": "payment required",
"macaroon": "...",
"invoice": "lnbc1...",
"payment_hash": "..."
}
Pay the invoice field (any LN wallet), capture the preimage, then retry:
curl -i -X POST http://localhost:3100/tools/bitcoin_data \
-H 'Content-Type: application/json' \
-H 'X-Caller-Pubkey: 02a1b2c3...your-hex-pubkey' \
-H 'Authorization: L402 <macaroon>:<preimage>' \
-d '{}'
You get back the BTC price, mempool fee estimates, and the caller's DoI score.
The manifest is also exposed for MCP clients that introspect tool catalogs:
curl http://localhost:3100/manifest.json
| Variable | Description | Required | Default |
|---|---|---|---|
GATE_HMAC_SECRET |
HMAC key for signing L402 macaroons. Generate with openssl rand -hex 32. |
yes | - |
LNBITS_URL |
Your LNBits instance base URL. | yes | - |
LNBITS_INVOICE_KEY |
LNBits invoice/read key. Never use the admin key. | yes | - |
ORACLE_URL |
DoI oracle base URL. | no | https://identity.powforge.dev |
PORT |
HTTP port. | no | 3100 |
SATS_AMOUNT |
Sats charged per call. | no | 1 |
MIN_SCORE |
Minimum DoI composite score to pass the gate. 0 disables identity gating. |
no | 0 |
These are the same buckets the oracle returns as rank. Pick the one that matches how expensive a wrong call is:
MIN_SCORE |
Rank | Fits |
|---|---|---|
| 0 | unknown | Pure paywall. Identity does not matter. |
| 10 | emerging | First-call abuse hurts. Sensible default for most public MCP tools. |
| 40 | active | The tool burns real GPU or has expensive side effects. |
| 100 | established | Compliance-sensitive or single-tenant SaaS-style endpoints. |
| 200 | trusted | High-trust admin tooling. |
Without the gate, a 402 + macaroon flow proves the caller paid 10 sats. A fresh attacker wallet pays the same 10 sats. That is fine wire format and weak abuse control.
@powforge/mcp-l402-gate keeps the L402 invoice and adds a second check: when the macaroon verifies, the gate calls the DoI oracle for the caller's pubkey, gets back a Schnorr-signed score, and compares to MIN_SCORE. The score is composed from observable irreversible work across four dimensions (social, access, vouch, economic), so a fresh sybil cannot grind it in a minute.
The full failure-mode table is in @powforge/mcp-l402-gate README.
server.js - the MCP server, ~110 lines..env.example - copy to .env and fill in.package.json - depends on express and @powforge/mcp-l402-gate.MIT.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"mcp-l402-gate-example": {
"command": "npx",
"args": []
}
}
}