Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ body:
attributes:
label: Which tool?
options:
- l402_config
- l402_discover
- l402_fetch
- l402_pay
- l402_credentials
- l402_balance
- l402_search
- l402_buy_credits
- l402_redeem_cashu
- l402_store_token
- l402-config
- l402-discover
- l402-fetch
- l402-pay
- l402-credentials
- l402-balance
- l402-search
- l402-buy-credits
- l402-redeem-cashu
- l402-store-token
- Other / not sure
validations:
required: true
Expand Down
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ claude mcp add 402-mcp -- npx 402-mcp

**3. Try it**

Ask Claude: *"Search for paid joke APIs using l402_search"* β€” no wallet needed, just discovery.
Ask Claude: *"Search for paid joke APIs using l402-search"* β€” no wallet needed, just discovery.

Ready to make paid calls? See the [full quickstart guide](./docs/quickstart.md) to set up a wallet and watch your agent pay for its first API call.

## How it works

```mermaid
graph LR
A["1. l402_config()"] --> B["2. l402_discover(url)"]
A["1. l402-config()"] --> B["2. l402-discover(url)"]
B --> C["3. Agent reasons<br/>about pricing"]
C --> D["4. l402_buy_credits()<br/>or l402_fetch()"]
D --> E["5. l402_fetch(url)<br/>with credentials"]
C --> D["4. l402-buy-credits()<br/>or l402-fetch()"]
D --> E["5. l402-fetch(url)<br/>with credentials"]
E --> F["6. Data returned<br/>+ balance cached"]
```

Expand All @@ -51,19 +51,19 @@ graph LR
```
Agent: "I need routing data from routing.trotters.cc"

1. l402_config()
1. l402-config()
-> nwcConfigured: true, maxAutoPaySats: 1000

2. l402_discover("https://routing.trotters.cc/api/route")
2. l402-discover("https://routing.trotters.cc/api/route")
-> 10 sats/request, toll-booth detected, tiers available

3. Agent reasons: "I need ~20 requests. The 500-sat tier
gives 555 credits. Better value."

4. l402_buy_credits(url, amountSats=500)
4. l402-buy-credits(url, amountSats=500)
-> Paid 500 sats, received 555 credits

5. l402_fetch("https://routing.trotters.cc/api/route?from=...&to=...")
5. l402-fetch("https://routing.trotters.cc/api/route?from=...&to=...")
-> 200 OK, route data, 545 credits remaining
```

