Add ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs
, '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 ldk-server-mcp crate scaffolding for MCP gateway - #202

Closed
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22
Closed

Add ldk-server-mcp crate scaffolding for MCP gateway#202
vincenzopalazzo wants to merge 1 commit into
lightningdevkit:mainfrom
vincenzopalazzo:claude/priceless-bardeen-0a8a22

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Member

Summary

v1 scaffolding for a new ldk-server-mcp workspace crate — an HTTPS gateway that will eventually expose the LDK Server gRPC API as an MCP (Model Context Protocol) server, plus a small admin web UI for minting scoped auth tokens to plug into Claude Desktop / Claude Code.

This PR is the foundational layer only. The daemon is unmodified.

  • New ldk-server-mcp workspace crate: TOML config + axum HTTPS listener (HTTP/1.1 + HTTP/2 via hyper-util auto builder) + /healthz
  • Self-signed TLS cert auto-generation, mirroring the daemon's pattern in ldk-server/src/util/tls.rs. Copied (not extracted into a shared util crate) to keep this PR scoped — the brainstorm doc flags the refactor as a v2 deferred item.
  • DaemonClient wrapper around ldk-server-client that loads the daemon's api_key and TLS cert from disk and verifies connectivity on boot via GetNodeInfo.
  • GatewayLogger matching the daemon's ServerLogger so operators see consistent log output across the two processes.
  • Sample contrib/ldk-server-mcp-config.toml and crate-level README.md.
  • Brainstorm doc at docs/brainstorms/2026-05-07-ldk-server-mcp.md capturing the full v1 spec and the PR breakdown for follow-ups (sqlite token store, web UI, MCP tool layer over the ~40 RPCs, SubscribeEvents -> MCP notifications fan-out, Connect-to-Claude UX).

Architecture

ldk-server-mcp is a separate process and a separate workspace crate from ldk-server. It calls the daemon over its existing gRPC + TLS interface using ldk-server-client. Token storage and scope enforcement live entirely in the gateway in v1; promoting them into the daemon is the v2 path described in the brainstorm.

New dependencies

  • axum 0.7 (default features off; json, tokio)
  • hyper 1 server features http1, http2
  • hyper-util 0.1 features tokio, service, server-auto, http1, http2
  • tower 0.5 (dev-only, for ServiceExt::oneshot in tests)

Everything else is reused from the workspace (tokio, tokio-rustls, ring, serde, toml, clap, log, chrono, hex-conservative, base64, getrandom, ldk-server-client, ldk-server-grpc).

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy -p ldk-server-mcp --all-targets -- -D warnings clean
  • cargo test -p ldk-server-mcp — 14 tests pass (config parse / unknown-field reject / log-level validate / TLS generate-and-load roundtrip / /healthz returns 200 / unknown path returns 404)
  • cargo check --release -p ldk-server-mcp clean
  • cargo doc --release -p ldk-server-mcp --no-deps clean
  • Manual smoke test against a running daemon (curl -k https://127.0.0.1:3537/healthz -> ok) — recommended before merge

Notes for review

  • The daemon's util/tls.rs is duplicated rather than shared. The brainstorm doc flags extracting it into a ldk-server-util crate as a v2 follow-up — keeping this PR to one new crate keeps the diff reviewable. ALPN here is ["h2", "http/1.1"] (vs. the daemon's ["h2"]) so browsers reach the future UI.
  • TLS handshake errors are at debug! (not error!) — port-scanning is normal in the threat model and we don't want to spam the log on each scan.
  • The bootstrap admin token, sqlite token store, and the /api/* UI endpoints are deliberately not in this PR — they land in PR2 of the breakdown in the brainstorm doc.

This change was developed with Claude Code assistance.

v1 scaffolding for an HTTPS gateway that will expose the LDK Server gRPC
API as an MCP (Model Context Protocol) server, plus a small admin web UI
for minting scoped auth tokens to plug into Claude Desktop / Claude Code.
This PR adds the foundational pieces only:
- New `ldk-server-mcp` workspace crate with a TOML config, an `axum`-based
HTTPS listener (HTTP/1.1 + HTTP/2 via `hyper-util`'s auto builder), and
a `/healthz` endpoint
- Self-signed TLS cert auto-generation in `storage_dir`, mirroring the
daemon's pattern in `ldk-server/src/util/tls.rs` (the daemon code is
unchanged; the v2 plan extracts the shared bits into a util crate)
- A `DaemonClient` wrapper around `ldk-server-client` that loads the
daemon's `api_key` and TLS cert from disk and verifies connectivity on
boot via `GetNodeInfo`
- `GatewayLogger` matching the daemon's `ServerLogger` style so operators
see consistent log output across the two processes
- Sample config in `contrib/ldk-server-mcp-config.toml` and a crate-level
`README.md`
- Brainstorm doc at `docs/brainstorms/2026-05-07-ldk-server-mcp.md`
capturing the full v1 spec and the suggested PR breakdown for the rest
of the work (sqlite token store, web UI, MCP tool layer over the ~40
RPCs, `SubscribeEvents` -> MCP notifications fan-out, Connect-to-Claude
UX)
The daemon is unmodified. 14 unit tests cover config parsing, scheme
stripping, log-level validation, unknown-field rejection, the cert
generate/load roundtrip, and the `/healthz` route. `cargo fmt`, `cargo
clippy --all-targets -- -D warnings`, `cargo test`, `cargo check
--release`, and `cargo doc --release` all pass for the new crate.
This change was developed with Claude Code assistance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ldk-reviews-bot

ldk-reviews-bot commented May 7, 2026

Copy link
Copy Markdown

I've assigned @wpaulino as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@AnyitechsAnyitechs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen #188 or this is different?

@vincenzopalazzo

Copy link
Copy Markdown
MemberAuthor

Ah sorry! i open the PR on the wrong repository.

Have you seen #188 or this is different?

Yes but this is an PoC over the Https transport layer and not only stdio See https://modelcontextprotocol.io/specification/2025-03-26/basic/transports but this is not ready to be proposed yet, sorry

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.

3 participants

@vincenzopalazzo@ldk-reviews-bot@Anyitechs