UNPKG

mcp-ynab

Version:

Model Context Protocol server for YNAB integration

112 lines (97 loc) 4.32 kB
import { YnabClient } from '../../shared/ynab-client.js'; import { CacheManager } from '../../shared/cache-manager.js'; import { ErrorHandler } from '../../shared/error-handler.js'; const cache = new CacheManager(); const errorHandler = new ErrorHandler(); const toolDefinition = { name: 'get_accounts', description: 'Get all budget accounts with current balances and account details', inputSchema: { type: 'object', properties: { budget_id: { type: 'string', description: 'Specific budget ID (optional, defaults to default budget)' }, include_closed: { type: 'boolean', description: 'Include closed accounts in results (optional, defaults to false)', default: false } }, additionalProperties: false } }; const handler = async (params) => { try { const ynab = new YnabClient(); const { budget_id, include_closed = false } = params; // Generate cache key const cacheKey = cache.generateKey('accounts', { budget_id, include_closed }); return await cache.getOrSet(cacheKey, async () => { const budgetId = budget_id || await ynab.getDefaultBudgetId(); // Get all accounts const accounts = await ynab.getAccounts(budgetId); // Filter accounts based on include_closed parameter let filteredAccounts = accounts; if (!include_closed) { filteredAccounts = accounts.filter(account => !account.closed); } // Transform accounts data for response const accountsData = filteredAccounts.map(account => ({ id: account.id, name: account.name, type: account.type, balance: ynab.milliunitsToAmount(account.balance), cleared_balance: ynab.milliunitsToAmount(account.cleared_balance), uncleared_balance: ynab.milliunitsToAmount(account.uncleared_balance), on_budget: account.on_budget, closed: account.closed, note: account.note || null, last_reconciled_at: account.last_reconciled_at || null, debt_original_balance: account.debt_original_balance ? ynab.milliunitsToAmount(account.debt_original_balance) : null, debt_interest_rates: account.debt_interest_rates || null, debt_minimum_payments: Array.isArray(account.debt_minimum_payments) ? account.debt_minimum_payments.map(payment => ({ ...payment, amount: ynab.milliunitsToAmount(payment.amount) })) : null })); // Calculate summary statistics const onBudgetAccounts = accountsData.filter(account => account.on_budget && !account.closed); const offBudgetAccounts = accountsData.filter(account => !account.on_budget && !account.closed); const closedAccounts = accountsData.filter(account => account.closed); const totalOnBudgetBalance = onBudgetAccounts.reduce((sum, account) => sum + account.balance, 0); const totalOffBudgetBalance = offBudgetAccounts.reduce((sum, account) => sum + account.balance, 0); const totalBalance = totalOnBudgetBalance + totalOffBudgetBalance; // Categorize by account type const byType = accountsData.reduce((acc, account) => { if (!acc[account.type]) { acc[account.type] = []; } acc[account.type].push(account); return acc; }, {}); return { accounts: accountsData, summary: { total_accounts: accountsData.length, on_budget_accounts: onBudgetAccounts.length, off_budget_accounts: offBudgetAccounts.length, closed_accounts: closedAccounts.length, total_balance: totalBalance, total_on_budget_balance: totalOnBudgetBalance, total_off_budget_balance: totalOffBudgetBalance }, by_type: Object.keys(byType).map(type => ({ type: type, count: byType[type].length, accounts: byType[type], total_balance: byType[type].reduce((sum, account) => sum + account.balance, 0) })) }; }, 10); // Cache for 10 minutes } catch (error) { return errorHandler.formatForMCP(error); } }; export { toolDefinition, handler };