Add a tutorial for managing an LDK Server node with an AI agent - #323
Merged
Conversation
✅ Deploy Preview for lightningdevkit ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
…n proof, tool accuracy
- Keep the API key out of shell history and committed config: show each
client's indirection syntax (${VAR}, {env:VAR}, env_vars) instead of a
literal --env LDK_API_KEY.
- Say what a connected server actually proves; the bridge warns and keeps
serving tools when the node is unreachable.
- Drop the claim that open_channel needs a prior connect_peer; its schema
takes the pubkey and address directly.
- Name bolt11_claim_for_hash, bolt11_fail_for_hash, and
update_channel_config among the consequential tools.
- Warn that invoice descriptions, BIP 353 names, and gossip aliases are
untrusted text reaching the agent's context.
- Separate "config lives elsewhere" from "node is on another machine".
…ncode Goose calls MCP servers extensions, so it gets its own tab in all four config groups: goose session --with-extension for a one-off, the ~/.config/goose/config.yaml stdio entry for a permanent one, envs plus env_keys for a remote node, and goose info -v to confirm. Two Goose-specific notes earn their place in the safety section: it ships in Autonomous mode and runs tools without asking until you switch to /mode approve or /mode smart_approve, and its per-tool Always Allow / Ask Before / Never Allow rules are the most precise way on this page to keep read-only tools loose and fund-moving ones gated. Also flag that this one server exposes 38 tools against Goose's own guidance to keep fewer than 25 enabled.
…nstructions - env_keys resolves from the uppercased environment variable first and only then from Goose's secret store, so the shell export above the examples is what feeds it; note that an exported value shadows a stored secret. - Drop the invented `goose settings` hop from the secrets path; Goose's docs put extension secrets directly under `goose configure`. - Give the --config alternative a Goose form (args list) instead of covering only the two --env CLIs and opencode. - Name the two CLIs that take --env and add Goose's inline VAR=value form. - Mark the Goose session tab as per-session so it no longer reads as equivalent to the permanent registrations beside it.
…rection wall The export example used the Linux data directory, which on macOS leaves LDK_API_KEY set to an empty string — xxd fails but the export succeeds, so the agent gets a blank key and the failure only shows up later as an auth error. Show both platform paths and add a length check that makes the failure loud. The per-client indirection guidance had grown into one ~250-word paragraph across successive edits, and it interrupted its own client list with two sentences of Goose detail. Lift the four syntaxes into a table and keep the resolution-order gotcha and the command-line warning as short paragraphs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Node operators can now point their AI agent at an LDK Server node and manage it conversationally — asking which channels are short on outbound liquidity, creating an invoice and checking whether it settled, reviewing a week of forwarding revenue — instead of running
ldk-server-clicalls and reconciling the output by hand. Theldk-server-mcpbridge already exists upstream, but nothing on this site pointed to it: the only mention of LDK Server anywhere was a home-page promo linking to GitHub.The new page at
/ldk-server-mcpis a complete path — build the bridge, locate the node's auto-generated API key and certificate, register it with the Claude Code CLI, the Codex CLI, Goose, or opencode, then run a first health-check prompt. It maps eight worked prompts to the tools they exercise, and treats safety as a section rather than a footnote: fourteen of the exposed tools move funds, settle or fail an in-flight payment, or change channel state.Two upstream README corrections
Following the crate README as written does not work for two of the four clients:
mcpServersblock in.claude/settings.json, which is not where Claude Code reads MCP configuration. The page usesclaude mcp addand.mcp.json, and flags the discrepancy for anyone who already tried the README's version.LDK_BASE_URLtolocalhost:3000. The gRPC service address defaults to127.0.0.1:3536(DEFAULT_GRPC_SERVICE_ADDRESSinldk-server-client), which is the address the node logs at startup.Both are worth upstreaming separately.
Design decisions
::: code-grouptabsdocs/key_management.mdand the node-building guidesLDK Serversidebar groupAdvanced Guidesentries are allrust-lightninglibrary topics. LDK Server is a different product surface, and the group gives future LDK Server pages somewhere to landEvery factual claim on the page was checked against
lightningdevkit/ldk-serveratmain— the tool registry inldk-server-mcp/src/tools/mod.rs, credential resolution inldk-server-client/src/config.rs, and both quoted error strings fromldk-server-mcp/src/config.rs— and against each vendor's current MCP documentation.Session-settled decisions carried from planning: one page covering every client (user-directed, over a page per client) — scoped to Claude Code, Codex, and opencode at plan time, with Goose added later on request.
Validation
npm run build:vitepresspasses — the same command the build workflow runs./ldk-server-mcprenders, all four code-group tab strips switch content across all four client tabs (clicking Goose swaps in itsgoose session --with-extensionline), and no console errors appear. The new sidebar group shows on existing docs pages and its link navigates to the page.New concepts
The Model Context Protocol (MCP)
What it is. MCP is an open protocol that lets an AI agent call tools that live in a separate process. The agent speaks JSON-RPC 2.0 to a server which advertises its tools (
tools/list) and executes them (tools/call); the server owns the credentials and the real API.ldk-server-mcpuses the stdio transport, so the agent launches it as a child process and they exchange one JSON message per line.flowchart TB A["AI agent<br/>(opencode / Claude Code / Codex)"] -->|"JSON-RPC 2.0 over stdio"| B["ldk-server-mcp<br/>(tool schemas + credentials)"] B -->|"gRPC over TLS + API key"| C["ldk-server<br/>(node daemon)"] C --> D["Bitcoin + Lightning"]Why here. LDK Server already had a gRPC API and a CLI, so an agent could just shell out to
ldk-server-cli— but then the agent needs every command's flags, output shape, and error semantics carried in its prompt, and each new RPC needs new scaffolding. An MCP server publishes typed tool schemas the agent discovers at connect time, so the bridge exposes the node's entire unary RPC surface without teaching the agent anything about the CLI.One example from this PR. "Which channels are running low on outbound liquidity?" becomes a single
list_channelscall whose JSON the agent interprets against capacity. The reader never names the tool — the discovered schema list is what makes that mapping possible.When not to use it. MCP tool calls are request/response, so event-driven work does not fit. The streaming
subscribe_eventsRPC is deliberately not exposed, which is why the page tells readers to pollget_payment_detailsrather than wait for a payment event.