关于 GnuCash
GnuCash MCP 将 Claude 连接到 GnuCash SQLite 账簿,用于读取账户和交易、编辑条目及导入银行 CSV 对账单。导入提示词会匹配列、建议分类,并在写入前标记重复项。
主要功能
- 01读取账户和交易
- 02创建、更新及删除条目
- 03导入银行 CSV 对账单
- 04预览行并标记重复项
- 05对账账户交易
适用场景
- 01查看 GnuCash 账簿中的交易
- 02导入银行 CSV 并分类
- 03查找并对账账户条目
MCP 相关
MCP 服务通过 stdio 提供 GnuCash 工具和提示词,包括账簿读取、交易写入,以及导入或逐行审核银行对账单的提示词。账簿须为 GnuCash SQLite 格式。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
gnucash-mcp
一个 MCP 服务,可让 Claude 读取你的 GnuCash 账簿,并将银行对账单导入其中。 上传任意银行的对账单 CSV,Claude 会识别其格式,为每一行建议一个 类别,并显示预览。写入任何内容前,它都会标记重复项。
它由两部分组成:
gnucash_storage:一个按账簿配置的 piecash 封装,提供读取辅助函数和 幂等写入。gnucash_mcp:通过标准输入/输出公开工具和提示词的 MCP 服务。
要求:SQLite 账簿
GnuCash 默认将账簿保存为 XML,通常会使用 gzip 压缩。本项目基于 piecash 构建,而 piecash 无法读取 XML。它只能读取 GnuCash 的 SQL 格式,本服务 打开的是 SQLite 文件。要转换账簿:
- 在 GnuCash 中打开账簿。
- 选择 文件 > 另存为。
- 将 数据格式 设置为 sqlite3,选择文件名并保存。
- 在账簿 TOML 文件的
book_path中指定新文件。
之后请一直在 GnuCash 中使用 SQLite 文件。导入的交易不会出现在 XML 文件中。
如果 book_path 指向 XML 账簿,每个工具都会失败,并提示你进行此转换。
你还需要 uv 和 Python 3.13 或更高版本。如有需要,uv 会为你安装 Python。
配置账簿
为账簿创建一个 TOML 文件,例如 ~/gnucash/personal.toml:
book_path = "personal.gnucash" # relative to this TOML file, or an absolute path
bank_account = "Assets:Current Assets:Checking Account" # default bank side for imports
open_if_lock = false # open for writing even while GnuCash has the file open
do_backup = true # piecash writes a timestamped backup before writing
# Optional: "posting" (booking date) or "transaction" (when the purchase happened).
date_source = "posting"
# Optional hints about your bank's statement format, added to the import prompts.
statement_notes = '''
Details holds the merchant and a card reference "REF <12 digits>" (use it as
external_id). The card date inside Details is YY/MM/DD.
'''
只有 book_path 是必填项。
statement_notes 用于记录银行的特殊情况:参考 ID 藏在哪里、两列日期中该使用哪一列,或某个特殊列的含义。Claude 会在列映射步骤中读取这些备注,但仍会显示映射供你确认。这样一来,服务无需针对特定银行,而每位用户的银行相关知识都保存在自己的配置中。
date_source 用于在对账单包含两个日期时,选择哪个日期作为交易日期:
银行的入账(记账)日期,或你实际付款时的交易日期。银行卡消费通常会晚一两天入账,而且银行卡日期往往只出现在描述中。如果未设置 date_source,每次导入时,只要对账单包含两个日期,Claude 就会询问。建议设置此项。对于没有参考 ID 的行,日期是重复检测的一部分,因此在不同导入操作中切换这两个日期,可能会导致同一行被导入两次。
安装
服务通过 uvx 运行,因此无需全局安装。将 GNUCASH_MCP_CONFIG 指向账簿 TOML 文件,并使用绝对路径。
Claude Code:
claude mcp add gnucash -e GNUCASH_MCP_CONFIG=/absolute/path/to/personal.toml -- uvx gnucash-mcp
Claude Desktop: 将以下内容添加到 claude_desktop_config.json(在 macOS 上,该文件位于
~/Library/Application Support/Claude/),然后重启 Claude Desktop:
{
"mcpServers": {
"gnucash": {
"command": "uvx",
"args": ["gnucash-mcp"],
"env": {"GNUCASH_MCP_CONFIG": "/absolute/path/to/personal.toml"}
}
}
}
如果 Claude Desktop 找不到 uvx,请将 "uvx" 替换为其完整路径(which uvx)。
工具和提示词
工具:
list_accountsget_account(fullname)list_transactions(fullname, start_date, end_date, limit)create_account(fullname, account_type, currency=None, description="", placeholder=False):父级账户必须存在;币种默认与父级账户相同find_transactions(search, limit=5):在任意账户中查找描述、备注或编号包含该词的交易,并按时间从新到旧排列。copy_transaction(guid, post_date, external_id=None, notes=None):复制现有交易及其所有拆分(包括多于两个的拆分);只有日期、编号和备注是新的。用于克隆选项处理add_transaction无法写入的条目。add_transaction(post_date, description, counter_account, amount, account=None, external_id=None, notes=None, force=False, quantity=None)update_transaction(guid, post_date=None, description=None, external_id=None, notes=None, counter_account=None, amount=None, account=None, quantity=None):修改现有交易;未指定的字段保持不变,空的external_id或notes会清除相应内容。通过list_transactions获取guid。修改amount、quantity或counter_account时,交易必须有两个拆分,并且两个拆分都会移动,以保持平衡;account(默认值:配置中的bank_account)用于指定amount指的是哪一方。如果只修改商品账户对应交易的amount,单位数保持不变,价格则会改变。要修改副本的金额,请对copy_transaction返回的 guid 调用此工具。delete_transaction(guid):永久删除交易及其拆分,并返回删除的内容。reconcile_transactions(guids | start_date/end_date, state="y", account, dry_run=True):将账户拆分的对账状态设为(y已对账,c已清算,n未对账),按 GUID 或过账日期范围(含首尾)选择。只有account上的拆分会改变。试运行会报告将更改的拆分数量及其日期范围。写入一次性保存,无需使用 GnuCash 的对账窗口。import_transactions(rows, dry_run=True):批量导入。每行会获得new、added或duplicate状态;重复项会包含与之匹配的现有交易。
如果省略 account,则默认使用配置中的 bank_account。读取工具和试运行会以只读方式打开账簿。写入操作会以可写方式打开账簿。批量导入只打开一次账簿,因此只会创建一个备份文件。
提示词:
import_bank_statement:导入银行 CSV 文件,并显示预览表格后一次性批量写入(在 Claude Code 中,运行/mcp__gnucash__import_bank_statement)。review_bank_statement:逐行导入银行 CSV 文件,并等待你对每行作出决定(在 Claude Code 中,运行/mcp__gnucash__review_bank_statement)。clone_transaction:请你提供一个搜索词,查找最新的相似条目,并在你确认日期和金额后,使用相同账户和描述添加新条目(在 Claude Code 中,运行/mcp__gnucash__clone_transaction)。
购买商品(黄金、股票)
当对方账户持有非货币商品(例如金币或股票)时,请传入 quantity:买入或卖出的单位数,必须为正数。amount 保持为银行账户中以银行币种计价的金额,每单位价格为 amount / quantity。交易会保留银行账户的币种;银行拆分记为 -amount,对方拆分的金额记为 -amount,数量记为 quantity(当 amount 为正数,即卖出时,数量为负数):
add_transaction(
post_date=date(2026, 9, 29),
description="Buy 5 from Anis",
counter_account="Assets:Gold English Coins 21 carat", # commodity XGL21-8
amount=Decimal("-3330"), # JOD out of the bank
quantity=Decimal("5"), # 666 JOD per coin
account="Assets:Bank Accounts:ArabBank Jordan", # commodity JOD
)
对此类对方账户,必须提供 quantity;如果对方账户使用银行账户的币种,则不接受该参数。该值必须为正数,且精度不得超过商品的小数位数。import_transactions 的行也使用相同的 quantity 字段。目前仍不支持在两种币种之间进行转换。
导入银行对账单
- 上传 CSV 并运行
import_bank_statement提示词。 - Claude 根据表头和前几行确定任何银行的 CSV 布局:分隔符、日期列及格式、描述列和金额。它支持单个带符号的金额列,也支持分别记录支出和收入的列,并支持两种小数分隔符(
1,234.56或1.234,56)。它会显示映射结果和一条解析后的行,并等待你确认后再解析全部内容。支出会记为负数,收入会记为正数。每行都会获得简短易读的描述(例如Zalatimo Sweets),银行的原始文本则会原样保留在交易备注中。Claude 会检查文件是否按日期从新到旧排列;如果是,就从底部向上读取,以便按银行原有顺序(同一天的行不会重新排序)从旧到新写入。如果你希望保留银行文本作为描述,请在确认映射时说明。然后 Claude 会为每行选择一个类别账户。 - Claude 调用
import_transactions(rows, dry_run=True),并显示预览,将每行标记为新交易或重复交易。 - 你确认后,Claude 调用
import_transactions(rows, dry_run=False)。所有新行会一次性写入,重复行则会被排除。 - 对于每笔重复交易,Claude 会询问是强制写入还是跳过。强制写入会调用
add_transaction(..., force=True)。例如,同一天确实发生了第二笔完全相同的消费时,就可以使用此选项。
每笔交易都以银行账户自身的币种记录,因此 USD 账簿中的 EUR 账户会记录 EUR 交易。类别账户必须使用相同币种,因为不支持币种转换。如果缺少你想要的类别,Claude 会提出创建该类别,并在你确认后调用 create_account 创建。
如果有任何行包含未知账户、混合使用不同币种,或金额的小数位数超过银行账户币种允许的位数,则不会写入任何内容。
逐行审核
改为运行 review_bank_statement。完成相同的币种、解析和类别步骤后,Claude 会逐行显示(Row i/N),并展示该行的 Num(作为交易编号保存的银行参考号)、建议类别,以及该行是新交易还是重复交易。你可以为每行选择以下一种操作:
- 接受: 立即使用
import_transactions([row], dry_run=False)写入该行。 - 修改: 编辑类别、描述或金额,然后重新审核该行。
- 跳过: 不写入任何内容。
- 强制写入: 仅适用于重复交易;仍使用
add_transaction(..., force=True)写入。 - 全部接受剩余行: 批量写入剩余的新行。重复交易仍需逐行审核。
- 停止: 结束审核并查看摘要。
你批准的行会立即写入。如果中途停止,这些行仍会保留在账簿中;再次运行时,它们会显示为重复交易。每次批准都会单独写入,因此当 do_backup = true 时,每行获批交易都会创建一个备份文件。如果不希望如此,请在账簿 TOML 中设置 do_backup = false。
幂等写入
from decimal import Decimal
from datetime import date
from pathlib import Path
from gnucash_storage import (
NewTransaction,
add_transaction,
load_config,
open_configured_book,
)
config = load_config(Path("books/development-book.toml"))
with open_configured_book(config, readonly=False) as book:
added = add_transaction(
book,
NewTransaction(
post_date=date(2025, 11, 28),
description="TEST BISTRO REST.",
account="Assets:Current Assets:Savings Account",
counter_account="Expenses:Dining",
amount=Decimal("-36.00"), # money out of the bank account
),
force=False, # set force=True to bypass duplicate checking
)
一条记录可以带有可选的 external_id:来自银行的唯一引用,例如银行卡检索参考号(REF 606006000101)、OFX FITID 或银行参考号。它会存储在交易的 Num 字段中。导入期间,Claude 会查找此类引用,并将其纳入你确认的列映射。
同一银行账户中的现有交易在以下情况下会被视为重复项:
- 具有相同的
external_id,无论日期或描述如何,因此银行在不同导出中更改描述格式不会导致重复导入;或 - 具有相同的过账日期、银行文本和金额(以账户的币种计),除非双方都有 ID 且 ID 不同。同一天发生的两笔相同消费如果有不同的银行卡参考号,都会导入;而在使用 ID 之前添加的交易仍能被识别。
银行文本是交易的备注;如果没有备注,则为交易描述。根据银行提供的原始文本而非整理后的描述进行匹配,意味着后续导入中的描述措辞不同,仍会被视为重复项。使用备注功能之前导入、并将银行文本保留为描述的交易,也仍能匹配。
当 force=False(默认值)时,add_transaction 不会添加任何内容,并会对重复项返回 False。传入 force=True 可跳过重复项检查并强制插入。
如果你的账簿启用了 GnuCash 的 Use Split Action Field for Number 选项,分录簿会在 Num 列中显示拆分操作。参考号仍会存储在交易中。
开发
服务本身只需要 mcp 和 piecash。开发工具和 notebook 库是可选附加项:
uv sync --extra dev # tests, ruff, mypy
uv sync --extra dev --extra notebooks # plus marimo, Jupyter, polars, pandas, openai
从检出目录运行服务:
GNUCASH_MCP_CONFIG=books/example.toml uv run gnucash-mcp
在此代码库中,.mcp.json 已将服务注册为 Claude Code 的 gnucash,并使用 books/development-book.toml。当 Claude Code 提示时批准,然后使用 claude mcp get gnucash 检查。
Notebooks
notebooks 需要 notebooks 附加项(uv sync --extra notebooks)。
启动 Marimo notebook 服务 / 编辑器:
uv run marimo edit notebooks/
或者以只读应用模式运行 notebook:
uv run marimo run notebooks/gnucash_exploration.py
notebooks/statement_mapping.py 使用 notebooks/samples/ 中的两个示例对账单检查通用 CSV 映射:
us_signed_amount.csv:逗号分隔、美国日期格式、一个带正负号的 Amount 列eu_debit_credit.csv:分号分隔、德语表头、dd.mm.yyyy 日期格式、单独的 Soll/Haben 列、小数逗号
对于每个示例,notebook 会应用 Claude 将确认的映射,并将行导入一个临时账簿。随后,它会检查正负号、余额,以及再次导入时每一行都会被报告为重复项:
uv run marimo edit notebooks/statement_mapping.py
检查
uv run pytest
uv run ruff check . && uv run ruff format --check .
uv run mypy src
若要在每次 git push 前运行与 CI 相同的检查,请在每个克隆中启用一次已跟踪的 pre-push hook:
git config core.hooksPath .githooks
单次推送时,可使用 git push --no-verify 跳过此检查。
发布
版本通过 .github/workflows/publish.yml 发布到 PyPI,使用
可信发布,因此无需 API 令牌。
PyPI 上的一次性设置:前往 Your account > Publishing > Add a new pending publisher,并填写:
| 字段 | 值 |
|---|---|
| PyPI 项目名称 | gnucash-mcp |
| 所有者 | tillawy |
| 仓库名称 | gnucash-mcp |
| 工作流名称 | publish.yml |
| 环境名称 | pypi |
发布步骤:
-
更新
pyproject.toml中的version,然后提交并推送。 -
创建一个 GitHub 发布版本,其标签为
v加上该版本号:gh release create v0.1.0 --generate-notes
工作流会检查标签是否与版本匹配,运行测试、ruff 和 mypy,构建软件包并上传。若要在每次上传前要求手动批准,请在 Settings > Environments 下为 pypi 环境添加必需的审核者。
若要在本地检查构建而不发布:
uv build
uvx twine check --strict dist/*
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。