Skip to main content
Glama

Bitcoin MCP Server

lnbits_clients.ts4.54 kB
import fetch from "node-fetch"; import bolt11 from "bolt11-decoder"; import { DecodedInvoice, HumanFriendlyInvoice, WalletInfo, PaymentResponse, } from "../types"; class LNBitsClient { private baseUrl: string; private adminKey: string; private readKey: string; constructor(baseUrl: string, adminKey: string, readKey: string) { this.baseUrl = baseUrl.replace(/\/$/, ""); // Remove trailing slash if present this.adminKey = adminKey; this.readKey = readKey; } async getWalletInfo(): Promise<WalletInfo> { const response = await fetch(`${this.baseUrl}/api/v1/wallet`, { headers: { "X-Api-Key": this.readKey, }, }); if (!response.ok) { throw new Error(`Failed to get wallet info: ${response.statusText}`); } const data = (await response.json()) as WalletInfo; return data; } async sendPayment(bolt11: string): Promise<PaymentResponse> { const response = await fetch(`${this.baseUrl}/api/v1/payments`, { method: "POST", headers: { "X-Api-Key": this.adminKey, "Content-Type": "application/json", }, body: JSON.stringify({ out: true, bolt11, }), }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to send payment: ${errorText}`); } const data = (await response.json()) as PaymentResponse; return data; } humanFriendlyInvoice(decoded: DecodedInvoice): HumanFriendlyInvoice { const network = decoded.prefix.startsWith("lnbc") ? "mainnet" : "testnet"; const descriptionTag = decoded.tags.find( (t) => t.tagName === "description" ); const description = descriptionTag ? String(descriptionTag.data) : "No description provided"; return { network: network, amount: decoded.satoshis, description: description, expiryDate: new Date(decoded.timestamp * 1000).toLocaleString(), status: "VALID", }; } toHumanFriendlyInvoice(bolt11Invoice: string): HumanFriendlyInvoice { const decoded = bolt11.decode(bolt11Invoice) as DecodedInvoice; return this.humanFriendlyInvoice(decoded); } displayInvoiceDetails(bolt11Invoice: string): void { try { const decoded = bolt11.decode(bolt11Invoice) as DecodedInvoice; console.log("\n=== Invoice Details ==="); console.log( `Network: ${bolt11Invoice.startsWith("lnbc") ? "mainnet" : "testnet"}` ); console.log(`Amount: ${decoded.satoshis} satoshis`); console.log( `Timestamp: ${new Date(decoded.timestamp * 1000).toLocaleString()}` ); // Find description tag const descriptionTag = decoded.tags.find( (t) => t.tagName === "description" ); const description = descriptionTag ? String(descriptionTag.data) : "No description provided"; console.log(`Description: ${description}`); // Find payment hash const paymentHashTag = decoded.tags.find( (t) => t.tagName === "payment_hash" ); console.log( "Payment Hash:", paymentHashTag ? String(paymentHashTag.data) : "Not found" ); // Find expiry const expiryTag = decoded.tags.find((t) => t.tagName === "expire_time"); const expirySeconds = expiryTag ? Number(expiryTag.data) : 3600; // default 1 hour console.log(`Expiry: ${expirySeconds} seconds`); // Calculate expiry time const expiryDate = new Date((decoded.timestamp + expirySeconds) * 1000); const now = new Date(); const isExpired = expiryDate < now; console.log("\nExpiry Status:"); console.log(`Expires at: ${expiryDate.toLocaleString()}`); console.log(`Status: ${isExpired ? "EXPIRED" : "VALID"}`); if (!isExpired) { const timeLeft = Math.floor( (expiryDate.getTime() - now.getTime()) / 1000 ); console.log(`Time remaining: ${timeLeft} seconds`); } // Route hints if any const routeHints = decoded.tags.filter( (t) => t.tagName === "routing_info" ); if (routeHints.length > 0) { console.log("\nRoute Hints Available:", routeHints.length); } console.log("===================\n"); } catch (error) { if (error instanceof Error) { console.error("Failed to decode invoice:", error.message); } else { console.error("Unknown error while decoding invoice:", error); } process.exit(1); } } } export { LNBitsClient };

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/AbdelStark/bitcoin-mcp'

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