cbc46314db
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
3.3 KiB
C#
81 lines
3.3 KiB
C#
using System.ComponentModel;
|
|
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using ModelContextProtocol.Server;
|
|
using MoneyMap.Data;
|
|
using MoneyMap.Services;
|
|
|
|
namespace MoneyMap.Mcp.Tools;
|
|
|
|
[McpServerToolType]
|
|
public static class CategoryTools
|
|
{
|
|
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
|
|
|
[McpServerTool(Name = "list_categories"), Description("List all categories with transaction counts.")]
|
|
public static async Task<string> ListCategories(
|
|
MoneyMapContext db = default!)
|
|
{
|
|
var categories = await db.Transactions
|
|
.Where(t => t.Category != null && t.Category != "")
|
|
.GroupBy(t => t.Category!)
|
|
.Select(g => new { Category = g.Key, Count = g.Count(), TotalSpent = g.Where(t => t.Amount < 0).Sum(t => Math.Abs(t.Amount)) })
|
|
.OrderByDescending(x => x.Count)
|
|
.ToListAsync();
|
|
|
|
var uncategorized = await db.Transactions
|
|
.CountAsync(t => t.Category == null || t.Category == "");
|
|
|
|
return JsonSerializer.Serialize(new { Categories = categories, UncategorizedCount = uncategorized }, JsonOptions);
|
|
}
|
|
|
|
[McpServerTool(Name = "get_category_mappings"), Description("Get auto-categorization pattern rules (CategoryMappings).")]
|
|
public static async Task<string> GetCategoryMappings(
|
|
[Description("Filter mappings to a specific category")] string? category = null,
|
|
ITransactionCategorizer categorizer = default!)
|
|
{
|
|
var mappings = await categorizer.GetAllMappingsAsync();
|
|
|
|
if (!string.IsNullOrWhiteSpace(category))
|
|
mappings = mappings.Where(m => m.Category.Equals(category, StringComparison.OrdinalIgnoreCase)).ToList();
|
|
|
|
var result = mappings.Select(m => new
|
|
{
|
|
m.Id,
|
|
m.Pattern,
|
|
m.Category,
|
|
m.MerchantId,
|
|
m.Priority
|
|
}).OrderBy(m => m.Category).ThenByDescending(m => m.Priority).ToList();
|
|
|
|
return JsonSerializer.Serialize(result, JsonOptions);
|
|
}
|
|
|
|
[McpServerTool(Name = "add_category_mapping"), Description("Add a new auto-categorization rule that maps transaction name patterns to categories.")]
|
|
public static async Task<string> AddCategoryMapping(
|
|
[Description("Pattern to match in transaction name (case-insensitive)")] string pattern,
|
|
[Description("Category to assign when pattern matches")] string category,
|
|
[Description("Merchant name to assign (creates if new)")] string? merchantName = null,
|
|
[Description("Priority (higher = checked first, default 0)")] int priority = 0,
|
|
MoneyMapContext db = default!,
|
|
IMerchantService merchantService = default!)
|
|
{
|
|
int? merchantId = null;
|
|
if (!string.IsNullOrWhiteSpace(merchantName))
|
|
merchantId = await merchantService.GetOrCreateIdAsync(merchantName);
|
|
|
|
var mapping = new MoneyMap.Models.CategoryMapping
|
|
{
|
|
Pattern = pattern,
|
|
Category = category,
|
|
MerchantId = merchantId,
|
|
Priority = priority
|
|
};
|
|
|
|
db.CategoryMappings.Add(mapping);
|
|
await db.SaveChangesAsync();
|
|
|
|
return JsonSerializer.Serialize(new { Created = true, mapping.Id, mapping.Pattern, mapping.Category, Merchant = merchantName, mapping.Priority }, JsonOptions);
|
|
}
|
|
}
|