io.github.theluckystrike/categorize-transactions
Measured conclusion: Deep-tested. L2 outcome: tools_ok.
Import a bank CSV, categorise it, summarise it per currency and reconcile it against your expenses.
| Author | io.github.theluckystrike |
|---|---|
| Access | mixed |
| Publisher key required | No |
| Measured state | Deep-tested |
| L1 liveness | alive |
| L1 latency | 88 ms |
| Last measured | 2026-10-24 |
Add to your agent
Copy this into your MCP client config:
{
"mcpServers": {
"categorize-transactions": {
"url": "https://mcp.zovo.one/mcp/categorize-transactions",
"transport": "streamable-http"
}
}
}
Measured tools (15)
statement_importCall this tool to read a bank CSV into the local ledger. Columns detected from headers (date, description, amount, currency, balance); amounts use the file's locale; stored lines skipped. Returns detected/stored/skipped.
Parameters:
path(required) — string — Name of a statement uploaded with bank_uploadbank— string — Bank profile. Default "auto": the headers decide. "generic" skips profile detection and uses the header heuristics aloneaccount— string — Name for this account, e.g. "business EUR". Default: the file name without its extension. Later imports of the same account are deduplicated against itcurrency— string — Currency for rows where the file names none. Defaults to the shared business profile's default_currency, else EUR; the response says which it usedoverwrite— boolean — Delete every transaction already stored for this account before importing, instead of merging. Use it when the bank reissued a corrected export
Hints: read-only no · destructive no · idempotent no · open-world no
transactions_listread-onlyList stored transactions in a date range, optionally for one account or category, or only the ones no rule has categorised yet. Totals are reported per currency and never added across currencies.
Parameters:
to— string — ISO date YYYY-MM-DD, inclusive. Default: todayfrom— string — ISO date YYYY-MM-DD, inclusive. Default: the start of the current monthlimit— integer — Rows returned, default 200. Totals always cover the whole rangeaccount— string — Limit to one account, as named at importcategory— string — Only transactions in this categoryuncategorized— boolean — Only transactions with no category yet
Hints: read-only yes · destructive no · idempotent yes · open-world no
transactions_searchread-onlyFind transactions whose description, counterparty, category or account contains the query. Case-insensitive substring search, never a regex, so a query with brackets in it cannot hang the server.
Parameters:
query(required) — string — Text to look for, e.g. "spotify" or "acme"to— string — ISO date, inclusivefrom— string — ISO date, inclusivelimit— integer — Rows returned, default 100
Hints: read-only yes · destructive no · idempotent yes · open-world no
category_rulesRead the category rules, or pass rules to REPLACE the whole list. A plain match is a substring; a regex compiles only if it cannot backtrack exponentially. An empty match is refused. Free: 5 rules.
Parameters:
rules— array — The complete rule list; it replaces the stored one. Omit to list the current rulesreapply_all— boolean — Also overwrite categories set by an earlier rule or by hand. Default false: only uncategorised transactions are touched
Hints: read-only no · destructive no · idempotent no · open-world no
transaction_categorizeSet or clear the category on transactions by id, for a one-off no rule is worth writing for. Every id is checked first, so one unknown id refuses the whole call. category_rules matches by text instead.
Parameters:
ids(required) — array — Transaction ids, as returned by transactions_list or transactions_searchcategory(required) — string — Category to set. Pass an empty string to clear it
Hints: read-only no · destructive no · idempotent no · open-world no
statement_summaryread-onlyWhat was spent/received in a date range per the BANK ACCOUNT, grouped by category, month, account or counterparty. For "what did I spend in August" once imported. Totals are per currency, never summed or converted.
Parameters:
to— string — ISO date, inclusive. Default: todaytop— integer — Groups returned per currency, largest net first. Default 25from— string — ISO date, inclusive. Default: the start of the current monthaccount— string — Limit the summary to one accountgroup_by— string — Default category
Hints: read-only yes · destructive no · idempotent yes · open-world no
reconcile_expensesMatch bank debits against mcp-expense-tracker entries: same currency and amount, date within a few days. Reports matches, unmatched bank lines, expenses never hitting the bank. Read-only. Free: 31 days; Pro: any range.
Parameters:
from(required) — string — ISO date, inclusiveto(required) — string — ISO date, inclusiveaccount— string — Limit to one bank accountwindow_days— integer — Allowed gap between the expense date and the bank date, default 3. A card payment usually settles a day or two after the receipt
Hints: read-only no · destructive no · idempotent no · open-world no
recurring_detectFind charges that come back: debits grouped by counterparty and currency with a steady amount and interval, with cadence, typical amount, next due date and annual cost. Free: 3 months, 5 charges.
Parameters:
months— integer — How far back to look, default 3. Two occurrences are enough to see a cadence, three make it certainaccount— string — Limit to one accountmin_occurrences— integer — Occurrences required before a charge counts as recurring, default 2
Hints: read-only no · destructive no · idempotent no · open-world no
statement_exportread-onlyExport the BANK transactions of a date range (a month, a quarter, a year) as .csv or .json and return a download link valid for one hour. This is the tool for "export September" once a statement has been imported. Nothing partial is ever written.
Parameters:
from(required) — string — ISO date, inclusiveto(required) — string — ISO date, inclusiveformat(required) — string — csv for a spreadsheet, json for a programpath(required) — string — Name for the downloaded file, e.g. september. It comes back as a download link valid for one houraccount— string — Limit to one accountcategory— string — Limit to one category
Hints: read-only yes · destructive no · idempotent yes · open-world no
accounts_listread-onlyList the imported accounts: bank, currencies, transaction count, first and last date, and the closing balance when the file carried one. Start here for the account names transactions_list and statement_export take.
Hints: read-only yes · destructive no · idempotent yes · open-world no
license_statusread-onlyReport this endpoint's licence state for your token as JSON: the product, the tier free or pro, why it is not Pro, and the checkout URL. Call it to explain a free-tier refusal. No arguments, nothing changes.
Hints: read-only yes · destructive no · idempotent yes · open-world no
license_activateTurn Pro on for this connection with key, an MCPL1.<payload>.<signature> issued at checkout for this server or the bundle. Data under your token stays; a wrong or expired key changes nothing. license_status confirms it.
Parameters:
key(required) — string — License key from checkout, MCPL1.<payload>.<signature>
Hints: read-only no · destructive no · idempotent no · open-world no
bank_uploadSend a bank export to this hosted endpoint. There is no filesystem here, so instead of a path you upload the file once with bank_upload and then pass its name as `path` to statement_import. Give exactly one of content (the export as text, header row included - this is the normal case for a CSV), content_base64 (the file's bytes, which keeps a UTF-16 export from Excel readable) or url. url: fetch a public file instead of pasting base64 (recommended above about 10 KB): the url is fetched here with a 10 second timeout, at most 3 redirects, public http(s) hosts only, and a 1 MB cap; the fetched file has to be delimited text, so a PDF statement is refused rather than stored. Uploads are kept for your token between calls; bank_files lists them and bank_delete_upload removes one. The request body cap is 256 KB, so a large export pasted as text has to be split by month.
Parameters:
name(required) — string — Name to refer to this statement by: 1-64 characters of letters, digits, underscore or dash, e.g. "september"url— string — url: fetch a public file instead of pasting base64 (recommended above about 10 KB). Public http(s) only; private, link-local and this endpoint's own zone are refusedcontent— string — The export as text, including the header rowcontent_base64— string — The file's bytes, base64-encoded, instead of text
Hints: read-only not declared · destructive not declared · idempotent not declared · open-world not declared
bank_filesList the statement files stored for your token, with their sizes.
Hints: read-only not declared · destructive not declared · idempotent not declared · open-world not declared
bank_delete_uploadDelete one statement file stored for your token. The transactions already imported from it are kept; transactions_list and the summary still see them.
Parameters:
name(required) — string
Hints: read-only not declared · destructive not declared · idempotent not declared · open-world not declared
Measured by MCPYP probing. Untested fields are omitted, never estimated. Listing is always free; MCPYP never proxies calls or stores user tokens.