beanie-mcp
The beanie-mcp server allows AI agents to inspect and query Beancount v3 financial ledgers using BQL (Beancount Query Language), returning structured JSON results.
Tools:
run_query— Execute arbitrary BQL queries (e.g., expenses, transactions, net worth). Returns structured JSON with columns and rows (capped at 200 rows, withoffsetfor paging).bean_check— Validate the ledger viabean-check, returning a clean confirmation or detailed errors with file paths and line numbers. The server refuses to run queries on broken ledgers.list_accounts— List all declared accounts (bypasses the 200-row cap).list_tables— Enumerate BQL-accessible table names.list_prices— Get the latest known price for every commodity with price history.find_unmatched_transfers— Identify orphaned postings in staging/suspense accounts.ledger_info— Get orientation facts: operating currency, title, date span, account count, and today's date.net_worth— Calculate net worth (Assets + Liabilities) in the operating currency, with an optionalas_ofdate.account_balance— Get the balance of an account and its subtree, with an optionalas_ofdate.holdings— View per-commodity units, cost basis, market value, and unrealized gain.
Resources:
beanie://accounts,beanie://tables,beanie://prices,beanie://bql-guide(BQL caveats and examples),beanie://context(ledger orientation facts).
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@beanie-mcpWhat did I spend on dining out last month?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
beanie-mcp
An MCP server that lets AI agents inspect and query Beancount v3 ledgers with BQL. Point it at your .bean file, connect it to any MCP-capable client, and ask questions about your finances while the server handles ledger loading, validation, and structured query results.
What it does
Once connected, your agent can query your ledger directly without you touching a terminal. Under the hood, the run_query tool accepts BQL, not arbitrary natural language, so the agent translates your question into a valid query:
"What did I spend on restaurants last month?" "What's my current net worth across all accounts?" "Are there any errors or failed balance assertions in my ledger?" "Show me all transactions in my brokerage account this tax year."
beanie-mcp exposes ten tools and five resources:
Name | Type | Description |
| Tool | Run a BQL query. Returns structured JSON with columns, stringified rows, returned row count, and truncation metadata. Supports an |
| Tool | Run bean-check on the ledger. Returns structured |
| Tool | Return all declared accounts as structured JSON, without the query row cap. |
| Tool | Return beanquery table names plus the key |
| Tool | Latest known price for every commodity with price history, without the 200-row cap. |
| Tool | Greedy-match postings to a staging/suspense account (opposite sign, equal amount, date within a window) and report unmatched orphans. |
| Tool | Orientation facts before querying: operating currency, title, date span, account count/roots, today's date. |
| Tool | Net worth (Assets + Liabilities) converted to the operating currency. Optional |
| Tool | Balance of an account (and its subtree) converted to the operating currency. Optional |
| Tool | Per-commodity units, cost basis, market value, and unrealised gain, converted to the operating currency. |
| Resource | All accounts in the ledger, one per line. |
| Resource | BQL-accessible table names. |
| Resource | JSON-encoded |
| Resource | Short BQL guide for agents, including caveats and examples. |
| Resource | JSON-encoded |
Related MCP server: mcp-beancount
BQL notes
BQL is SQL-like, but it is not SQL. The most important caveat: FROM is a date/filter clause, not a table selector. A query like this does not list accounts from the accounts table:
SELECT account FROM accounts ORDER BY accountFor account discovery, use the list_accounts tool or beanie://accounts resource instead. For table discovery, use list_tables or beanie://tables.
Income, Liabilities, and Equity accounts are credit-normal in Beancount. A row-level query shows each posting's stored sign correctly, but sum(position) aggregates on these account types can read as inverted from what you'd expect — cross-check with a row-level query if an aggregate sign looks surprising.
Useful query examples:
SELECT account, sum(position)
WHERE account ~ "Expenses"
GROUP BY account
ORDER BY accountSELECT date, payee, narration, account, position
WHERE account ~ "Expenses:Food"
LIMIT 50SELECT account, sum(position)
WHERE account ~ "Assets|Liabilities"
GROUP BY accountReconciling staging accounts
BQL has no self-join, so matching the two legs of a transfer routed through a staging/suspense account (e.g. Equity:Transfers:Pending) can't be expressed as a query. find_unmatched_transfers does the greedy matching instead: it pairs postings by opposite sign, equal amount, same currency, and date within window_days, and reports whatever's left over as orphans.
find_unmatched_transfers(account="Equity:Transfers:Pending", window_days=2){
"matched_count": 41,
"orphans": [
{"date": "2024-03-02", "amount": "150.00", "currency": "USD", "narration": "..."}
],
"orphan_count": 1
}Result contract
run_query returns one of three shapes.
Successful query:
{
"columns": ["account", "sum_position"],
"rows": [["Expenses:Food", "123.45 USD"]],
"truncated": false,
"returned_rows": 1,
"offset": 0,
"total_rows": 1,
"total_rows_known": true
}Broken ledger:
{
"error": "Ledger has bean-check errors; fix them before querying.",
"error_type": "ledger",
"errors": [
{
"file": "/path/to/main.bean",
"line": 42,
"type": "BalanceError",
"message": "Balance failed for ..."
}
]
}Invalid BQL:
{
"error": "syntax error or beanquery error message",
"error_type": "bql"
}Rows are capped at 200. To keep broad queries from materialising an entire ledger, beanie-mcp fetches at most 201 rows. When truncated is true, total_rows is null and total_rows_known is false; add a narrower WHERE, ORDER BY, or LIMIT clause if you need a smaller answer — or page through the full result with offset: call again with offset set to the sum of returned_rows seen so far until truncated comes back false. BQL itself has no OFFSET keyword, so this is handled server-side. Row values are returned as strings so MCP clients get stable JSON even when beanquery returns Python dates, decimals, inventories, or other typed Beancount values.
bean_check returns:
{
"ok": true,
"message": "Ledger is clean - no errors or warnings.",
"errors": []
}or:
{
"ok": false,
"message": "Ledger has 1 error(s).",
"errors": [
{
"file": "/path/to/main.bean",
"line": 42,
"type": "BalanceError",
"message": "Balance failed for ..."
}
]
}Design goals
beanie-mcp is designed for real-world ledgers, not just small demos:
Structured JSON output - switched from
BQLShelltext tables to the beanquery DB-API (beanquery.connect()). Agents get columns and stringified rows they can actually work with, not a text table to parse.Fail-loud ledger errors -
run_queryrefuses to query ledgers with loader errors or failed balance assertions instead of returning plausible empty results.Structured
bean_checktool - surfaces loader errors and failed balance assertions as machine-readable JSON with file, line, type, and message.Resource-safe row limit - query responses cap at 200 rows and only fetch one extra row to detect truncation.
Account tools bypass the cap - account enumeration fetches the full declared account list regardless of ledger size.
Locked ledger path - the ledger path is fixed by the
BEANCOUNT_LEDGERenv var at startup, so the agent cannot point the server at arbitrary files on your filesystem.include-aware cache - the ledger is only re-parsed when the root file or any loaded
includefile changes, not on every query.Watchdog auto-reload - file system watcher invalidates the cache when
.beanfiles are modified, created, moved, or deleted.Explicit
pydantic-settingsdependency - configuration loading does not rely on accidental transitive dependencies.Python
<3.14ceiling - beancount 3.x has no prebuilt wheel for Python 3.14; building from source fails on macOS (Apple ships bison 2.3, beancount needs >=3.8). The ceiling prevents a confusing build failure.
Requirements
Python 3.10-3.13
Beancount v3 ledger (
.beanfile)
Beancount v3 is the supported target. Beancount v2 ledgers may not work; if you are on v2, use a v2-compatible MCP server or query tool.
Install
Clone the repo and install the Python dependencies with uv:
git clone https://github.com/klinikal/beanie-mcp.git
cd beanie-mcp
uv syncFind the absolute path to your main Beancount file. For example:
realpath ~/finance/main.beanUse that full path as BEANCOUNT_LEDGER in the MCP config below. Relative paths are deliberately avoided because MCP clients may start the server from a different working directory.
You can smoke-test the server before adding it to an MCP client:
BEANCOUNT_LEDGER=/absolute/path/to/your/ledger/main.bean uv run beanie-mcpThe command starts an MCP stdio server and waits for a client. Press Ctrl+C to stop it.
Configure an MCP client
beanie-mcp is not tied to a particular model or agent. It is a standard local MCP stdio server. Any client that can launch a local MCP command with environment variables should be able to use it. That includes Claude Code/Desktop-style configs, Codex-style agent runners, Cursor-style IDE agents, Gemini-based agents, and other MCP-compatible tools. The exact config UI or file format depends on the client.
The generic command is:
{
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}Some clients wrap that command in an mcpServers object. Others have a GUI where you enter the same command, args, and env vars separately.
Example: Claude Code / Claude Desktop
For clients that use an mcpServers JSON block, add:
{
"mcpServers": {
"beanie": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}
}
}Example: Codex
Add a server entry to your Codex config:
[mcp_servers.beanie]
command = "uv"
args = [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp",
]
[mcp_servers.beanie.env]
BEANCOUNT_LEDGER = "/absolute/path/to/your/ledger/main.bean"Other MCP clients
Use the same command, args, and env vars wherever your client defines local MCP servers:
{
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}Restart the client after changing MCP config. MCP clients usually read the tool list only when they start.
Verify
Once connected, ask your agent to run:
bean_checklist_accountslist_tables
Then try a small BQL query:
SELECT account, sum(position)
WHERE account ~ "Expenses"
GROUP BY account
LIMIT 20If bean_check reports errors, fix the ledger first. run_query refuses to query a broken ledger so the agent does not mistake an invalid ledger for an empty result.
Update
To update an existing local checkout:
cd /absolute/path/to/beanie-mcp
git pull
uv syncRestart your MCP client after updating.
Troubleshooting
The client cannot find uv
Use the absolute path to uv in your config. Find it with:
which uvThen replace "command": "uv" with something like "command": "/opt/homebrew/bin/uv".
No ledger configured
Set BEANCOUNT_LEDGER in the MCP config env block. It must point to your main .bean file.
Ledger file not found
Use absolute paths for both /absolute/path/to/beanie-mcp and BEANCOUNT_LEDGER. ~ may not expand inside every MCP client.
Tool list did not change after updating
Restart the client. Long-running MCP clients often keep the old tool list until they reconnect.
Development
Run the MCP inspector:
BEANCOUNT_LEDGER=/absolute/path/to/your/ledger/main.bean uv run mcp dev src/beanie_mcp/server.pyRunning tests
uv run pytest server_test.py -v
uv run ruff check .
uv buildPrivacy
This tool sends parts of your Beancount ledger to whatever model/provider your MCP client uses. Only connect it to a provider and client you trust with your financial data. The relevant data handling policy is the one for the model/provider/client you choose.
You are responsible for your financial data. Don't connect this to a service you wouldn't trust with your bank statements. Run this at your own risk.
License
MIT. See LICENSE.
Available Tools
2 toolsbean_checkA
Validate the ledger with bean-check.
Returns a clean confirmation message if there are no problems, or a newline-separated list of errors with file path and line number.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It explains the output: a clean confirmation on success, or a list of errors with file path and line number on failure. This provides sufficient behavioral context for a validation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loaded with the action and followed by output details. No redundant phrases; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (no parameters, no output schema), the description fully covers what the tool does and what it returns. It is complete for an agent to understand and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no parameters, so the description does not need to add parameter information. The baseline for 0 parameters is 4, and the description fulfills this without needing extra detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool validates the ledger using bean-check, which is a specific verb and resource. It distinguishes itself from the sibling tool run_query by focusing on validation rather than querying.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for ledger validation, but does not explicitly state when to use it over run_query or provide exclusion criteria. The purpose is clear, but usage guidelines are not fully articulated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_queryA
Query the Beancount ledger using BQL.
Returns a dict with: columns — list of column name strings rows — list of rows, each a list of value strings truncated — true if the result was cut at 200 rows total_rows — full result count before any truncation error — present (instead of the above) if the BQL is invalid
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | A BQL query, e.g. 'SELECT account, sum(position) WHERE account ~ "Expenses" GROUP BY account'. Results are capped at 200 rows — add LIMIT for smaller sets. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Details the return structure (columns, rows, truncated, total_rows, error), truncation behavior at 200 rows, and error handling for invalid BQL. Since no annotations are provided, the description fully covers behavioral aspects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, with each bullet point serving a purpose. It efficiently communicates input, output, and error conditions without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter query tool with no output schema, the description is complete. It covers input format, output structure, truncation, and error handling. No gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes the 'query' parameter with an example. The tool description adds value by mentioning the 200-row cap and suggesting LIMIT usage. With 100% schema coverage, this extra context justifies a score above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it queries a Beancount ledger using BQL. The verb 'Query' is specific, and it distinguishes itself from 'bean_check' by focusing on querying rather than checking.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides usage context: it is used to query the ledger with BQL. Mentions adding LIMIT for smaller result sets, but does not explicitly discuss when to use this tool over alternatives or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
2 tool updates
v0.1.0- First observed
bean_check - First observed
run_query
TDQS
The two tools have completely distinct purposes: one validates the ledger for errors, the other executes BQL queries. There is no ambiguity in what each tool does.
Both tools use snake_case, but the naming pattern differs slightly: 'bean_check' is a compound noun or verb-object reversed ('check bean'), while 'run_query' is a clear verb-object. Still, the style is consistent and readable.
Only 2 tools for a ledger management server is too few. Typical accounting workflows require more operations (e.g., insert transactions, list accounts, generate reports), making this set feel incomplete for its domain.
The tool surface is severely incomplete: there is no way to create, update, or delete ledger entries, no account management, and only basic validation and querying. Users cannot perform core accounting tasks.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
An MCP server that provides read access to your cloud storage providers, bank accounts and more.
The Ramp MCP server enables users to securely connect Ramp with AI assistants like ChatGPT and Claude to query financial data and take actions using natural language. It transforms Ramp's developer API into a SQL interface that LLMs can query, allowing admins to analyze spend trends, identify cost savings, and run complex SQL analyses on comprehensive datasets (transactions, purchase orders, vendors, users), while all users can manage cards, view transactions, request reimbursements, and get expense policy answers.
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
MCP server giving Claude AI access to 22+ NYC public-record databases for real estate due diligence
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn experimental server implementing the Model Context Protocol to allow AI assistants to query and analyze financial data stored in Beancount ledger files using the Beancount Query Language.52MIT
- FlicenseNot gradedqualityBmaintenanceA read-only MCP server that gives AI agents structured access to a Beancount personal finance ledger.1-
- FlicenseNot gradedqualityCmaintenanceAn MCP server that lets you log and query your own spending through natural conversation with Claude, instead of a spreadsheet or app.6-
- FlicenseNot gradedqualityCmaintenanceMCP server for Beancount ledgers that enables querying with BQL, listing accounts, getting balances, searching transactions, validating the ledger, and appending new entries.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/klinikal/beanie-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server