Budget Summary
ynab_budget_summaryRetrieve a monthly budget summary that identifies overspent categories requiring attention and highlights categories with positive balances.
Instructions
Get a summary of the budget for a specific month highlighting overspent categories that need attention and categories with a positive balance that are doing well.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| budgetId | No | The ID of the budget to get a summary for (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable) | |
| month | No | The budget month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC) | current |
Implementation Reference
- src/tools/BudgetSummaryTool.ts:25-59 (handler)The main execute function that fetches accounts and budget month data from YNAB API and returns a summary with month budget details, active accounts, and a note about dividing by 1000 for dollar amounts.
export async function execute(input: BudgetSummaryInput, api: ynab.API) { try { const budgetId = getBudgetId(input.budgetId); const month = input.month || "current"; console.error(`Getting accounts and categories for budget ${budgetId} and month ${month}`); const accountsResponse = await api.accounts.getAccounts(budgetId); const accounts = accountsResponse.data.accounts.filter( (account) => account.deleted === false && account.closed === false ); const monthBudget = await api.months.getBudgetMonth(budgetId, month); const categories = monthBudget.data.month.categories .filter( (category) => category.deleted === false && category.hidden === false ); return { content: [{ type: "text" as const, text: JSON.stringify({ monthBudget: monthBudget.data.month, accounts: accounts, note: "Divide all numbers by 1000 to get the balance in dollars.", }, null, 2) }] }; } catch (error: unknown) { console.error("Error getting budget summary:", error); return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, error: getErrorMessage(error), }, null, 2) }] }; } } - src/tools/BudgetSummaryTool.ts:5-10 (schema)Exports: name='ynab_budget_summary', description, and inputSchema with optional budgetId and month (default 'current', accepts ISO date or 'current').
export const name = "ynab_budget_summary"; export const description = "Get a summary of the budget for a specific month highlighting overspent categories that need attention and categories with a positive balance that are doing well."; export const inputSchema = { budgetId: z.string().optional().describe("The ID of the budget to get a summary for (optional, defaults to the budget set in the YNAB_BUDGET_ID environment variable)"), month: z.string().regex(/^(current|\d{4}-\d{2}-\d{2})$/).default("current").describe("The budget month in ISO format (e.g. 2016-12-01). The string 'current' can also be used to specify the current calendar month (UTC)"), }; - src/index.ts:45-49 (registration)Tool registration via server.registerTool using BudgetSummaryTool.name, description, inputSchema, and execute handler.
server.registerTool(BudgetSummaryTool.name, { title: "Budget Summary", description: BudgetSummaryTool.description, inputSchema: BudgetSummaryTool.inputSchema, }, async (input) => BudgetSummaryTool.execute(input, api)); - src/tools/BudgetSummaryTool.ts:17-23 (helper)Helper function getBudgetId that resolves the budget ID from input or falls back to YNAB_BUDGET_ID env variable.
function getBudgetId(inputBudgetId?: string): string { const budgetId = inputBudgetId || process.env.YNAB_BUDGET_ID || ""; if (!budgetId) { throw new Error("No budget ID provided. Please provide a budget ID or set the YNAB_BUDGET_ID environment variable."); } return budgetId; } - src/tools/errorUtils.ts:5-39 (helper)getErrorMessage utility used to extract meaningful error messages from various error types including YNAB API errors.
export function getErrorMessage(error: unknown): string { // Handle standard Error objects if (error instanceof Error) { return error.message; } // Handle YNAB API error responses which have the structure: // { error: { id: '...', name: '...', detail: '...' } } if ( typeof error === 'object' && error !== null && 'error' in error && typeof (error as any).error === 'object' ) { const ynabError = (error as any).error; if (ynabError.detail) { return ynabError.detail; } if (ynabError.name) { return ynabError.name; } } // Fallback: try to stringify the error try { const stringified = JSON.stringify(error); if (stringified !== '{}') { return stringified; } } catch { // Ignore stringify errors } return 'Unknown error occurred'; }