mcpField
G
GnuCash

GnuCash

本地服务
github.com/tillawy金融数据03 周前更新

关于 GnuCash

GnuCash MCP 将 Claude 连接到 GnuCash SQLite 账簿,用于读取账户和交易、编辑条目及导入银行 CSV 对账单。导入提示词会匹配列、建议分类,并在写入前标记重复项。

主要功能

  1. 01读取账户和交易
  2. 02创建、更新及删除条目
  3. 03导入银行 CSV 对账单
  4. 04预览行并标记重复项
  5. 05对账账户交易

适用场景

  1. 01查看 GnuCash 账簿中的交易
  2. 02导入银行 CSV 并分类
  3. 03查找并对账账户条目

MCP 相关

MCP 服务通过 stdio 提供 GnuCash 工具和提示词,包括账簿读取、交易写入,以及导入或逐行审核银行对账单的提示词。账簿须为 GnuCash SQLite 格式。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"tillawy-gnucash": {
"command": "uvx",
"args": [
"gnucash-mcp"
],
"env": {
"GNUCASH_MCP_CONFIG": "<GNUCASH_MCP_CONFIG>"
}
}
}
}
启动命令uvx gnucash-mcp
需要配置的环境变量
GNUCASH_MCP_CONFIGAbsolute path to the TOML file that configures your GnuCash book.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypignucash-mcp0.1.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

gnucash-mcp

一个 MCP 服务,可让 Claude 读取你的 GnuCash 账簿,并将银行对账单导入其中。 上传任意银行的对账单 CSV,Claude 会识别其格式,为每一行建议一个 类别,并显示预览。写入任何内容前,它都会标记重复项。

它由两部分组成:

  • gnucash_storage:一个按账簿配置的 piecash 封装,提供读取辅助函数和 幂等写入。
  • gnucash_mcp:通过标准输入/输出公开工具和提示词的 MCP 服务。

要求:SQLite 账簿

GnuCash 默认将账簿保存为 XML,通常会使用 gzip 压缩。本项目基于 piecash 构建,而 piecash 无法读取 XML。它只能读取 GnuCash 的 SQL 格式,本服务 打开的是 SQLite 文件。要转换账簿:

  1. 在 GnuCash 中打开账簿。
  2. 选择 文件 > 另存为。
  3. 将 数据格式 设置为 sqlite3,选择文件名并保存。
  4. 在账簿 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_accounts
  • get_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 字段。目前仍不支持在两种币种之间进行转换。

导入银行对账单

  1. 上传 CSV 并运行 import_bank_statement 提示词。
  2. Claude 根据表头和前几行确定任何银行的 CSV 布局:分隔符、日期列及格式、描述列和金额。它支持单个带符号的金额列,也支持分别记录支出和收入的列,并支持两种小数分隔符(1,234.56 或 1.234,56)。它会显示映射结果和一条解析后的行,并等待你确认后再解析全部内容。支出会记为负数,收入会记为正数。每行都会获得简短易读的描述(例如 Zalatimo Sweets),银行的原始文本则会原样保留在交易备注中。Claude 会检查文件是否按日期从新到旧排列;如果是,就从底部向上读取,以便按银行原有顺序(同一天的行不会重新排序)从旧到新写入。如果你希望保留银行文本作为描述,请在确认映射时说明。然后 Claude 会为每行选择一个类别账户。
  3. Claude 调用 import_transactions(rows, dry_run=True),并显示预览,将每行标记为新交易或重复交易。
  4. 你确认后,Claude 调用 import_transactions(rows, dry_run=False)。所有新行会一次性写入,重复行则会被排除。
  5. 对于每笔重复交易,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

发布步骤:

  1. 更新 pyproject.toml 中的 version,然后提交并推送。

  2. 创建一个 GitHub 发布版本,其标签为 v 加上该版本号:

    gh release create v0.1.0 --generate-notes
    

工作流会检查标签是否与版本匹配,运行测试、ruff 和 mypy,构建软件包并上传。若要在每次上传前要求手动批准,请在 Settings > Environments 下为 pypi 环境添加必需的审核者。

若要在本地检查构建而不发布:

uv build
uvx twine check --strict dist/*

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。