Skip to main content
Glama
StevenGeller

LDK MCP Server

by StevenGeller

ldk_chain_sync

Retrieve chain synchronization implementations for Lightning Development Kit using Electrum, Esplora, or other methods to maintain blockchain data consistency.

Instructions

Get chain synchronization implementations for LDK with Electrum/Esplora

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
syncMethodYesChain synchronization method to get implementation for

Implementation Reference

  • The complete tool definition with the 'execute' handler that provides Swift code examples for various LDK chain synchronization methods (Electrum, Esplora, Bitcoin Core RPC, compact filters, sync management, reorg handling) based on input syncMethod.
    export const chainSyncTool: Tool = {
      name: 'ldk_chain_sync',
      description: 'Get chain synchronization implementations for LDK with Electrum/Esplora',
      inputSchema: {
        type: 'object',
        properties: {
          syncMethod: {
            type: 'string',
            enum: [
              'electrum_sync',
              'esplora_sync',
              'bitcoin_core_rpc',
              'compact_filters',
              'sync_management',
              'reorg_handling'
            ],
            description: 'Chain synchronization method to get implementation for'
          }
        },
        required: ['syncMethod']
      },
      execute: async (args: any): Promise<ToolResult> => {
        const syncExamples: Record<string, string> = {
          electrum_sync: `
    // Electrum-based chain synchronization for LDK
    import LightningDevKit
    import Foundation
    
    class ElectrumChainSync {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        private var electrumClient: ElectrumClient!
        private var lastSyncHeight: UInt32 = 0
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
        }
        
        // Connect to Electrum server
        func connect(to server: String, port: UInt16 = 50001, useTLS: Bool = true) async throws {
            electrumClient = ElectrumClient(
                server: server,
                port: port,
                useTLS: useTLS,
                logger: logger
            )
            
            try await electrumClient.connect()
            logger.log(message: "Connected to Electrum server: \\(server):\\(port)")
        }
        
        // Perform full synchronization
        func performSync() async throws {
            // Get current chain tip
            let chainTip = try await electrumClient.getChainTip()
            let currentHeight = chainTip.height
            let tipHash = chainTip.hash
            
            logger.log(message: "Syncing to block \\(currentHeight)")
            
            // Get transactions to monitor
            let relevantTxs = getRelevantTransactions()
            
            // Check for reorgs
            if lastSyncHeight > 0 {
                try await checkForReorgs(from: lastSyncHeight, to: currentHeight)
            }
            
            // Sync confirmed transactions
            for txid in relevantTxs {
                if let txInfo = try await electrumClient.getTransaction(txid: txid) {
                    if txInfo.confirmations > 0 {
                        try await confirmTransaction(
                            txid: txid,
                            blockHeight: txInfo.blockHeight,
                            blockHash: txInfo.blockHash,
                            txData: txInfo.rawTx
                        )
                    }
                }
            }
            
            // Update to chain tip
            channelManager.asConfirm().bestBlockUpdated(
                header: tipHash,
                height: currentHeight
            )
            chainMonitor.asConfirm().bestBlockUpdated(
                header: tipHash,
                height: currentHeight
            )
            
            lastSyncHeight = currentHeight
            
            // Persist sync state
            UserDefaults.standard.set(currentHeight, forKey: "lastSyncHeight")
        }
        
        // Get relevant transactions from LDK
        private func getRelevantTransactions() -> Set<[UInt8]> {
            var txids = Set<[UInt8]>()
            
            // From ChannelManager
            let channelTxs = channelManager.asConfirm().getRelevantTxids()
            for (txid, _) in channelTxs {
                txids.insert(txid)
            }
            
            // From ChainMonitor
            let monitorTxs = chainMonitor.asConfirm().getRelevantTxids()
            for (txid, _) in monitorTxs {
                txids.insert(txid)
            }
            
            return txids
        }
        
        // Check for blockchain reorganizations
        private func checkForReorgs(from startHeight: UInt32, to endHeight: UInt32) async throws {
            logger.log(message: "Checking for reorgs from \\(startHeight) to \\(endHeight)")
            
            // Get block headers to verify chain
            for height in startHeight...min(endHeight, startHeight + 100) {
                let header = try await electrumClient.getBlockHeader(height: height)
                
                // Check if this block is still in the main chain
                let currentHeader = try await electrumClient.getBlockHeaderAt(
                    height: height,
                    checkMainChain: true
                )
                
                if header.hash != currentHeader.hash {
                    // Reorg detected!
                    logger.log(message: "Reorg detected at height \\(height)")
                    try await handleReorg(fromHeight: height)
                    break
                }
            }
        }
        
        // Handle blockchain reorganization
        private func handleReorg(fromHeight: UInt32) async throws {
            // Get all transactions that need to be re-checked
            let relevantTxs = getRelevantTransactions()
            
            for txid in relevantTxs {
                // Check if transaction is still confirmed
                if let txInfo = try await electrumClient.getTransaction(txid: txid) {
                    if txInfo.confirmations == 0 || txInfo.blockHeight >= fromHeight {
                        // Transaction was reorged out
                        channelManager.asConfirm().transactionUnconfirmed(txid: txid)
                        chainMonitor.asConfirm().transactionUnconfirmed(txid: txid)
                        
                        logger.log(message: "Transaction unconfirmed due to reorg: \\(Data(txid).hexString)")
                    }
                }
            }
            
            // Re-sync from the reorg point
            lastSyncHeight = fromHeight - 1
            try await performSync()
        }
        
        // Confirm a transaction
        private func confirmTransaction(
            txid: [UInt8],
            blockHeight: UInt32,
            blockHash: [UInt8],
            txData: [UInt8]
        ) async throws {
            // Get block header
            let header = try await electrumClient.getBlockHeader(height: blockHeight)
            
            // Get transaction position in block
            let txPos = try await electrumClient.getTransactionPosition(
                txid: txid,
                blockHeight: blockHeight
            )
            
            // Notify LDK of confirmation
            let txdata = [(txPos, txData)]
            
            channelManager.asConfirm().transactionsConfirmed(
                header: header.serialize(),
                txdata: txdata,
                height: blockHeight
            )
            
            chainMonitor.asConfirm().transactionsConfirmed(
                header: header.serialize(),
                txdata: txdata,
                height: blockHeight
            )
            
            logger.log(message: "Transaction confirmed at height \\(blockHeight): \\(Data(txid).hexString)")
        }
    }
    
    // Electrum Client Implementation
    class ElectrumClient {
        private let server: String
        private let port: UInt16
        private let useTLS: Bool
        private let logger: Bindings.Logger
        private var connection: NWConnection?
        
        struct ChainTip {
            let height: UInt32
            let hash: [UInt8]
        }
        
        struct TransactionInfo {
            let txid: [UInt8]
            let rawTx: [UInt8]
            let confirmations: Int
            let blockHeight: UInt32
            let blockHash: [UInt8]
        }
        
        init(server: String, port: UInt16, useTLS: Bool, logger: Bindings.Logger) {
            self.server = server
            self.port = port
            self.useTLS = useTLS
            self.logger = logger
        }
        
        func connect() async throws {
            // Implementation of Electrum protocol connection
            // This would involve TCP/TLS connection and JSON-RPC communication
        }
        
        func getChainTip() async throws -> ChainTip {
            // Call blockchain.headers.subscribe
            let response = try await sendRequest(
                method: "blockchain.headers.subscribe",
                params: []
            )
            
            // Parse response
            let height = response["height"] as? UInt32 ?? 0
            let hashHex = response["hex"] as? String ?? ""
            
            return ChainTip(
                height: height,
                hash: Data(hexString: hashHex)?.bytes ?? []
            )
        }
        
        func getTransaction(txid: [UInt8]) async throws -> TransactionInfo? {
            // Call blockchain.transaction.get
            let txidHex = Data(txid).hexString
            
            do {
                let rawTxHex = try await sendRequest(
                    method: "blockchain.transaction.get",
                    params: [txidHex, true]
                ) as? String ?? ""
                
                // Get confirmation status
                let txInfo = try await sendRequest(
                    method: "blockchain.transaction.get_merkle",
                    params: [txidHex]
                )
                
                let blockHeight = txInfo["block_height"] as? UInt32 ?? 0
                let confirmations = blockHeight > 0 ? 
                    (try await getChainTip().height - blockHeight + 1) : 0
                
                return TransactionInfo(
                    txid: txid,
                    rawTx: Data(hexString: rawTxHex)?.bytes ?? [],
                    confirmations: Int(confirmations),
                    blockHeight: blockHeight,
                    blockHash: [] // Would need to fetch block hash separately
                )
            } catch {
                return nil
            }
        }
        
        private func sendRequest(method: String, params: [Any]) async throws -> Any {
            // Implementation of Electrum JSON-RPC protocol
            // This is a simplified version - real implementation would handle
            // proper JSON-RPC formatting, response parsing, error handling, etc.
            fatalError("Implement Electrum protocol communication")
        }
    }`.trim(),
    
          esplora_sync: `
    // Esplora-based chain synchronization for LDK
    import LightningDevKit
    import Foundation
    
    class EsploraChainSync {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        private let esploraClient: EsploraClient
        private var lastSyncTimestamp: Date = Date.distantPast
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger,
            esploraUrl: String
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
            self.esploraClient = EsploraClient(baseUrl: esploraUrl)
        }
        
        // Perform synchronization
        func sync() async throws {
            logger.log(message: "Starting Esplora sync...")
            
            // Get current tip
            let tip = try await esploraClient.getTip()
            
            // Get all outputs to watch
            let outputsToWatch = getWatchedOutputs()
            
            // Check each output
            for output in outputsToWatch {
                try await syncOutput(output, currentTip: tip)
            }
            
            // Update best block
            let tipHash = try await esploraClient.getBlockHash(height: tip.height)
            channelManager.asConfirm().bestBlockUpdated(
                header: tipHash,
                height: tip.height
            )
            chainMonitor.asConfirm().bestBlockUpdated(
                header: tipHash,
                height: tip.height
            )
            
            lastSyncTimestamp = Date()
            logger.log(message: "Esplora sync completed at height \\(tip.height)")
        }
        
        // Get outputs we need to watch
        private func getWatchedOutputs() -> [WatchedOutput] {
            var outputs: [WatchedOutput] = []
            
            // Get from Filter interface
            if let filter = LDKManager.shared.filter {
                outputs.append(contentsOf: filter.getWatchedOutputs())
            }
            
            // Get relevant transactions
            let relevantTxs = channelManager.asConfirm().getRelevantTxids()
            for (txid, outputIndices) in relevantTxs {
                for index in outputIndices {
                    outputs.append(WatchedOutput(
                        txid: txid,
                        index: index,
                        script: nil
                    ))
                }
            }
            
            return outputs
        }
        
        // Sync a specific output
        private func syncOutput(_ output: WatchedOutput, currentTip: BlockTip) async throws {
            // Get spending status
            let outpoint = "\\(Data(output.txid).hexString):\\(output.index)"
            let status = try await esploraClient.getOutputStatus(outpoint: outpoint)
            
            if let txid = status.txid {
                // Get transaction details
                let tx = try await esploraClient.getTransaction(txid: txid)
                
                if let confirmedHeight = status.status?.confirmedHeight {
                    // Transaction is confirmed
                    let header = try await esploraClient.getBlockHeader(height: confirmedHeight)
                    let txPos = tx.status?.blockTxPosition ?? 0
                    
                    channelManager.asConfirm().transactionsConfirmed(
                        header: header,
                        txdata: [(UInt(txPos), tx.raw)],
                        height: confirmedHeight
                    )
                    
                    chainMonitor.asConfirm().transactionsConfirmed(
                        header: header,
                        txdata: [(UInt(txPos), tx.raw)],
                        height: confirmedHeight
                    )
                    
                    logger.log(message: "Output confirmed at height \\(confirmedHeight): \\(outpoint)")
                    
                } else if tx.status?.confirmed == false {
                    // Transaction is unconfirmed
                    channelManager.asConfirm().transactionUnconfirmed(txid: output.txid)
                    chainMonitor.asConfirm().transactionUnconfirmed(txid: output.txid)
                    
                    logger.log(message: "Output unconfirmed: \\(outpoint)")
                }
            }
            
            // Check if output is spent
            if let spendingTxid = status.spendingTxid {
                let spendingTx = try await esploraClient.getTransaction(txid: spendingTxid)
                
                if let confirmedHeight = spendingTx.status?.confirmedHeight {
                    // Spending transaction is confirmed
                    let header = try await esploraClient.getBlockHeader(height: confirmedHeight)
                    let txPos = spendingTx.status?.blockTxPosition ?? 0
                    
                    channelManager.asConfirm().transactionsConfirmed(
                        header: header,
                        txdata: [(UInt(txPos), spendingTx.raw)],
                        height: confirmedHeight
                    )
                    
                    chainMonitor.asConfirm().transactionsConfirmed(
                        header: header,
                        txdata: [(UInt(txPos), spendingTx.raw)],
                        height: confirmedHeight
                    )
                    
                    logger.log(message: "Output spent at height \\(confirmedHeight): \\(outpoint)")
                }
            }
        }
    }
    
    // Esplora API Client
    class EsploraClient {
        private let baseUrl: String
        private let session: URLSession
        
        init(baseUrl: String) {
            self.baseUrl = baseUrl.trimmingCharacters(in: .init(charactersIn: "/"))
            
            let config = URLSessionConfiguration.default
            config.timeoutIntervalForRequest = 30
            config.timeoutIntervalForResource = 60
            self.session = URLSession(configuration: config)
        }
        
        struct BlockTip: Codable {
            let height: UInt32
            let hash: String
        }
        
        struct Transaction: Codable {
            let txid: String
            let raw: [UInt8]
            let status: TransactionStatus?
        }
        
        struct TransactionStatus: Codable {
            let confirmed: Bool
            let confirmedHeight: UInt32?
            let blockHash: String?
            let blockTime: UInt64?
            let blockTxPosition: UInt?
        }
        
        struct OutputStatus: Codable {
            let txid: String?
            let status: TransactionStatus?
            let spendingTxid: String?
        }
        
        // Get current chain tip
        func getTip() async throws -> BlockTip {
            let url = URL(string: "\\(baseUrl)/blocks/tip/height")!
            let (data, _) = try await session.data(from: url)
            let height = try JSONDecoder().decode(UInt32.self, from: data)
            
            let hashUrl = URL(string: "\\(baseUrl)/blocks/tip/hash")!
            let (hashData, _) = try await session.data(from: hashUrl)
            let hash = String(data: hashData, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
            
            return BlockTip(height: height, hash: hash)
        }
        
        // Get block hash at height
        func getBlockHash(height: UInt32) async throws -> [UInt8] {
            let url = URL(string: "\\(baseUrl)/block-height/\\(height)")!
            let (data, _) = try await session.data(from: url)
            let hashHex = String(data: data, encoding: .utf8)?
                .trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
            
            return Data(hexString: hashHex)?.bytes ?? []
        }
        
        // Get block header
        func getBlockHeader(height: UInt32) async throws -> [UInt8] {
            let hash = try await getBlockHash(height: height)
            let hashHex = Data(hash).hexString
            
            let url = URL(string: "\\(baseUrl)/block/\\(hashHex)/header")!
            let (data, _) = try await session.data(from: url)
            let headerHex = String(data: data, encoding: .utf8)?
                .trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
            
            return Data(hexString: headerHex)?.bytes ?? []
        }
        
        // Get transaction
        func getTransaction(txid: String) async throws -> Transaction {
            // Get raw transaction
            let rawUrl = URL(string: "\\(baseUrl)/tx/\\(txid)/raw")!
            let (rawData, _) = try await session.data(from: rawUrl)
            
            // Get transaction status
            let statusUrl = URL(string: "\\(baseUrl)/tx/\\(txid)/status")!
            let (statusData, _) = try await session.data(from: statusUrl)
            let status = try? JSONDecoder().decode(TransactionStatus.self, from: statusData)
            
            return Transaction(
                txid: txid,
                raw: [UInt8](rawData),
                status: status
            )
        }
        
        // Get output status
        func getOutputStatus(outpoint: String) async throws -> OutputStatus {
            let url = URL(string: "\\(baseUrl)/tx/\\(outpoint)/outspend")!
            let (data, response) = try await session.data(from: url)
            
            if (response as? HTTPURLResponse)?.statusCode == 404 {
                // Output not found or not spent
                return OutputStatus(txid: nil, status: nil, spendingTxid: nil)
            }
            
            return try JSONDecoder().decode(OutputStatus.self, from: data)
        }
    }
    
    // Watched output structure
    struct WatchedOutput {
        let txid: [UInt8]
        let index: UInt32
        let script: [UInt8]?
    }`.trim(),
    
          bitcoin_core_rpc: `
    // Bitcoin Core RPC chain synchronization
    import LightningDevKit
    import Foundation
    
    class BitcoinCoreSync {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        private let rpcClient: BitcoinCoreRPC
        private var lastProcessedBlock: String?
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger,
            rpcUrl: String,
            rpcUser: String,
            rpcPassword: String
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
            self.rpcClient = BitcoinCoreRPC(
                url: rpcUrl,
                user: rpcUser,
                password: rpcPassword
            )
        }
        
        // Start block monitoring
        func startBlockMonitoring() async {
            // Load last processed block
            lastProcessedBlock = UserDefaults.standard.string(forKey: "lastProcessedBlock")
            
            // Start monitoring loop
            while true {
                do {
                    try await checkForNewBlocks()
                    try await Task.sleep(nanoseconds: 10_000_000_000) // 10 seconds
                } catch {
                    logger.log(message: "Block monitoring error: \\(error)")
                    try? await Task.sleep(nanoseconds: 30_000_000_000) // 30 seconds retry
                }
            }
        }
        
        // Check for new blocks
        private func checkForNewBlocks() async throws {
            let currentTip = try await rpcClient.getBestBlockHash()
            
            if currentTip != lastProcessedBlock {
                logger.log(message: "New block detected: \\(currentTip)")
                
                // Get block info
                let blockInfo = try await rpcClient.getBlock(hash: currentTip)
                
                // Process all blocks from last known to current
                var blocksToProcess: [BlockInfo] = [blockInfo]
                var prevHash = blockInfo.previousblockhash
                
                // Walk back to find common ancestor
                while let prev = prevHash, prev != lastProcessedBlock {
                    if let prevBlock = try? await rpcClient.getBlock(hash: prev) {
                        blocksToProcess.insert(prevBlock, at: 0)
                        prevHash = prevBlock.previousblockhash
                    } else {
                        break
                    }
                }
                
                // Process blocks in order
                for block in blocksToProcess {
                    try await processBlock(block)
                }
                
                lastProcessedBlock = currentTip
                UserDefaults.standard.set(currentTip, forKey: "lastProcessedBlock")
            }
        }
        
        // Process a single block
        private func processBlock(_ block: BlockInfo) async throws {
            logger.log(message: "Processing block \\(block.height): \\(block.hash)")
            
            // Get block header
            let header = try await rpcClient.getBlockHeader(hash: block.hash)
            
            // Get relevant transactions
            let relevantTxids = getRelevantTransactionIds()
            var confirmedTxs: [(UInt, [UInt8])] = []
            
            // Check each transaction in the block
            for (index, txid) in block.tx.enumerated() {
                let txidBytes = Data(hexString: txid)?.bytes ?? []
                
                if relevantTxids.contains(txidBytes) {
                    // Get raw transaction
                    let rawTx = try await rpcClient.getRawTransaction(txid: txid)
                    confirmedTxs.append((UInt(index), rawTx))
                    
                    logger.log(message: "Found relevant transaction: \\(txid)")
                }
            }
            
            // Notify LDK of confirmations
            if !confirmedTxs.isEmpty {
                channelManager.asConfirm().transactionsConfirmed(
                    header: header,
                    txdata: confirmedTxs,
                    height: block.height
                )
                
                chainMonitor.asConfirm().transactionsConfirmed(
                    header: header,
                    txdata: confirmedTxs,
                    height: block.height
                )
            }
            
            // Update best block
            channelManager.asConfirm().bestBlockUpdated(
                header: header,
                height: block.height
            )
            
            chainMonitor.asConfirm().bestBlockUpdated(
                header: header,
                height: block.height
            )
        }
        
        // Get relevant transaction IDs
        private func getRelevantTransactionIds() -> Set<[UInt8]> {
            var txids = Set<[UInt8]>()
            
            // From ChannelManager
            let channelTxs = channelManager.asConfirm().getRelevantTxids()
            for (txid, _) in channelTxs {
                txids.insert(txid)
            }
            
            // From ChainMonitor
            let monitorTxs = chainMonitor.asConfirm().getRelevantTxids()
            for (txid, _) in monitorTxs {
                txids.insert(txid)
            }
            
            return txids
        }
    }
    
    // Bitcoin Core RPC Client
    class BitcoinCoreRPC {
        private let url: String
        private let user: String
        private let password: String
        private let session: URLSession
        
        init(url: String, user: String, password: String) {
            self.url = url
            self.user = user
            self.password = password
            
            let config = URLSessionConfiguration.default
            let authString = "\\(user):\\(password)"
            let authData = authString.data(using: .utf8)!.base64EncodedString()
            config.httpAdditionalHeaders = ["Authorization": "Basic \\(authData)"]
            
            self.session = URLSession(configuration: config)
        }
        
        struct BlockInfo: Codable {
            let hash: String
            let height: UInt32
            let previousblockhash: String?
            let tx: [String]
            let time: UInt64
        }
        
        // RPC call helper
        private func rpcCall<T: Decodable>(method: String, params: [Any] = []) async throws -> T {
            let requestBody: [String: Any] = [
                "jsonrpc": "1.0",
                "id": UUID().uuidString,
                "method": method,
                "params": params
            ]
            
            var request = URLRequest(url: URL(string: url)!)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
            
            let (data, response) = try await session.data(for: request)
            
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                throw RPCError.requestFailed
            }
            
            let rpcResponse = try JSONSerialization.jsonObject(with: data) as? [String: Any]
            
            if let error = rpcResponse?["error"] as? [String: Any] {
                throw RPCError.rpcError(
                    code: error["code"] as? Int ?? -1,
                    message: error["message"] as? String ?? "Unknown error"
                )
            }
            
            guard let result = rpcResponse?["result"] else {
                throw RPCError.noResult
            }
            
            let resultData = try JSONSerialization.data(withJSONObject: result)
            return try JSONDecoder().decode(T.self, from: resultData)
        }
        
        // Get best block hash
        func getBestBlockHash() async throws -> String {
            return try await rpcCall(method: "getbestblockhash")
        }
        
        // Get block
        func getBlock(hash: String) async throws -> BlockInfo {
            return try await rpcCall(method: "getblock", params: [hash, 1])
        }
        
        // Get block header
        func getBlockHeader(hash: String) async throws -> [UInt8] {
            let headerHex: String = try await rpcCall(
                method: "getblockheader",
                params: [hash, false]
            )
            return Data(hexString: headerHex)?.bytes ?? []
        }
        
        // Get raw transaction
        func getRawTransaction(txid: String) async throws -> [UInt8] {
            let rawHex: String = try await rpcCall(
                method: "getrawtransaction",
                params: [txid]
            )
            return Data(hexString: rawHex)?.bytes ?? []
        }
    }
    
    enum RPCError: LocalizedError {
        case requestFailed
        case noResult
        case rpcError(code: Int, message: String)
        
        var errorDescription: String? {
            switch self {
            case .requestFailed:
                return "RPC request failed"
            case .noResult:
                return "No result in RPC response"
            case .rpcError(let code, let message):
                return "RPC error \\(code): \\(message)"
            }
        }
    }`.trim(),
    
          compact_filters: `
    // Compact block filters (BIP157/158) synchronization
    import LightningDevKit
    import Foundation
    
    class CompactFilterSync {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        private let filterClient: CompactFilterClient
        private var lastSyncHeight: UInt32 = 0
        private var cachedFilters: [UInt32: CompactFilter] = [:]
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger,
            peers: [String]
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
            self.filterClient = CompactFilterClient(peers: peers)
        }
        
        // Start synchronization
        func startSync() async throws {
            // Connect to peers
            try await filterClient.connectToPeers()
            
            // Get filter headers
            let filterHeaders = try await filterClient.downloadFilterHeaders(
                startHeight: lastSyncHeight
            )
            
            // Download and process filters
            for (height, filterHeader) in filterHeaders {
                try await processBlock(at: height, filterHeader: filterHeader)
            }
            
            logger.log(message: "Compact filter sync completed")
        }
        
        // Process a block using compact filters
        private func processBlock(at height: UInt32, filterHeader: [UInt8]) async throws {
            // Get watched scripts
            let watchedScripts = getWatchedScripts()
            
            // Download filter for this block
            let filter = try await filterClient.downloadFilter(
                height: height,
                filterHeader: filterHeader
            )
            
            // Check if any of our scripts match
            let matches = filter.match(scripts: watchedScripts)
            
            if !matches.isEmpty {
                logger.log(message: "Filter match at height \\(height), downloading block")
                
                // Download full block
                let block = try await filterClient.downloadBlock(height: height)
                
                // Process relevant transactions
                try await processBlockTransactions(
                    block: block,
                    height: height,
                    matchingScripts: matches
                )
            }
            
            // Update sync progress
            lastSyncHeight = height
            
            // Update best block
            let blockHash = try await filterClient.getBlockHash(height: height)
            channelManager.asConfirm().bestBlockUpdated(
                header: blockHash,
                height: height
            )
            chainMonitor.asConfirm().bestBlockUpdated(
                header: blockHash,
                height: height
            )
        }
        
        // Get scripts we're watching
        private func getWatchedScripts() -> Set<[UInt8]> {
            var scripts = Set<[UInt8]>()
            
            // Get from Filter interface
            if let filter = LDKManager.shared.filter {
                scripts.formUnion(filter.getWatchedScripts())
            }
            
            // Add funding output scripts
            let channels = channelManager.listChannels()
            for channel in channels {
                if let fundingTxo = channel.getFundingTxo() {
                    // Would need to derive script from funding output
                    // This is simplified
                }
            }
            
            return scripts
        }
        
        // Process transactions in a block
        private func processBlockTransactions(
            block: Block,
            height: UInt32,
            matchingScripts: Set<[UInt8]>
        ) async throws {
            var confirmedTxs: [(UInt, [UInt8])] = []
            let relevantTxids = getRelevantTransactionIds()
            
            for (index, tx) in block.transactions.enumerated() {
                let txid = tx.txid()
                
                // Check if this is a relevant transaction
                if relevantTxids.contains(txid) || 
                   transactionMatchesScripts(tx: tx, scripts: matchingScripts) {
                    confirmedTxs.append((UInt(index), tx.serialize()))
                    logger.log(message: "Found relevant transaction at height \\(height)")
                }
            }
            
            // Notify LDK
            if !confirmedTxs.isEmpty {
                channelManager.asConfirm().transactionsConfirmed(
                    header: block.header,
                    txdata: confirmedTxs,
                    height: height
                )
                
                chainMonitor.asConfirm().transactionsConfirmed(
                    header: block.header,
                    txdata: confirmedTxs,
                    height: height
                )
            }
        }
        
        private func transactionMatchesScripts(
            tx: Transaction,
            scripts: Set<[UInt8]>
        ) -> Bool {
            // Check if any output scripts match our watched scripts
            for output in tx.outputs {
                if scripts.contains(output.scriptPubkey) {
                    return true
                }
            }
            return false
        }
    }
    
    // Compact Filter Client
    class CompactFilterClient {
        private let peers: [String]
        private var connections: [PeerConnection] = []
        
        init(peers: [String]) {
            self.peers = peers
        }
        
        // Connect to peers
        func connectToPeers() async throws {
            for peer in peers {
                if let connection = try? await PeerConnection.connect(to: peer) {
                    connections.append(connection)
                }
            }
            
            guard !connections.isEmpty else {
                throw FilterError.noPeersAvailable
            }
        }
        
        // Download filter headers
        func downloadFilterHeaders(
            startHeight: UInt32
        ) async throws -> [(height: UInt32, header: [UInt8])] {
            guard let peer = connections.first else {
                throw FilterError.noPeersAvailable
            }
            
            return try await peer.getFilterHeaders(startHeight: startHeight)
        }
        
        // Download specific filter
        func downloadFilter(
            height: UInt32,
            filterHeader: [UInt8]
        ) async throws -> CompactFilter {
            guard let peer = connections.first else {
                throw FilterError.noPeersAvailable
            }
            
            let filterData = try await peer.getFilter(height: height)
            return CompactFilter(data: filterData, header: filterHeader)
        }
        
        // Download full block
        func downloadBlock(height: UInt32) async throws -> Block {
            guard let peer = connections.first else {
                throw FilterError.noPeersAvailable
            }
            
            return try await peer.getBlock(height: height)
        }
        
        // Get block hash
        func getBlockHash(height: UInt32) async throws -> [UInt8] {
            guard let peer = connections.first else {
                throw FilterError.noPeersAvailable
            }
            
            return try await peer.getBlockHash(height: height)
        }
    }
    
    // Compact Filter implementation
    struct CompactFilter {
        private let data: [UInt8]
        private let header: [UInt8]
        private let p: UInt8 = 19 // BIP158 P value
        private let m: UInt64 = 784931 // BIP158 M value
        
        init(data: [UInt8], header: [UInt8]) {
            self.data = data
            self.header = header
        }
        
        // Check if filter matches any of the provided scripts
        func match(scripts: Set<[UInt8]>) -> Set<[UInt8]> {
            var matches = Set<[UInt8]>()
            
            // Decode filter using Golomb-Rice coding
            // This is a simplified version - real implementation would need
            // proper Golomb-Rice decoding
            
            for script in scripts {
                if filterContains(element: script) {
                    matches.insert(script)
                }
            }
            
            return matches
        }
        
        private func filterContains(element: [UInt8]) -> Bool {
            // Simplified - would need actual Golomb-Rice filter checking
            // using SipHash and proper decoding
            return false
        }
    }
    
    // Block structure
    struct Block {
        let header: [UInt8]
        let transactions: [Transaction]
    }
    
    struct Transaction {
        let version: Int32
        let inputs: [TransactionInput]
        let outputs: [TransactionOutput]
        let lockTime: UInt32
        
        func txid() -> [UInt8] {
            // Calculate transaction ID
            let serialized = serialize()
            return dsha256(serialized)
        }
        
        func serialize() -> [UInt8] {
            // Serialize transaction
            return []
        }
    }
    
    struct TransactionInput {
        let previousOutput: OutPoint
        let scriptSig: [UInt8]
        let sequence: UInt32
    }
    
    struct TransactionOutput {
        let value: Int64
        let scriptPubkey: [UInt8]
    }
    
    struct OutPoint {
        let txid: [UInt8]
        let vout: UInt32
    }
    
    // Peer connection for compact filters
    class PeerConnection {
        private let address: String
        
        private init(address: String) {
            self.address = address
        }
        
        static func connect(to address: String) async throws -> PeerConnection {
            // Implement P2P connection
            return PeerConnection(address: address)
        }
        
        func getFilterHeaders(startHeight: UInt32) async throws -> [(UInt32, [UInt8])] {
            // Implement getcfheaders message
            return []
        }
        
        func getFilter(height: UInt32) async throws -> [UInt8] {
            // Implement getcfilters message
            return []
        }
        
        func getBlock(height: UInt32) async throws -> Block {
            // Implement getdata message for block
            return Block(header: [], transactions: [])
        }
        
        func getBlockHash(height: UInt32) async throws -> [UInt8] {
            // Get block hash at height
            return []
        }
    }
    
    enum FilterError: LocalizedError {
        case noPeersAvailable
        case downloadFailed
        case invalidFilter
        
        var errorDescription: String? {
            switch self {
            case .noPeersAvailable:
                return "No peers available for compact filter sync"
            case .downloadFailed:
                return "Failed to download filter data"
            case .invalidFilter:
                return "Invalid compact filter data"
            }
        }
    }`.trim(),
    
          sync_management: `
    // Chain synchronization management and coordination
    import LightningDevKit
    import Foundation
    
    class ChainSyncManager {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        
        private var syncMethod: SyncMethod
        private var syncTask: Task<Void, Error>?
        private var lastSyncTime: Date = Date.distantPast
        private var syncInterval: TimeInterval = 30 // 30 seconds
        
        enum SyncMethod {
            case electrum(ElectrumChainSync)
            case esplora(EsploraChainSync)
            case bitcoinCore(BitcoinCoreSync)
            case compactFilters(CompactFilterSync)
        }
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger,
            syncMethod: SyncMethod
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
            self.syncMethod = syncMethod
        }
        
        // Start automatic synchronization
        func startSync() {
            syncTask = Task {
                while !Task.isCancelled {
                    do {
                        try await performSync()
                        lastSyncTime = Date()
                        
                        // Wait for next sync interval
                        try await Task.sleep(nanoseconds: UInt64(syncInterval * 1_000_000_000))
                        
                    } catch {
                        logger.log(message: "Sync error: \\(error)")
                        
                        // Exponential backoff on error
                        let backoffInterval = min(syncInterval * 2, 300) // Max 5 minutes
                        try? await Task.sleep(nanoseconds: UInt64(backoffInterval * 1_000_000_000))
                    }
                }
            }
        }
        
        // Stop synchronization
        func stopSync() {
            syncTask?.cancel()
            syncTask = nil
        }
        
        // Perform synchronization based on method
        private func performSync() async throws {
            logger.log(message: "Starting chain sync...")
            
            switch syncMethod {
            case .electrum(let electrumSync):
                try await electrumSync.performSync()
                
            case .esplora(let esploraSync):
                try await esploraSync.sync()
                
            case .bitcoinCore(let bitcoinCoreSync):
                try await bitcoinCoreSync.checkForNewBlocks()
                
            case .compactFilters(let compactFilterSync):
                try await compactFilterSync.startSync()
            }
            
            // After sync, process any pending events
            channelManager.processPendingHtlcForwards()
            
            // Persist state
            LDKManager.shared.persistState()
            
            logger.log(message: "Chain sync completed")
        }
        
        // Force immediate sync
        func syncNow() async throws {
            try await performSync()
        }
        
        // Get sync status
        func getSyncStatus() -> SyncStatus {
            let currentTime = Date()
            let timeSinceLastSync = currentTime.timeIntervalSince(lastSyncTime)
            
            return SyncStatus(
                lastSyncTime: lastSyncTime,
                isSyncing: syncTask != nil && !syncTask!.isCancelled,
                syncMethod: syncMethodName(),
                isUpToDate: timeSinceLastSync < syncInterval * 2
            )
        }
        
        private func syncMethodName() -> String {
            switch syncMethod {
            case .electrum: return "Electrum"
            case .esplora: return "Esplora"
            case .bitcoinCore: return "Bitcoin Core"
            case .compactFilters: return "Compact Filters"
            }
        }
    }
    
    // Sync status
    struct SyncStatus {
        let lastSyncTime: Date
        let isSyncing: Bool
        let syncMethod: String
        let isUpToDate: Bool
    }
    
    // SwiftUI Sync Status View
    struct SyncStatusView: View {
        @StateObject private var viewModel = SyncStatusViewModel()
        
        var body: some View {
            VStack(spacing: 16) {
                // Sync indicator
                HStack {
                    if viewModel.isSyncing {
                        ProgressView()
                            .scaleEffect(0.8)
                    } else {
                        Image(systemName: viewModel.isUpToDate ? "checkmark.circle.fill" : "exclamationmark.triangle.fill")
                            .foregroundColor(viewModel.isUpToDate ? .green : .orange)
                    }
                    
                    Text(viewModel.statusText)
                        .font(.headline)
                    
                    Spacer()
                }
                
                // Sync details
                VStack(alignment: .leading, spacing: 8) {
                    HStack {
                        Text("Method:")
                        Spacer()
                        Text(viewModel.syncMethod)
                            .foregroundColor(.secondary)
                    }
                    
                    HStack {
                        Text("Last Sync:")
                        Spacer()
                        Text(viewModel.lastSyncTime, style: .relative)
                            .foregroundColor(.secondary)
                    }
                    
                    HStack {
                        Text("Block Height:")
                        Spacer()
                        Text("\\(viewModel.blockHeight)")
                            .foregroundColor(.secondary)
                    }
                }
                .font(.subheadline)
                
                // Manual sync button
                Button(action: {
                    Task {
                        await viewModel.syncNow()
                    }
                }) {
                    Label("Sync Now", systemImage: "arrow.clockwise")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.borderedProminent)
                .disabled(viewModel.isSyncing)
            }
            .padding()
            .background(Color(UIColor.secondarySystemBackground))
            .cornerRadius(12)
            .onAppear {
                viewModel.startMonitoring()
            }
            .onDisappear {
                viewModel.stopMonitoring()
            }
        }
    }
    
    // View Model for sync status
    @MainActor
    class SyncStatusViewModel: ObservableObject {
        @Published var isSyncing = false
        @Published var isUpToDate = true
        @Published var syncMethod = "Unknown"
        @Published var lastSyncTime = Date()
        @Published var blockHeight: UInt32 = 0
        
        private var timer: Timer?
        
        var statusText: String {
            if isSyncing {
                return "Syncing..."
            } else if isUpToDate {
                return "Synchronized"
            } else {
                return "Out of Sync"
            }
        }
        
        func startMonitoring() {
            updateStatus()
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                self.updateStatus()
            }
        }
        
        func stopMonitoring() {
            timer?.invalidate()
            timer = nil
        }
        
        func syncNow() async {
            do {
                try await LDKManager.shared.chainSyncManager.syncNow()
            } catch {
                print("Manual sync failed: \\(error)")
            }
        }
        
        private func updateStatus() {
            let status = LDKManager.shared.chainSyncManager.getSyncStatus()
            isSyncing = status.isSyncing
            isUpToDate = status.isUpToDate
            syncMethod = status.syncMethod
            lastSyncTime = status.lastSyncTime
            
            // Get current block height
            if let nodeInfo = try? LDKManager.shared.channelManager.getNodeInfo() {
                blockHeight = nodeInfo.blockHeight
            }
        }
    }`.trim(),
    
          reorg_handling: `
    // Blockchain reorganization handling
    import LightningDevKit
    import Foundation
    
    class ReorgHandler {
        private let channelManager: Bindings.ChannelManager
        private let chainMonitor: Bindings.ChainMonitor
        private let logger: Bindings.Logger
        
        private var blockHistory: [UInt32: BlockRecord] = [:]
        private let maxHistoryDepth: UInt32 = 100
        
        struct BlockRecord {
            let height: UInt32
            let hash: [UInt8]
            let previousHash: [UInt8]
            let timestamp: Date
            let confirmedTransactions: Set<[UInt8]>
        }
        
        init(
            channelManager: Bindings.ChannelManager,
            chainMonitor: Bindings.ChainMonitor,
            logger: Bindings.Logger
        ) {
            self.channelManager = channelManager
            self.chainMonitor = chainMonitor
            self.logger = logger
            
            loadBlockHistory()
        }
        
        // Check for and handle reorganization
        func checkForReorg(newBlock: BlockInfo) async throws -> ReorgResult {
            let newHeight = newBlock.height
            let newHash = newBlock.hash
            let previousHash = newBlock.previousHash
            
            // Check if this connects to our known chain
            if let knownBlock = blockHistory[newHeight - 1] {
                if knownBlock.hash == previousHash {
                    // Normal case - new block extends our chain
                    addBlockToHistory(newBlock)
                    return .noReorg
                }
            }
            
            // Potential reorg - find common ancestor
            let reorgDepth = findReorgDepth(
                startHeight: newHeight - 1,
                targetHash: previousHash
            )
            
            if reorgDepth > 0 {
                logger.log(message: "Reorg detected! Depth: \\(reorgDepth) blocks")
                
                // Handle the reorg
                try await handleReorg(
                    fromHeight: newHeight - reorgDepth,
                    newChainTip: newBlock
                )
                
                return .reorgDetected(depth: reorgDepth)
            }
            
            // Add to history
            addBlockToHistory(newBlock)
            return .noReorg
        }
        
        // Find how deep the reorg is
        private func findReorgDepth(startHeight: UInt32, targetHash: [UInt8]) -> UInt32 {
            var depth: UInt32 = 0
            var currentHeight = startHeight
            
            while currentHeight > 0 && depth < maxHistoryDepth {
                if let block = blockHistory[currentHeight] {
                    if block.hash == targetHash {
                        return depth
                    }
                }
                depth += 1
                currentHeight -= 1
            }
            
            // Reorg deeper than our history
            return depth
        }
        
        // Handle reorganization
        private func handleReorg(
            fromHeight: UInt32,
            newChainTip: BlockInfo
        ) async throws {
            logger.log(message: "Handling reorg from height \\(fromHeight)")
            
            // 1. Collect all transactions that were confirmed after reorg point
            var reorgedTransactions = Set<[UInt8]>()
            
            for height in fromHeight...newChainTip.height {
                if let block = blockHistory[height] {
                    reorgedTransactions.formUnion(block.confirmedTransactions)
                }
            }
            
            // 2. Mark transactions as unconfirmed
            for txid in reorgedTransactions {
                channelManager.asConfirm().transactionUnconfirmed(txid: txid)
                chainMonitor.asConfirm().transactionUnconfirmed(txid: txid)
                
                logger.log(message: "Transaction unconfirmed: \\(Data(txid).hexString)")
            }
            
            // 3. Remove reorged blocks from history
            for height in fromHeight...newChainTip.height {
                blockHistory.removeValue(forKey: height)
            }
            
            // 4. Re-scan from reorg point
            // This would involve re-downloading blocks and checking transactions
            try await rescanFromHeight(fromHeight)
            
            // 5. Update to new chain tip
            channelManager.asConfirm().bestBlockUpdated(
                header: newChainTip.hash,
                height: newChainTip.height
            )
            chainMonitor.asConfirm().bestBlockUpdated(
                header: newChainTip.hash,
                height: newChainTip.height
            )
            
            // 6. Check if any channels need to be force closed
            checkChannelsAfterReorg()
        }
        
        // Rescan blockchain from given height
        private func rescanFromHeight(_ height: UInt32) async throws {
            logger.log(message: "Rescanning from height \\(height)")
            
            // This would involve:
            // 1. Re-downloading blocks from the reorg point
            // 2. Re-checking all relevant transactions
            // 3. Re-confirming transactions that are still in the chain
            
            // Implementation depends on the chain source (Electrum/Esplora/etc)
        }
        
        // Check channels after reorg
        private func checkChannelsAfterReorg() {
            let channels = channelManager.listChannels()
            
            for channel in channels {
                // Check if funding transaction is still confirmed
                if let fundingTxo = channel.getFundingTxo() {
                    // Would need to check if funding tx is still confirmed
                    // If not, the channel may need to be closed
                }
                
                // Check if any commitment transactions were broadcast
                // This is handled automatically by LDK's chain monitoring
            }
        }
        
        // Add block to history
        private func addBlockToHistory(_ block: BlockInfo) {
            let record = BlockRecord(
                height: block.height,
                hash: block.hash,
                previousHash: block.previousHash,
                timestamp: Date(),
                confirmedTransactions: Set(block.confirmedTransactions)
            )
            
            blockHistory[block.height] = record
            
            // Prune old history
            let pruneHeight = block.height.saturatingSubtraction(maxHistoryDepth)
            blockHistory = blockHistory.filter { $0.key >= pruneHeight }
            
            // Persist history
            saveBlockHistory()
        }
        
        // Persistence
        private func saveBlockHistory() {
            // Save to UserDefaults or file
            // Only save recent blocks to limit storage
            let recentBlocks = blockHistory.filter { 
                $0.key > (blockHistory.keys.max() ?? 0).saturatingSubtraction(20)
            }
            
            if let encoded = try? JSONEncoder().encode(recentBlocks) {
                UserDefaults.standard.set(encoded, forKey: "blockHistory")
            }
        }
        
        private func loadBlockHistory() {
            // Load from UserDefaults or file
            if let data = UserDefaults.standard.data(forKey: "blockHistory"),
               let decoded = try? JSONDecoder().decode([UInt32: BlockRecord].self, from: data) {
                blockHistory = decoded
            }
        }
    }
    
    // Block info for reorg detection
    struct BlockInfo {
        let height: UInt32
        let hash: [UInt8]
        let previousHash: [UInt8]
        let confirmedTransactions: [[UInt8]]
    }
    
    // Reorg result
    enum ReorgResult {
        case noReorg
        case reorgDetected(depth: UInt32)
    }
    
    // Reorg monitoring service
    class ReorgMonitor {
        private let reorgHandler: ReorgHandler
        private let logger: Bindings.Logger
        private var monitoringTask: Task<Void, Never>?
        
        init(reorgHandler: ReorgHandler, logger: Bindings.Logger) {
            self.reorgHandler = reorgHandler
            self.logger = logger
        }
        
        // Start monitoring for reorgs
        func startMonitoring() {
            monitoringTask = Task {
                while !Task.isCancelled {
                    await checkForReorgs()
                    
                    // Check every 30 seconds
                    try? await Task.sleep(nanoseconds: 30_000_000_000)
                }
            }
        }
        
        // Stop monitoring
        func stopMonitoring() {
            monitoringTask?.cancel()
            monitoringTask = nil
        }
        
        private func checkForReorgs() async {
            // This would get the latest block and check for reorgs
            // Implementation depends on chain source
        }
    }
    
    // SwiftUI Reorg Alert
    struct ReorgAlertView: View {
        let reorgDepth: UInt32
        let onDismiss: () -> Void
        
        var body: some View {
            VStack(spacing: 20) {
                Image(systemName: "exclamationmark.triangle.fill")
                    .font(.system(size: 50))
                    .foregroundColor(.orange)
                
                Text("Blockchain Reorganization")
                    .font(.title2)
                    .fontWeight(.bold)
                
                Text("A \\(reorgDepth)-block reorganization has been detected.")
                    .multilineTextAlignment(.center)
                
                Text("Your wallet is automatically handling this. Some recent transactions may have changed confirmation status.")
                    .font(.caption)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                
                Button("Understood") {
                    onDismiss()
                }
                .buttonStyle(.borderedProminent)
            }
            .padding()
            .background(Color(UIColor.systemBackground))
            .cornerRadius(16)
            .shadow(radius: 10)
            .padding()
        }
    }`.trim()
        };
    
        try {
          const code = syncExamples[args.syncMethod];
          if (!code) {
            throw new Error(`Unknown sync method: ${args.syncMethod}`);
          }
    
          return {
            content: [{
              type: 'text',
              text: JSON.stringify({
                success: true,
                syncMethod: args.syncMethod,
                swiftCode: code,
                description: `Chain synchronization implementation for ${args.syncMethod}`
              }, 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 validating the 'syncMethod' parameter with allowed values for different synchronization implementations.
    inputSchema: {
      type: 'object',
      properties: {
        syncMethod: {
          type: 'string',
          enum: [
            'electrum_sync',
            'esplora_sync',
            'bitcoin_core_rpc',
            'compact_filters',
            'sync_management',
            'reorg_handling'
          ],
          description: 'Chain synchronization method to get implementation for'
        }
      },
      required: ['syncMethod']
    },
  • src/index.ts:38-62 (registration)
    Registration of chainSyncTool in the main tools array used by the MCP server for tool discovery and execution.
    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:35-35 (registration)
    Import of the chainSyncTool for inclusion in the MCP tools registry.
    import { chainSyncTool } from './tools/chainSync.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