402-mcp 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -1
- package/build/tools/nostr-subscribe.d.ts +5 -0
- package/build/tools/nostr-subscribe.js +7 -2
- package/build/tools/nostr-subscribe.js.map +1 -1
- package/build/tools/search.d.ts +2 -1
- package/build/tools/search.js +8 -11
- package/build/tools/search.js.map +1 -1
- package/llms-full.txt +399 -0
- package/llms.txt +148 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -9,6 +9,72 @@ L402 + x402 client MCP that gives AI agents economic agency. Discover, pay for,
|
|
|
9
9
|
|
|
10
10
|
Works with **any L402-compliant server** (toll-booth, Aperture, or any future implementation), with bonus features when talking to a [toll-booth](https://github.com/TheCryptoDonkey/toll-booth) instance.
|
|
11
11
|
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
graph TB
|
|
16
|
+
Agent["AI Agent<br/>(Claude, Cursor, etc.)"]
|
|
17
|
+
MCP["402-mcp<br/>MCP Server"]
|
|
18
|
+
|
|
19
|
+
subgraph Wallets["Payment Rails"]
|
|
20
|
+
NWC["NWC<br/>(Lightning)"]
|
|
21
|
+
Cashu["Cashu<br/>(Ecash)"]
|
|
22
|
+
Human["Human-in-the-loop<br/>(QR code)"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
subgraph Storage["Local Storage"]
|
|
26
|
+
Creds["Credential Store<br/>(AES-256-GCM)"]
|
|
27
|
+
Tokens["Cashu Token Store"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
subgraph Servers["Any L402 Server"]
|
|
31
|
+
TB["toll-booth"]
|
|
32
|
+
Aperture["Aperture"]
|
|
33
|
+
Other["Any L402<br/>implementation"]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Nostr["Nostr Relays<br/>(Service Discovery)"]
|
|
37
|
+
|
|
38
|
+
Agent <-->|"MCP protocol<br/>(stdio / HTTP)"| MCP
|
|
39
|
+
MCP --> NWC
|
|
40
|
+
MCP --> Cashu
|
|
41
|
+
MCP --> Human
|
|
42
|
+
MCP <--> Creds
|
|
43
|
+
MCP <--> Tokens
|
|
44
|
+
MCP <-->|"HTTP + L402"| TB
|
|
45
|
+
MCP <-->|"HTTP + L402"| Aperture
|
|
46
|
+
MCP <-->|"HTTP + L402"| Other
|
|
47
|
+
MCP <-->|"kind 31402"| Nostr
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Payment flow
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
sequenceDiagram
|
|
54
|
+
participant Agent as AI Agent
|
|
55
|
+
participant MCP as 402-mcp
|
|
56
|
+
participant API as L402 API
|
|
57
|
+
participant Wallet as Wallet (NWC/Cashu)
|
|
58
|
+
|
|
59
|
+
Agent->>MCP: l402_discover(url)
|
|
60
|
+
MCP->>API: GET /endpoint
|
|
61
|
+
API-->>MCP: 402 + invoice + macaroon
|
|
62
|
+
MCP-->>Agent: price: 10 sats, server: toll-booth
|
|
63
|
+
|
|
64
|
+
Agent->>Agent: Reason about pricing
|
|
65
|
+
|
|
66
|
+
Agent->>MCP: l402_fetch(url)
|
|
67
|
+
MCP->>API: GET /endpoint
|
|
68
|
+
API-->>MCP: 402 + invoice + macaroon
|
|
69
|
+
MCP->>MCP: Amount ≤ MAX_AUTO_PAY_SATS?
|
|
70
|
+
MCP->>Wallet: Pay invoice
|
|
71
|
+
Wallet-->>MCP: preimage
|
|
72
|
+
MCP->>MCP: Store credential
|
|
73
|
+
MCP->>API: GET /endpoint + Authorization: L402
|
|
74
|
+
API-->>MCP: 200 OK + data
|
|
75
|
+
MCP-->>Agent: Response data + balance
|
|
76
|
+
```
|
|
77
|
+
|
|
12
78
|
## Quick start
|
|
13
79
|
|
|
14
80
|
```bash
|
|
@@ -57,6 +123,7 @@ Add to your MCP configuration:
|
|
|
57
123
|
| `l402_pay` | Pay a specific invoice (NWC, Cashu, or human-in-the-loop) |
|
|
58
124
|
| `l402_credentials` | List stored credentials and cached balances |
|
|
59
125
|
| `l402_balance` | Check cached credit balance for a server |
|
|
126
|
+
| `l402_search` | Discover L402 services on Nostr relays (kind 31402 announcements) |
|
|
60
127
|
|
|
61
128
|
### toll-booth extensions
|
|
62
129
|
|
|
@@ -65,8 +132,36 @@ Add to your MCP configuration:
|
|
|
65
132
|
| `l402_buy_credits` | Browse and purchase volume discount tiers |
|
|
66
133
|
| `l402_redeem_cashu` | Redeem Cashu tokens directly (avoids Lightning round-trip) |
|
|
67
134
|
|
|
135
|
+
## Service discovery
|
|
136
|
+
|
|
137
|
+
Agents can discover paid APIs without knowing URLs upfront. `l402_search` queries Nostr relays for kind 31402 service announcements — the decentralised registry for L402 services.
|
|
138
|
+
|
|
139
|
+
```mermaid
|
|
140
|
+
sequenceDiagram
|
|
141
|
+
participant Agent as AI Agent
|
|
142
|
+
participant MCP as 402-mcp
|
|
143
|
+
participant Relay as Nostr Relays
|
|
144
|
+
|
|
145
|
+
Agent->>MCP: l402_search("routing")
|
|
146
|
+
MCP->>Relay: Subscribe kind 31402
|
|
147
|
+
Relay-->>MCP: Matching service events
|
|
148
|
+
MCP-->>Agent: Services with URLs, pricing, capabilities
|
|
149
|
+
Agent->>MCP: l402_discover(service_url)
|
|
150
|
+
Note over Agent: Continue with payment flow...
|
|
151
|
+
```
|
|
152
|
+
|
|
68
153
|
## Payment methods
|
|
69
154
|
|
|
155
|
+
```mermaid
|
|
156
|
+
graph TD
|
|
157
|
+
Pay["Pay Invoice"]
|
|
158
|
+
Pay --> NWC{"NWC configured?"}
|
|
159
|
+
NWC -->|Yes| NWCPay["Pay via Lightning wallet<br/>(fully autonomous)"]
|
|
160
|
+
NWC -->|No| CashuQ{"Cashu tokens<br/>available?"}
|
|
161
|
+
CashuQ -->|Yes| CashuPay["Melt ecash tokens<br/>(fully autonomous)"]
|
|
162
|
+
CashuQ -->|No| HumanPay["Present QR code<br/>(human pays)"]
|
|
163
|
+
```
|
|
164
|
+
|
|
70
165
|
Three payment rails, tried in priority order:
|
|
71
166
|
|
|
72
167
|
1. **NWC** (Nostr Wallet Connect) - fully autonomous; pays from your connected wallet
|
|
@@ -77,6 +172,17 @@ The agent can override the method per-call, or you can configure only the method
|
|
|
77
172
|
|
|
78
173
|
## How it works
|
|
79
174
|
|
|
175
|
+
```mermaid
|
|
176
|
+
graph LR
|
|
177
|
+
A["1. l402_config()"] --> B["2. l402_discover(url)"]
|
|
178
|
+
B --> C["3. Agent reasons<br/>about pricing"]
|
|
179
|
+
C --> D["4. l402_buy_credits()<br/>or l402_fetch()"]
|
|
180
|
+
D --> E["5. l402_fetch(url)<br/>with credentials"]
|
|
181
|
+
E --> F["6. Data returned<br/>+ balance cached"]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Example session:**
|
|
185
|
+
|
|
80
186
|
```
|
|
81
187
|
Agent: "I need routing data from routing.trotters.cc"
|
|
82
188
|
|
|
@@ -125,7 +231,8 @@ Use Lightning Labs' tools if you want agents that **run their own Lightning node
|
|
|
125
231
|
|---------|------|
|
|
126
232
|
| [toll-booth](https://github.com/TheCryptoDonkey/toll-booth) | Payment-rail agnostic HTTP 402 middleware |
|
|
127
233
|
| [satgate](https://github.com/TheCryptoDonkey/satgate) | Pay-per-token AI inference proxy (built on toll-booth) |
|
|
128
|
-
| **[402-mcp](https://github.com/TheCryptoDonkey/402-mcp)** | **MCP client
|
|
234
|
+
| **[402-mcp](https://github.com/TheCryptoDonkey/402-mcp)** | **MCP client — AI agents discover, pay, and consume L402 + x402 APIs** |
|
|
235
|
+
| [402-announce](https://github.com/TheCryptoDonkey/402-announce) | Publish L402 services on Nostr for decentralised discovery |
|
|
129
236
|
|
|
130
237
|
---
|
|
131
238
|
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import type { SearchDeps } from './search.js';
|
|
2
|
+
/** Optional tag filters to pass to relays, reducing bandwidth by filtering server-side. */
|
|
3
|
+
export interface SubscribeFilters {
|
|
4
|
+
'#t'?: string[];
|
|
5
|
+
'#pmi'?: string[];
|
|
6
|
+
}
|
|
2
7
|
export declare function createNostrSubscriber(): SearchDeps['subscribeEvents'];
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
const MAX_EVENTS = 1000;
|
|
7
7
|
export function createNostrSubscriber() {
|
|
8
|
-
return async (relays, kinds, timeout) => {
|
|
8
|
+
return async (relays, kinds, timeout, filters) => {
|
|
9
9
|
const { Relay } = await import('nostr-tools/relay');
|
|
10
10
|
const { verifyEvent } = await import('nostr-tools/pure');
|
|
11
11
|
const events = [];
|
|
@@ -21,7 +21,12 @@ export function createNostrSubscriber() {
|
|
|
21
21
|
]);
|
|
22
22
|
connections.push(relay);
|
|
23
23
|
return new Promise((resolve) => {
|
|
24
|
-
const
|
|
24
|
+
const filter = { kinds };
|
|
25
|
+
if (filters?.['#t']?.length)
|
|
26
|
+
filter['#t'] = filters['#t'];
|
|
27
|
+
if (filters?.['#pmi']?.length)
|
|
28
|
+
filter['#pmi'] = filters['#pmi'];
|
|
29
|
+
const sub = relay.subscribe([filter], {
|
|
25
30
|
onevent: (event) => {
|
|
26
31
|
if (events.length < MAX_EVENTS && verifyEvent(event)) {
|
|
27
32
|
events.push(event);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nostr-subscribe.js","sourceRoot":"","sources":["../../src/tools/nostr-subscribe.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,UAAU,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"nostr-subscribe.js","sourceRoot":"","sources":["../../src/tools/nostr-subscribe.ts"],"names":[],"mappings":"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"}
|
package/build/tools/search.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { NostrEvent } from 'nostr-tools/core';
|
|
3
|
+
import type { SubscribeFilters } from './nostr-subscribe.js';
|
|
3
4
|
export interface SearchDeps {
|
|
4
|
-
subscribeEvents: (relays: string[], kinds: number[], timeout: number) => Promise<NostrEvent[]>;
|
|
5
|
+
subscribeEvents: (relays: string[], kinds: number[], timeout: number, filters?: SubscribeFilters) => Promise<NostrEvent[]>;
|
|
5
6
|
}
|
|
6
7
|
export interface ParsedService {
|
|
7
8
|
name: string | undefined;
|
package/build/tools/search.js
CHANGED
|
@@ -50,9 +50,15 @@ export async function handleSearch(args, deps) {
|
|
|
50
50
|
const timeout = args.timeout ?? 5000;
|
|
51
51
|
const maxResults = args.maxResults ?? 20;
|
|
52
52
|
const queryLower = args.query.toLowerCase();
|
|
53
|
-
|
|
53
|
+
// Build relay-side tag filters — relays handle topic and payment method filtering
|
|
54
|
+
const relayFilters = {};
|
|
55
|
+
if (args.topics?.length)
|
|
56
|
+
relayFilters['#t'] = args.topics;
|
|
57
|
+
if (args.paymentMethod)
|
|
58
|
+
relayFilters['#pmi'] = [args.paymentMethod];
|
|
59
|
+
const events = await deps.subscribeEvents(relays, [KIND_L402_ANNOUNCE], timeout, relayFilters);
|
|
54
60
|
let services = events.map(parseAnnounceEvent);
|
|
55
|
-
// Filter by query text —
|
|
61
|
+
// Filter by query text — relays cannot do substring search so this remains client-side
|
|
56
62
|
if (queryLower) {
|
|
57
63
|
services = services.filter(svc => {
|
|
58
64
|
const searchable = [
|
|
@@ -64,15 +70,6 @@ export async function handleSearch(args, deps) {
|
|
|
64
70
|
return searchable.includes(queryLower);
|
|
65
71
|
});
|
|
66
72
|
}
|
|
67
|
-
// Filter by payment method
|
|
68
|
-
if (args.paymentMethod) {
|
|
69
|
-
services = services.filter(svc => svc.paymentMethods.includes(args.paymentMethod));
|
|
70
|
-
}
|
|
71
|
-
// Filter by topics — service must have at least one matching topic
|
|
72
|
-
if (args.topics && args.topics.length > 0) {
|
|
73
|
-
const topicSet = new Set(args.topics.map(t => t.toLowerCase()));
|
|
74
|
-
services = services.filter(svc => svc.topics.some(t => topicSet.has(t.toLowerCase())));
|
|
75
|
-
}
|
|
76
73
|
// Limit results
|
|
77
74
|
const results = services.slice(0, maxResults);
|
|
78
75
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
package/llms-full.txt
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# 402-mcp — Full Technical Reference
|
|
2
|
+
|
|
3
|
+
> For a concise overview, see [llms.txt](llms.txt). This document provides the complete technical reference for integrating with, building on, or contributing to 402-mcp.
|
|
4
|
+
|
|
5
|
+
## What is 402-mcp?
|
|
6
|
+
|
|
7
|
+
402-mcp is an MCP (Model Context Protocol) server that gives AI agents economic agency — the ability to discover, pay for, and consume any L402 or x402 payment-gated API without human registration, API keys, or middlemen.
|
|
8
|
+
|
|
9
|
+
It implements the client side of the L402 protocol: when an API responds with HTTP 402 (Payment Required), 402-mcp automatically parses the challenge, pays the Lightning invoice, stores the credential, and retries the request — all within a single tool call from the agent's perspective.
|
|
10
|
+
|
|
11
|
+
## Architecture Overview
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
15
|
+
│ AI Agent (Claude, Cursor, GPT, custom) │
|
|
16
|
+
│ Communicates via MCP protocol (stdio or HTTP transport) │
|
|
17
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
18
|
+
│ MCP tool calls
|
|
19
|
+
┌──────────────────────▼──────────────────────────────────────┐
|
|
20
|
+
│ 402-mcp MCP Server │
|
|
21
|
+
│ │
|
|
22
|
+
│ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
|
|
23
|
+
│ │ Tools │ │ Wallets │ │ Stores │ │
|
|
24
|
+
│ │ │ │ │ │ │ │
|
|
25
|
+
│ │ config │ │ NWC │ │ Credentials │ │
|
|
26
|
+
│ │ discover │ │ Cashu │ │ (AES-256) │ │
|
|
27
|
+
│ │ fetch │ │ Human │ │ │ │
|
|
28
|
+
│ │ pay │ │ │ │ Cashu │ │
|
|
29
|
+
│ │ creds │ │ │ │ Tokens │ │
|
|
30
|
+
│ │ balance │ │ │ │ │ │
|
|
31
|
+
│ │ search │ │ │ │ │ │
|
|
32
|
+
│ │ buy_cred │ │ │ │ │ │
|
|
33
|
+
│ │ redeem │ │ │ │ │ │
|
|
34
|
+
│ └──────────┘ └──────────┘ └─────────────┘ │
|
|
35
|
+
│ │
|
|
36
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
|
37
|
+
│ │ L402 Protocol│ │ Resilient │ │ Spend │ │
|
|
38
|
+
│ │ parse, detect│ │ Fetch │ │ Tracker │ │
|
|
39
|
+
│ │ cache, bolt11│ │ SSRF, retry │ │ atomic caps │ │
|
|
40
|
+
│ └──────────────┘ └──────────────┘ └───────────────┘ │
|
|
41
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
42
|
+
│ HTTP + L402 / Nostr
|
|
43
|
+
┌─────────────┼─────────────┐
|
|
44
|
+
▼ ▼ ▼
|
|
45
|
+
┌─────────┐ ┌──────────┐ ┌──────────┐
|
|
46
|
+
│toll-booth│ │ Aperture │ │ Nostr │
|
|
47
|
+
│ server │ │ server │ │ Relays │
|
|
48
|
+
└─────────┘ └──────────┘ └──────────┘
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Source Structure
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/
|
|
55
|
+
index.ts # Entry point: config, wiring, transport setup
|
|
56
|
+
config.ts # Environment variable parsing with validation
|
|
57
|
+
spend-tracker.ts # Atomic rolling-window spend limiter
|
|
58
|
+
tools/
|
|
59
|
+
config.ts # l402_config — introspect capabilities
|
|
60
|
+
discover.ts # l402_discover — probe pricing without paying
|
|
61
|
+
fetch.ts # l402_fetch — full L402 payment flow
|
|
62
|
+
pay.ts # l402_pay — explicit invoice payment
|
|
63
|
+
credentials.ts # l402_credentials — list stored credentials
|
|
64
|
+
balance.ts # l402_balance — check cached credit balance
|
|
65
|
+
search.ts # l402_search — discover services on Nostr
|
|
66
|
+
buy-credits.ts # l402_buy_credits — toll-booth credit tiers
|
|
67
|
+
redeem-cashu.ts # l402_redeem_cashu — direct ecash redemption
|
|
68
|
+
nostr-subscribe.ts # Nostr relay subscription for search
|
|
69
|
+
safe-error.ts # Error sanitisation (strips internal details)
|
|
70
|
+
safe-headers.ts # Header sanitisation (strips auth tokens)
|
|
71
|
+
wallet/
|
|
72
|
+
types.ts # WalletProvider interface
|
|
73
|
+
resolve.ts # Priority-ordered wallet resolution
|
|
74
|
+
nwc.ts # NWC (Nostr Wallet Connect) implementation
|
|
75
|
+
cashu.ts # Cashu ecash melt implementation
|
|
76
|
+
human.ts # Human-in-the-loop (QR code + polling)
|
|
77
|
+
l402/
|
|
78
|
+
parse.ts # Parse WWW-Authenticate L402 challenges
|
|
79
|
+
detect.ts # Detect toll-booth vs generic L402 servers
|
|
80
|
+
bolt11.ts # Decode BOLT11 invoices (amount extraction)
|
|
81
|
+
challenge-cache.ts # Cache parsed challenges for l402_pay
|
|
82
|
+
store/
|
|
83
|
+
credentials.ts # Encrypted credential persistence (JSON)
|
|
84
|
+
cashu-tokens.ts # Cashu token store (add/remove/balance)
|
|
85
|
+
encryption.ts # AES-256-GCM encryption (keychain or file key)
|
|
86
|
+
fetch/
|
|
87
|
+
resilient-fetch.ts # Timeout, retry, response size limits
|
|
88
|
+
ssrf-guard.ts # Block requests to private/internal IPs
|
|
89
|
+
errors.ts # Fetch error types
|
|
90
|
+
tests/ # Mirrors src/ structure
|
|
91
|
+
e2e/ # Integration tests against in-process toll-booth
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Complete Tool Reference
|
|
95
|
+
|
|
96
|
+
### l402_config
|
|
97
|
+
|
|
98
|
+
**Purpose:** Introspect the agent's payment capabilities and current configuration.
|
|
99
|
+
|
|
100
|
+
**Parameters:** None.
|
|
101
|
+
|
|
102
|
+
**Returns:**
|
|
103
|
+
- `nwcConfigured` (boolean) — whether an NWC wallet URI is set
|
|
104
|
+
- `cashuConfigured` (boolean) — whether Cashu tokens are loaded with balance > 0
|
|
105
|
+
- `cashuBalanceSats` (number) — total Cashu token balance in satoshis
|
|
106
|
+
- `maxAutoPaySats` (number) — per-payment safety cap
|
|
107
|
+
- `credentialCount` (number) — number of stored L402 credentials
|
|
108
|
+
|
|
109
|
+
**When to use:** Call first in any session to understand what the agent can do autonomously.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### l402_discover
|
|
114
|
+
|
|
115
|
+
**Purpose:** Probe an endpoint to discover pricing without paying.
|
|
116
|
+
|
|
117
|
+
**Parameters:**
|
|
118
|
+
- `url` (string, required) — the endpoint to probe
|
|
119
|
+
- `method` (string, optional) — HTTP method (default: GET)
|
|
120
|
+
- `headers` (object, optional) — additional headers
|
|
121
|
+
|
|
122
|
+
**Returns:**
|
|
123
|
+
- `amountSats` (number) — price in satoshis
|
|
124
|
+
- `server` (string) — detected server type ("toll-booth" or null)
|
|
125
|
+
- `hasTiers` (boolean) — whether credit tiers are available
|
|
126
|
+
- `challenge` — cached for subsequent `l402_pay`
|
|
127
|
+
|
|
128
|
+
**When to use:** Before committing to a purchase, so the agent can reason about value.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### l402_fetch
|
|
133
|
+
|
|
134
|
+
**Purpose:** Make an HTTP request with automatic L402 payment handling.
|
|
135
|
+
|
|
136
|
+
**Parameters:**
|
|
137
|
+
- `url` (string, required) — the endpoint to fetch
|
|
138
|
+
- `method` (string, optional) — HTTP method (default: GET)
|
|
139
|
+
- `headers` (object, optional) — additional headers
|
|
140
|
+
- `body` (string, optional) — request body
|
|
141
|
+
- `paymentMethod` (string, optional) — force a specific payment rail
|
|
142
|
+
|
|
143
|
+
**Behaviour:**
|
|
144
|
+
1. Checks for existing credential for the origin
|
|
145
|
+
2. Makes the HTTP request (with credential if available)
|
|
146
|
+
3. If 402 received: parses challenge, checks amount against `MAX_AUTO_PAY_SATS` and rolling spend cap
|
|
147
|
+
4. If within budget: pays invoice, stores credential, retries request
|
|
148
|
+
5. If over budget: returns the price and asks for human approval
|
|
149
|
+
6. Returns response body, status, headers, and remaining credit balance
|
|
150
|
+
|
|
151
|
+
**When to use:** Primary tool for consuming L402 APIs. Handles the entire flow.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### l402_pay
|
|
156
|
+
|
|
157
|
+
**Purpose:** Pay a specific Lightning invoice.
|
|
158
|
+
|
|
159
|
+
**Parameters:**
|
|
160
|
+
- `invoice` (string, required) — BOLT11 invoice to pay
|
|
161
|
+
- `paymentMethod` (string, optional) — force a specific payment rail
|
|
162
|
+
- `challengeId` (string, optional) — ID from a previous `l402_discover` to associate the payment
|
|
163
|
+
|
|
164
|
+
**Returns:**
|
|
165
|
+
- `paid` (boolean)
|
|
166
|
+
- `preimage` (string) — payment proof
|
|
167
|
+
- `method` (string) — which wallet paid
|
|
168
|
+
|
|
169
|
+
**When to use:** When you have an invoice from a non-L402 source, or want explicit control.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### l402_credentials
|
|
174
|
+
|
|
175
|
+
**Purpose:** List all stored L402 credentials.
|
|
176
|
+
|
|
177
|
+
**Parameters:** None.
|
|
178
|
+
|
|
179
|
+
**Returns:** Array of credentials with:
|
|
180
|
+
- `origin` — server origin
|
|
181
|
+
- `creditBalance` — cached balance (if known)
|
|
182
|
+
- `server` — detected server type
|
|
183
|
+
- `storedAt` / `lastUsed` — timestamps
|
|
184
|
+
|
|
185
|
+
**When to use:** Auditing spend, checking which servers have been paid.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### l402_balance
|
|
190
|
+
|
|
191
|
+
**Purpose:** Check cached credit balance for a server.
|
|
192
|
+
|
|
193
|
+
**Parameters:**
|
|
194
|
+
- `url` (string, required) — server URL to check
|
|
195
|
+
|
|
196
|
+
**Returns:**
|
|
197
|
+
- `balance` (number | null) — credits remaining, or null if unknown
|
|
198
|
+
|
|
199
|
+
**When to use:** Before calling `l402_fetch` to confirm sufficient balance.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### l402_search
|
|
204
|
+
|
|
205
|
+
**Purpose:** Discover L402 services on Nostr relays.
|
|
206
|
+
|
|
207
|
+
**Parameters:**
|
|
208
|
+
- `query` (string, required) — search text to match against service names, descriptions, capabilities
|
|
209
|
+
- `relays` (string[], optional) — Nostr relay URLs (defaults to damus, primal, nos.lol)
|
|
210
|
+
- `topics` (string[], optional) — filter by topic tags (e.g. ["ai", "data"])
|
|
211
|
+
- `paymentMethod` (string, optional) — filter by payment method (e.g. "bitcoin-lightning-bolt11")
|
|
212
|
+
- `maxResults` (number, optional) — max results (default 20)
|
|
213
|
+
- `timeout` (number, optional) — relay timeout in ms (default 5000)
|
|
214
|
+
|
|
215
|
+
**Returns:** Array of services with:
|
|
216
|
+
- `name`, `url`, `about` — service metadata
|
|
217
|
+
- `pricing` — array of `{ capability, amount, unit }`
|
|
218
|
+
- `paymentMethods` — supported payment methods
|
|
219
|
+
- `topics` — topic tags
|
|
220
|
+
- `capabilities` — array of `{ name, description }`
|
|
221
|
+
|
|
222
|
+
**When to use:** When the agent needs a paid API but doesn't know the URL. Searches the decentralised Nostr network for kind 31402 service announcements.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### l402_buy_credits (toll-booth only)
|
|
227
|
+
|
|
228
|
+
**Purpose:** Browse and purchase volume discount credit tiers.
|
|
229
|
+
|
|
230
|
+
**Parameters:**
|
|
231
|
+
- `url` (string, required) — toll-booth server URL
|
|
232
|
+
- `amountSats` (number, optional) — specific tier to purchase
|
|
233
|
+
- `paymentMethod` (string, optional) — force a specific payment rail
|
|
234
|
+
|
|
235
|
+
**Behaviour:** Fetches available tiers, purchases the specified tier, stores the credential with the credit balance.
|
|
236
|
+
|
|
237
|
+
**When to use:** When multiple requests are needed — buying a tier upfront is cheaper than paying per-request.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### l402_redeem_cashu (toll-booth only)
|
|
242
|
+
|
|
243
|
+
**Purpose:** Redeem Cashu ecash tokens directly with the server.
|
|
244
|
+
|
|
245
|
+
**Parameters:**
|
|
246
|
+
- `url` (string, required) — toll-booth server URL
|
|
247
|
+
- `token` (string, required) — Cashu token to redeem
|
|
248
|
+
|
|
249
|
+
**Behaviour:** Sends the raw Cashu token to the toll-booth's redemption endpoint. The server credits the balance immediately without a Lightning round-trip.
|
|
250
|
+
|
|
251
|
+
**When to use:** When both agent and server support Cashu — faster and cheaper than melting tokens to pay an invoice.
|
|
252
|
+
|
|
253
|
+
## L402 Protocol Flow
|
|
254
|
+
|
|
255
|
+
The L402 protocol is an extension of HTTP 402 (Payment Required):
|
|
256
|
+
|
|
257
|
+
1. **Client** sends a request to a protected endpoint
|
|
258
|
+
2. **Server** responds with `402 Payment Required` and headers:
|
|
259
|
+
- `WWW-Authenticate: L402 macaroon="<base64>", invoice="<bolt11>"`
|
|
260
|
+
3. **Client** decodes the BOLT11 invoice, pays it via Lightning, receives a preimage
|
|
261
|
+
4. **Client** retries the request with:
|
|
262
|
+
- `Authorization: L402 <base64-macaroon>:<hex-preimage>`
|
|
263
|
+
5. **Server** validates the macaroon + preimage and returns the data
|
|
264
|
+
|
|
265
|
+
402-mcp handles steps 2–5 automatically within `l402_fetch`.
|
|
266
|
+
|
|
267
|
+
## Wallet Priority and Resolution
|
|
268
|
+
|
|
269
|
+
Wallets are tried in order: NWC → Cashu → Human. The first wallet that succeeds is used.
|
|
270
|
+
|
|
271
|
+
| Wallet | Autonomy | Requirements | Speed |
|
|
272
|
+
|--------|----------|-------------|-------|
|
|
273
|
+
| NWC | Fully autonomous | `NWC_URI` env var pointing to a Lightning wallet | ~2-5 seconds |
|
|
274
|
+
| Cashu | Fully autonomous | `CASHU_TOKENS` file with ecash tokens | ~3-8 seconds |
|
|
275
|
+
| Human | Requires human | None — always available as fallback | Minutes |
|
|
276
|
+
|
|
277
|
+
The agent can force a specific method per-call using the `paymentMethod` parameter.
|
|
278
|
+
|
|
279
|
+
## Safety and Spend Limits
|
|
280
|
+
|
|
281
|
+
### Per-payment cap
|
|
282
|
+
|
|
283
|
+
`MAX_AUTO_PAY_SATS` (default: 1000) caps any single payment. If an invoice exceeds this:
|
|
284
|
+
- The agent is told the price and asked to seek human approval
|
|
285
|
+
- The human wallet (QR code) is used for the actual payment
|
|
286
|
+
- The credential is stored normally after payment
|
|
287
|
+
|
|
288
|
+
### Rolling spend cap
|
|
289
|
+
|
|
290
|
+
`MAX_SPEND_PER_MINUTE_SATS` (default: 10000) caps total spend in any 60-second window. This prevents:
|
|
291
|
+
- Rapid successive small payments exceeding a total budget
|
|
292
|
+
- Runaway loops where the agent keeps buying credits
|
|
293
|
+
- Both caps use atomic `tryRecord()` to prevent TOCTOU race conditions
|
|
294
|
+
|
|
295
|
+
### SSRF Protection
|
|
296
|
+
|
|
297
|
+
All outbound HTTP requests pass through an SSRF guard:
|
|
298
|
+
- Blocks requests to private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, ::1)
|
|
299
|
+
- Blocks requests to link-local, loopback, and metadata service IPs
|
|
300
|
+
- `SSRF_ALLOW_PRIVATE=true` disables this for local development only
|
|
301
|
+
|
|
302
|
+
### Credential Security
|
|
303
|
+
|
|
304
|
+
- Credentials encrypted with AES-256-GCM
|
|
305
|
+
- Encryption key stored in OS keychain (macOS Keychain, Windows Credential Vault, Linux Secret Service) when available
|
|
306
|
+
- Falls back to file-based key at `~/.402-mcp/encryption.key` with a console warning
|
|
307
|
+
- Preimages validated as hex before storage to prevent header injection
|
|
308
|
+
- Credential store path must be within the home directory (path traversal protection)
|
|
309
|
+
|
|
310
|
+
## Transport Modes
|
|
311
|
+
|
|
312
|
+
### stdio (default)
|
|
313
|
+
|
|
314
|
+
Standard MCP transport — used by Claude Desktop, Cursor, and most MCP clients. The server reads JSON-RPC from stdin and writes to stdout.
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npx 402-mcp
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### HTTP
|
|
321
|
+
|
|
322
|
+
StreamableHTTP transport for network access. Useful for remote agents, multi-client setups, or deployment behind a reverse proxy.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
TRANSPORT=http PORT=3402 npx 402-mcp
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
HTTP transport includes:
|
|
329
|
+
- Rate limiting: 100 requests per 60 seconds per IP
|
|
330
|
+
- Security headers: CSP, X-Frame-Options, X-Content-Type-Options, Cache-Control
|
|
331
|
+
- Loopback-only binding by default (`BIND_ADDRESS=127.0.0.1`)
|
|
332
|
+
- Health endpoint at `GET /health`
|
|
333
|
+
- Graceful shutdown on SIGTERM/SIGINT
|
|
334
|
+
|
|
335
|
+
## Configuration Reference
|
|
336
|
+
|
|
337
|
+
| Variable | Default | Description |
|
|
338
|
+
|----------|---------|-------------|
|
|
339
|
+
| `NWC_URI` | — | Nostr Wallet Connect URI for autonomous Lightning payments. Cleared from env after reading. |
|
|
340
|
+
| `CASHU_TOKENS` | — | Path to Cashu token store file. Must be within home directory. |
|
|
341
|
+
| `MAX_AUTO_PAY_SATS` | 1000 | Per-payment safety cap (satoshis). 0 disables autonomous payments. |
|
|
342
|
+
| `MAX_SPEND_PER_MINUTE_SATS` | 10000 | Rolling 60-second spend cap (satoshis). |
|
|
343
|
+
| `CREDENTIAL_STORE` | `~/.402-mcp/credentials.json` | Path to encrypted credential store. Must be within home directory. |
|
|
344
|
+
| `TRANSPORT` | `stdio` | Transport mode: `stdio` or `http`. |
|
|
345
|
+
| `PORT` | 3402 | HTTP server port (when `TRANSPORT=http`). |
|
|
346
|
+
| `BIND_ADDRESS` | `127.0.0.1` | HTTP bind address. Warning emitted for non-loopback addresses. |
|
|
347
|
+
| `CORS_ORIGIN` | disabled | CORS origin for HTTP transport. |
|
|
348
|
+
| `FETCH_TIMEOUT_MS` | 30000 | HTTP request timeout in milliseconds. |
|
|
349
|
+
| `FETCH_MAX_RETRIES` | 2 | Maximum retry attempts for failed requests. Money-mutating POSTs use 0. |
|
|
350
|
+
| `FETCH_MAX_RESPONSE_BYTES` | 10485760 | Maximum response body size (10 MB). |
|
|
351
|
+
| `HUMAN_PAY_TIMEOUT_S` | 600 | Timeout for human payment (seconds). |
|
|
352
|
+
| `HUMAN_PAY_POLL_S` | 3 | Initial polling interval for human payment (seconds). |
|
|
353
|
+
| `SSRF_ALLOW_PRIVATE` | false | Allow requests to private IP ranges. Local development only. |
|
|
354
|
+
| `NODE_TLS_REJECT_UNAUTHORIZED` | — | Warning emitted if set to "0" (disables TLS validation). |
|
|
355
|
+
|
|
356
|
+
## Ecosystem
|
|
357
|
+
|
|
358
|
+
| Project | Role | URL |
|
|
359
|
+
|---------|------|-----|
|
|
360
|
+
| **402-mcp** | MCP client — AI agents discover, pay, and consume L402 APIs | https://github.com/TheCryptoDonkey/402-mcp |
|
|
361
|
+
| **toll-booth** | L402 payment middleware for any Node.js server | https://github.com/TheCryptoDonkey/toll-booth |
|
|
362
|
+
| **satgate** | Pay-per-token AI inference proxy (built on toll-booth) | https://github.com/TheCryptoDonkey/satgate |
|
|
363
|
+
| **402-announce** | Publish L402 services on Nostr for decentralised discovery | https://github.com/TheCryptoDonkey/402-announce |
|
|
364
|
+
|
|
365
|
+
## Integration Patterns
|
|
366
|
+
|
|
367
|
+
### Agent discovers and consumes a paid API
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
1. l402_config() → Understand capabilities
|
|
371
|
+
2. l402_search("routing") → Find services on Nostr
|
|
372
|
+
3. l402_discover(service_url) → Check pricing
|
|
373
|
+
4. l402_fetch(service_url, ...) → Pay and consume
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Agent buys credits for repeated access
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
1. l402_discover(url) → Detect toll-booth, check tiers
|
|
380
|
+
2. l402_buy_credits(url, 500) → Buy 500-sat tier (555 credits)
|
|
381
|
+
3. l402_fetch(url, ...) × N → Use credits (no payment per-request)
|
|
382
|
+
4. l402_balance(url) → Check remaining credits
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Agent redeems Cashu tokens directly
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
1. l402_discover(url) → Confirm toll-booth server
|
|
389
|
+
2. l402_redeem_cashu(url, token) → Direct ecash redemption
|
|
390
|
+
3. l402_fetch(url, ...) → Use credits from redemption
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Agent with no wallet (human-in-the-loop)
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
1. l402_fetch(url) → 402 received, amount shown
|
|
397
|
+
2. Agent presents QR code to user → Human pays via wallet app
|
|
398
|
+
3. Poll detects payment → Credential stored, data returned
|
|
399
|
+
```
|
package/llms.txt
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# 402-mcp
|
|
2
|
+
|
|
3
|
+
> 402-mcp is an MCP server that gives AI agents economic agency — the ability to discover, pay for, and consume any L402 or x402 payment-gated API without human registration, API keys, or middlemen. It speaks the L402 protocol natively, carries its own payment methods, and makes autonomous purchasing decisions within human-set safety limits.
|
|
4
|
+
|
|
5
|
+
402-mcp is protocol-loyal: it works with any L402-compliant server (toll-booth, Aperture, or any conforming implementation), not just a specific vendor's stack. Bonus features activate automatically when talking to a toll-booth server. Three payment rails are supported — NWC (Nostr Wallet Connect), Cashu ecash, and human-in-the-loop — tried in that priority order so the agent picks the most autonomous option available.
|
|
6
|
+
|
|
7
|
+
Agents can also discover paid APIs without knowing URLs upfront. The `l402_search` tool queries Nostr relays for kind 31402 service announcements — a decentralised registry of L402-enabled services.
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
|
|
11
|
+
Run instantly with no configuration required:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx 402-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For HTTP transport (useful for remote agents or multi-client setups):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
TRANSPORT=http npx 402-mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Claude Desktop / Cursor
|
|
24
|
+
|
|
25
|
+
Add to your MCP configuration:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"l402": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["402-mcp"],
|
|
33
|
+
"env": {
|
|
34
|
+
"NWC_URI": "nostr+walletconnect://...",
|
|
35
|
+
"MAX_AUTO_PAY_SATS": "1000"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Configuration
|
|
43
|
+
|
|
44
|
+
| Variable | Default | Description |
|
|
45
|
+
|----------|---------|-------------|
|
|
46
|
+
| `NWC_URI` | — | Nostr Wallet Connect URI for autonomous Lightning payments |
|
|
47
|
+
| `CASHU_TOKENS` | — | Path to Cashu token store file |
|
|
48
|
+
| `MAX_AUTO_PAY_SATS` | 1000 | Safety cap; payments above this require human confirmation |
|
|
49
|
+
| `MAX_SPEND_PER_MINUTE_SATS` | 10000 | Rolling 60-second spend cap across all payments |
|
|
50
|
+
| `CREDENTIAL_STORE` | `~/.402-mcp/credentials.json` | Persistent macaroon/credential storage |
|
|
51
|
+
| `TRANSPORT` | `stdio` | Transport mode: `stdio` or `http` |
|
|
52
|
+
| `PORT` | 3402 | HTTP server port (when `TRANSPORT=http`) |
|
|
53
|
+
|
|
54
|
+
## Key Concepts
|
|
55
|
+
|
|
56
|
+
- **L402** — an HTTP payment protocol where a server responds to unauthenticated requests with HTTP 402, a Lightning invoice, and a macaroon. The client pays the invoice, then sends `Authorization: L402 <macaroon>:<preimage>` to access the API.
|
|
57
|
+
- **Economic agency** — the agent discovers a service, reads the price, pays the invoice, and retrieves the data, all within a single tool call. No human registration required.
|
|
58
|
+
- **Safety cap** — `MAX_AUTO_PAY_SATS` sets the maximum any single autonomous payment can be. Above this limit, the agent asks for human approval. A rolling 60-second spend cap (`MAX_SPEND_PER_MINUTE_SATS`) prevents runaway spending.
|
|
59
|
+
- **Credential store** — paid macaroons are persisted locally and encrypted with AES-256-GCM. Subsequent requests to the same server reuse credentials rather than paying again.
|
|
60
|
+
- **Credit balance** — many L402 servers (including toll-booth) grant a credit balance after payment. 402-mcp tracks and caches that balance so the agent can reason about remaining capacity.
|
|
61
|
+
- **Service discovery** — agents can search for L402 services on Nostr relays by querying kind 31402 announcements, finding paid APIs by topic, capability, or payment method.
|
|
62
|
+
|
|
63
|
+
## Core L402 Tools
|
|
64
|
+
|
|
65
|
+
These tools work with any L402-compliant server.
|
|
66
|
+
|
|
67
|
+
### `l402_config`
|
|
68
|
+
|
|
69
|
+
Introspect the agent's payment capabilities and current configuration. Returns wallet status (NWC connected, Cashu tokens loaded), the `MAX_AUTO_PAY_SATS` limit, and the number of stored credentials. Call this first so the agent knows what it can do autonomously.
|
|
70
|
+
|
|
71
|
+
### `l402_discover`
|
|
72
|
+
|
|
73
|
+
Probe an endpoint to discover its pricing without making a payment. Returns the invoice amount in satoshis, the macaroon challenge, and whether the server is a toll-booth instance (which enables extension tools). Use this before committing to a purchase so the agent can reason about value.
|
|
74
|
+
|
|
75
|
+
### `l402_fetch`
|
|
76
|
+
|
|
77
|
+
Make an HTTP request to an L402-protected endpoint. Handles the full payment flow automatically: detects 402 responses, pays the invoice if the amount is within the `MAX_AUTO_PAY_SATS` budget and the rolling spend cap, stores the credential, and retries the request. Returns the response body on success. This is the primary tool for consuming L402 APIs.
|
|
78
|
+
|
|
79
|
+
### `l402_pay`
|
|
80
|
+
|
|
81
|
+
Pay a specific Lightning invoice directly. Tries payment methods in priority order: NWC, Cashu, human-in-the-loop. Use this when you have an invoice from a source other than `l402_fetch`, or when you want explicit control over the payment step.
|
|
82
|
+
|
|
83
|
+
### `l402_credentials`
|
|
84
|
+
|
|
85
|
+
List all stored L402 credentials and their cached credit balances. Shows which servers the agent has already paid and what capacity remains. Useful for auditing spend and avoiding redundant payments.
|
|
86
|
+
|
|
87
|
+
### `l402_balance`
|
|
88
|
+
|
|
89
|
+
Check the cached credit balance for a specific server URL. Returns the number of credits remaining without making a network request. Use this before calling `l402_fetch` to confirm there is sufficient balance before consuming credits.
|
|
90
|
+
|
|
91
|
+
### `l402_search`
|
|
92
|
+
|
|
93
|
+
Search for L402 services on Nostr relays. Queries kind 31402 announcement events and returns matching services with their names, URLs, pricing, capabilities, and supported payment methods. Filter by query text, topics (e.g. "ai", "data"), or payment method. Use the returned URL with `l402_discover` or `l402_fetch` to interact with the service. This enables agents to find paid APIs without knowing URLs upfront — a decentralised alternative to API directories.
|
|
94
|
+
|
|
95
|
+
## toll-booth Extension Tools
|
|
96
|
+
|
|
97
|
+
These tools activate automatically when the target server is a toll-booth instance (detected via `l402_discover`).
|
|
98
|
+
|
|
99
|
+
### `l402_buy_credits`
|
|
100
|
+
|
|
101
|
+
Browse and purchase volume discount credit tiers offered by the server. toll-booth servers can expose multiple tiers (e.g. 100 sats for 110 credits, 500 sats for 555 credits). The agent can inspect the tiers, reason about how many requests it needs, and buy the best-value tier upfront rather than paying per-request.
|
|
102
|
+
|
|
103
|
+
### `l402_redeem_cashu`
|
|
104
|
+
|
|
105
|
+
Redeem Cashu ecash tokens directly with the toll-booth server, bypassing the Lightning round-trip. toll-booth accepts raw ecash tokens and credits the balance immediately. This is faster and cheaper than melting tokens to pay a Lightning invoice when both sides support Cashu.
|
|
106
|
+
|
|
107
|
+
## Payment Methods
|
|
108
|
+
|
|
109
|
+
Three payment rails are tried in priority order:
|
|
110
|
+
|
|
111
|
+
1. **NWC (Nostr Wallet Connect)** — fully autonomous. The agent pays invoices directly from a connected Lightning wallet via the NWC protocol. Configure with `NWC_URI`. No human interaction required.
|
|
112
|
+
|
|
113
|
+
2. **Cashu** — fully autonomous. The agent melts ecash tokens to pay invoices. Configure with `CASHU_TOKENS` pointing to a token store file. No Lightning node required on the agent side.
|
|
114
|
+
|
|
115
|
+
3. **Human-in-the-loop** — fallback when no autonomous payment method is configured or when a payment exceeds the `MAX_AUTO_PAY_SATS` cap. The agent presents a payment QR code and polls for settlement. Control returns to the agent once the human has paid.
|
|
116
|
+
|
|
117
|
+
The agent can override the payment method per-call, or you can configure only the methods you want available.
|
|
118
|
+
|
|
119
|
+
## Safety Model
|
|
120
|
+
|
|
121
|
+
Two safety primitives protect against runaway spending:
|
|
122
|
+
|
|
123
|
+
1. **`MAX_AUTO_PAY_SATS`** — caps any single autonomous payment. Above this threshold, the agent must ask for human approval.
|
|
124
|
+
2. **`MAX_SPEND_PER_MINUTE_SATS`** — rolling 60-second window cap across all payments. Prevents rapid successive payments from exceeding a total budget even if each individual payment is below the per-payment cap.
|
|
125
|
+
|
|
126
|
+
The human stays in control of three things: the safety caps, which payment methods are available, and credential visibility. The agent operates within those boundaries, not around them.
|
|
127
|
+
|
|
128
|
+
## Security
|
|
129
|
+
|
|
130
|
+
- **SSRF protection** — all outbound requests pass through an SSRF guard that blocks private/internal IP ranges by default. Set `SSRF_ALLOW_PRIVATE=true` only for local development.
|
|
131
|
+
- **Credential encryption** — stored credentials are encrypted with AES-256-GCM. The encryption key is stored in the OS keychain when available, falling back to a file-based key with a warning.
|
|
132
|
+
- **Preimage validation** — preimages are validated as hex before storage to prevent header injection.
|
|
133
|
+
- **Spend tracking** — atomic `tryRecord()` prevents TOCTOU race conditions in concurrent spend checks.
|
|
134
|
+
- **HTTP transport hardening** — rate limiting (100 req/60s per IP), security headers (CSP, X-Frame-Options, nosniff), and loopback-only binding by default.
|
|
135
|
+
|
|
136
|
+
## Ecosystem
|
|
137
|
+
|
|
138
|
+
**toll-booth** is the server counterpart to 402-mcp. It is L402 payment middleware that embeds into any Node.js application (Express 5, Deno, Bun, Cloudflare Workers), gates endpoints behind Lightning or Cashu payments, and supports credit tiers and free tiers. Any server protected by toll-booth automatically gets the full set of 402-mcp tools including the extension tools.
|
|
139
|
+
|
|
140
|
+
https://github.com/TheCryptoDonkey/toll-booth
|
|
141
|
+
|
|
142
|
+
**satgate** demonstrates the AI inference use case: a proxy that gates access to AI model endpoints (Ollama, vLLM, llama.cpp) behind L402 payments. Agents use 402-mcp to discover pricing, pay per-request or buy credit tiers, and consume inference capacity without pre-provisioned API keys.
|
|
143
|
+
|
|
144
|
+
https://github.com/TheCryptoDonkey/satgate
|
|
145
|
+
|
|
146
|
+
**402-announce** publishes HTTP 402 services on Nostr as kind 31402 events, making them discoverable by `l402_search`. Operators run it alongside their L402 server to announce capabilities, pricing, and payment methods to the decentralised network.
|
|
147
|
+
|
|
148
|
+
https://github.com/TheCryptoDonkey/402-announce
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "402-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "L402 + x402 client MCP - AI agents discover, pay for, and consume any payment-gated API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -71,7 +71,9 @@
|
|
|
71
71
|
"files": [
|
|
72
72
|
"build",
|
|
73
73
|
"LICENSE",
|
|
74
|
-
"README.md"
|
|
74
|
+
"README.md",
|
|
75
|
+
"llms.txt",
|
|
76
|
+
"llms-full.txt"
|
|
75
77
|
],
|
|
76
78
|
"license": "MIT"
|
|
77
79
|
}
|