UNPKG

@baruchiro/actual-mcp

Version:

Actual Budget MCP server exposing API functionality

54 lines (53 loc) 2.77 kB
// Orchestrator for spending-by-category tool import { SpendingByCategoryInputParser } from "./input-parser.js"; import { SpendingByCategoryDataFetcher } from "./data-fetcher.js"; import { SpendingByCategoryCategoryMapper } from "./category-mapper.js"; import { SpendingByCategoryTransactionGrouper } from "./transaction-grouper.js"; import { SpendingByCategoryGroupAggregator } from "./group-aggregator.js"; import { SpendingByCategoryReportGenerator } from "./report-generator.js"; import { successWithContent, errorFromCatch } from "../../utils/response.js"; export const schema = { name: "spending-by-category", description: "Get spending breakdown by category for a specified date range", inputSchema: { type: "object", properties: { startDate: { type: "string", description: "Start date in YYYY-MM-DD format", }, endDate: { type: "string", description: "End date in YYYY-MM-DD format", }, accountId: { type: "string", description: "Optional ID of a specific account to analyze. If not provided, all on-budget accounts will be used.", }, includeIncome: { type: "boolean", description: "Whether to include income categories in the report (default: false)", }, }, }, }; export async function handler(args) { try { const input = new SpendingByCategoryInputParser().parse(args); const { startDate, endDate, accountId, includeIncome } = input; const { accounts, categories, categoryGroups, transactions } = await new SpendingByCategoryDataFetcher().fetchAll(accountId, startDate, endDate); const categoryMapper = new SpendingByCategoryCategoryMapper(categories, categoryGroups); const spendingByCategory = new SpendingByCategoryTransactionGrouper().groupByCategory(transactions, (categoryId) => categoryMapper.getCategoryName(categoryId), (categoryId) => categoryMapper.getGroupInfo(categoryId), includeIncome); const sortedGroups = new SpendingByCategoryGroupAggregator().aggregateAndSort(spendingByCategory); let accountLabel = "Accounts: All on-budget accounts"; if (accountId) { const account = accounts.find((a) => a.id === accountId); accountLabel = `Account: ${account ? account.name : accountId}`; } const markdown = new SpendingByCategoryReportGenerator().generate(sortedGroups, { start: startDate, end: endDate }, accountLabel, includeIncome); return successWithContent([{ type: "text", text: markdown }]); } catch (err) { return errorFromCatch(err); } }