Skip to main content
Glama
StevenGeller

LDK MCP Server

by StevenGeller

ldk_generate_invoice

Create Lightning invoices with real payment hashes for testing iOS wallet development, specifying amount, description, and expiry time.

Instructions

Generate a Lightning invoice with real payment hash for testing

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
amountSatsYesAmount in satoshis
descriptionNoInvoice description
expirySecondsNoInvoice expiry time in seconds (default: 3600)

Implementation Reference

  • The execute handler function that implements the core logic: converts amount to millisatoshis, generates invoice via LightningService, formats response with success details and SwiftUI example code.
      execute: async (args: any): Promise<ToolResult> => {
        try {
          const amountMsat = args.amountSats * 1000;
          const invoice = await lightningService.generateInvoice(
            amountMsat,
            args.description,
            args.expirySeconds || 3600
          );
    
          return {
            content: [{
              type: 'text',
              text: JSON.stringify({
                success: true,
                invoice: invoice.bolt11,
                paymentHash: invoice.paymentHash,
                amountSats: args.amountSats,
                expiryTime: invoice.expiryTime,
                description: invoice.description,
                swiftExample: `
    // Swift code to generate and display Lightning invoice using LDK
    import SwiftUI
    import LightningDevKit
    import CoreImage.CIFilterBuiltins
    
    class InvoiceGenerator {
        let channelManager: Bindings.ChannelManager
        let logger: Bindings.Logger
        let keys: Bindings.KeysManager
        
        init(channelManager: Bindings.ChannelManager, logger: Bindings.Logger, keys: Bindings.KeysManager) {
            self.channelManager = channelManager
            self.logger = logger
            self.keys = keys
        }
        
        func createInvoice(amountMsat: UInt64?, description: String, expirySecs: UInt32 = 3600) -> Result<Bindings.Bolt11Invoice, Error> {
            let invoiceParams = Bindings.InvoiceBuilder.newInvoiceBuilder()
            
            if let amount = amountMsat {
                invoiceParams.amountMsat(amount)
            }
            
            invoiceParams.description(description.asLdkStr())
            invoiceParams.expiryTime(expirySecs)
            
            do {
                let invoice = try invoiceParams.build()
                return .success(invoice)
            } catch {
                return .failure(error)
            }
        }
    }
    
    struct InvoiceView: View {
        let invoice = "${invoice.bolt11}"
        let amountSats = ${args.amountSats}
        @State private var isCopied = false
        
        var body: some View {
            VStack(spacing: 20) {
                Text("Lightning Invoice")
                    .font(.title)
                
                // QR Code
                Image(uiImage: generateQRCode(from: invoice))
                    .interpolation(.none)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 250, height: 250)
                    .overlay(
                        RoundedRectangle(cornerRadius: 16)
                            .stroke(Color.secondary.opacity(0.3), lineWidth: 1)
                    )
                
                // Amount
                VStack(spacing: 4) {
                    Text("\\(amountSats)")
                        .font(.system(size: 36, weight: .bold, design: .rounded))
                    Text("sats")
                        .font(.subheadline)
                        .foregroundColor(.secondary)
                }
                
                // Invoice details
                Text("${args.description || 'Lightning Payment'}")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                
                // Copy button with feedback
                Button(action: {
                    UIPasteboard.general.string = invoice
                    withAnimation(.easeInOut(duration: 0.2)) {
                        isCopied = true
                    }
                    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                        withAnimation(.easeInOut(duration: 0.2)) {
                            isCopied = false
                        }
                    }
                }) {
                    Label(
                        isCopied ? "Copied!" : "Copy Invoice",
                        systemImage: isCopied ? "checkmark.circle.fill" : "doc.on.doc"
                    )
                    .frame(minWidth: 150)
                }
                .buttonStyle(.borderedProminent)
                .tint(isCopied ? .green : .accentColor)
                
                // Share button
                ShareLink(item: invoice) {
                    Label("Share", systemImage: "square.and.arrow.up")
                }
                .buttonStyle(.bordered)
            }
            .padding()
        }
        
        func generateQRCode(from string: String) -> UIImage {
            let context = CIContext()
            let filter = CIFilter.qrCodeGenerator()
            filter.message = Data(string.utf8)
            
            if let outputImage = filter.outputImage {
                let transform = CGAffineTransform(scaleX: 10, y: 10)
                let scaledImage = outputImage.transformed(by: transform)
                
                if let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
            
            return UIImage(systemName: "xmark.circle") ?? UIImage()
        }
    }`.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
          };
        }
      }
  • Input schema defining the parameters for generating the invoice: amountSats (required number >=1), optional description (string), optional expirySeconds (number, default 3600).
    inputSchema: {
      type: 'object',
      properties: {
        amountSats: {
          type: 'number',
          description: 'Amount in satoshis',
          minimum: 1
        },
        description: {
          type: 'string',
          description: 'Invoice description'
        },
        expirySeconds: {
          type: 'number',
          description: 'Invoice expiry time in seconds (default: 3600)',
          default: 3600
        }
      },
      required: ['amountSats']
    },
  • src/index.ts:38-62 (registration)
    Registration of the tool in the main tools array used by the MCP server for handling listTools and callTool requests.
    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,
    ];
  • src/index.ts:13-13 (registration)
    Import of the generateInvoiceTool for registration in the MCP server.
    import { generateInvoiceTool } from './tools/generateInvoice.js';

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