Expand Down Expand Up @@ -100,21 +100,21 @@ Services can announce multiple endpoints for the **same service** (same pricing,

| Tool | Description |
|------|-------------|
| `l402_config` | Introspect payment capabilities (wallets, limits, credential count) |
| `l402_discover` | Probe an endpoint to discover pricing without paying |
| `l402_fetch` | HTTP request with L402 support; auto-pays if within budget |
| `l402_pay` | Pay a specific invoice (NWC, Cashu, or human-in-the-loop) |
| `l402_credentials` | List stored credentials and cached balances |
| `l402_balance` | Check cached credit balance for a server |
| `l402_search` | Discover L402 services on Nostr relays (kind 31402 announcements) |
| `l402_store_token` | Store an L402 token obtained from a payment page |
| `l402-config` | Introspect payment capabilities (wallets, limits, credential count) |
| `l402-discover` | Probe an endpoint to discover pricing without paying |
| `l402-fetch` | HTTP request with L402 support; auto-pays if within budget |
| `l402-pay` | Pay a specific invoice (NWC, Cashu, or human-in-the-loop) |
| `l402-credentials` | List stored credentials and cached balances |
| `l402-balance` | Check cached credit balance for a server |
| `l402-search` | Discover L402 services on Nostr relays (kind 31402 announcements) |
| `l402-store-token` | Store an L402 token obtained from a payment page |

### toll-booth extensions

| Tool | Description |
|------|-------------|
| `l402_buy_credits` | Browse and purchase volume discount tiers |
| `l402_redeem_cashu` | Redeem Cashu tokens directly (avoids Lightning round-trip) |
| `l402-buy-credits` | Browse and purchase volume discount tiers |
| `l402-redeem-cashu` | Redeem Cashu tokens directly (avoids Lightning round-trip) |

## Payment methods

Expand All @@ -128,7 +128,7 @@ The agent can override the method per-call, or you can configure only the method

## Safety

`MAX_AUTO_PAY_SATS` caps any single autonomous payment. Above this limit, the agent must ask the human for approval. The agent can read this limit via `l402_config` and factor it into purchasing decisions.
`MAX_AUTO_PAY_SATS` caps any single autonomous payment. Above this limit, the agent must ask the human for approval. The agent can read this limit via `l402-config` and factor it into purchasing decisions.

## Privacy

Expand Down
10 changes: 5 additions & 5 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ sequenceDiagram
participant API as L402 API
participant Wallet as Wallet (NWC/Cashu)

Agent->>MCP: l402_discover(url)
Agent->>MCP: l402-discover(url)
MCP->>API: GET /endpoint
API-->>MCP: 402 + invoice + macaroon
MCP-->>Agent: price: 10 sats, server: toll-booth

Agent->>Agent: Reason about pricing

Agent->>MCP: l402_fetch(url)
Agent->>MCP: l402-fetch(url)
MCP->>API: GET /endpoint
API-->>MCP: 402 + invoice + macaroon
MCP->>MCP: Amount ≀ MAX_AUTO_PAY_SATS?
Expand All @@ -74,19 +74,19 @@ sequenceDiagram

## Service discovery

Agents discover paid APIs without knowing URLs upfront. `l402_search` queries Nostr relays for kind 31402 service announcements β€” the decentralised registry for L402 services.
Agents discover paid APIs without knowing URLs upfront. `l402-search` queries Nostr relays for kind 31402 service announcements β€” the decentralised registry for L402 services.

```mermaid
sequenceDiagram
participant Agent as AI Agent
participant MCP as 402-mcp
participant Relay as Nostr Relays

Agent->>MCP: l402_search("routing")
Agent->>MCP: l402-search("routing")
MCP->>Relay: Subscribe kind 31402
Relay-->>MCP: Matching service events
MCP-->>Agent: Services with URLs, pricing, capabilities
Agent->>MCP: l402_discover(service_url)
Agent->>MCP: l402-discover(service_url)
Note over Agent: Continue with payment flow...
```

Expand Down
14 changes: 7 additions & 7 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ Add the same JSON block to your Cursor MCP configuration. See [Cursor MCP docs](

Ask your AI agent:

> "Search for paid joke APIs using l402_search"
> "Search for paid joke APIs using l402-search"

The agent will query Nostr relays for kind 31402 service announcements and return a list of live paid APIs β€” URLs, pricing, and capabilities. No wallet, no cost. This is just discovery.

Try other searches too β€” `l402_search("AI inference")` will find [satgate](https://github.com/forgesworn/satgate) (pay-per-token AI inference) and any other services announcing on Nostr.
Try other searches too β€” `l402-search("AI inference")` will find [satgate](https://github.com/forgesworn/satgate) (pay-per-token AI inference) and any other services announcing on Nostr.

## 4. Set up a wallet

Expand Down Expand Up @@ -129,8 +129,8 @@ Now ask your agent:
Watch what happens:

1. The agent discovers the endpoint and its pricing
2. It checks your spend limits via `l402_config`
3. It calls `l402_fetch` β€” 402-mcp pays the invoice automatically (or shows you a QR)
2. It checks your spend limits via `l402-config`
3. It calls `l402-fetch` β€” 402-mcp pays the invoice automatically (or shows you a QR)
4. The joke comes back, and the credential is cached for future requests

That's it. Your AI agent just paid for an API call autonomously.
Expand All @@ -145,8 +145,8 @@ That's it. Your AI agent just paid for an API call autonomously.

## Troubleshooting

**Service unavailable?** Use `l402_search` to find other live services β€” the Nostr relay network has a growing catalogue.
**Service unavailable?** Use `l402-search` to find other live services β€” the Nostr relay network has a growing catalogue.

**Payment failed?** Check your wallet balance and that your NWC URI is correct. Try `l402_config` to verify your payment methods are detected.
**Payment failed?** Check your wallet balance and that your NWC URI is correct. Try `l402-config` to verify your payment methods are detected.

**Want to see what's stored?** Use `l402_credentials` to list cached credentials and `l402_balance` to check remaining credits.
**Want to see what's stored?** Use `l402-credentials` to list cached credentials and `l402-balance` to check remaining credits.
2 changes: 1 addition & 1 deletion docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ All outbound HTTP uses the resilient fetch wrapper (`src/fetch/resilient-fetch.t

- **Preimage hex validation** β€” preimages are validated as strict hex before storage (see Credential encryption above).
- **Macaroon base64 validation** β€” macaroons are validated against a base64-safe character set before storage.
- **Blocked hop-by-hop headers** β€” user-supplied headers on `l402_fetch` are filtered against a blocklist of hop-by-hop and security-sensitive headers (`host`, `transfer-encoding`, `connection`, `upgrade`, `proxy-authorization`, `te`, `trailer`) to prevent request smuggling.
- **Blocked hop-by-hop headers** β€” user-supplied headers on `l402-fetch` are filtered against a blocklist of hop-by-hop and security-sensitive headers (`host`, `transfer-encoding`, `connection`, `upgrade`, `proxy-authorization`, `te`, `trailer`) to prevent request smuggling.
- **Zod schema validation** β€” all MCP tool inputs are validated with Zod schemas at the tool registration layer, rejecting malformed or unexpected input before any handler logic executes.
- **Path traversal prevention** β€” `CREDENTIAL_STORE` and `CASHU_TOKENS` paths are validated to ensure they resolve within the user's home directory.
- **NWC URI scrubbing** β€” the `NWC_URI` environment variable is deleted from `process.env` immediately after reading to prevent accidental exposure via process inspection or child processes.
Expand Down
12 changes: 6 additions & 6 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ TRANSPORT=http PORT=3402 NWC_URI="nostr+walletconnect://..." npx 402-mcp
An AI agent using 402-mcp follows this pattern:

```
1. l402_config()
1. l402-config()
β†’ Check what payment methods are available and the spending limits

2. l402_search("weather data")
2. l402-search("weather data")
β†’ Discover L402 services on Nostr relays matching "weather data"
β†’ Returns service URLs, pricing, and capabilities

3. l402_discover("https://api.example.com/weather")
3. l402-discover("https://api.example.com/weather")
β†’ Probe the endpoint: 5 sats/request, toll-booth server detected

4. l402_buy_credits("https://api.example.com/weather", 100)
4. l402-buy-credits("https://api.example.com/weather", 100)
β†’ Buy 100 sats of credits (toll-booth returns 110 credits at this tier)

5. l402_fetch("https://api.example.com/weather?city=London")
5. l402-fetch("https://api.example.com/weather?city=London")
β†’ 200 OK, weather data returned, 109 credits remaining

6. l402_balance("https://api.example.com/weather")
6. l402-balance("https://api.example.com/weather")
β†’ 109 credits remaining (no network request needed)
```

Expand Down
Loading
Loading