upsert_budget
Create or update a budget for a specific category and budget period. Requires a valid start date from budget settings.
Instructions
Create or update a budget for a category and budget period. The start_date must be a valid budget period start for the account (see get_budget_settings).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| start_date | Yes | Budget period start date in YYYY-MM-DD format. Must be a valid budget period start; if not, the API returns the previous and next valid start dates. | |
| category_id | Yes | Category ID for the budget. | |
| amount | Yes | Budget amount. | |
| currency | No | Three-letter lowercase currency code (defaults to primary currency). | |
| notes | No | Optional notes for the budget period. |
Implementation Reference
- src/tools/budgets.ts:178-199 (handler)The async handler function for the 'upsert_budget' tool. It takes start_date, category_id, amount, optional currency and notes, then sends a PUT request to /budgets and returns the API response.
async ({ start_date, category_id, amount, currency, notes }) => { try { const body: Record<string, unknown> = { start_date, category_id, amount, }; if (currency) body.currency = currency; if (notes !== undefined) body.notes = notes; const response = await api.put("/budgets", body); if (!response.ok) { return handleApiError(response, "Failed to upsert budget"); } return dataResponse(await response.json()); } catch (error) { return catchError(error, "Failed to upsert budget"); } }, - src/tools/budgets.ts:148-173 (schema)Input schema for upsert_budget using Zod validations: start_date (regex YYYY-MM-DD), category_id (coerced number), amount (coerced number), optional currency (3-letter), optional notes (max 350 chars).
description: "Create or update a budget for a category and budget period. The start_date must be a valid budget period start for the account (see get_budget_settings).", inputSchema: { start_date: z .string() .regex(/^\d{4}-\d{2}-\d{2}$/, "Must be YYYY-MM-DD format") .describe( "Budget period start date in YYYY-MM-DD format. Must be a valid budget period start; if not, the API returns the previous and next valid start dates.", ), category_id: z.coerce .number() .describe("Category ID for the budget."), amount: z.coerce.number().describe("Budget amount."), currency: z .string() .length(3) .optional() .describe( "Three-letter lowercase currency code (defaults to primary currency).", ), notes: z .string() .max(350) .optional() .describe("Optional notes for the budget period."), }, - src/tools/budgets.ts:145-200 (registration)Registration of the 'upsert_budget' tool on the MCP server via server.registerTool(), including description, inputSchema, annotations (idempotentHint: true), and the handler function.
server.registerTool( "upsert_budget", { description: "Create or update a budget for a category and budget period. The start_date must be a valid budget period start for the account (see get_budget_settings).", inputSchema: { start_date: z .string() .regex(/^\d{4}-\d{2}-\d{2}$/, "Must be YYYY-MM-DD format") .describe( "Budget period start date in YYYY-MM-DD format. Must be a valid budget period start; if not, the API returns the previous and next valid start dates.", ), category_id: z.coerce .number() .describe("Category ID for the budget."), amount: z.coerce.number().describe("Budget amount."), currency: z .string() .length(3) .optional() .describe( "Three-letter lowercase currency code (defaults to primary currency).", ), notes: z .string() .max(350) .optional() .describe("Optional notes for the budget period."), }, annotations: { idempotentHint: true, }, }, async ({ start_date, category_id, amount, currency, notes }) => { try { const body: Record<string, unknown> = { start_date, category_id, amount, }; if (currency) body.currency = currency; if (notes !== undefined) body.notes = notes; const response = await api.put("/budgets", body); if (!response.ok) { return handleApiError(response, "Failed to upsert budget"); } return dataResponse(await response.json()); } catch (error) { return catchError(error, "Failed to upsert budget"); } }, ); - src/index.ts:30-30 (registration)The registerBudgetTools(server) call in the main entry point that wires up the tool registration.
registerBudgetTools(server); - src/api.ts:146-153 (helper)The api.put() method used by the handler to send the PUT request to the LunchMoney API. api is a helper exported from src/api.ts.
export const api = { get: (path: string) => apiRequest("GET", path), post: (path: string, body?: unknown) => apiRequest("POST", path, body), put: (path: string, body: unknown) => apiRequest("PUT", path, body), delete: (path: string, body?: unknown) => apiRequest("DELETE", path, body), upload: (path: string, formData: FormData) => apiUpload("POST", path, formData), };