Skip to main content
Glama
StevenGeller

LDK MCP Server

by StevenGeller

ldk_generate_mnemonic

Generate BIP39 mnemonic phrases for wallet initialization, supporting 12 or 24 word configurations to create secure seed phrases for Lightning wallet development.

Instructions

Generate BIP39 mnemonic for wallet initialization

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
strengthNoMnemonic strength (128 = 12 words, 256 = 24 words)
wordCountNoNumber of words in mnemonic (12 or 24)

Implementation Reference

  • The main tool handler (execute function) that processes input args, generates BIP39 mnemonic and seed using WalletService, formats response with JSON including mnemonic, seed hex, word count, and embedded SwiftUI example code for secure mnemonic handling.
      execute: async (args: any): Promise<ToolResult> => {
        try {
          // Convert wordCount to strength if provided
          let strength = args.strength;
          if (args.wordCount) {
            strength = args.wordCount === 12 ? 128 : 256;
          }
          
          const mnemonic = walletService.generateMnemonic(strength || 256);
          const seedBuffer = walletService.mnemonicToSeed(mnemonic);
          const wordCount = mnemonic.split(' ').length;
    
          return {
            content: [{
              type: 'text',
              text: JSON.stringify({
                success: true,
                mnemonic,
                wordCount,
                seed: seedBuffer.toString('hex'),
                swiftExample: `
    // Swift code for secure mnemonic generation in your iOS app
    import SwiftUI
    import CryptoKit
    import LightningDevKit
    
    class MnemonicGenerator {
        enum MnemonicLength: Int {
            case words12 = 128
            case words24 = 256
            
            var wordCount: Int {
                switch self {
                case .words12: return 12
                case .words24: return 24
                }
            }
        }
        
        static func generateMnemonic(length: MnemonicLength = .words24) throws -> [String] {
            // Generate entropy
            let entropyBytes = length.rawValue / 8
            var entropy = Data(count: entropyBytes)
            let result = entropy.withUnsafeMutableBytes { bytes in
                SecRandomCopyBytes(kSecRandomDefault, entropyBytes, bytes.baseAddress!)
            }
            
            guard result == errSecSuccess else {
                throw WalletError.entropyGenerationFailed
            }
            
            // Convert to mnemonic
            let mnemonic = Mnemonic.toMnemonic(entropy: [UInt8](entropy))
            guard let words = mnemonic else {
                throw WalletError.mnemonicGenerationFailed
            }
            
            return words.components(separatedBy: " ")
        }
        
        static func mnemonicToSeed(words: [String], passphrase: String = "") -> Data {
            let mnemonic = words.joined(separator: " ")
            let seed = Mnemonic.toSeed(phrase: mnemonic, password: passphrase)
            return Data(seed)
        }
    }
    
    // SwiftUI view for secure mnemonic display
    struct MnemonicSetupView: View {
        @State private var mnemonicWords: [String] = []
        @State private var currentStep: SetupStep = .generate
        @State private var verificationWords: Set<Int> = []
        @State private var verificationInput: [Int: String] = [:]
        @State private var showError = false
        
        enum SetupStep {
            case generate
            case display
            case verify
            case complete
        }
        
        var body: some View {
            VStack(spacing: 0) {
                // Progress indicator
                ProgressBar(currentStep: currentStep)
                    .padding()
                
                // Content
                Group {
                    switch currentStep {
                    case .generate:
                        GenerateView(onGenerate: generateMnemonic)
                        
                    case .display:
                        DisplayView(words: mnemonicWords, onContinue: {
                            setupVerification()
                            currentStep = .verify
                        })
                        
                    case .verify:
                        VerifyView(
                            words: mnemonicWords,
                            verificationIndices: Array(verificationWords),
                            verificationInput: $verificationInput,
                            onVerify: verifyMnemonic
                        )
                        
                    case .complete:
                        CompleteView()
                    }
                }
                .padding()
                
                Spacer()
            }
            .navigationTitle("Wallet Setup")
            .navigationBarBackButtonHidden(currentStep != .generate)
            .alert("Verification Failed", isPresented: $showError) {
                Button("Try Again") { }
            } message: {
                Text("Please check the words and try again.")
            }
        }
        
        func generateMnemonic() {
            do {
                mnemonicWords = try MnemonicGenerator.generateMnemonic()
                currentStep = .display
            } catch {
                // Handle error
            }
        }
        
        func setupVerification() {
            // Select random words to verify
            verificationWords = Set((0..<mnemonicWords.count).shuffled().prefix(3))
            verificationInput = [:]
        }
        
        func verifyMnemonic() {
            var allCorrect = true
            
            for index in verificationWords {
                let expectedWord = mnemonicWords[index]
                let inputWord = verificationInput[index]?.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
                
                if inputWord != expectedWord {
                    allCorrect = false
                    break
                }
            }
            
            if allCorrect {
                saveMnemonicSecurely()
                currentStep = .complete
            } else {
                showError = true
            }
        }
        
        func saveMnemonicSecurely() {
            // Save to keychain with biometric protection
            Task {
                do {
                    let seed = MnemonicGenerator.mnemonicToSeed(words: mnemonicWords)
                    _ = try await BiometricLightningAuth.protectSeedWithBiometrics(seed: seed)
                    
                    // Clear mnemonic from memory
                    mnemonicWords = []
                    verificationInput = [:]
                } catch {
                    // Handle error
                }
            }
        }
    }
    
    struct DisplayView: View {
        let words: [String]
        let onContinue: () -> Void
        @State private var hasScreenshot = false
        
        var body: some View {
            VStack(spacing: 24) {
                // Warning
                VStack(spacing: 12) {
                    Image(systemName: "exclamationmark.triangle.fill")
                        .font(.largeTitle)
                        .foregroundColor(.orange)
                    
                    Text("Write Down Your Recovery Phrase")
                        .font(.title2)
                        .fontWeight(.semibold)
                    
                    Text("Write these words on paper. Never share them with anyone.")
                        .font(.callout)
                        .foregroundColor(.secondary)
                        .multilineTextAlignment(.center)
                }
                
                // Mnemonic grid
                LazyVGrid(columns: [
                    GridItem(.flexible()),
                    GridItem(.flexible()),
                    GridItem(.flexible())
                ], spacing: 12) {
                    ForEach(Array(words.enumerated()), id: \\.offset) { index, word in
                        WordCell(number: index + 1, word: word)
                    }
                }
                .padding()
                .background(Color(UIColor.secondarySystemBackground))
                .cornerRadius(12)
                
                // Screenshot warning
                Toggle("I have written down all words", isOn: $hasScreenshot)
                    .toggleStyle(CheckboxToggleStyle())
                
                Button(action: onContinue) {
                    Text("Continue to Verification")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.borderedProminent)
                .controlSize(.large)
                .disabled(!hasScreenshot)
            }
        }
    }
    
    struct WordCell: View {
        let number: Int
        let word: String
        
        var body: some View {
            HStack(spacing: 8) {
                Text("\\(number).")
                    .font(.caption)
                    .foregroundColor(.secondary)
                    .frame(width: 20, alignment: .trailing)
                
                Text(word)
                    .font(.system(.body, design: .monospaced))
                    .fontWeight(.medium)
            }
            .padding(.vertical, 8)
            .padding(.horizontal, 12)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(Color(UIColor.tertiarySystemBackground))
            .cornerRadius(8)
        }
    }`.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 optional parameters for mnemonic strength (128/256 bits) or word count (12/24 words).
    inputSchema: {
      type: 'object',
      properties: {
        strength: {
          type: 'number',
          enum: [128, 256],
          description: 'Mnemonic strength (128 = 12 words, 256 = 24 words)',
          default: 256
        },
        wordCount: {
          type: 'number',
          enum: [12, 24],
          description: 'Number of words in mnemonic (12 or 24)',
          default: 24
        }
      }
    },
  • Tool registration defining the name 'ldk_generate_mnemonic', description, schema, and handler.
    export const generateMnemonicTool: Tool = {
      name: 'ldk_generate_mnemonic',
  • WalletService helper method that generates the BIP39 mnemonic string using the bip39 library.
    generateMnemonic(strength: 128 | 256 = 256): string {
      return bip39.generateMnemonic(strength);
    }
  • WalletService helper method that converts mnemonic to seed buffer using bip39, with validation.
    mnemonicToSeed(mnemonic: string, passphrase: string = ''): Buffer {
      if (!bip39.validateMnemonic(mnemonic)) {
        throw new Error('Invalid mnemonic');
      }
      return bip39.mnemonicToSeedSync(mnemonic, passphrase);
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool generates a mnemonic but does not cover critical aspects like security implications (e.g., randomness source, storage), whether it requires user confirmation, or what the output format is. This is a significant gap for a tool handling cryptographic keys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's purpose without unnecessary words. It is front-loaded with the core action and resource, making it easy to parse quickly, which is ideal for conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of cryptographic key generation, lack of annotations, and no output schema, the description is incomplete. It fails to address security behaviors, output format, or integration with other tools (e.g., how the mnemonic is used in wallet initialization), leaving the agent with insufficient context for safe and effective use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with clear descriptions for both parameters (strength and wordCount) including enums and defaults. The description does not add any meaning beyond the schema, such as explaining the relationship between strength and word count or typical use cases for each option, so it meets the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Generate') and the resource ('BIP39 mnemonic'), with the purpose 'for wallet initialization' providing context. It does not explicitly differentiate from sibling tools like 'ldk_derive_address' or 'ldk_create_channel', which might also relate to wallet setup, but the specificity of generating a mnemonic is sufficient for clarity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, such as whether it's for initial setup versus recovery, or how it relates to sibling tools like 'ldk_derive_address'. It mentions 'wallet initialization', but this is part of the purpose statement rather than explicit usage instructions, leaving gaps in context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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