CountBean
Countbean plugin for Claude Code
Hosted plain-text accounting in Claude Code: a git-backed Beancount ledger, AI ingestion of statements and receipts into validated double-entry, and HTML/Excel reports.
Install
Run these one at a time — Claude Code reads a multi-line paste as a single
slash command, so sending them together makes marketplace add swallow the
install line and fail with URL rejected: Malformed input to a URL function.
/plugin marketplace add https://github.com/CPUtester5465/countbean-plugin.git/plugin install countbean@countbeanThen reload, so the running session picks up the plugin's commands and MCP tools — they are bound when Claude Code starts, so a fresh install is not live until you do:
/reload-pluginsUse the full HTTPS URL, not the CPUtester5465/countbean-plugin shorthand — the shorthand resolves
to git@github.com, which needs an SSH key and GitHub's host key already in your known_hosts.
Then connect it to your book. Say this to Claude with nothing after it:
/countbean:connectIt prints a short code and a link. Open the link, sign in at
app.countbean.com, pick the book, and approve —
Claude picks it up within a few seconds. There is no key to copy between
windows. (If you would rather paste a key you already have, put it on the same
line: /countbean:connect cbk_… bok_….)
Full documentation is in plugin/README.md.
Related MCP server: bookie
This repository is published, not authored
The source of truth is the plugin/ directory of the Countbean monorepo. This repo is a mirror,
pushed by CI on every change.
Pull requests here cannot be merged — they would be overwritten by the next publish. The
mirror exists so that installing the plugin does not require access to the private monorepo,
and so plugin/mcp/countbean_mcp/ledger.py can keep being byte-compared against its
ledger_core original by tests that need both in one tree.
Available Tools
21 toolsadd_directivesA
Append arbitrary Beancount directives (auto-routed by kind) and commit.
Use for batch setup ("set up my whole situation"): opens, balances, transactions and prices in one validated commit.
Inputs: beancount_text (required), message. Returns: result
add_transactionsA
Append one or more transactions (raw Beancount syntax) to the book.
The text is validated with bean-check and only committed if valid; on failure nothing is written and the validation errors are returned. Postings must balance. Open any new accounts first (open_accounts).
Inputs: beancount_text (required). Returns: result
assess_bookA
Review the book and return COMPUTED facts about it as JSON.
Coverage, monthly income/expense, cash, run rate and runway, category shares, month-over-month movers, unusually large postings, and data-quality flags.
Read this and report it. Do NOT compute your own figures from it, do not
extrapolate past the coverage window, and do not turn a sufficient: false
into a number with a caveat — that field means the data cannot support the
figure, and the honest answer is to say which data is missing.
Every month is marked complete. Only complete months are averaged: a
trailing partial month makes spending look like it fell in every category.
Inputs: no named parameters. Returns: result
await_device_approvalA
Step 2: wait for the user to approve the code from start_device_authorization.
Blocks until they approve, decline, or the code expires. On success the connection is saved and every countbean tool switches to that book.
Inputs: no named parameters. Returns: result
balancesA
Show balances grouped by account, optionally filtered by a regex.
account_filter is a BQL regex like 'Assets' or 'Expenses:Food'.
Inputs: account_filter. Returns: result
book_statusA
Summarise the current book: location, account count, balances, last commits.
Inputs: no named parameters. Returns: result
connect_bookA
Connect this plugin to a hosted Countbean book, permanently.
Give it the key shown once on your book's page (cbk_…) and the book id
(bok_…). Verifies the pair against the live book BEFORE saving, then
stores it in ~/.countbean/credentials.json (0600). Takes effect immediately
— no restart, no environment variables.
Paste both on one line and this tool sorts them out; the bok_… id can be
omitted if you have already connected to that book before.
Inputs: api_key (required), book_id, control_url. Returns: result
connection_statusA
Show which book this plugin is talking to, and which config chose it.
Answers the question that actually gets asked when something looks wrong: not "is it configured" but "WHICH of my configs won". Environment beats a .env, which beats the saved connection.
Inputs: no named parameters. Returns: result
create_bookA
Initialise a new, empty cloud book (git-backed Beancount ledger).
Safe to call once per book; errors if a book already exists at the location.
Inputs: name, currency. Returns: result
disconnect_bookA
Forget the saved hosted-book connection (the key stays valid; revoke it on the book's page if you want it dead).
Inputs: no named parameters. Returns: result
generate_reportB
Generate a financial report from the book.
format: 'html' (styled, self-contained) or 'xlsx' (Excel workbook with Balance Sheet, Income Statement and Transactions sheets). Returns the path to the written file.
Inputs: as_of, format. Returns: result
get_ledgerA
Return the full plain-text ledger (accounts, transactions, prices).
Inputs: no named parameters. Returns: result
historyA
Show the book's git history (each AI or human change is one commit).
Inputs: limit. Returns: result
list_accountsA
List every account currently open in the book.
Inputs: no named parameters. Returns: result
open_accountsB
Add account open (or close/commodity) directives to the book.
Example: 2026-01-01 open Assets:Checking USD
Inputs: beancount_text (required). Returns: result
propose_receipt_transactionA
Turn what you read off a staged receipt into a PROPOSED transaction.
You supply the reading and, for every field, how sure you are of it on a 0.0-1.0 scale. Be honest about the confidences — they are the whole mechanism. Anything below the floor comes back flagged rather than as a value, and the floor can be raised by argument but never lowered, so a low confidence is not a suggestion.
expense_account and paid_from_account are yours to choose:
categorisation is the part of this a model is genuinely good at. The book's
open directives are read here so that two failures which would otherwise
land AT THE WRITE — an account that was never opened, and an account pinned
to a currency this receipt is not in — arrive now, as a sentence, instead of
as a bean-check dump after the customer has already approved the entry.
exchange_rate is how much ONE unit of the receipt's currency cost in the
paying account's currency. Take it off the card statement; no rate is ever
invented here.
Returns JSON. It NEVER writes. Show the person the merchant, the date and
the total, ask about anything flagged, and only then pass beancount to
add_transactions unchanged.
Inputs: receipt_sha256 (required), tax, date, total, +15 more. Returns: result
propose_transactionsA
Parse a bank statement (CSV or OFX/QFX) into PROPOSED transactions.
THIS TOOL NEVER WRITES. It returns proposals as JSON; add_transactions is
still the only way anything reaches the book, so the bean-check gate and the
git commit stay where they are.
content is the statement itself — base64-encoded bytes, or the text pasted
straight in. NOT a path: the hosted chat agent has no filesystem in common
with your machine, and a tool that only works from one of them is the defect
this replaces.
account is the book account the statement belongs to, e.g.
'Assets:Checking' or 'Liabilities:Visa'. Required — every row in an export
is one side of that account and the file never says which.
WHAT YOU MUST DO WITH THE RESULT
Read
mapping. It says which column was read as what, which date format, which decimal separator, and whether a positive amount was taken to mean money in or money out — with the evidence for each. If any of it is wrong, call again with the matching override rather than editing the numbers.CATEGORISE. Every proposal's counter-account is a placeholder (Income:Unclassified / Expenses:Unclassified). Replacing those with real accounts is your job; parsing was this tool's. Keep the
import-id:metadata line exactly as given — it is what stops the same statement being booked twice.Keep the
!flags. A flagged row has an ambiguity the file cannot settle, listed inambiguities. Do not silently promote one to*.Open anything in
accounts_to_openfirst (open_directivesis ready to paste intoopen_accounts).Show the user
countsand anything flagged before you write.
Overrides, all optional: amount_shape ('signed' | 'debit_credit' | 'balance'), columns (a JSON object like {"date": "Posted Date", "amount": "Amount"} — header names or 0-based indices), date_format (strptime), delimiter, decimal_separator ('.' or ','), sign ('normal' | 'inverted'), opening_balance (for a running-balance file whose first row has no predecessor), counter_account, currency, file_format, content_encoding.
Inputs: account (required), content (required), sign, columns, +9 more. Returns: result
revertA
Revert a specific commit (undo a change), creating a new commit.
Inputs: commit (required). Returns: result
run_queryA
Run a Beancount Query Language (BQL) query and return CSV-style rows.
Example: SELECT account, sum(position) WHERE account ~ 'Expenses' GROUP BY account
Inputs: bql (required). Returns: result
stage_receiptA
Store a receipt photo or PDF as evidence and return a reference to it.
Call this FIRST, before proposing anything. A receipt is the source document for the entry it becomes, and an entry whose evidence was thrown away is a promise we cannot keep two years from now.
Give it EITHER file_path (a photo or PDF on this machine — the plugin
path) OR content_base64 (raw bytes, for a chat agent that has no
filesystem in common with the book). declared_name is recorded in the
reply for your convenience and is used for NOTHING else — never for the
file type, never for where the bytes are stored.
Returns JSON with the bucket key and the content hash. Pass both to
propose_receipt_transaction. Then read the image yourself: this tool does
not look at it.
Inputs: file_path, declared_name, content_base64. Returns: result
start_device_authorizationA
Step 1 of connecting a hosted book: get a code for the user to approve.
Returns IMMEDIATELY with a short code and a link. Show both to the user,
then call await_device_approval to wait for them to approve it.
Deliberately two tools and not one. An MCP tool returns a single result, at the end — so a tool that fetched the code and then waited for approval could never show the code to the person who has to type it. It could only ever expire. That was the first version of this, and it was unusable.
Inputs: control_url. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
TDQS
Scored across 21 tools
Some overlap exists: add_transactions and add_directives can both commit transactions, and open_accounts overlaps with add_directives for account opens. The descriptions do clarify intended use cases, but an agent could still hesitate between these pairs.
Most tools follow a clear verb_noun pattern (connect_book, add_transactions, open_accounts, run_query), but a few are bare nouns (balances, history, book_status, connection_status). The device-auth tools also mix 'authorization' and 'approval' terminology, though the overall pattern remains readable.
With 21 tools, the server is in the heavy range, though the count is justified by the two-step auth flow and separate workflows for statements, receipts, and reporting. Still, some consolidation (e.g. merging open_accounts into add_directives) could tighten the surface.
The tool set covers the full bookkeeping lifecycle: connecting and creating books, adding validated transactions and directives, opening accounts, querying balances, generating reports, proposing from statements and receipts, and undoing changes via history/revert. No critical operations are missing for the stated purpose.
Maintenance
Related MCP Connectors
Read-only finance MCP server. Connects your banks, cards, payment apps, books and payroll into one ledger for your AI. Can't move money. Open source (AGPL-3.0), free during beta.
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
Log, query, and edit expenses, budgets, and accounts in Manilo from any MCP-compatible AI assistant.
Headless API-first double-entry accounting & bookkeeping engine. 84 MCP tools over HTTP.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP Server to query from your Beancount ledger, or submit transaction.11MIT
- AlicenseNot gradedqualityBmaintenanceA Model Context Protocol (MCP) server that keeps the books for your personal and business finances using double-entry accounting — driven entirely from an LLM.60 npm1MIT
- FlicenseNot gradedqualityDmaintenanceA read-only MCP server that gives AI agents structured access to a Beancount personal finance ledger.1-
- FlicenseNot gradedqualityDmaintenanceMCP server for Beancount ledgers that enables querying with BQL, listing accounts, getting balances, searching transactions, validating the ledger, and appending new entries.-