A private money workbench your agent can use. The statement never leaves the tab; WebMCP lets the agent come to it.
Tallyroom demonstrates solid tool design with consistent naming (verb_noun pattern), comprehensive parameter schemas, and thoughtful descriptions. All 17 tools have explicit schemas and descriptions. Tool names are action-oriented (get_, query_, summarize_, find_, list_, set_, propose_, apply_, discard_). Descriptions average ~150 chars and explain WHEN to use each tool. Parameters include type definitions and constraints (enums for flow/sort/groupBy). However, output schemas are not formally documented, responses are JSON text blocks without declared field structures. Error handling is basic (fail() returns JSON error, but no recovery guidance). Some parameter descriptions could be more prescriptive about valid ranges and formats. The design prioritizes agent usability (fuzzy merchant matching, capped result sets, staged changes for safety) but lacks explicit output schema documentation that would help LLMs plan downstream calls.
Add a note to a transaction or flag it for review.
Apply the staged categorisation changes. Only available after propose_categories has been called.
Return all budgets and whether each one is on track. If no budgets are set, returns an empty list.
Discard the staged categorisation changes without applying them.
Find outliers (charges far outside the normal range for that merchant), duplicates (identical merchant + amount within a couple of days), and large one-offs.
Find charges that repeat on a schedule: subscriptions, rent, memberships. Also reports amount drift, so a price rise you never noticed shows up.
Output schemas not formally documented. Tools return JSON text blocks, but field structures, types, and required fields are not declared in tool definitions. LLMs cannot plan downstream calls or extract fields reliably without explicit output schema documentation.
Error handling lacks recovery guidance. fail() returns JSON with error message, but does not categorize errors as retryable/user-fixable/fatal or suggest next steps. E.g., 'No statement is loaded yet' could suggest 'Call load_sample_data or ask user to upload CSV', but currently just fails.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Filter the on-screen view to a subset of transactions. This is the same code path as clicking a filter chip in the UI.
Start here. Returns what is loaded (files, row count, date range, accounts, currencies), the money totals, how much of the data is still uncategorised, any budgets, what the person is currently looking at on screen, and the page's egress meter showing how many bytes have left the browser.
Return spending or income by month, optionally filtered to one category or merchant. Use this to spot seasonal patterns or price changes.
Return all merchants (normalised, clustered), with counts and totals. Useful for spotting patterns or deciding what to categorise next.
Load a synthetic statement for testing. Useful for trying the app without real data.
Pin an insight or finding to the top of the page for the user to see.
Stage a bulk categorisation. This does not apply the changes; it stages them for review, just like the UI's bulk-edit panel. Approving it registers two more tools at runtime: set_transaction_category and apply_staged_changes.
Return individual transactions matching a filter, newest first by default, together with the totals for the whole matching set. Use this when you need to look at specific rows. The row list is capped (default 50, maximum 500) but the totals always cover every match, so prefer summarize_spending when you only need a number.
Set or update a monthly budget for a category.
Categorise one or more transactions. Only available after propose_categories has been called and approved.
Group spending by category, merchant, or account and return totals. Use this when you need a number without the row details.
Parameter descriptions lack prescriptive constraints. E.g., 'minOccurrences' in find_recurring has no stated default or range; 'sensitivity' in find_anomalies lacks guidance on valid range (0 - 10? 1 - 100?). LLMs may pass invalid values without clear bounds.
Destructive operations (set_transaction_category, apply_staged_changes) lack confirmation or dry-run support. Agents can apply bulk categorizations without explicit user approval, risking data misclassification. propose_categories stages changes, but approval flow is UI-only.
Transport mechanism unknown. Source code shows tool registration via WebMCP (browser-based), but no explicit HTTP/SSE/STDIO transport layer is visible. Cannot verify remote accessibility or protocol compliance without seeing server bootstrap code.