MCP server for tracking and managing expenses with database operations
The server has 6 tools with basic input schemas and generic descriptions. Tool names follow verb_noun convention (add_expense, get_expenses, delete_expense), which is correct. However, descriptions are extremely brief (12-50 chars), falling well below the 194-char production baseline and insufficient for LLM decision-making. Parameter descriptions exist but are minimal and lack constraint details (e.g., date format is mentioned only in add_expense description, not in range_expenses). Output schemas are not documented, the code shows functions return database records or strings without specifying the structure or fields LLMs should expect. Error handling is present but minimal: most tools return plain string messages without recovery guidance or error classification. Schemas are present and properly typed (string, float, integer), but lack enum constraints where appropriate (e.g., category/subcategory are free-form strings prone to hallucination). No tool has parameter validation constraints, bounds, or actionable error messages. The composition is reasonable, one tool per operation, but tools lack chaining metadata (e.g., after add_expense succeeds, there's no confirmation ID returned). Overall, this server meets a minimum baseline but falls short of production quality across description depth, output documentation, and error guidance.
Add a new expense entry to the database
Delete an expense by ID
Retrieve all expenses from the database
Retrieve expenses within a date range
Get a summary of expenses grouped by category with totals
Calculate the total of all expenses
Tool descriptions are critically short (12 - 50 chars), well below the 194-char production baseline. Descriptions lack WHAT the tool does, WHEN to use it, and what it returns. Examples: 'Add a new expense entry to the database' (45 chars) does not explain when to call it vs. other tools, or what data structure is returned.
Output schemas are not documented. Tools return database records (asyncpg Record objects or dicts) without documenting field names, types, or structure. LLMs cannot plan downstream calls or extract the right fields without knowing what get_expenses() returns. Example: get_expenses() returns 'expenses' (a list of Records with fields id, date, amount, category, subcategory, note) but this structure is nowhere in the tool definition.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 43 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 42 | - | v1 |
No enum constraints on free-form string parameters. 'category' and 'subcategory' are free-text strings, inviting LLM hallucination of invalid values like 'food/pizza', 'transportation/gas', or made-up categories. Should define enums of valid categories/subcategories or document the expected format explicitly.
Date format validation is mentioned in add_expense description ('YYYY-MM-DD format') but not in range_expenses, which also accepts start_date and end_date. Inconsistent parameter documentation forces LLMs to guess or infer format from context, risking type mismatches.
Error messages are plain strings without recovery guidance. Example from deleteExpense.py: 'Failed to delete expense: <error>' tells the LLM nothing about whether to retry, ask the user, or try a different approach. Should categorize errors and provide actionable next steps.
Destructive operation (delete_expense) lacks confirmation or dry-run support. An agent could accidentally delete all expenses. Should support a confirm_before_execute pattern or require explicit confirmation.
No pagination support on list-like tools. get_expenses() returns all expenses without limit or offset. Large datasets will blow the context window and degrade LLM reasoning. Should add limit and offset/cursor parameters and return total count.
Parameter descriptions are minimal or missing constraint details. Example: 'date' in range_expenses has no description at all; 'expense_id' is described only as 'The ID of the expense to delete' without stating if it's a required integer >= 1. LLMs cannot infer valid ranges or formats without explicit constraints.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) present in FastMCP tool registration. Clients and LLMs cannot automatically infer which tools are safe to retry or which modify state without reading descriptions. Should add @mcp.tool decorators with annotations.