Skip to main content
Glama

ldk_node_info

Retrieve real-time node status and connectivity details to monitor and manage Lightning Network operations with LDK MCP Server tools.

Instructions

Get current node status and connectivity information

Input Schema

NameRequiredDescriptionDefault

No arguments

Input Schema (JSON Schema)

{ "properties": {}, "type": "object" }

Implementation Reference

  • The main handler function for the 'ldk_node_info' tool. It fetches node information and balance from LightningService, formats the response as JSON with additional SwiftUI example code, and handles errors.
    execute: async (args: any): Promise<ToolResult> => { try { const nodeInfo = await lightningService.getNodeInfo(); const balance = await lightningService.getBalance(); return { content: [{ type: 'text', text: JSON.stringify({ success: true, nodeInfo: { nodeId: nodeInfo.nodeId, alias: nodeInfo.alias, version: nodeInfo.version, blockHeight: nodeInfo.blockHeight, syncedToChain: nodeInfo.syncedToChain, channels: { total: nodeInfo.numChannels, usable: nodeInfo.numUsableChannels }, balance: { totalSats: Math.floor(balance.totalMsat / 1000), spendableSats: Math.floor(balance.spendableMsat / 1000) }, peers: nodeInfo.numPeers }, swiftExample: ` // Swift code to display node info in your iOS app import SwiftUI import LightningDevKit struct NodeInfoView: View { @State private var nodeInfo: NodeInfo? @State private var isLoading = true @State private var isSyncing = false var body: some View { ScrollView { VStack(spacing: 20) { // Node Identity Card VStack(alignment: .leading, spacing: 12) { HStack { Image(systemName: "bolt.circle.fill") .font(.largeTitle) .foregroundColor(.orange) VStack(alignment: .leading) { Text(nodeInfo?.alias ?? "Lightning Node") .font(.title2) .fontWeight(.semibold) Text(nodeInfo?.nodeId.prefix(16) ?? "") .font(.caption) .foregroundColor(.secondary) .monospaced() } Spacer() } Divider() // Sync Status HStack { Label( nodeInfo?.syncedToChain == true ? "Synced" : "Syncing...", systemImage: nodeInfo?.syncedToChain == true ? "checkmark.circle.fill" : "arrow.triangle.2.circlepath" ) .foregroundColor(nodeInfo?.syncedToChain == true ? .green : .orange) Spacer() Text("Block \\(nodeInfo?.blockHeight ?? 0)") .font(.caption) .foregroundColor(.secondary) } } .padding() .background(Color(UIColor.secondarySystemBackground)) .cornerRadius(12) // Stats Grid LazyVGrid(columns: [ GridItem(.flexible()), GridItem(.flexible()) ], spacing: 16) { StatCard( title: "Channels", value: "\\(nodeInfo?.numUsableChannels ?? 0)/\\(nodeInfo?.numChannels ?? 0)", icon: "link", color: .blue ) StatCard( title: "Peers", value: "\\(nodeInfo?.numPeers ?? 0)", icon: "person.2", color: .green ) StatCard( title: "Total Balance", value: "\\(formatSats(nodeInfo?.totalBalanceSats ?? 0))", icon: "bitcoinsign.circle", color: .orange ) StatCard( title: "Spendable", value: "\\(formatSats(nodeInfo?.spendableBalanceSats ?? 0))", icon: "paperplane", color: .purple ) } // Actions VStack(spacing: 12) { Button(action: syncToTip) { Label("Sync to Chain Tip", systemImage: "arrow.clockwise") .frame(maxWidth: .infinity) } .buttonStyle(.bordered) .disabled(isSyncing) Button(action: openChannel) { Label("Open Channel", systemImage: "plus.circle") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) } .padding(.top) } .padding() } .navigationTitle("Node Info") .navigationBarTitleDisplayMode(.inline) .refreshable { await loadNodeInfo() } .task { await loadNodeInfo() } .overlay { if isLoading { ProgressView("Loading node info...") .padding() .background(Color(UIColor.systemBackground)) .cornerRadius(10) .shadow(radius: 5) } } } func loadNodeInfo() async { isLoading = true defer { isLoading = false } // Fetch node info from LDK let ldkManager = LDKManager.shared nodeInfo = await ldkManager.getNodeInfo() } func syncToTip() { Task { isSyncing = true defer { isSyncing = false } await LDKManager.shared.syncToChainTip() await loadNodeInfo() } } func openChannel() { // Navigate to channel opening view } func formatSats(_ sats: Int64) -> String { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.groupingSeparator = "," return formatter.string(from: NSNumber(value: sats)) ?? "0" } } struct StatCard: View { let title: String let value: String let icon: String let color: Color var body: some View { VStack(spacing: 8) { HStack { Image(systemName: icon) .foregroundColor(color) Spacer() } VStack(alignment: .leading, spacing: 4) { Text(value) .font(.title3) .fontWeight(.semibold) Text(title) .font(.caption) .foregroundColor(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) } .padding() .background(Color(UIColor.secondarySystemBackground)) .cornerRadius(10) } }`.trim() }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } }
  • src/index.ts:16-62 (registration)
    The tool is imported and added to the central tools array used by the MCP server to handle listTools and callTool requests.
    import { getNodeInfoTool } from './tools/getNodeInfo.js'; import { backupStateTool } from './tools/backupState.js'; import { keychainTestTool } from './tools/iosKeychainTest.js'; import { backgroundTestTool } from './tools/iosBackgroundTest.js'; import { pushNotificationTool } from './tools/iosPushNotification.js'; import { biometricAuthTool } from './tools/iosBiometricAuth.js'; import { createChannelTool } from './tools/createChannel.js'; import { closeChannelTool } from './tools/closeChannel.js'; import { getBalanceTool } from './tools/getBalance.js'; import { decodeInvoiceTool } from './tools/decodeInvoice.js'; import { listPaymentsTool } from './tools/listPayments.js'; import { estimateFeeTool } from './tools/estimateFee.js'; import { generateMnemonicTool } from './tools/generateMnemonic.js'; import { deriveAddressTool } from './tools/deriveAddress.js'; import { getSwiftCodeTool } from './tools/getSwiftCode.js'; import { getArchitectureTool } from './tools/getArchitecture.js'; import { testScenarioTool } from './tools/testScenario.js'; import { networkGraphTool } from './tools/networkGraph.js'; import { eventHandlingTool } from './tools/eventHandling.js'; import { chainSyncTool } from './tools/chainSync.js'; // Aggregate all tools const tools = [ generateInvoiceTool, payInvoiceTool, getChannelStatusTool, getNodeInfoTool, backupStateTool, keychainTestTool, backgroundTestTool, pushNotificationTool, biometricAuthTool, createChannelTool, closeChannelTool, getBalanceTool, decodeInvoiceTool, listPaymentsTool, estimateFeeTool, generateMnemonicTool, deriveAddressTool, getSwiftCodeTool, getArchitectureTool, testScenarioTool, networkGraphTool, eventHandlingTool, chainSyncTool, ];
  • Input schema for the tool, which takes no parameters (empty object).
    inputSchema: { type: 'object', properties: {} },
  • Helper method in LightningService that returns the current mock NodeInfo object used by the tool handler.
    async getNodeInfo(): Promise<NodeInfo> { return this.nodeInfo; }
  • Helper method in LightningService that calculates total and spendable balance from channels, used in the tool response.
    async getBalance(): Promise<{ totalMsat: number; spendableMsat: number }> { let totalMsat = 0; let spendableMsat = 0; for (const channel of this.channels.values()) { if (channel.state === ChannelState.Open) { totalMsat += channel.localBalanceMsat; if (channel.isUsable) { // Reserve 1% for fees spendableMsat += Math.floor(channel.localBalanceMsat * 0.99); } } } return { totalMsat, spendableMsat }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/StevenGeller/ldk-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server