Check Lightning budget
l402_balanceCheck the remaining Bitcoin Lightning budget for the current MCP session to confirm sufficient sats before making API calls.
Instructions
Returns the remaining Bitcoin Lightning budget for this MCP session. Use this before calling l402_fetch to confirm you have enough sats — avoids wasted attempts when budget is exhausted. Returns: ' sats remaining of total (spent: sats)'. Read-only — does not trigger any payment or side effect. Budget is set at server startup via BUDGET_SATS (default: 1000 sats ≈ $0.60); to increase it, restart the MCP server.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- mcp/server.ts:163-194 (registration)Registration of the l402_balance tool via server.registerTool(...) with description and handler.
// Tool: l402_balance server.registerTool( "l402_balance", { title: "Check Lightning budget", description: "Returns the remaining Bitcoin Lightning budget for this MCP session. " + "Use this before calling l402_fetch to confirm you have enough sats — avoids wasted attempts when budget is exhausted. " + "Returns: '<remaining> sats remaining of <total> total (spent: <spent> sats)'. " + "Read-only — does not trigger any payment or side effect. " + "Budget is set at server startup via BUDGET_SATS (default: 1000 sats ≈ $0.60); to increase it, restart the MCP server.", inputSchema: {}, annotations: { readOnlyHint: true, idempotentHint: true, }, }, async () => { const report = requireClient().spendingReport(); if (!report) { return { content: [{ type: "text" as const, text: "No budget configured." }], }; } return { content: [{ type: "text" as const, text: `Budget: ${report.remaining} sats remaining of ${budgetSats} total (spent: ${report.total} sats)`, }], }; } ); - mcp/server.ts:180-193 (handler)Handler function for l402_balance tool. Calls requireClient().spendingReport() and returns a formatted string of remaining budget.
async () => { const report = requireClient().spendingReport(); if (!report) { return { content: [{ type: "text" as const, text: "No budget configured." }], }; } return { content: [{ type: "text" as const, text: `Budget: ${report.remaining} sats remaining of ${budgetSats} total (spent: ${report.total} sats)`, }], }; } - src/agent/budget.ts:12-100 (helper)SpendingReport interface defining the shape of the report returned by BudgetTracker.report() — used by l402_balance handler.
export interface SpendingReport { total: number; remaining: number; byDomain: Record<string, number>; transactions: Array<{ url: string; sats: number; ts: number }>; } export class BudgetTracker { private spent = 0; private byDomain: Record<string, number> = {}; private transactions: Array<{ url: string; sats: number; ts: number }> = []; constructor( private readonly limitSats: number, private readonly perDomain?: Record<string, number>, private readonly onSpend?: (sats: number, url: string) => void, private readonly onBudgetExceeded?: (url: string, sats: number) => void, ) {} check(url: string, sats: number): void { const remaining = this.limitSats - this.spent; if (sats > remaining) { this.onBudgetExceeded?.(url, sats); throw new BudgetExceededError(url, sats, remaining); } if (this.perDomain) { const domain = this._domain(url); const domainLimit = this.perDomain[domain]; if (domainLimit !== undefined) { const domainSpent = this.byDomain[domain] ?? 0; const domainRemaining = domainLimit - domainSpent; if (sats > domainRemaining) { this.onBudgetExceeded?.(url, sats); throw new BudgetExceededError(url, sats, domainRemaining); } } } } record(url: string, sats: number): void { this.spent += sats; const domain = this._domain(url); this.byDomain[domain] = (this.byDomain[domain] ?? 0) + sats; this.transactions.push({ url, sats, ts: Date.now() }); this.onSpend?.(sats, url); } report(): SpendingReport { return { total: this.spent, remaining: Math.max(0, this.limitSats - this.spent), byDomain: { ...this.byDomain }, transactions: [...this.transactions], }; } private _domain(url: string): string { try { return new URL(url).hostname; } catch { return url; } } } - src/agent/budget.ts:60-73 (helper)BudgetTracker.report() method produces the SpendingReport consumed by spendingReport() on L402Client.
report(): SpendingReport { return { total: this.spent, remaining: Math.max(0, this.limitSats - this.spent), byDomain: { ...this.byDomain }, transactions: [...this.transactions], }; } private _domain(url: string): string { try { return new URL(url).hostname; } catch { return url; } } } - src/client.ts:96-100 (helper)L402Client.spendingReport() — delegates to BudgetTracker.report(). Called by the l402_balance handler to get budget data.
/** Returns a spending report. Only available when budgetSats is configured. */ spendingReport() { if (!this.budget) return null; return this.budget.report(); }