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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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

@ConorOkusConorOkus 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

DecisionWhy
One page for all four clients, with ::: code-group tabsEverything 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 pathWith 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 groupThe 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 componentThis 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

netlifyBot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

NameLink
🔨 Latest commit69d99ba
🔍 Latest deploy loghttps://app.netlify.com/projects/lightningdevkit/deploys/6a86141ca5e2800008e37d95
😎 Deploy Previewhttps://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 mainAug 19, 2026
5 checks passed
@ConorOkus
ConorOkus deleted the docs/ldk-server-mcp-agent-tutorial branch August 19, 2026 20:44
Sign up for freeto 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

@ConorOkus