内容
# beanie-mcp
一个MCP服务器,允许AI代理使用BQL检查和查询[Beancount](https://beancount.github.io/) v3账本。将其指向您的`.bean`文件,与任何支持MCP的客户端连接,并询问有关您的财务状况的问题,同时服务器处理账本加载、验证和结构化查询结果。
---
## 功能
连接后,您的代理可以直接查询账本,无需您手动操作终端。在后台,`run_query`工具接受[BQL](https://beancount.github.io/docs/beancount_query_language.html),而非任意自然语言,因此代理会将您的问题翻译成有效的查询:
> *"我上个月在餐厅花了多少钱?"*
> *"我当前所有账户的净资产是多少?"*
> *"我的账本中是否有错误或失败的余额断言?"*
> *"请显示我这个税务年度在我的证券账户中的所有交易。"*
beanie-mcp公开了四个工具和三个资源:
| 名称 | 类型 | 描述 |
|---|---|---|
| `run_query` | 工具 | 运行BQL查询。返回具有列、字符串化行、返回行数和截断元数据的结构化JSON。无效的BQL或损坏的账本返回一个`error`字段。 |
| `bean_check` | 工具 | 对账本运行bean-check。返回结构化的`{ ok, message, errors }` JSON。 |
| `list_accounts` | 工具 | 返回所有已声明的账户,作为结构化JSON,无查询行限制。 |
| `list_tables` | 工具 | 返回beanquery表名以及关键的`FROM`限制。 |
| `beanie://accounts` | 资源 | 账本中的所有账户,一行一个。 |
| `beanie://tables` | 资源 | BQL可访问的表名。 |
| `beanie://bql-guide` | 资源 | 适用于代理的BQL指南,包括限制和示例。 |
## BQL说明
BQL类似SQL,但并非SQL。最重要的限制是:`FROM`是日期/过滤子句,而非表选择器。像这样查询:
```sql
SELECT account FROM accounts ORDER BY account
```
**不**列出`accounts`表中的账户。
要发现账户,请使用`list_accounts`工具或`beanie://accounts`资源。 要发现表,请使用`list_tables`或`beanie://tables`。
有用的查询示例:
```sql
SELECT account, sum(position)
WHERE account ~ "Expenses"
GROUP BY account
ORDER BY account
```
```sql
SELECT date, payee, narration, account, position
WHERE account ~ "Expenses:Food"
LIMIT 50
```
```sql
SELECT account, sum(position)
WHERE account ~ "Assets|Liabilities"
GROUP BY account
```
## 结果契约
`run_query`返回三种格式之一。
成功查询:
```json
{
"columns": ["account", "sum_position"],
"rows": [["Expenses:Food", "123.45 USD"]],
"truncated": false,
"returned_rows": 1,
"total_rows": 1,
"total_rows_known": true
}
```
损坏的账本:
```json
{
"error": "账本有bean-check错误;查询前请修复它们。",
"error_type": "ledger",
"errors": [
{
"file": "/path/to/main.bean",
"line": 42,
"type": "BalanceError",
"message": "余额失败,原因:..."
}
]
}
```
无效BQL:
```json
{
"error": "语法错误或beanquery错误消息",
"error_type": "bql"
}
```
行数限制为200。为了防止广泛的查询具体化整个账本,beanie-mcp最多获取201行。当`truncated`为`true`时,`total_rows`为`null`,`total_rows_known`为`false`;如果需要更小的答案,请添加更窄的`WHERE`、`ORDER BY`或`LIMIT`子句。行值作为字符串返回,以便MCP客户端即使beanquery返回Python日期、十进制数、库存或其他类型的Beancount值,也能获得稳定的JSON。
`bean_check`返回:
```json
{
"ok": true,
"message": "账本干净 - 无错误或警告。",
"errors": []
}
```
或:
```json
{
"ok": false,
"message": "账本有1个错误。",
"errors": [
{
"file": "/path/to/main.bean",
"line": 42,
"type": "BalanceError",
"message": "余额失败,原因:..."
}
]
}
```
## 设计目标
beanie-mcp针对实际账本而设计,而非小型演示:
- **结构化JSON输出** - 从`BQLShell`文本表切换到beanquery DB-API(`beanquery.connect()`)。代理获取列和字符串化行,而非要解析的文本表。
- **故障账本错误** - `run_query`拒绝查询具有加载错误或失败余额断言的账本,而非返回看似合理的空结果。
- **结构化的`bean_check`工具** - 将加载错误和失败余额断言作为机器可读的JSON返回,包含文件、行、类型和消息。
- **资源安全的行限制** - 查询响应限制在200行,仅多取一行以检测截断。
- **账户工具绕过限制** - 账户枚举获取完整的已声明账户列表,而不管账本大小如何。
- **锁定账本路径** - 账本路径由启动时的`BEANCOUNT_LEDGER`环境变量固定,因此代理无法将服务器指向您文件系统上的任意文件。
- **包含感知缓存** - 仅在根文件或任何加载的`include`文件更改时重新解析账本,而非每次查询。
- **监视器自动重新加载** - 文件系统监视器在`.bean`文件被修改、创建、移动或删除时使缓存失效。
- **显式`pydantic-settings`依赖** - 配置加载不依赖于意外的传递依赖。
- **Python `<3.14`上限** - beancount 3.x没有针对Python 3.14的预构建轮;从源代码构建在macOS上失败(Apple提供bison 2.3,而beancount需要>=3.8)。上限防止混淆的构建失败。
## 要求
- Python 3.10-3.13
- [uv](https://docs.astral.sh/uv/)
- Beancount v3账本(`.bean`文件)
> **Beancount v3是支持的目标。** Beancount v2账本可能不适用;如果您使用v2,请使用v2兼容的MCP服务器或查询工具。
## 安装
克隆仓库并使用`uv`安装Python依赖:
```bash
git clone https://github.com/klinikal/beanie-mcp.git
cd beanie-mcp
uv sync
```
找到您的主要Beancount文件的绝对路径。例如:
```bash
realpath ~/finance/main.bean
```
在下面的MCP配置中使用该完整路径作为`BEANCOUNT_LEDGER`。 故意避免使用相对路径,因为MCP客户端可能从不同的工作目录启动服务器。
您可以在将其添加到MCP客户端之前测试服务器:
```bash
BEANCOUNT_LEDGER=/absolute/path/to/your/ledger/main.bean uv run beanie-mcp
```
该命令启动一个MCP stdio服务器并等待客户端。按`Ctrl+C`停止它。
## 配置MCP客户端
beanie-mcp不绑定到特定的模型或代理。它是一个标准的本地MCP stdio服务器。任何可以启动带有环境变量的本地MCP命令的客户端都可以使用它。 这包括Claude Code/Desktop样式配置、Codex样式代理运行器、Cursor样式IDE代理、Gemini样式代理和其他MCP兼容工具。确切的配置UI或文件格式取决于客户端。
通用命令是:
```json
{
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}
```
一些客户端在`mcpServers`对象中包装此命令。 其他客户端具有GUI,您可以在其中分别输入相同的命令、参数和环境变量。
### 示例:Claude Code / Claude Desktop
对于使用`mcpServers` JSON块的客户端,请添加:
```json
{
"mcpServers": {
"beanie": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}
}
}
```
### 示例:Codex
在Codex配置中添加服务器条目:
```toml
[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"
```
### 其他MCP客户端
在客户端定义本地MCP服务器的地方使用相同的命令、参数和环境变量:
```json
{
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/beanie-mcp",
"beanie-mcp"
],
"env": {
"BEANCOUNT_LEDGER": "/absolute/path/to/your/ledger/main.bean"
}
}
```
在更新MCP配置后重启客户端。MCP客户端通常只在启动时读取工具列表。
## 验证
连接后,让您的代理运行:
- `bean_check`
- `list_accounts`
- `list_tables`
然后尝试一个小的BQL查询:
```sql
SELECT account, sum(position)
WHERE account ~ "Expenses"
GROUP BY account
LIMIT 20
```
如果`bean_check`报告错误,请先修复账本。`run_query`拒绝查询损坏的账本,以免代理将无效账本误认为为空结果。
## 更新
更新现有的本地checkout:
```bash
cd /absolute/path/to/beanie-mcp
git pull
uv sync
```
在更新后重启MCP客户端。
## 故障排除
**客户端无法找到`uv`**
在您的配置中使用`uv`的绝对路径。 使用以下命令查找:
```bash
which uv
```
然后将`"command": "uv"`替换为类似`"command": "/opt/homebrew/bin/uv"`。
**`No ledger configured`**
在MCP配置的`env`块中设置`BEANCOUNT_LEDGER`。 它必须指向您的主要`.bean`文件。
**账本文件未找到**
为`/absolute/path/to/beanie-mcp`和`BEANCOUNT_LEDGER`使用绝对路径。 `~`可能不在每个MCP客户端中扩展。
**更新后工具列表未更改**
重启客户端。 长时间运行的MCP客户端通常在重新连接之前保留旧工具列表。
## 开发
运行MCP检查器:
```bash
BEANCOUNT_LEDGER=/absolute/path/to/your/ledger/main.bean uv run mcp dev src/beanie_mcp/server.py
```
## 运行测试
```bash
uv run pytest server_test.py -v
uv run ruff check .
uv build
```
## 隐私
此工具会将您的Beancount账本的部分内容发送到MCP客户端使用的模型/提供商。仅与您信任的提供商和客户端连接,并信任您的财务数据。相关的政策是您选择的模型/提供商/客户端的政策。
> 您负责您的财务数据。 请勿将其连接到您不信任的服务。 请自担风险。
## 许可证
MIT。 见[LICENSE](LICENSE)。