@lightninglabs/lightning-mcp-server 0.2.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/.claude-plugin/marketplace.json +36 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +307 -0
- package/bin/lightning-mcp-server +15 -0
- package/docs/architecture.md +455 -0
- package/docs/commerce.md +357 -0
- package/docs/l402-and-lnget.md +267 -0
- package/docs/mcp-server.md +285 -0
- package/docs/quickref.md +263 -0
- package/docs/security.md +298 -0
- package/docs/two-agent-setup.md +394 -0
- package/package.json +52 -0
- package/postinstall.js +160 -0
- package/skills/aperture/SKILL.md +330 -0
- package/skills/aperture/scripts/install.sh +68 -0
- package/skills/aperture/scripts/setup.sh +155 -0
- package/skills/aperture/scripts/start.sh +81 -0
- package/skills/aperture/scripts/stop.sh +57 -0
- package/skills/aperture/templates/aperture-regtest.yaml +36 -0
- package/skills/aperture/templates/aperture.yaml.template +64 -0
- package/skills/aperture/templates/docker-compose-aperture.yml +59 -0
- package/skills/commerce/SKILL.md +211 -0
- package/skills/lib/config-gen.sh +127 -0
- package/skills/lib/rest.sh +69 -0
- package/skills/lightning-security-module/SKILL.md +253 -0
- package/skills/lightning-security-module/references/architecture.md +133 -0
- package/skills/lightning-security-module/scripts/docker-start.sh +117 -0
- package/skills/lightning-security-module/scripts/docker-stop.sh +53 -0
- package/skills/lightning-security-module/scripts/export-credentials.sh +268 -0
- package/skills/lightning-security-module/scripts/install.sh +178 -0
- package/skills/lightning-security-module/scripts/setup-signer.sh +307 -0
- package/skills/lightning-security-module/scripts/start-signer.sh +152 -0
- package/skills/lightning-security-module/scripts/stop-signer.sh +240 -0
- package/skills/lightning-security-module/templates/docker-compose-signer.yml +35 -0
- package/skills/lightning-security-module/templates/signer-lnd.conf.template +69 -0
- package/skills/lnd/SKILL.md +441 -0
- package/skills/lnd/profiles/debug.env +4 -0
- package/skills/lnd/profiles/default.env +3 -0
- package/skills/lnd/profiles/regtest.env +4 -0
- package/skills/lnd/profiles/taproot.env +3 -0
- package/skills/lnd/profiles/wumbo.env +3 -0
- package/skills/lnd/references/security.md +156 -0
- package/skills/lnd/scripts/create-wallet.sh +464 -0
- package/skills/lnd/scripts/docker-start.sh +256 -0
- package/skills/lnd/scripts/docker-stop.sh +109 -0
- package/skills/lnd/scripts/import-credentials.sh +145 -0
- package/skills/lnd/scripts/install.sh +195 -0
- package/skills/lnd/scripts/lncli.sh +150 -0
- package/skills/lnd/scripts/start-lnd.sh +241 -0
- package/skills/lnd/scripts/stop-lnd.sh +218 -0
- package/skills/lnd/scripts/unlock-wallet.sh +134 -0
- package/skills/lnd/templates/docker-compose-regtest.yml +122 -0
- package/skills/lnd/templates/docker-compose-watchonly.yml +71 -0
- package/skills/lnd/templates/docker-compose.yml +49 -0
- package/skills/lnd/templates/litd-regtest.conf.template +61 -0
- package/skills/lnd/templates/litd-watchonly.conf.template +57 -0
- package/skills/lnd/templates/litd.conf.template +88 -0
- package/skills/lnd/templates/lnd.conf.template +91 -0
- package/skills/lnget/SKILL.md +288 -0
- package/skills/lnget/scripts/install.sh +69 -0
- package/skills/macaroon-bakery/SKILL.md +179 -0
- package/skills/macaroon-bakery/scripts/bake.sh +337 -0
- package/skills/mcp-lnc/SKILL.md +280 -0
- package/skills/mcp-lnc/scripts/configure.sh +130 -0
- package/skills/mcp-lnc/scripts/install.sh +103 -0
- package/skills/mcp-lnc/scripts/setup-claude-config.sh +162 -0
- package/skills/mcp-lnc/templates/env.template +16 -0
- package/versions.env +23 -0
package/docs/commerce.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Agent Commerce
|
|
2
|
+
|
|
3
|
+
> Setting up buyer and seller agents for autonomous Lightning payments.
|
|
4
|
+
|
|
5
|
+
Lightning Agent Tools enables a payment pattern where agents buy and sell
|
|
6
|
+
resources from each other over the Lightning Network without any pre-arranged
|
|
7
|
+
billing relationship. A buyer agent uses `lnget` to fetch paid content. A
|
|
8
|
+
seller agent uses `aperture` to gate access behind Lightning invoices. Both run
|
|
9
|
+
their own `lnd` nodes for payment infrastructure. The three components compose
|
|
10
|
+
into a self-contained commerce loop.
|
|
11
|
+
|
|
12
|
+
This document walks through setting up both sides and running them together.
|
|
13
|
+
|
|
14
|
+
## The Commerce Loop
|
|
15
|
+
|
|
16
|
+
When a buyer agent fetches a resource from a seller, the following exchange
|
|
17
|
+
happens automatically:
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
sequenceDiagram
|
|
21
|
+
participant BA as Buyer Agent
|
|
22
|
+
participant BL as Buyer lnd
|
|
23
|
+
participant LN as Lightning Network
|
|
24
|
+
participant SL as Seller lnd
|
|
25
|
+
participant AP as Aperture
|
|
26
|
+
participant BE as Backend Service
|
|
27
|
+
|
|
28
|
+
BA->>AP: GET /api/data (via lnget)
|
|
29
|
+
AP->>SL: Generate invoice (100 sats)
|
|
30
|
+
SL-->>AP: BOLT11 invoice
|
|
31
|
+
AP-->>BA: 402 + L402 challenge
|
|
32
|
+
|
|
33
|
+
BA->>BL: Pay invoice (100 sats)
|
|
34
|
+
BL->>LN: Route payment
|
|
35
|
+
LN->>SL: Deliver payment
|
|
36
|
+
SL-->>LN: Preimage
|
|
37
|
+
LN-->>BL: Preimage
|
|
38
|
+
BL-->>BA: Payment settled
|
|
39
|
+
|
|
40
|
+
BA->>AP: GET /api/data + L402 token
|
|
41
|
+
AP->>AP: Validate token
|
|
42
|
+
AP->>BE: Proxy request
|
|
43
|
+
BE-->>AP: Response data
|
|
44
|
+
AP-->>BA: 200 OK + data
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
From the buyer agent's perspective, this is a single command:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
lnget --max-cost 100 -q https://seller-host:8081/api/data | jq .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
From the seller's perspective, aperture handles everything: invoice
|
|
54
|
+
generation, challenge issuance, token validation, and request proxying. The
|
|
55
|
+
backend service just serves HTTP requests.
|
|
56
|
+
|
|
57
|
+
## Buyer Agent Setup
|
|
58
|
+
|
|
59
|
+
A buyer agent needs two components: an `lnd` node for payments and `lnget` for
|
|
60
|
+
HTTP requests with automatic L402 handling.
|
|
61
|
+
|
|
62
|
+
### Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Pulls Docker images by default; add --source to build from source.
|
|
66
|
+
skills/lnd/scripts/install.sh
|
|
67
|
+
skills/lnget/scripts/install.sh
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Create and Start the Node
|
|
71
|
+
|
|
72
|
+
All commands below auto-detect Docker and launch containers. Pass `--native` to
|
|
73
|
+
any script to use a locally built binary instead.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Create a wallet (standalone mode for testing, watch-only for production)
|
|
77
|
+
skills/lnd/scripts/create-wallet.sh --mode standalone
|
|
78
|
+
|
|
79
|
+
# Start lnd (launches a litd Docker container)
|
|
80
|
+
skills/lnd/scripts/start-lnd.sh
|
|
81
|
+
|
|
82
|
+
# Verify it's running
|
|
83
|
+
skills/lnd/scripts/lncli.sh getinfo
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
For production deployments, use watch-only mode with a remote signer. See
|
|
87
|
+
[Security](security.md#tier-1-watch-only-with-remote-signer).
|
|
88
|
+
|
|
89
|
+
### Fund the Wallet
|
|
90
|
+
|
|
91
|
+
The node needs on-chain bitcoin to open payment channels.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Generate a funding address
|
|
95
|
+
skills/lnd/scripts/lncli.sh newaddress p2tr
|
|
96
|
+
|
|
97
|
+
# Send BTC to this address from an exchange or another wallet
|
|
98
|
+
|
|
99
|
+
# Check balance (wait for confirmations)
|
|
100
|
+
skills/lnd/scripts/lncli.sh walletbalance
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Open a Channel
|
|
104
|
+
|
|
105
|
+
Lightning payments travel through channels. The buyer needs at least one channel
|
|
106
|
+
with outbound capacity to reach the seller (or a path to the seller through the
|
|
107
|
+
network).
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Connect to a well-connected node
|
|
111
|
+
skills/lnd/scripts/lncli.sh connect <pubkey>@<host>:9735
|
|
112
|
+
|
|
113
|
+
# Open a channel (amount in satoshis)
|
|
114
|
+
skills/lnd/scripts/lncli.sh openchannel --node_key=<pubkey> --local_amt=1000000
|
|
115
|
+
|
|
116
|
+
# Wait for the funding transaction to confirm (typically 3-6 blocks)
|
|
117
|
+
skills/lnd/scripts/lncli.sh pendingchannels
|
|
118
|
+
skills/lnd/scripts/lncli.sh listchannels
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Configure lnget
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Initialize config (auto-detects local lnd)
|
|
125
|
+
lnget config init
|
|
126
|
+
|
|
127
|
+
# Verify backend connection
|
|
128
|
+
lnget ln status
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Fetch Paid Resources
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Fetch with a spending cap
|
|
135
|
+
lnget --max-cost 500 https://api.example.com/paid-data.json
|
|
136
|
+
|
|
137
|
+
# Preview cost without paying
|
|
138
|
+
lnget --no-pay --json https://api.example.com/paid-data.json | jq '.invoice_amount_sat'
|
|
139
|
+
|
|
140
|
+
# Pipe to other tools
|
|
141
|
+
lnget -q https://api.example.com/market-data.json | jq '.price'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Seller Agent Setup
|
|
145
|
+
|
|
146
|
+
A seller agent needs three components: an `lnd` node for invoice generation,
|
|
147
|
+
`aperture` as the L402 reverse proxy, and a backend HTTP service to serve the
|
|
148
|
+
actual content.
|
|
149
|
+
|
|
150
|
+
### Install
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
skills/lnd/scripts/install.sh
|
|
154
|
+
skills/aperture/scripts/install.sh
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Create and Start the Node
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
skills/lnd/scripts/create-wallet.sh --mode standalone
|
|
161
|
+
skills/lnd/scripts/start-lnd.sh # Docker container by default
|
|
162
|
+
skills/lnd/scripts/lncli.sh getinfo
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The seller's lnd node generates invoices for aperture. It needs inbound channel
|
|
166
|
+
capacity to receive payments. Other nodes must have channels open _to_ the
|
|
167
|
+
seller, not just from the seller.
|
|
168
|
+
|
|
169
|
+
### Start a Backend Service
|
|
170
|
+
|
|
171
|
+
Aperture proxies authenticated requests to a backend HTTP service. For testing,
|
|
172
|
+
a simple file server works:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
mkdir -p /tmp/api-data
|
|
176
|
+
echo '{"market_data": {"btc_usd": 104250, "timestamp": "2025-02-09T12:00:00Z"}}' \
|
|
177
|
+
> /tmp/api-data/data.json
|
|
178
|
+
cd /tmp/api-data && python3 -m http.server 8080 &
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
In production, the backend is whatever service you want to monetize: a REST
|
|
182
|
+
API, a data feed, an inference endpoint.
|
|
183
|
+
|
|
184
|
+
### Configure and Start Aperture
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Generate aperture config connected to local lnd
|
|
188
|
+
skills/aperture/scripts/setup.sh --insecure --port 8081
|
|
189
|
+
|
|
190
|
+
# Start the L402 proxy
|
|
191
|
+
skills/aperture/scripts/start.sh
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The `--insecure` flag disables TLS (suitable for development). For production,
|
|
195
|
+
configure TLS with Let's Encrypt (`--autocert`) or your own certificates.
|
|
196
|
+
|
|
197
|
+
For regtest testing, a Docker Compose file at
|
|
198
|
+
`skills/aperture/templates/docker-compose-aperture.yml` runs aperture alongside
|
|
199
|
+
a busybox backend on the same Docker network as the litd regtest stack.
|
|
200
|
+
|
|
201
|
+
Aperture's config (`~/.aperture/aperture.yaml`) defines which paths are
|
|
202
|
+
protected and how much they cost:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
services:
|
|
206
|
+
- name: "market-data"
|
|
207
|
+
hostregexp: ".*"
|
|
208
|
+
pathregexp: "^/api/.*$"
|
|
209
|
+
address: "127.0.0.1:8080"
|
|
210
|
+
protocol: http
|
|
211
|
+
price: 100 # satoshis per request
|
|
212
|
+
authwhitelistpaths:
|
|
213
|
+
- "^/health$" # free health check endpoint
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Each request to a path matching `^/api/.*$` costs 100 satoshis. Requests to
|
|
217
|
+
`/health` pass through without payment. The `address` field points to the
|
|
218
|
+
backend service.
|
|
219
|
+
|
|
220
|
+
### Verify
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Should return 402 with L402 challenge
|
|
224
|
+
lnget -k --no-pay https://localhost:8081/api/data.json
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Running Both Sides
|
|
228
|
+
|
|
229
|
+
With both agents running, the buyer fetches data from the seller:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Buyer fetches paid data
|
|
233
|
+
lnget --max-cost 100 -q https://seller-host:8081/api/data.json | jq .
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Verify the payment went through:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# On the buyer
|
|
240
|
+
lnget tokens list # shows cached token
|
|
241
|
+
skills/lnd/scripts/lncli.sh channelbalance # outbound decreased
|
|
242
|
+
|
|
243
|
+
# On the seller
|
|
244
|
+
skills/lnd/scripts/lncli.sh listinvoices # shows settled invoice
|
|
245
|
+
skills/lnd/scripts/lncli.sh channelbalance # inbound converted to local
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Subsequent requests from the buyer to the same domain reuse the cached token
|
|
249
|
+
without additional payment (until the token expires).
|
|
250
|
+
|
|
251
|
+
## Deployment Diagram
|
|
252
|
+
|
|
253
|
+
A production deployment separates the signing infrastructure from the
|
|
254
|
+
agent-facing components:
|
|
255
|
+
|
|
256
|
+
```mermaid
|
|
257
|
+
graph TB
|
|
258
|
+
subgraph Buyer["Buyer Agent"]
|
|
259
|
+
B_Agent["Agent Process"]
|
|
260
|
+
B_lnget["lnget"]
|
|
261
|
+
B_lnd["lnd (watch-only)"]
|
|
262
|
+
B_Signer["lnd signer<br/>(separate machine)"]
|
|
263
|
+
|
|
264
|
+
B_Agent --> B_lnget
|
|
265
|
+
B_lnget --> B_lnd
|
|
266
|
+
B_lnd <-->|"gRPC :10012"| B_Signer
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
subgraph Seller["Seller Agent"]
|
|
270
|
+
S_Agent["Agent Process"]
|
|
271
|
+
S_Aperture["aperture :8081"]
|
|
272
|
+
S_Backend["Backend :8080"]
|
|
273
|
+
S_lnd["lnd (watch-only)"]
|
|
274
|
+
S_Signer["lnd signer<br/>(separate machine)"]
|
|
275
|
+
|
|
276
|
+
S_Agent --> S_Aperture
|
|
277
|
+
S_Aperture --> S_Backend
|
|
278
|
+
S_Aperture --> S_lnd
|
|
279
|
+
S_lnd <-->|"gRPC :10012"| S_Signer
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
LN["Lightning Network"]
|
|
283
|
+
B_lnd <-->|":9735"| LN
|
|
284
|
+
S_lnd <-->|":9735"| LN
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Cost Management
|
|
288
|
+
|
|
289
|
+
Agents operating autonomously need spending guardrails at multiple levels:
|
|
290
|
+
|
|
291
|
+
**Per-request limits.** Set `--max-cost` on every lnget call. If the seller's
|
|
292
|
+
price exceeds the limit, lnget refuses to pay and exits with code 2:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
lnget --max-cost 500 https://api.example.com/data
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Cost preview.** Before committing to a purchase, preview what the server is
|
|
299
|
+
charging:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
lnget --no-pay --json https://api.example.com/data | jq '.invoice_amount_sat'
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Spending tracking.** Monitor cumulative spending through the token list:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
lnget tokens list --json | jq '[.[] | .amount_paid_sat] | add'
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Wallet balance monitoring.** Check channel balance to ensure the agent has
|
|
312
|
+
sufficient capacity:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
skills/lnd/scripts/lncli.sh channelbalance
|
|
316
|
+
skills/lnd/scripts/lncli.sh walletbalance
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Node-level controls.** Use a `pay-only` macaroon (via `macaroon-bakery`) for
|
|
320
|
+
the buyer agent. This restricts lnget to payment and invoice-decoding operations
|
|
321
|
+
only. The agent cannot open channels, change configuration, or access any
|
|
322
|
+
other node functionality:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
skills/macaroon-bakery/scripts/bake.sh --role pay-only
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
For the seller agent, use an `invoice-only` macaroon for aperture. It only needs
|
|
329
|
+
to create and look up invoices.
|
|
330
|
+
|
|
331
|
+
## Production Considerations
|
|
332
|
+
|
|
333
|
+
**Remote signer.** Both buyer and seller nodes should run in watch-only mode
|
|
334
|
+
with a remote signer in production. See
|
|
335
|
+
[Security](security.md#tier-1-watch-only-with-remote-signer).
|
|
336
|
+
|
|
337
|
+
**Inbound liquidity.** The seller's lnd node needs inbound channel capacity to
|
|
338
|
+
receive payments. This means other nodes must open channels _to_ the seller.
|
|
339
|
+
Options include requesting inbound channels from LSPs (Lightning Service
|
|
340
|
+
Providers), or using circular rebalancing to shift local capacity to the remote
|
|
341
|
+
side.
|
|
342
|
+
|
|
343
|
+
**Channel sizing.** Size channels based on expected payment volume. A 1,000,000
|
|
344
|
+
sat channel can handle many 100-sat L402 payments before rebalancing is needed.
|
|
345
|
+
Monitor channel balances and open new channels proactively.
|
|
346
|
+
|
|
347
|
+
**TLS for aperture.** Use `--autocert` with a domain name for automatic Let's
|
|
348
|
+
Encrypt TLS, or provide your own certificate. Never run `--insecure` on
|
|
349
|
+
public-facing endpoints.
|
|
350
|
+
|
|
351
|
+
**Stopping everything.**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
skills/aperture/scripts/stop.sh
|
|
355
|
+
skills/lnd/scripts/stop-lnd.sh
|
|
356
|
+
skills/lnd/scripts/stop-lnd.sh --clean # also remove Docker volumes
|
|
357
|
+
```
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# L402 and lnget
|
|
2
|
+
|
|
3
|
+
> The payment protocol that makes agent commerce work, and the CLI client that
|
|
4
|
+
> automates it.
|
|
5
|
+
|
|
6
|
+
L402 is an HTTP authentication scheme built on Lightning Network payments. It
|
|
7
|
+
repurposes the HTTP 402 "Payment Required" status code, reserved since the
|
|
8
|
+
early days of the HTTP spec but never widely adopted, to gate access to web
|
|
9
|
+
resources behind Lightning invoices. An agent doesn't need an account, an API
|
|
10
|
+
key, or a pre-existing relationship with the server. It pays a Lightning invoice
|
|
11
|
+
and receives access. That's it.
|
|
12
|
+
|
|
13
|
+
`lnget` is a command-line HTTP client (in the tradition of `wget` and `curl`)
|
|
14
|
+
that handles L402 payments automatically. When it encounters a 402 response, it
|
|
15
|
+
pays the embedded invoice, caches the resulting token, and retries the request.
|
|
16
|
+
To the agent, the paid resource looks like any other HTTP fetch.
|
|
17
|
+
|
|
18
|
+
## The L402 Protocol
|
|
19
|
+
|
|
20
|
+
An L402 exchange has four steps:
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
sequenceDiagram
|
|
24
|
+
participant C as Client (lnget)
|
|
25
|
+
participant S as Server (aperture)
|
|
26
|
+
participant LN as Lightning Network
|
|
27
|
+
|
|
28
|
+
C->>S: GET /api/resource
|
|
29
|
+
S-->>C: 402 Payment Required<br/>WWW-Authenticate: L402<br/>macaroon="...", invoice="lnbc..."
|
|
30
|
+
|
|
31
|
+
Note over C: Parse macaroon and BOLT11 invoice<br/>Check: amount ≤ max-cost?
|
|
32
|
+
|
|
33
|
+
C->>LN: Pay BOLT11 invoice
|
|
34
|
+
LN-->>C: Preimage (proof of payment)
|
|
35
|
+
|
|
36
|
+
Note over C: Construct token: macaroon + preimage<br/>Cache token for this domain
|
|
37
|
+
|
|
38
|
+
C->>S: GET /api/resource<br/>Authorization: L402 <macaroon>:<preimage>
|
|
39
|
+
S-->>C: 200 OK + response body
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Step 1: The challenge.** The client requests a protected resource. The server
|
|
43
|
+
responds with HTTP 402 and a `WWW-Authenticate` header containing two values: a
|
|
44
|
+
macaroon (a bearer token encoding the access grant) and a BOLT11 Lightning
|
|
45
|
+
invoice (the payment request).
|
|
46
|
+
|
|
47
|
+
**Step 2: Payment.** The client decodes the BOLT11 invoice, verifies the amount
|
|
48
|
+
is acceptable, and pays it through the Lightning Network. Payment settlement
|
|
49
|
+
reveals a preimage, a 32-byte value that serves as cryptographic proof of
|
|
50
|
+
payment.
|
|
51
|
+
|
|
52
|
+
**Step 3: Token construction.** The client combines the macaroon from the
|
|
53
|
+
challenge with the preimage from the payment to form an L402 token. This token
|
|
54
|
+
is cached locally for future requests to the same domain.
|
|
55
|
+
|
|
56
|
+
**Step 4: Authenticated retry.** The client retries the original request with an
|
|
57
|
+
`Authorization: L402 <macaroon>:<preimage>` header. The server validates the
|
|
58
|
+
token (verifying that the preimage matches the payment hash embedded in the
|
|
59
|
+
macaroon) and serves the resource.
|
|
60
|
+
|
|
61
|
+
The key property of L402 is that credentials are **purchased, not provisioned**.
|
|
62
|
+
There is no signup flow, no API key management, no OAuth dance. Any client with
|
|
63
|
+
access to the Lightning Network can authenticate with any L402 server
|
|
64
|
+
instantly. This is what makes L402 native to agent workflows: agents can
|
|
65
|
+
discover and pay for resources on the fly without requiring a human to pre-register
|
|
66
|
+
accounts.
|
|
67
|
+
|
|
68
|
+
## lnget
|
|
69
|
+
|
|
70
|
+
`lnget` automates the entire L402 flow in a single command:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
lnget https://api.example.com/premium-data.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If the server returns 200, lnget writes the response to stdout (or a file with
|
|
77
|
+
`-o`). If it returns 402, lnget parses the challenge, pays the invoice, caches
|
|
78
|
+
the token, and retries. All of this is transparent. Subsequent requests to the same
|
|
79
|
+
domain reuse the cached token without additional payment.
|
|
80
|
+
|
|
81
|
+
### Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
skills/lnget/scripts/install.sh
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This runs `go install github.com/lightninglabs/lnget/cmd/lnget@latest`.
|
|
88
|
+
|
|
89
|
+
### Lightning Backends
|
|
90
|
+
|
|
91
|
+
lnget needs a Lightning backend to pay invoices. It supports three:
|
|
92
|
+
|
|
93
|
+
```mermaid
|
|
94
|
+
graph TD
|
|
95
|
+
lnget["lnget"]
|
|
96
|
+
|
|
97
|
+
lnget -->|"mode: lnd"| lnd["lnd (direct gRPC)<br/>Requires: host, TLS cert, macaroon<br/>Full payment capabilities"]
|
|
98
|
+
lnget -->|"mode: lnc"| lnc["LNC (Lightning Node Connect)<br/>Requires: pairing phrase<br/>Encrypted tunnel, no direct access"]
|
|
99
|
+
lnget -->|"mode: neutrino"| neutrino["Neutrino (embedded wallet)<br/>Self-contained light client<br/>No external node needed"]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**lnd (direct gRPC).** Connects to an lnd node over gRPC using a TLS
|
|
103
|
+
certificate and macaroon. This is the standard mode when the agent runs its own
|
|
104
|
+
lnd node via the `lnd` skill. Configure with:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
lnget config init # auto-detects local lnd
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Or manually in `~/.lnget/config.yaml`:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
ln:
|
|
114
|
+
mode: lnd
|
|
115
|
+
lnd:
|
|
116
|
+
host: localhost:10009
|
|
117
|
+
tls_cert: ~/.lnd/tls.cert
|
|
118
|
+
macaroon: ~/.lnd/data/chain/bitcoin/mainnet/admin.macaroon
|
|
119
|
+
network: mainnet
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Use a `pay-only` macaroon instead of `admin.macaroon` for agents. See
|
|
123
|
+
[Security](security.md#preset-roles).
|
|
124
|
+
|
|
125
|
+
**LNC (Lightning Node Connect).** Connects through an encrypted WebSocket
|
|
126
|
+
tunnel using a pairing phrase. No direct network access to the lnd node is
|
|
127
|
+
needed. Pair with:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
lnget ln lnc pair "your ten word pairing phrase from lightning terminal"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Neutrino (embedded wallet).** lnget runs its own lightweight Lightning wallet
|
|
134
|
+
internally, using the Neutrino light client. No external lnd node required.
|
|
135
|
+
Initialize with:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
lnget ln neutrino init
|
|
139
|
+
lnget ln neutrino fund # generates a funding address
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This mode is useful for quick experiments but has limited routing capability
|
|
143
|
+
compared to a full lnd node.
|
|
144
|
+
|
|
145
|
+
## Spending Controls
|
|
146
|
+
|
|
147
|
+
Autonomous agents should never have unlimited spending authority. lnget provides
|
|
148
|
+
two mechanisms for cost control:
|
|
149
|
+
|
|
150
|
+
**Per-request ceiling.** The `--max-cost` flag sets the maximum amount (in
|
|
151
|
+
satoshis) that lnget will auto-pay for a single request. If the invoice exceeds
|
|
152
|
+
this amount, lnget exits with code 2 without paying:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
lnget --max-cost 500 https://api.example.com/data
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Preview mode.** The `--no-pay` flag sends the request and displays the L402
|
|
159
|
+
challenge (including the invoice amount) without paying. Agents can inspect
|
|
160
|
+
costs before committing:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
lnget --no-pay --json https://api.example.com/data | jq '.invoice_amount_sat'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
For node-level spending limits, use the `macaroon-bakery` to bake a `pay-only`
|
|
167
|
+
macaroon. This restricts the agent to payment operations only and prevents it
|
|
168
|
+
from opening channels, modifying configuration, or performing other
|
|
169
|
+
state-changing operations on the node.
|
|
170
|
+
|
|
171
|
+
### Exit Codes
|
|
172
|
+
|
|
173
|
+
| Code | Meaning |
|
|
174
|
+
|------|---------|
|
|
175
|
+
| 0 | Request succeeded |
|
|
176
|
+
| 1 | General error |
|
|
177
|
+
| 2 | Invoice amount exceeds `--max-cost` |
|
|
178
|
+
| 3 | Lightning payment failed |
|
|
179
|
+
| 4 | Network or connection error |
|
|
180
|
+
|
|
181
|
+
## Token Caching
|
|
182
|
+
|
|
183
|
+
Paid L402 tokens are cached at `~/.lnget/tokens/<domain>/` and reused
|
|
184
|
+
automatically on subsequent requests to the same domain. This means an agent
|
|
185
|
+
pays once per domain (until the token expires) rather than once per request.
|
|
186
|
+
|
|
187
|
+
Manage cached tokens with:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
lnget tokens list # list all cached tokens
|
|
191
|
+
lnget tokens show api.example.com # show token for a specific domain
|
|
192
|
+
lnget tokens remove api.example.com # remove a token (force re-payment)
|
|
193
|
+
lnget tokens clear --force # clear all tokens
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Configuration
|
|
197
|
+
|
|
198
|
+
lnget reads its configuration from `~/.lnget/config.yaml`. Initialize it with:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
lnget config init # creates config with defaults, auto-detects local lnd
|
|
202
|
+
lnget config show # display current config
|
|
203
|
+
lnget config path # print config file path
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The config file controls L402 behavior, HTTP settings, Lightning backend
|
|
207
|
+
selection, and output formatting:
|
|
208
|
+
|
|
209
|
+
```yaml
|
|
210
|
+
l402:
|
|
211
|
+
max_cost_sats: 1000 # default spending ceiling
|
|
212
|
+
max_fee_sats: 10 # max routing fee
|
|
213
|
+
payment_timeout: 60s
|
|
214
|
+
auto_pay: true # pay automatically on 402
|
|
215
|
+
|
|
216
|
+
http:
|
|
217
|
+
timeout: 30s
|
|
218
|
+
max_redirects: 10
|
|
219
|
+
user_agent: "lnget/0.1.0"
|
|
220
|
+
allow_insecure: false # set true for self-signed certs (dev only)
|
|
221
|
+
|
|
222
|
+
ln:
|
|
223
|
+
mode: lnd # lnd | lnc | neutrino
|
|
224
|
+
|
|
225
|
+
output:
|
|
226
|
+
format: json
|
|
227
|
+
progress: true
|
|
228
|
+
verbose: false
|
|
229
|
+
|
|
230
|
+
tokens:
|
|
231
|
+
dir: ~/.lnget/tokens
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Common Usage Patterns
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Fetch and pipe to jq
|
|
238
|
+
lnget -q https://api.example.com/data.json | jq .
|
|
239
|
+
|
|
240
|
+
# Save to file
|
|
241
|
+
lnget -o data.json https://api.example.com/data.json
|
|
242
|
+
|
|
243
|
+
# POST with body
|
|
244
|
+
lnget -X POST -d '{"query":"test"}' https://api.example.com/search
|
|
245
|
+
|
|
246
|
+
# Check backend connection
|
|
247
|
+
lnget ln status
|
|
248
|
+
lnget ln info
|
|
249
|
+
|
|
250
|
+
# Track total spending
|
|
251
|
+
lnget tokens list --json | jq '[.[] | .amount_paid_sat] | add'
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## The Server Side: Aperture
|
|
255
|
+
|
|
256
|
+
lnget handles the client side of L402. On the server side,
|
|
257
|
+
[Aperture](https://github.com/lightninglabs/aperture) is an L402-aware reverse
|
|
258
|
+
proxy that sits in front of a backend HTTP service and gates access behind
|
|
259
|
+
Lightning payments.
|
|
260
|
+
|
|
261
|
+
Aperture handles invoice generation (through its connected lnd node), L402
|
|
262
|
+
challenge issuance, token validation, and request proxying. The backend service
|
|
263
|
+
doesn't need any awareness of Lightning or L402. It just serves HTTP requests
|
|
264
|
+
that arrive through aperture.
|
|
265
|
+
|
|
266
|
+
For a complete walkthrough of setting up both the client and server sides, see
|
|
267
|
+
[Commerce](commerce.md).
|