{"name":"io.github.theluckystrike/bank-statement-csv-categorize-reconcile-ledger","slug":"theluckystrike-bank-statement-csv-categorize-reconcile-ledger","title":null,"description":"Import a bank CSV, categorise it, summarise it per currency and reconcile it against your expenses.","url":"https://mcp.market/server/theluckystrike-bank-statement-csv-categorize-reconcile-ledger","grade":"C","score":64,"certified":false,"status":"active","category":"finance","tags":["finance"],"transport":"mixed","callable_via_gateway":true,"default_price_micros":0,"repository":"https://github.com/theluckystrike/mcp-servers","website":"https://mcp.zovo.one/s/bank-statement","version":"0.22.0","remotes":[{"type":"streamable-http","url":"https://mcp.zovo.one/mcp/bank-statement","headers":[{"description":"Bearer <Pro license key or anonymous token from GET https://mcp.zovo.one/mcp/token>","isRequired":true,"isSecret":true,"name":"Authorization"}]}],"packages":[{"registryType":"mcpb","identifier":"https://github.com/theluckystrike/mcp-servers/releases/download/v0.22.0/bank-statement.mcpb","version":"0.22.0","fileSha256":"15f85d0ff6c81042a417d8c1b33c80b0867f33fc7f32064c7fdd4bbdfd6b9105","transport":{"type":"stdio"},"environmentVariables":[{"description":"Optional Pro license key (MCPL1....). Verified offline.","isSecret":true,"name":"MCP_LICENSE_KEY"}]}],"tools":[{"name":"accounts_list","description":"List 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"bank_delete_upload","description":"Delete one statement file stored for your token. The transactions already imported from it are kept; transactions_list and the summary still see them.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":70}},"required":["name"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"bank_files","description":"List the statement files stored for your token, with their sizes.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"bank_upload","description":"Send 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.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":70,"description":"Name to refer to this statement by: 1-64 characters of letters, digits, underscore or dash, e.g. \"september\""},"content":{"type":"string","description":"The export as text, including the header row"},"content_base64":{"type":"string","description":"The file's bytes, base64-encoded, instead of text"},"url":{"type":"string","description":"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 refused"}},"required":["name"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"category_rules","description":"Read 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"rules":{"type":"array","items":{"type":"object","properties":{"match":{"type":"string","maxLength":200,"description":"Text to look for in the counterparty or description, e.g. \"spotify\""},"category":{"type":"string","maxLength":120,"description":"Category to set, e.g. \"software\""},"regex":{"type":"boolean","description":"Treat match as a regular expression. A pattern that can backtrack exponentially is refused and used as a substring instead"}},"required":["match","category"],"additionalProperties":false},"description":"The complete rule list; it replaces the stored one. Omit to list the current rules"},"reapply_all":{"type":"boolean","description":"Also overwrite categories set by an earlier rule or by hand. Default false: only uncategorised transactions are touched"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"license_activate","description":"Turn 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"key":{"type":"string","description":"License key from checkout, MCPL1.<payload>.<signature>"}},"required":["key"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"license_status","description":"Report 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"reconcile_expenses","description":"Match 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"from":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"to":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"account":{"type":"string","maxLength":120,"description":"Limit to one bank account"},"window_days":{"type":"integer","minimum":0,"maximum":31,"description":"Allowed gap between the expense date and the bank date, default 3. A card payment usually settles a day or two after the receipt"}},"required":["from","to"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"recurring_detect","description":"Find 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"months":{"type":"integer","minimum":1,"maximum":60,"description":"How far back to look, default 3. Two occurrences are enough to see a cadence, three make it certain"},"account":{"type":"string","maxLength":120,"description":"Limit to one account"},"min_occurrences":{"type":"integer","minimum":2,"maximum":24,"description":"Occurrences required before a charge counts as recurring, default 2"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"statement_export","description":"Export 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"from":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"to":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"format":{"type":"string","enum":["csv","json"],"description":"csv for a spreadsheet, json for a program"},"path":{"type":"string","maxLength":4096,"description":"Name for the downloaded file, e.g. september. It comes back as a download link valid for one hour"},"account":{"type":"string","maxLength":120,"description":"Limit to one account"},"category":{"type":"string","maxLength":500,"description":"Limit to one category"}},"required":["from","to","format","path"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"statement_import","description":"Call 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"path":{"type":"string","maxLength":4096,"description":"Name of a statement uploaded with bank_upload"},"account":{"type":"string","maxLength":120,"description":"Name for this account, e.g. \"business EUR\". Default: the file name without its extension. Later imports of the same account are deduplicated against it"},"bank":{"type":"string","enum":["auto","revolut","wise","mbank","pko","ing","n26","generic"],"description":"Bank profile. Default \"auto\": the headers decide. \"generic\" skips profile detection and uses the header heuristics alone"},"overwrite":{"type":"boolean","description":"Delete every transaction already stored for this account before importing, instead of merging. Use it when the bank reissued a corrected export"},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$","description":"Currency for rows where the file names none. Defaults to the shared business profile's default_currency, else EUR; the response says which it used"}},"required":["path"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"statement_summary","description":"What 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"from":{"type":"string","maxLength":10,"description":"ISO date, inclusive. Default: the start of the current month"},"to":{"type":"string","maxLength":10,"description":"ISO date, inclusive. Default: today"},"group_by":{"type":"string","enum":["category","month","account","counterparty"],"description":"Default category"},"account":{"type":"string","maxLength":120,"description":"Limit the summary to one account"},"top":{"type":"integer","minimum":1,"maximum":200,"description":"Groups returned per currency, largest net first. Default 25"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"transaction_categorize","description":"Set 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","maxLength":64},"minItems":1,"description":"Transaction ids, as returned by transactions_list or transactions_search"},"category":{"type":"string","maxLength":120,"description":"Category to set. Pass an empty string to clear it"}},"required":["ids","category"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"transactions_list","description":"List 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"from":{"type":"string","maxLength":10,"description":"ISO date YYYY-MM-DD, inclusive. Default: the start of the current month"},"to":{"type":"string","maxLength":10,"description":"ISO date YYYY-MM-DD, inclusive. Default: today"},"account":{"type":"string","maxLength":120,"description":"Limit to one account, as named at import"},"category":{"type":"string","maxLength":500,"description":"Only transactions in this category"},"uncategorized":{"type":"boolean","description":"Only transactions with no category yet"},"limit":{"type":"integer","minimum":1,"maximum":1000,"description":"Rows returned, default 200. Totals always cover the whole range"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"transactions_search","description":"Find 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"query":{"type":"string","maxLength":200,"description":"Text to look for, e.g. \"spotify\" or \"acme\""},"from":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"to":{"type":"string","maxLength":10,"description":"ISO date, inclusive"},"limit":{"type":"integer","minimum":1,"maximum":500,"description":"Rows returned, default 100"}},"required":["query"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}],"scan":{"score":64,"grade":"C","scanned_at":"2026-09-17T16:32:17.848Z","report":{"scannerVersion":"0.1.2","scannedAt":"2026-09-17T16:32:17.746Z","components":{"code":{"score":-1,"max":25,"notes":["package could not be scanned"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 474ms"]},"poisoning":{"score":15,"max":15,"notes":["15 tool descriptions checked"]},"auth":{"score":8,"max":15,"notes":["API key sent as a header"]},"maintenance":{"score":3,"max":15,"notes":["repository not readable: github 401"]},"identity":{"score":2,"max":10,"notes":["no repository or website to verify"]}},"findings":[],"inputs":{"probes":[{"url":"https://mcp.zovo.one/mcp/bank-statement","reachable":true,"authRequired":false,"latencyMs":474,"serverInfo":{"name":"mcp-bank-statement","version":"0.22.0"}}],"packages":[],"repo":{"found":false,"owner":"theluckystrike","repo":"mcp-servers","error":"github 401"}}}},"grade_history":[]}