MCP server providing authenticated tools for personal finance, investing, health tracking, and task management. Supports voice and web clients through FastMCP.
The Lifestack API MCP server demonstrates solid tool design with comprehensive schemas and descriptions across 25 tools. Most tools follow verb_noun naming conventions (create_*, update_*, delete_*, get_*, list_*). However, there are gaps: (1) toolAnnotations (readOnlyHint, destructiveHint, idempotentHint) are not declared in the source, limiting agent visibility into operation safety; (2) output schemas are not documented in the provided code, we see input schemas but not response structures, which blocks LLMs from planning downstream calls effectively; (3) error handling guidance is minimal, tools do not return actionable recovery hints; (4) some parameter descriptions could be more specific about constraints (e.g., timezone format, date format strictness). The tool-dedup.py module shows thoughtful idempotency handling for resumed WebSocket sessions, indicating mature thinking about composition and retries. Overall, naming and basic descriptions are strong, but schema completeness and error guidance need improvement.
Create a recurring todo rule for reminders that repeat on a schedule. Use this (not `create_todo_task`) whenever the user's reminder repeats — e.g. "every other day", "every Monday", "on the 1st of each month".
create_todo_taskwriteauthsource verified87/100
Create a new todo task/item for the user.
create_transferwriteauthsource verified83/100
Create a capital transfer between accounts (e.g., transfer cash from checking to investment account).
Output schemas not documented in source code. Input schemas are present and properly typed, but response structures are not visible. LLMs cannot plan downstream tool chaining without knowing what fields will be returned.
Add tool annotations (readOnlyHint=true for all get_*, list_* tools; destructiveHint=true for all delete_* tools; idempotentHint=true for idempotent write operations like create_investment_dividend) to the MCP tool definitions. This requires updating the fastmcp server registration to include annotations in the tool metadata.
Document response schemas for all tools. For list operations, include fields like 'items' (array), 'total' (int), 'limit' (int), 'offset' (int). For create/update operations, return the created/updated resource with all key fields (ID, timestamp, computed fields). For delete operations, return a success indicator or empty object.
Enhance error responses with structured guidance. Instead of returning raw HTTP status codes, return JSON errors like {"error": "INVALID_PRIORITY", "message": "Priority must be one of: low, medium, high. Got: invalid", "recovery": "Use list_spending_categories to discover valid values."}
Add confirm_delete or dry_run parameter to destructive tools (delete_todo, delete_spending_transaction, delete_transfer). A dry_run=true response should show what would be deleted without committing. This aligns with pattern:confirmation-request.
Enforce IANA timezone validation in timezone parameter descriptions. E.g., 'IANA timezone string (e.g., America/New_York, Europe/London). Invalid timezones will be rejected.'
Cap get_holdings limit to max 50 instead of 100. Large result sets bloat LLM context windows and degrade reasoning. State in description: 'Maximum 50 results per request to respect context budgets.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↑ 67 points across a rubric change (v1 → v2)
67/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
C
67
<=2025-11-25
v2
2026-03-09
F
0
-
v1
destructive
auth
source verified
80/100
Delete a capital transfer.
get_account_balanceread onlyauth50/100
Get the current balance of an account.
get_dividendsread onlyauth50/100
List dividend payments received.
get_holdingsread onlyauth50/100
List investment holdings with optional filtering, sorting, and pagination.
get_net_worthread onlyauthsource verified78/100
Get the user's total net worth (sum of all account balances in reporting currency).
get_portfolio_summaryread onlyauth50/100
Get a summary of the investment portfolio including total values and allocation.
get_spending_summaryread onlyauth50/100
Get a spending summary by category for a date range.
get_spending_transactionsread onlyauth50/100
List spending transactions with optional filtering and pagination.
get_todosread onlyauth50/100
List todos with optional filtering and pagination.
Record a spending transaction (purchase, expense, or income). For voice: narrate naturally, e.g. 'bought coffee for $5.50 today' or 'got paid $2000 on Friday'.
Error handling lacks actionable recovery guidance. Errors do not suggest next steps or alternative operations. Tools should return structured error messages that guide LLM recovery (e.g., 'User not found. Try search_users() first.').
Parameter descriptions for timezone, ISO date formats, and enum constraints are present but could be more prescriptive. Some tools (log_spending_transaction, create_recurring_todo) accept 'timezone' but the description does not enforce IANA format validation guidance.
No confirmation or dry-run pattern for destructive operations (delete_todo, delete_spending_transaction, delete_transfer). High-risk operations should support a confirmation step to prevent accidental destruction.
Pagination limits are documented (max 50 for most list tools) but not enforced with hard caps in descriptions. get_holdings allows max 100 which may exceed reasonable token budgets for LLM context windows.
Add 'next_cursor' or 'has_more' field to paginated responses. This lets agents know whether to fetch more pages without repeated failed requests.
Document which tools are safe to retry (idempotent) and which have side effects. The tool_dedup.py module shows you are tracking this for WebSocket resume scenarios, expose this as tool annotation hints.
For tools accepting arrays (tags in log_spending_transaction), document max array length and per-element constraints. E.g., 'Array of tag strings, max 10 tags, each 1-50 characters.'
Add a 'description' or 'notes' parameter to destructive operations (delete_todo, delete_spending_transaction) to capture audit context. E.g., why was this deleted? This improves compliance and debugging.