Skip to content

Add a tutorial for managing an LDK Server node with an AI agent - #323

Merged
ConorOkus merged 11 commits into
mainfrom
docs/ldk-server-mcp-agent-tutorial
Aug 19, 2026
Merged

Add a tutorial for managing an LDK Server node with an AI agent#323
ConorOkus merged 11 commits into
mainfrom
docs/ldk-server-mcp-agent-tutorial

Conversation

@ConorOkus

@ConorOkus ConorOkus commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

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-cli calls and reconciling the output by hand. The ldk-server-mcp bridge 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-mcp is 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:

  • It tells Claude Code users to put an mcpServers block in .claude/settings.json, which is not where Claude Code reads MCP configuration. The page uses claude mcp add and .mcp.json, and flags the discrepancy for anyone who already tried the README's version.
  • Its examples set LDK_BASE_URL to localhost:3000. The gRPC service address defaults to 127.0.0.1:3536 (DEFAULT_GRPC_SERVICE_ADDRESS in ldk-server-client), which is the address the node logs at startup.

Both are worth upstreaming separately.

Design decisions

Decision Why
One page for all four clients, with ::: code-group tabs Everything except registration is identical across clients; splitting would quadruplicate the credentials, showcase, and safety content. Tabs match existing usage in docs/key_management.md and the node-building guides
Zero-secret registration as the default path With the node local and on its default data directory, the bridge discovers config, certificate, and key itself, so the agent config holds only a binary path — no API key in a file that might get committed. Environment variables are shown second, for a remote node
A new LDK Server sidebar group The five Advanced Guides entries are all rust-lightning library topics. LDK Server is a different product surface, and the group gives future LDK Server pages somewhere to land
Fenced text diagram rather than mermaid or a Vue component This VitePress install has no mermaid plugin, so a mermaid fence would render as a code block; a component is real build surface for a four-box hop chain

Every factual claim on the page was checked against lightningdevkit/ldk-server at main — the tool registry in ldk-server-mcp/src/tools/mod.rs, credential resolution in ldk-server-client/src/config.rs, and both quoted error strings from ldk-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:vitepress passes — the same command the build workflow runs.
  • Headless browser check against the dev server: /ldk-server-mcp renders, all four code-group tab strips switch content across all four client tabs (clicking Goose swaps in its goose session --with-extension line), and no console errors appear. The new sidebar group shows on existing docs pages and its link navigates to the page.
  • All 38 tool names on the page cross-check against the upstream registry; no invented names.

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-mcp uses 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"]
Loading

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_channels call 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_events RPC is deliberately not exposed, which is why the page tells readers to poll get_payment_details rather than wait for a payment event.


Compound Engineering

@netlify

netlify Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

Name Link
🔨 Latest commit 69d99ba
🔍 Latest deploy log https://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Preview https://deploy-preview-323--lightningdevkit.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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.
@ConorOkus
ConorOkus merged commit 0a6f76b into main Aug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant