using System.ComponentModel; using ModelContextProtocol.Server; namespace MoneyMap.Mcp.Tools; [McpServerToolType] public static class TransactionTools { [McpServerTool(Name = "search_transactions"), Description("Search and filter transactions. Returns matching transactions with details.")] public static async Task SearchTransactions( [Description("Full-text search across name, memo, and category")] string? query = null, [Description("Start date (inclusive), e.g. 2026-01-01")] string? startDate = null, [Description("End date (inclusive), e.g. 2026-01-31")] string? endDate = null, [Description("Filter by category name (exact match)")] string? category = null, [Description("Filter by merchant name (contains)")] string? merchantName = null, [Description("Minimum amount (absolute value)")] decimal? minAmount = null, [Description("Maximum amount (absolute value)")] decimal? maxAmount = null, [Description("Filter by account ID")] int? accountId = null, [Description("Filter by card ID")] int? cardId = null, [Description("Filter by type: 'debit' or 'credit'")] string? type = null, [Description("Only show uncategorized transactions")] bool? uncategorizedOnly = null, [Description("Max results to return (default 50)")] int? limit = null, MoneyMapApiClient api = default!) { return await api.SearchTransactionsAsync(query, startDate, endDate, category, merchantName, minAmount, maxAmount, accountId, cardId, type, uncategorizedOnly, limit); } [McpServerTool(Name = "get_transaction"), Description("Get a single transaction with all details including receipts.")] public static async Task GetTransaction( [Description("Transaction ID")] long transactionId, MoneyMapApiClient api = default!) { return await api.GetTransactionAsync(transactionId); } [McpServerTool(Name = "get_spending_summary"), Description("Get spending totals grouped by category for a date range. Excludes transfers.")] public static async Task GetSpendingSummary( [Description("Start date (inclusive), e.g. 2026-01-01")] string startDate, [Description("End date (inclusive), e.g. 2026-01-31")] string endDate, [Description("Filter to specific account ID")] int? accountId = null, MoneyMapApiClient api = default!) { return await api.GetSpendingSummaryAsync(startDate, endDate, accountId); } [McpServerTool(Name = "get_income_summary"), Description("Get income (credits) grouped by source/name for a date range.")] public static async Task GetIncomeSummary( [Description("Start date (inclusive), e.g. 2026-01-01")] string startDate, [Description("End date (inclusive), e.g. 2026-01-31")] string endDate, [Description("Filter to specific account ID")] int? accountId = null, MoneyMapApiClient api = default!) { return await api.GetIncomeSummaryAsync(startDate, endDate, accountId); } [McpServerTool(Name = "update_transaction_category"), Description("Update the category (and optionally merchant) on one or more transactions.")] public static async Task UpdateTransactionCategory( [Description("Array of transaction IDs to update")] long[] transactionIds, [Description("New category to assign")] string category, [Description("Merchant name to assign (creates if new)")] string? merchantName = null, MoneyMapApiClient api = default!) { return await api.UpdateTransactionCategoryAsync(transactionIds, category, merchantName); } [McpServerTool(Name = "bulk_recategorize"), Description("Recategorize all transactions matching a name pattern. Use dryRun=true (default) to preview changes first.")] public static async Task BulkRecategorize( [Description("Pattern to match in transaction name (case-insensitive contains)")] string namePattern, [Description("New category to assign")] string toCategory, [Description("Only recategorize transactions currently in this category")] string? fromCategory = null, [Description("Merchant name to assign (creates if new)")] string? merchantName = null, [Description("If true (default), only shows what would change without applying")] bool dryRun = true, MoneyMapApiClient api = default!) { return await api.BulkRecategorizeAsync(namePattern, toCategory, fromCategory, merchantName, dryRun); } }