@baruchiro/actual-mcp
Version:
Actual Budget MCP server exposing API functionality
94 lines (93 loc) • 3.93 kB
JavaScript
// Orchestrator for get-transactions tool
import { GetTransactionsInputParser } from "./input-parser.js";
import { GetTransactionsDataFetcher } from "./data-fetcher.js";
import { GetTransactionsMapper } from "./transaction-mapper.js";
import { GetTransactionsReportGenerator } from "./report-generator.js";
import { successWithContent, errorFromCatch } from "../../utils/response.js";
import { getDateRange } from "../../utils.js";
export const schema = {
name: "get-transactions",
description: "Get transactions for an account with optional filtering",
inputSchema: {
type: "object",
properties: {
accountId: {
type: "string",
description: "ID of the account to get transactions for. Should be in UUID format and retrieved from the accounts resource.",
},
startDate: {
type: "string",
description: "Start date in YYYY-MM-DD format",
},
endDate: {
type: "string",
description: "End date in YYYY-MM-DD format",
},
minAmount: {
type: "number",
description: "Minimum transaction amount in dollars",
},
maxAmount: {
type: "number",
description: "Maximum transaction amount in dollars",
},
category: {
type: "string",
description: "Filter by category name",
},
payee: {
type: "string",
description: "Filter by payee name",
},
limit: {
type: "number",
description: "Maximum number of transactions to return",
},
},
required: ["accountId"],
},
};
export async function handler(args) {
try {
const input = new GetTransactionsInputParser().parse(args);
const { accountId, startDate, endDate, minAmount, maxAmount, category, payee, limit, } = input;
const { startDate: start, endDate: end } = getDateRange(startDate, endDate);
// Fetch transactions
const transactions = await new GetTransactionsDataFetcher().fetch(accountId, start, end);
let filtered = [...transactions];
if (minAmount !== undefined) {
filtered = filtered.filter((t) => t.amount >= minAmount * 100);
}
if (maxAmount !== undefined) {
filtered = filtered.filter((t) => t.amount <= maxAmount * 100);
}
if (category) {
const lowerCategory = category.toLowerCase();
filtered = filtered.filter((t) => (t.category_name || "").toLowerCase().includes(lowerCategory));
}
if (payee) {
const lowerPayee = payee.toLowerCase();
filtered = filtered.filter((t) => (t.payee_name || "").toLowerCase().includes(lowerPayee));
}
if (limit && filtered.length > limit) {
filtered = filtered.slice(0, limit);
}
// Map transactions for output
const mapped = new GetTransactionsMapper().map(filtered);
// Build filter description
const filterDescription = [
startDate || endDate ? `Date range: ${startDate} to ${endDate}` : null,
minAmount !== undefined ? `Min amount: $${minAmount.toFixed(2)}` : null,
maxAmount !== undefined ? `Max amount: $${maxAmount.toFixed(2)}` : null,
category ? `Category: ${category}` : null,
payee ? `Payee: ${payee}` : null,
]
.filter(Boolean)
.join(", ");
const markdown = new GetTransactionsReportGenerator().generate(mapped, filterDescription, filtered.length, transactions.length);
return successWithContent([{ type: "text", text: markdown }]);
}
catch (err) {
return errorFromCatch(err);
}
}