MCP server for converting PDF bank statements to checked Excel, CSV, or JSON with MainBook
MainBook Bank Statement Converter
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
**A finance MCP server scoped to one job: turning PDF bank statements into checked JSON, Excel or
CSV — not a general accounting MCP.** It runs locally after one mainbook-mcp auth login, or over
MainBook's hosted endpoint at https://mcp.mainbook.ai/mcp, where your client signs you in with your
MainBook account. Existing mb_live_ API keys keep working for scripts and older clients.
Point your assistant at a statement and ask for a spreadsheet. The PDF goes to
MainBook, which extracts every transaction, normalises dates to
YYYY-MM-DD, keeps money as exact amounts, and re-adds the statement so that
opening balance + credits − debits has to match the closing balance. Rows that do not fit are
flagged instead of being passed on quietly.
What it is not
It does **not** connect to bank accounts and is **not** an Open Banking or bank-data API. It reads
statement files you already have. Nothing is scraped and no banking credentials are involved.
What you need
A MainBook account and the folders holding your statements. Conversion is the only tool that spends
page credits. Of the other four, get_balance and list_conversions only read, get_conversion
may write a result file, and output_folder changes a local preference; none of them changes
anything in your MainBook account.
Add it to your client
Sign in once from a terminal:
The command opens MainBook in your browser, shows the same short code in both places, and waits for
your approval. It stores the credential in the OS keyring when the optional keyring package is
installed and working. Otherwise it uses ~/.config/mainbook/credentials.json with private
directory and file permissions. Use mainbook-mcp auth status to check the active credential
server-side without spending page credits. mainbook-mcp auth logout revokes that stored key first,
then removes the local copy; if MainBook cannot be reached, it says plainly that the key may still be
active. Signing in again revokes the previously stored key before saving its replacement. The device
token response does not include an email or account ID, so status says that account identity was not
provided instead of guessing.
Then add one entry to your client's MCP configuration. This is the same block for Claude Desktop
(**Settings → Developer → Edit Config**), Claude Code, and Cursor; no key is copied into it:
Codex reads TOML, so put the same thing in ~/.codex/config.toml:
uvx comes with uv; install it once with brew install uv or
curl -LsSf https://astral.sh/uv/install.sh | sh. It fetches and runs the published package, so
there is nothing to download by hand and nothing to update. If you would rather not add uv, run
pip install mainbook-mcp and use "command": "mainbook-mcp" with the same arguments — you then
upgrade it yourself with pip install -U mainbook-mcp.
The folder arguments are the only places the server may read a statement from or write a result to;
anything outside them is refused. MAINBOOK_ALLOWED_DIRS sets the same list through the
environment instead, separated by the platform's os.pathsep (: on macOS/Linux, ; on Windows).
Manual API key for scripts and CI
MAINBOOK_API_KEY takes precedence over any stored login. Keep the manual method for automation
where an interactive browser is not available. auth login warns when this variable will keep
overriding the newly stored credential:
Create and revoke manual keys at . Never commit them.
Claude Desktop, without touching a config file
Claude Desktop also accepts a one-file bundle: **Extensions → Install Extension…** and pick
mainbook.mcpb. It asks for the API key and the folders in a dialog and manages its own Python
runtime, so nothing needs installing first. The config block above does the same job and is the
better fit if you already keep other servers there. Build the bundle from this directory with:
What it exposes
- convert_bank_statement: creates a paid page-credit job, uploads one PDF, starts conversion,
polls for up to 30-900 seconds, and returns the reviewed result. JSON stays inline. In local