get_my_budget
Check the current budget status for your virtual key, with options for 24h, 7d, 30d, or billing cycle periods.
Instructions
Returns budget status for the current virtual key.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | Budget window for cockpit/budget-status query param | billing_cycle |
Implementation Reference
- src/tools/vk/budget.ts:7-20 (handler)Registers the 'get_my_budget' tool with a Zod schema for the 'period' parameter (24h, 7d, 30d, billing_cycle; defaults to billing_cycle). The handler calls cockpit.budgetStatus(period) via safeCall.
export function registerVkBudgetTools(server: McpServer, deps: ToolDeps): void { server.tool( "get_my_budget", { period: z .enum(["24h", "7d", "30d", "billing_cycle"]) .default("billing_cycle") .describe("Budget window for cockpit/budget-status query param"), }, async ({ period }) => { const cockpit = requireCockpit(deps); return safeCall(() => cockpit.budgetStatus(period), "vk"); }, ); - src/clients/cockpit-client.ts:60-65 (helper)The CockpitClient.budgetStatus method that makes the actual HTTP GET request to /api/v1/cockpit/budget-status with the period query param and returns BudgetStatusResponse.
async budgetStatus(period = "30d"): Promise<BudgetStatusResponse> { const { data } = await this.http.get("/api/v1/cockpit/budget-status", { params: { period }, }); return data as BudgetStatusResponse; } - src/clients/types.ts:32-39 (schema)BudgetStatusResponse interface: budgetCents, spentCents, remainingCents, percentUsed, exceededAction, period.
export interface BudgetStatusResponse { budgetCents: number; spentCents: number; remainingCents: number; percentUsed: number; exceededAction: string; period: string; } - src/tools/registry.ts:32-33 (registration)TOOL_DESCRIPTIONS entry for 'get_my_budget' with description 'Returns budget status for the current virtual key.' Also registered via registerVkBudgetTools on line 213.
get_my_budget: "Returns budget status for the current virtual key.", - src/utils/safe-call.ts:112-189 (helper)safeCall utility used by the tool handler to wrap the async call with error handling, rate limiting, and JSON serialization.
export async function safeCall<T>( fn: () => Promise<T>, mode: AuthMode, ): Promise<CallToolResult> { await acquireGlobalRateSlot(); try { const data = await fn(); let text: string; try { text = JSON.stringify(data, null, 2); } catch { if (data && typeof data === "object") { text = JSON.stringify(data) || String(data); } else { text = String(data); } } return { content: [{ type: "text", text }], }; } catch (err) { const e = toHttpLike(err); const statusLabel = e.status ? `HTTP ${e.status}` : e.code ?? "unknown"; console.error(`[safeCall] ${statusLabel}: ${e.message}`); const authOrRate = toolResultForAuthAndRateLimit(e, mode); if (authOrRate) return authOrRate; if (e.status === 400) { return { content: [{ type: "text", text: `Bad request: ${e.message}` }], isError: true, }; } if (e.status === 404) { return { content: [{ type: "text", text: `Not found: ${e.message}` }], isError: true, }; } if (e.status === 502) { return { content: [{ type: "text", text: "Bad gateway. The backend service is unavailable." }], isError: true, }; } if (e.status === 504) { return { content: [ { type: "text", text: "Gateway timeout. The backend service is slow to respond.", }, ], isError: true, }; } if (e.status === 500) { return { content: [{ type: "text", text: "Internal server error. Please contact support." }], isError: true, }; } if (e.code === "ETIMEDOUT" || e.code === "ECONNABORTED") { return { content: [ { type: "text", text: "Request timeout. Check your network connection or API availability.", }, ], isError: true, }; } return { content: [{ type: "text", text: `Unexpected error: ${e.message}` }], isError: true, }; } }