@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
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Bake, inspect, and manage lnd macaroons for least-privilege agent access.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bake.sh --role pay-only # Bake a preset role
|
|
6
|
+
# bake.sh --role invoice-only # Invoice-only agent
|
|
7
|
+
# bake.sh --role read-only # Read-only agent
|
|
8
|
+
# bake.sh --role channel-admin # Channel management agent
|
|
9
|
+
# bake.sh --role signer-only # Remote signer scoped macaroon
|
|
10
|
+
# bake.sh --custom uri:/lnrpc.Lightning/... # Custom permissions
|
|
11
|
+
# bake.sh --inspect <macaroon-path> # Inspect a macaroon
|
|
12
|
+
# bake.sh --list-permissions # List all available permissions
|
|
13
|
+
# bake.sh --container sam --role pay-only # Bake inside a Docker container
|
|
14
|
+
# bake.sh --rpcserver remote:10009 \ # Bake on a remote node
|
|
15
|
+
# --tlscertpath ~/tls.cert \
|
|
16
|
+
# --macaroonpath ~/admin.macaroon --role pay-only
|
|
17
|
+
|
|
18
|
+
set -e
|
|
19
|
+
|
|
20
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
LND_DIR="${LND_DIR:-}"
|
|
22
|
+
NETWORK="${NETWORK:-testnet}"
|
|
23
|
+
RPC_PORT=""
|
|
24
|
+
SAVE_TO=""
|
|
25
|
+
ROLE=""
|
|
26
|
+
INSPECT=""
|
|
27
|
+
LIST_PERMS=false
|
|
28
|
+
CUSTOM_PERMS=()
|
|
29
|
+
CONTAINER=""
|
|
30
|
+
RPCSERVER=""
|
|
31
|
+
TLSCERTPATH=""
|
|
32
|
+
MACAROONPATH=""
|
|
33
|
+
|
|
34
|
+
# Parse arguments.
|
|
35
|
+
while [[ $# -gt 0 ]]; do
|
|
36
|
+
case $1 in
|
|
37
|
+
--role)
|
|
38
|
+
ROLE="$2"
|
|
39
|
+
shift 2
|
|
40
|
+
;;
|
|
41
|
+
--custom)
|
|
42
|
+
shift
|
|
43
|
+
# Collect all remaining non-flag args as permissions.
|
|
44
|
+
while [[ $# -gt 0 ]] && [[ ! "$1" =~ ^-- ]]; do
|
|
45
|
+
CUSTOM_PERMS+=("$1")
|
|
46
|
+
shift
|
|
47
|
+
done
|
|
48
|
+
;;
|
|
49
|
+
--inspect)
|
|
50
|
+
INSPECT="$2"
|
|
51
|
+
shift 2
|
|
52
|
+
;;
|
|
53
|
+
--list-permissions)
|
|
54
|
+
LIST_PERMS=true
|
|
55
|
+
shift
|
|
56
|
+
;;
|
|
57
|
+
--save-to)
|
|
58
|
+
SAVE_TO="$2"
|
|
59
|
+
shift 2
|
|
60
|
+
;;
|
|
61
|
+
--network)
|
|
62
|
+
NETWORK="$2"
|
|
63
|
+
shift 2
|
|
64
|
+
;;
|
|
65
|
+
--lnddir)
|
|
66
|
+
LND_DIR="$2"
|
|
67
|
+
shift 2
|
|
68
|
+
;;
|
|
69
|
+
--rpc-port)
|
|
70
|
+
RPC_PORT="$2"
|
|
71
|
+
shift 2
|
|
72
|
+
;;
|
|
73
|
+
--container)
|
|
74
|
+
CONTAINER="$2"
|
|
75
|
+
shift 2
|
|
76
|
+
;;
|
|
77
|
+
--rpcserver)
|
|
78
|
+
RPCSERVER="$2"
|
|
79
|
+
shift 2
|
|
80
|
+
;;
|
|
81
|
+
--tlscertpath)
|
|
82
|
+
TLSCERTPATH="$2"
|
|
83
|
+
shift 2
|
|
84
|
+
;;
|
|
85
|
+
--macaroonpath)
|
|
86
|
+
MACAROONPATH="$2"
|
|
87
|
+
shift 2
|
|
88
|
+
;;
|
|
89
|
+
-h|--help)
|
|
90
|
+
echo "Usage: bake.sh [options]"
|
|
91
|
+
echo ""
|
|
92
|
+
echo "Bake, inspect, and manage lnd macaroons."
|
|
93
|
+
echo ""
|
|
94
|
+
echo "Actions:"
|
|
95
|
+
echo " --role ROLE Bake a preset role macaroon"
|
|
96
|
+
echo " --custom URI [URI...] Bake with custom permission URIs"
|
|
97
|
+
echo " --inspect PATH Inspect a macaroon file"
|
|
98
|
+
echo " --list-permissions List all available permission URIs"
|
|
99
|
+
echo ""
|
|
100
|
+
echo "Preset roles: pay-only, invoice-only, read-only, channel-admin, signer-only"
|
|
101
|
+
echo ""
|
|
102
|
+
echo "Options:"
|
|
103
|
+
echo " --save-to PATH Output path (default: auto-generated)"
|
|
104
|
+
echo " --network NETWORK Bitcoin network (default: testnet)"
|
|
105
|
+
echo " --lnddir DIR lnd data directory (default: ~/.lnd)"
|
|
106
|
+
echo " --rpc-port PORT lnd RPC port (for non-default setups)"
|
|
107
|
+
echo " --container NAME Run lncli inside a Docker container"
|
|
108
|
+
echo " --rpcserver HOST:PORT Connect to a remote lnd node"
|
|
109
|
+
echo " --tlscertpath PATH TLS certificate for remote connection"
|
|
110
|
+
echo " --macaroonpath PATH Macaroon for remote authentication"
|
|
111
|
+
exit 0
|
|
112
|
+
;;
|
|
113
|
+
*)
|
|
114
|
+
echo "Unknown option: $1" >&2
|
|
115
|
+
exit 1
|
|
116
|
+
;;
|
|
117
|
+
esac
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
# Apply default lnddir if not set.
|
|
121
|
+
if [ -z "$LND_DIR" ]; then
|
|
122
|
+
if [ -n "$CONTAINER" ]; then
|
|
123
|
+
LND_DIR="/root/.lnd"
|
|
124
|
+
else
|
|
125
|
+
LND_DIR="$HOME/.lnd"
|
|
126
|
+
fi
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# Build lncli base command as an array (preserves paths with spaces).
|
|
130
|
+
LNCLI_CMD=()
|
|
131
|
+
if [ -n "$CONTAINER" ]; then
|
|
132
|
+
LNCLI_CMD+=(docker exec "$CONTAINER")
|
|
133
|
+
fi
|
|
134
|
+
LNCLI_CMD+=(lncli "--network=$NETWORK" "--lnddir=$LND_DIR")
|
|
135
|
+
if [ -n "$RPCSERVER" ]; then
|
|
136
|
+
LNCLI_CMD+=("--rpcserver=$RPCSERVER")
|
|
137
|
+
elif [ -n "$RPC_PORT" ]; then
|
|
138
|
+
LNCLI_CMD+=("--rpcserver=localhost:$RPC_PORT")
|
|
139
|
+
fi
|
|
140
|
+
if [ -n "$TLSCERTPATH" ]; then
|
|
141
|
+
LNCLI_CMD+=("--tlscertpath=$TLSCERTPATH")
|
|
142
|
+
fi
|
|
143
|
+
if [ -n "$MACAROONPATH" ]; then
|
|
144
|
+
LNCLI_CMD+=("--macaroonpath=$MACAROONPATH")
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Verify lncli is available.
|
|
148
|
+
if [ -n "$CONTAINER" ]; then
|
|
149
|
+
if ! docker exec "$CONTAINER" which lncli &>/dev/null; then
|
|
150
|
+
echo "Error: lncli not found in container '$CONTAINER'." >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
elif ! command -v lncli &>/dev/null; then
|
|
154
|
+
echo "Error: lncli not found. Run the lnd skill's install.sh first." >&2
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# --- Inspect mode ---
|
|
159
|
+
if [ -n "$INSPECT" ]; then
|
|
160
|
+
if [ -n "$CONTAINER" ]; then
|
|
161
|
+
# The macaroon may be on the host or inside the container. If it
|
|
162
|
+
# exists on the host, copy it into the container for inspection.
|
|
163
|
+
if [ -f "$INSPECT" ]; then
|
|
164
|
+
CONTAINER_TMP="/tmp/inspect-$(date +%s).macaroon"
|
|
165
|
+
docker cp "$INSPECT" "$CONTAINER:$CONTAINER_TMP"
|
|
166
|
+
INSPECT_PATH="$CONTAINER_TMP"
|
|
167
|
+
elif docker exec "$CONTAINER" test -f "$INSPECT" 2>/dev/null; then
|
|
168
|
+
INSPECT_PATH="$INSPECT"
|
|
169
|
+
else
|
|
170
|
+
echo "Error: Macaroon file not found: $INSPECT" >&2
|
|
171
|
+
exit 1
|
|
172
|
+
fi
|
|
173
|
+
elif [ ! -f "$INSPECT" ]; then
|
|
174
|
+
echo "Error: Macaroon file not found: $INSPECT" >&2
|
|
175
|
+
exit 1
|
|
176
|
+
else
|
|
177
|
+
INSPECT_PATH="$INSPECT"
|
|
178
|
+
fi
|
|
179
|
+
echo "=== Macaroon: $(basename "$INSPECT") ==="
|
|
180
|
+
echo "Path: $INSPECT"
|
|
181
|
+
if [ -n "$CONTAINER" ]; then
|
|
182
|
+
echo "Container: $CONTAINER"
|
|
183
|
+
fi
|
|
184
|
+
echo ""
|
|
185
|
+
"${LNCLI_CMD[@]}" printmacaroon --macaroon_file "$INSPECT_PATH"
|
|
186
|
+
# Clean up temporary copy if we created one.
|
|
187
|
+
if [ -n "$CONTAINER" ] && [ -f "$INSPECT" ]; then
|
|
188
|
+
docker exec "$CONTAINER" rm -f "$INSPECT_PATH" 2>/dev/null || true
|
|
189
|
+
fi
|
|
190
|
+
exit 0
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# --- List permissions mode ---
|
|
194
|
+
if [ "$LIST_PERMS" = true ]; then
|
|
195
|
+
echo "=== Available Macaroon Permissions ==="
|
|
196
|
+
echo ""
|
|
197
|
+
"${LNCLI_CMD[@]}" listpermissions | jq -r '.method_permissions | to_entries[] | .key' | sort
|
|
198
|
+
exit 0
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# --- Bake mode ---
|
|
202
|
+
|
|
203
|
+
# Resolve permissions from role or custom.
|
|
204
|
+
PERMS=()
|
|
205
|
+
|
|
206
|
+
if [ -n "$ROLE" ]; then
|
|
207
|
+
case $ROLE in
|
|
208
|
+
pay-only)
|
|
209
|
+
PERMS=(
|
|
210
|
+
"uri:/lnrpc.Lightning/SendPaymentSync"
|
|
211
|
+
"uri:/routerrpc.Router/SendPaymentV2"
|
|
212
|
+
"uri:/lnrpc.Lightning/DecodePayReq"
|
|
213
|
+
"uri:/lnrpc.Lightning/GetInfo"
|
|
214
|
+
)
|
|
215
|
+
;;
|
|
216
|
+
invoice-only)
|
|
217
|
+
PERMS=(
|
|
218
|
+
"uri:/lnrpc.Lightning/AddInvoice"
|
|
219
|
+
"uri:/invoicesrpc.Invoices/AddHoldInvoice"
|
|
220
|
+
"uri:/lnrpc.Lightning/LookupInvoice"
|
|
221
|
+
"uri:/lnrpc.Lightning/ListInvoices"
|
|
222
|
+
"uri:/lnrpc.Lightning/GetInfo"
|
|
223
|
+
)
|
|
224
|
+
;;
|
|
225
|
+
read-only)
|
|
226
|
+
PERMS=(
|
|
227
|
+
"uri:/lnrpc.Lightning/GetInfo"
|
|
228
|
+
"uri:/lnrpc.Lightning/WalletBalance"
|
|
229
|
+
"uri:/lnrpc.Lightning/ChannelBalance"
|
|
230
|
+
"uri:/lnrpc.Lightning/ListChannels"
|
|
231
|
+
"uri:/lnrpc.Lightning/ListPeers"
|
|
232
|
+
"uri:/lnrpc.Lightning/ListPayments"
|
|
233
|
+
"uri:/lnrpc.Lightning/ListInvoices"
|
|
234
|
+
"uri:/lnrpc.Lightning/GetNodeInfo"
|
|
235
|
+
"uri:/lnrpc.Lightning/GetChanInfo"
|
|
236
|
+
)
|
|
237
|
+
;;
|
|
238
|
+
channel-admin)
|
|
239
|
+
PERMS=(
|
|
240
|
+
"uri:/lnrpc.Lightning/GetInfo"
|
|
241
|
+
"uri:/lnrpc.Lightning/WalletBalance"
|
|
242
|
+
"uri:/lnrpc.Lightning/ChannelBalance"
|
|
243
|
+
"uri:/lnrpc.Lightning/ListChannels"
|
|
244
|
+
"uri:/lnrpc.Lightning/ListPeers"
|
|
245
|
+
"uri:/lnrpc.Lightning/ConnectPeer"
|
|
246
|
+
"uri:/lnrpc.Lightning/DisconnectPeer"
|
|
247
|
+
"uri:/lnrpc.Lightning/OpenChannelSync"
|
|
248
|
+
"uri:/lnrpc.Lightning/CloseChannel"
|
|
249
|
+
"uri:/lnrpc.Lightning/ClosedChannels"
|
|
250
|
+
"uri:/lnrpc.Lightning/GetNodeInfo"
|
|
251
|
+
"uri:/lnrpc.Lightning/GetChanInfo"
|
|
252
|
+
)
|
|
253
|
+
;;
|
|
254
|
+
signer-only)
|
|
255
|
+
PERMS=(
|
|
256
|
+
"uri:/signrpc.Signer/SignOutputRaw"
|
|
257
|
+
"uri:/signrpc.Signer/ComputeInputScript"
|
|
258
|
+
"uri:/signrpc.Signer/MuSig2Sign"
|
|
259
|
+
"uri:/signrpc.Signer/MuSig2Cleanup"
|
|
260
|
+
"uri:/signrpc.Signer/MuSig2CreateSession"
|
|
261
|
+
"uri:/signrpc.Signer/MuSig2RegisterNonces"
|
|
262
|
+
"uri:/signrpc.Signer/MuSig2CombineSig"
|
|
263
|
+
"uri:/walletrpc.WalletKit/DeriveKey"
|
|
264
|
+
"uri:/walletrpc.WalletKit/DeriveNextKey"
|
|
265
|
+
"uri:/lnrpc.Lightning/GetInfo"
|
|
266
|
+
)
|
|
267
|
+
;;
|
|
268
|
+
*)
|
|
269
|
+
echo "Error: Unknown role '$ROLE'." >&2
|
|
270
|
+
echo "Available roles: pay-only, invoice-only, read-only, channel-admin, signer-only" >&2
|
|
271
|
+
exit 1
|
|
272
|
+
;;
|
|
273
|
+
esac
|
|
274
|
+
elif [ ${#CUSTOM_PERMS[@]} -gt 0 ]; then
|
|
275
|
+
PERMS=("${CUSTOM_PERMS[@]}")
|
|
276
|
+
else
|
|
277
|
+
echo "Error: Specify --role, --custom, --inspect, or --list-permissions." >&2
|
|
278
|
+
echo "Run bake.sh --help for usage." >&2
|
|
279
|
+
exit 1
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
# Determine output path.
|
|
283
|
+
if [ -z "$SAVE_TO" ]; then
|
|
284
|
+
if [ -n "$CONTAINER" ] || [ -n "$RPCSERVER" ]; then
|
|
285
|
+
# Container/remote mode: save locally, not inside the container or on the remote.
|
|
286
|
+
MACAROON_DIR="$HOME/.lnget/macaroons"
|
|
287
|
+
else
|
|
288
|
+
MACAROON_DIR="$LND_DIR/data/chain/bitcoin/$NETWORK"
|
|
289
|
+
fi
|
|
290
|
+
if [ -n "$ROLE" ]; then
|
|
291
|
+
SAVE_TO="$MACAROON_DIR/${ROLE}.macaroon"
|
|
292
|
+
else
|
|
293
|
+
SAVE_TO="$MACAROON_DIR/custom-$(date +%s).macaroon"
|
|
294
|
+
fi
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
# Ensure output directory exists.
|
|
298
|
+
mkdir -p "$(dirname "$SAVE_TO")"
|
|
299
|
+
|
|
300
|
+
echo "=== Baking Macaroon ==="
|
|
301
|
+
if [ -n "$ROLE" ]; then
|
|
302
|
+
echo "Role: $ROLE"
|
|
303
|
+
fi
|
|
304
|
+
echo "Permissions: ${#PERMS[@]}"
|
|
305
|
+
echo "Output: $SAVE_TO"
|
|
306
|
+
echo ""
|
|
307
|
+
|
|
308
|
+
# Bake the macaroon.
|
|
309
|
+
if [ -n "$CONTAINER" ]; then
|
|
310
|
+
# Bake inside container, then copy out to local path.
|
|
311
|
+
CONTAINER_TMP="/tmp/baked-$(date +%s).macaroon"
|
|
312
|
+
"${LNCLI_CMD[@]}" bakemacaroon "${PERMS[@]}" --save_to="$CONTAINER_TMP"
|
|
313
|
+
docker cp "$CONTAINER:$CONTAINER_TMP" "$SAVE_TO"
|
|
314
|
+
docker exec "$CONTAINER" rm -f "$CONTAINER_TMP"
|
|
315
|
+
else
|
|
316
|
+
"${LNCLI_CMD[@]}" bakemacaroon "${PERMS[@]}" --save_to="$SAVE_TO"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
# Set restrictive permissions.
|
|
320
|
+
chmod 600 "$SAVE_TO"
|
|
321
|
+
|
|
322
|
+
echo ""
|
|
323
|
+
echo "=== Macaroon Baked ==="
|
|
324
|
+
echo "Saved to: $SAVE_TO (mode 0600)"
|
|
325
|
+
echo ""
|
|
326
|
+
echo "Permissions granted:"
|
|
327
|
+
for p in "${PERMS[@]}"; do
|
|
328
|
+
echo " $p"
|
|
329
|
+
done
|
|
330
|
+
echo ""
|
|
331
|
+
echo "To verify:"
|
|
332
|
+
echo " bake.sh --inspect $SAVE_TO"
|
|
333
|
+
echo ""
|
|
334
|
+
echo "To use with lnget:"
|
|
335
|
+
echo " ln:"
|
|
336
|
+
echo " lnd:"
|
|
337
|
+
echo " macaroon: $SAVE_TO"
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-lnc
|
|
3
|
+
description: Build and configure the MCP server for Lightning Node Connect (LNC). Connects AI assistants to lnd nodes via encrypted WebSocket tunnels using pairing phrases — no direct network access or TLS certs needed. Read-only by default (18 tools for querying node state, channels, payments, invoices, peers, on-chain data).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# MCP LNC Server
|
|
7
|
+
|
|
8
|
+
Build and configure the MCP server that connects AI assistants to Lightning
|
|
9
|
+
nodes via **Lightning Node Connect (LNC)**. LNC uses encrypted WebSocket tunnels
|
|
10
|
+
through a mailbox relay, so the agent never needs direct gRPC access, TLS
|
|
11
|
+
certificates, or macaroons — just a 10-word pairing phrase from Lightning
|
|
12
|
+
Terminal.
|
|
13
|
+
|
|
14
|
+
The MCP server is **read-only by default** — it exposes 18 tools for querying
|
|
15
|
+
node state but cannot send payments or modify channels.
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# 1. Build the MCP server binary
|
|
21
|
+
skills/mcp-lnc/scripts/install.sh
|
|
22
|
+
|
|
23
|
+
# 2. Configure environment (mailbox server, dev mode, etc.)
|
|
24
|
+
skills/mcp-lnc/scripts/configure.sh
|
|
25
|
+
|
|
26
|
+
# 3. Add to Claude Code as an MCP server
|
|
27
|
+
skills/mcp-lnc/scripts/setup-claude-config.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then restart Claude Code. The `lnc_connect` tool will be available to connect
|
|
31
|
+
to any lnd node using a pairing phrase.
|
|
32
|
+
|
|
33
|
+
## How It Works
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Claude Code <--stdio--> mcp-lnc-server <--LNC WebSocket--> Mailbox <--> lnd
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
1. Claude Code launches `mcp-lnc-server` as a subprocess (stdio transport)
|
|
40
|
+
2. Agent calls `lnc_connect` with a pairing phrase and password
|
|
41
|
+
3. Server generates an ephemeral ECDSA keypair and opens an encrypted WebSocket
|
|
42
|
+
tunnel through the mailbox relay
|
|
43
|
+
4. Once connected, the agent can call any of the 18 read-only tools
|
|
44
|
+
5. `lnc_disconnect` closes the tunnel
|
|
45
|
+
|
|
46
|
+
No keys, certs, or macaroons are stored on disk — the pairing phrase is the
|
|
47
|
+
only credential, and it's handled in-memory only.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Build from source (requires Go 1.24+)
|
|
53
|
+
skills/mcp-lnc/scripts/install.sh
|
|
54
|
+
|
|
55
|
+
# Verify
|
|
56
|
+
mcp-lnc-server -version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The install script builds from the `mcp-server/` directory in this repo.
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Generate .env with defaults
|
|
65
|
+
skills/mcp-lnc/scripts/configure.sh
|
|
66
|
+
|
|
67
|
+
# Production (mainnet via Lightning Terminal)
|
|
68
|
+
skills/mcp-lnc/scripts/configure.sh --production
|
|
69
|
+
|
|
70
|
+
# Development (local regtest)
|
|
71
|
+
skills/mcp-lnc/scripts/configure.sh --dev --mailbox aperture:11110
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Configuration is stored in `mcp-server/.env`. Key settings:
|
|
75
|
+
|
|
76
|
+
| Variable | Default | Description |
|
|
77
|
+
|----------|---------|-------------|
|
|
78
|
+
| `LNC_MAILBOX_SERVER` | `mailbox.terminal.lightning.today:443` | Mailbox relay server |
|
|
79
|
+
| `LNC_DEV_MODE` | `false` | Enable development mode |
|
|
80
|
+
| `LNC_INSECURE` | `false` | Skip TLS verification (dev only) |
|
|
81
|
+
| `LNC_CONNECT_TIMEOUT` | `30` | Connection timeout in seconds |
|
|
82
|
+
|
|
83
|
+
## Claude Code Integration
|
|
84
|
+
|
|
85
|
+
### Option 1: `claude mcp add` (recommended)
|
|
86
|
+
|
|
87
|
+
Register the MCP server with a single command — no build step required:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Zero-install via npx (downloads pre-built binary)
|
|
91
|
+
claude mcp add --transport stdio lnc -- npx -y @lightninglabs/lightning-mcp-server
|
|
92
|
+
|
|
93
|
+
# With environment variables for production
|
|
94
|
+
claude mcp add --transport stdio \
|
|
95
|
+
--env LNC_MAILBOX_SERVER=mailbox.terminal.lightning.today:443 \
|
|
96
|
+
lnc -- npx -y @lightninglabs/lightning-mcp-server
|
|
97
|
+
|
|
98
|
+
# For development/regtest
|
|
99
|
+
claude mcp add --transport stdio \
|
|
100
|
+
--env LNC_MAILBOX_SERVER=localhost:11110 \
|
|
101
|
+
--env LNC_DEV_MODE=true \
|
|
102
|
+
--env LNC_INSECURE=true \
|
|
103
|
+
lnc -- npx -y @lightninglabs/lightning-mcp-server
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Scope options: `--scope local` (default, just you), `--scope project` (shared
|
|
107
|
+
via `.mcp.json`), `--scope user` (all your projects).
|
|
108
|
+
|
|
109
|
+
### Option 2: Setup script (from source)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Add mcp-lnc-server to Claude Code's MCP config
|
|
113
|
+
skills/mcp-lnc/scripts/setup-claude-config.sh
|
|
114
|
+
|
|
115
|
+
# Project-level config (current project only)
|
|
116
|
+
skills/mcp-lnc/scripts/setup-claude-config.sh --scope project
|
|
117
|
+
|
|
118
|
+
# Global config (all projects)
|
|
119
|
+
skills/mcp-lnc/scripts/setup-claude-config.sh --scope global
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This adds the server to Claude Code's `.mcp.json` (project) or
|
|
123
|
+
`~/.claude.json` (global) configuration. After restarting Claude Code, the
|
|
124
|
+
LNC tools will be available.
|
|
125
|
+
|
|
126
|
+
### Option 3: Manual configuration
|
|
127
|
+
|
|
128
|
+
Add to `.mcp.json` in your project root:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"mcpServers": {
|
|
133
|
+
"lnc": {
|
|
134
|
+
"command": "npx",
|
|
135
|
+
"args": ["-y", "@lightninglabs/lightning-mcp-server"],
|
|
136
|
+
"env": {
|
|
137
|
+
"LNC_MAILBOX_SERVER": "mailbox.terminal.lightning.today:443"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Or with a locally built binary:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mcpServers": {
|
|
149
|
+
"lnc": {
|
|
150
|
+
"command": "mcp-lnc-server",
|
|
151
|
+
"env": {
|
|
152
|
+
"LNC_MAILBOX_SERVER": "mailbox.terminal.lightning.today:443"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Or run via Docker:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"mcpServers": {
|
|
164
|
+
"lnc": {
|
|
165
|
+
"command": "docker",
|
|
166
|
+
"args": [
|
|
167
|
+
"run", "--rm", "-i", "--network", "host",
|
|
168
|
+
"--env", "LNC_MAILBOX_SERVER",
|
|
169
|
+
"--env", "LNC_DEV_MODE",
|
|
170
|
+
"--env", "LNC_INSECURE",
|
|
171
|
+
"mcp-lnc-server"
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Available Tools (18)
|
|
179
|
+
|
|
180
|
+
### Connection
|
|
181
|
+
|
|
182
|
+
| Tool | Description |
|
|
183
|
+
|------|-------------|
|
|
184
|
+
| `lnc_connect` | Connect to lnd via LNC pairing phrase |
|
|
185
|
+
| `lnc_disconnect` | Close active LNC connection |
|
|
186
|
+
|
|
187
|
+
### Node
|
|
188
|
+
|
|
189
|
+
| Tool | Description |
|
|
190
|
+
|------|-------------|
|
|
191
|
+
| `lnc_get_info` | Node alias, version, sync status, block height |
|
|
192
|
+
| `lnc_get_balance` | Wallet balance (on-chain) and channel balance |
|
|
193
|
+
|
|
194
|
+
### Channels
|
|
195
|
+
|
|
196
|
+
| Tool | Description |
|
|
197
|
+
|------|-------------|
|
|
198
|
+
| `lnc_list_channels` | Active/inactive channels with capacity, balances |
|
|
199
|
+
| `lnc_pending_channels` | Channels being opened or closed |
|
|
200
|
+
|
|
201
|
+
### Invoices
|
|
202
|
+
|
|
203
|
+
| Tool | Description |
|
|
204
|
+
|------|-------------|
|
|
205
|
+
| `lnc_decode_invoice` | Decode a BOLT11 invoice |
|
|
206
|
+
| `lnc_list_invoices` | List invoices with pagination |
|
|
207
|
+
| `lnc_lookup_invoice` | Look up invoice by payment hash |
|
|
208
|
+
|
|
209
|
+
### Payments
|
|
210
|
+
|
|
211
|
+
| Tool | Description |
|
|
212
|
+
|------|-------------|
|
|
213
|
+
| `lnc_list_payments` | Payment history with pagination |
|
|
214
|
+
| `lnc_track_payment` | Track specific payment by hash |
|
|
215
|
+
|
|
216
|
+
### Peers & Network
|
|
217
|
+
|
|
218
|
+
| Tool | Description |
|
|
219
|
+
|------|-------------|
|
|
220
|
+
| `lnc_list_peers` | Connected peers with stats |
|
|
221
|
+
| `lnc_describe_graph` | Lightning Network topology sample |
|
|
222
|
+
| `lnc_get_node_info` | Detailed info about a specific node |
|
|
223
|
+
|
|
224
|
+
### On-Chain
|
|
225
|
+
|
|
226
|
+
| Tool | Description |
|
|
227
|
+
|------|-------------|
|
|
228
|
+
| `lnc_list_unspent` | UTXOs with confirmations |
|
|
229
|
+
| `lnc_get_transactions` | On-chain transaction history |
|
|
230
|
+
| `lnc_estimate_fee` | Fee estimates for confirmation targets |
|
|
231
|
+
|
|
232
|
+
## Security Model
|
|
233
|
+
|
|
234
|
+
- **No stored credentials:** Pairing phrase is handled in-memory only. Ephemeral
|
|
235
|
+
ECDSA keypairs are generated per session.
|
|
236
|
+
- **Read-only:** No payment, channel, or state-changing operations are exposed.
|
|
237
|
+
The agent can observe but not modify.
|
|
238
|
+
- **Encrypted tunnels:** All traffic is encrypted end-to-end through the mailbox
|
|
239
|
+
relay. The mailbox cannot read the traffic.
|
|
240
|
+
- **No direct access:** The agent machine never connects directly to the lnd
|
|
241
|
+
node's gRPC port — all traffic goes through the mailbox.
|
|
242
|
+
|
|
243
|
+
### Comparison with Direct gRPC Access
|
|
244
|
+
|
|
245
|
+
| | MCP LNC Server | Direct lncli/gRPC |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| **Credential** | Pairing phrase (in-memory) | TLS cert + macaroon (on disk) |
|
|
248
|
+
| **Network** | WebSocket via mailbox relay | Direct TCP to gRPC port |
|
|
249
|
+
| **Firewall** | No inbound ports needed | Port 10009 must be reachable |
|
|
250
|
+
| **Permissions** | Read-only (hardcoded) | Depends on macaroon scope |
|
|
251
|
+
| **Setup** | Pairing phrase from Lightning Terminal | Export cert + macaroon files |
|
|
252
|
+
|
|
253
|
+
## Prerequisites
|
|
254
|
+
|
|
255
|
+
- **Go 1.24+** for building from source
|
|
256
|
+
- **Lightning Terminal (litd)** on the target node for generating pairing phrases
|
|
257
|
+
- **Claude Code** for MCP integration
|
|
258
|
+
|
|
259
|
+
## Troubleshooting
|
|
260
|
+
|
|
261
|
+
### "pairing phrase must be exactly 10 words"
|
|
262
|
+
The pairing phrase is generated by Lightning Terminal. It must be exactly 10
|
|
263
|
+
space-separated words.
|
|
264
|
+
|
|
265
|
+
### "connection timeout"
|
|
266
|
+
Check that the mailbox server is reachable. For production, ensure
|
|
267
|
+
`mailbox.terminal.lightning.today:443` is not blocked by a firewall.
|
|
268
|
+
|
|
269
|
+
### "TLS handshake failure"
|
|
270
|
+
If using a local regtest setup, enable dev mode and insecure mode:
|
|
271
|
+
```bash
|
|
272
|
+
skills/mcp-lnc/scripts/configure.sh --dev --insecure
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Tools not appearing in Claude Code
|
|
276
|
+
Restart Claude Code after running `setup-claude-config.sh`. Check that
|
|
277
|
+
`mcp-lnc-server` is on your `$PATH`:
|
|
278
|
+
```bash
|
|
279
|
+
which mcp-lnc-server
|
|
280
|
+
```
|