使用说明
mcp-ynab
A. 默认情况下为只读 模型上下文协议服务器 你需要一个预算 API预算编制。让LLM(Claude Desktop、Cursor、Claude Code或任何兼容MCP的客户端)检查您的计划、账户、类别、交易和月度摘要。编写工具(创建/更新/批准交易、更新预算类别)可用 只有当 YNAB_ALLOW_WRITES=1 在环境中设置——未设置时,启动时不会注册写入,也无法调用。
内置Go against the 官方MCP Go SDK一个二进制stdio传输,无入站网络表面,操作系统密钥环令牌存储。
为什么只读
YNAB个人访问令牌是长期和全范围的——它们授予读取权限 和 在账户上的每个计划上都写上,YNAB对突变没有批量撤销。LLM可以调用 deleteTransaction 这是一份及时注入的交易备忘录,可以避免在没有追索权的情况下扰乱预算。此服务器故意暴露 仅 该设计没有改变YNAB数据的代码路径。
工具
读取工具(始终可用)
| 工具 | 说明 |
|---|---|
list_plans |
列出经过身份验证的用户拥有的所有YNAB计划(在YNAB UI中称为“预算”)。 |
list_accounts |
列出计划中具有当前余额的账户。默认情况下不包括已关闭的帐户。Delta已同步。 |
list_categories |
列出计划中的所有类别,包括本月分配/活动/余额金额和目标详细信息。 |
list_transactions |
列出计划的交易记录,最近的交易记录排在第一位。筛选依据 since_date,批准状态(type),或范围-- 之一 account_id, category_id,或 payee_id。未过滤的变体是增量同步的。类别/收款人范围简化了拆分交易。默认限制100,最大500。 |
list_months |
最近几个月的月度汇总摘要(收入、预算、活动、预算、货币年龄),最近的先到。用于逐月趋势。默认限制6,最大60。 |
get_month |
完整的计划月,按类别细分。接受 "current" 或 YYYY-MM-01。用于周日仪式/真实费用检查 |
list_scheduled_transactions |
按date_next顺序(最快优先)排列的定期和未来日期的计划交易。可选的 upcoming_days 过滤器 |
list_payees |
在计划中列出收款人。可选的 name_contains 执行不区分大小写的子字符串匹配——用于在调用之前将收款人名称解析为ID list_transactions 和 payee_id 或 ynab_spending_check 和 excluded_payee_ids. |
任务型工具(基元组合)
| 工具 | 说明 |
|---|---|
ynab_status |
一个呼叫周日仪式仪表板:准备分配、超支类别(不包括信用卡支付类别)、具有可选APR增额的债务账户、流动账户(支票/储蓄/现金)、每个账户自上次对账以来的天数、未批准的计数以及未来7天具有重复扩展的计划现金流。 |
ynab_spending_check |
“我本周在杂货上的花费是否低于500美元?”与预算相比,在一个日期范围内,一个或多个类别的净流出之和,返回 on_plan 超出预算时的判决和违规交易。支持 excluded_payee_ids 比如“约会之夜除了Chipotle”。 |
ynab_weekly_checkin |
收入、流出和未批准计数的每周比较,加上每月新超支类别和货币年龄增量。 |
ynab_debt_snapshot |
当前债务余额+雪崩式回报预测。整数基点模拟,复合循环中没有浮点数。可选的 extra_per_month_milliunits 运行一个比较场景。当最低金额无法覆盖利息时,返回结构化负摊销误差和短缺金额。 |
ynab_waterfall_assignment |
咨询,不写。 按类别行走优先瀑布 need_milliunits 技能已经计算,返回建议的分配和剩余部分。法学硕士介绍了该计划;如果获得批准,则发布 update_category_budgeted 单独通话。 |
编写工具(选择加入,需要 YNAB_ALLOW_WRITES=1)
书写工具有 启动时未注册 除非 YNAB_ALLOW_WRITES=1 在MCP服务器的环境中设置。禁用时,它们不会出现在 tools/list 根本无法调用。
| 工具 | 说明 |
|---|---|
create_transaction |
创建新交易。通过启发要求MCP客户确认。金额>1万美元需要 amount_override_milliunits 回复确认。提供一个 import_id 在重试时进行幂等重复数据删除。 |
update_category_budgeted |
更改单个计划月的单个类别的分配数量。规则3货币的原始货币在周日仪式中移动。返回预算和余额快照之前/之后的结果。 |
update_transaction |
交易的部分更新:类别、收款人、备注、已批准状态、已清算状态、标志颜色。 金额变化在结构上不受支持 --输入结构体没有数量字段,由反射回归测试强制执行。 |
approve_transaction |
便利包装设置 approved=true 在一笔交易中。 每次通话引发跳过 以支持批处理日常待处理清理工作流。这 YNAB_ALLOW_WRITES=1 env-var-gate仍然是主要的防御手段。 |
所有阅读和任务型工具都有广告 readOnlyHint: true 在他们的MCP注释中。写工具广告 readOnlyHint: false.
工具数量:
- 没有
YNAB_ALLOW_WRITES: 13工具 (8次阅读+5次任务型) - 随着
YNAB_ALLOW_WRITES=1: 17工具 (添加4条文字)
每种工具都能实现什么
| 用例 | 工具 |
|---|---|
| “我这周在杂货店花了多少钱?” | list_categories → 查找杂货id→ list_transactions 和 category_id |
| 债务快照(所有债务账户+余额) | list_accounts (筛选到信用卡/贷款/债务类型) |
| 真实费用检查/超支检测 | list_categories 或 get_month |
| 环比趋势(“我的支出是否比上个月多?”) | list_months |
| “这个月有什么计划?”(租金、订阅费) | list_scheduled_transactions 和 upcoming_days: 30 |
| 已准备好分配瀑布对话 | get_month → to_be_budgeted 现场 |
| 收款人模式检测 | list_transactions 和 payee_id |
| 饮食计划审核 | list_categories → 杂货店/餐厅ID→ list_transactions 和 category_id 和 since_date |
金钱代表
工具响应中的每个货币值都是 Money 具有两个字段的对象:
"balance": { "milliunits": 123456, "decimal": "123.456" }
milliunits是权威的int64值——YNAB的原生格式,适用于每种货币。decimal是一个具有3个小数位数(毫单位精度)的预格式化字符串。
此服务器中没有使用代码路径 float64 对于货币。 格式化仅通过整数运算执行。看 money.go.
安装
自制/预构建二进制文件
从下载版本 GitHub 发布 --Linux、macOS和Windows的静态二进制文件(amd64和arm64)。
码头工人
docker pull ghcr.io/bold-minds/mcp-ynab:latest
基于Distroles的映像(没有shell,没有包管理器),以非根、静态二进制、仅stdio的形式运行——没有暴露的端口。
来源
go install github.com/bold-minds/mcp-ynab@latest
需要Go 1.25或更高版本。
配置
获取YNAB个人访问令牌
登录YNAB,转到 账户设置→ 开发人员设置,并创建一个 个人访问令牌。复制一次,以后无法检索。
将令牌提供给服务器
三个选项,按优先顺序排列。服务器按以下顺序检查它们,并使用提供非空值的第一个源。
1.OS钥匙圈(推荐)
将令牌一次性存储在操作系统的本机凭据存储中(macOS Keychain、Linux Secret Service、Windows凭据管理器):
printf '%s' "your-ynab-personal-access-token" | mcp-ynab store-token
令牌是从stdin读取的——它从不出现在命令行上,因此它永远不会出现在shell历史记录中或 /proc/PID/cmdline后续的运行 mcp-ynab 自动拾取它,不需要环境变量。
要旋转,请重新运行 store-token 新的价值。
2.基于文件的秘密
适用于Docker secrets、systemd LoadCredential,或Kubernetes秘密卷:
export YNAB_API_TOKEN_FILE=/run/secrets/ynab_token
将文件保存在 chmod 600.
3.环境变量(明文)
最简单的选择,但令牌在进程环境中以明文形式存在:
export YNAB_API_TOKEN=your_personal_access_token
将其连接到您的MCP客户端
克劳德桌面
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)或您操作系统上的等效软件。如果您已将令牌存储在操作系统密钥环中,则不需要 env 完全阻塞:
{
"mcpServers": {
"ynab": {
"command": "/path/to/mcp-ynab"
}
}
}
如果您更喜欢基于文件的:
{
"mcpServers": {
"ynab": {
"command": "/path/to/mcp-ynab",
"env": {
"YNAB_API_TOKEN_FILE": "/Users/you/.config/ynab/token"
}
}
}
}
做 不 将原始令牌粘贴到 claude_desktop_config.json --该文件通常是全球可读的,可以通过iCloud/Time Machine进行备份。请改用钥匙圈。
光标
编辑 ~/.cursor/mcp.json:
{
"mcpServers": {
"ynab": {
"command": "mcp-ynab"
}
}
}
(令牌来自钥匙圈。)
其他MCP客户端
任何使用MCP stdio传输的客户端都可以启动 mcp-ynab 作为一个子流程。配置命令以运行二进制文件,并通过以下方式提供令牌 YNAB_API_TOKEN, YNAB_API_TOKEN_FILE,或OS钥匙圈(推荐)。
安全模型
此服务器保护什么
| 威胁 | 缓解 |
|---|---|
| 提示注入指令,告诉LLM删除/修改财务数据 | 写入工具被关闭 YNAB_ALLOW_WRITES=1 (在启动时选择加入),每次写入都会引发每次呼叫确认,外加1万美元的安全上限和回显覆盖。当env-var未设置时,没有注册写工具,也没有 POST/PATCH/PUT 可以到达代码路径。 |
通过日志语句泄漏令牌/ %+v 在配置结构体上 |
令牌被封装在密文中 Token 类型。 String, GoString, Format, MarshalJSON, MarshalText 全部返回 [REDACTED]原始值只能通过私有包访问 reveal() 只在一个地方打电话。 |
| 通过HTTP客户端错误导致令牌泄漏(错误模式中的axios样式配置) | 对抗性回归测试:病理性RoundTripper返回包含文字令牌的错误;每个工具的错误路径都被断言不会与之产生回声 |
| 通过恶意URL过滤YNAB令牌(SSRF/spec注入) | 自定义 http.RoundTripper 拒绝任何主机名不是的请求 api.ynab.com (不区分大小写,端口容忍)。条带 Authorization 防守。拒绝所有重定向。 |
| LLM通过YNAB错误响应发现令牌泄漏 | 所有YNAB错误都会通过 sanitize(),哪些条带 Bearer <token> 和 Authorization: 模式。没有代码路径将原始令牌格式化为错误。 |
| 失控LLM耗尽YNAB的每令牌速率限制(200 req/小时) | 令牌桶速率限制器:每20秒重新填充1个请求,突发10个。峰值:10次爆发+3600/20次补充=第一小时190次呼叫。突发耗尽后的稳态:180个呼叫/小时(3600/20)。在RoundTripper中强制执行。 |
| 具有凭据的LLM的无限制写访问 | 写入工具是可选的。 除非 YNAB_ALLOW_WRITES=1 在MCP服务器启动时设置,写入工具根本没有注册,无法调用。启用写入后,每次写入都会经过MCP启发确认,这是一个金额安全上限,对>1万美元的交易进行回显覆盖,并在响应中返回状态之前/之后,以便调用技能可以保留审计记录。 |
| 现有交易的金额更新错误 | update_transaction 其输入结构体上没有amount字段——通过此工具在结构上无法更改amount。回归测试通过反射来强制字段的缺失。 |
| 上游挂起 | 每个请求超时30秒,8 MB响应体上限。 |
| 明文令牌存储 | OS密钥环是推荐的存储路径;基于文件和env-var是折衷的后备方案。 |
| 仅对服务器 | stdio传输进行入站网络攻击--没有侦听套接字,没有HTTP端点。 |
| 货币算术中的浮点漂移 | 所有货币存储为64 million单位。格式化仅限于整数算术。不 float64 在金钱之路上的任何地方。 |
纵深防御
- 令牌类型:
Tokenstruct会阻塞每个标准格式/序列化路径。UnmarshalJSON和UnmarshalText拒绝,因此攻击者控制的有效载荷无法注入有效的令牌。 - 模式验证:在任何处理程序运行之前,工具参数都会根据SDK派生的JSON模式进行验证。缺少必填字段将生成JSON-RPC
-32602 invalid paramsSDK层的协议错误——我们的处理程序永远无法访问。 - 工具边界处的错误清理:每个处理程序都会将其错误打包
sanitizedErr在返回之前,作为最后的防御,即使内部错误没有经过客户端自己的清理就逃脱了。 - 不执行shell:没有
os/exec调用凭据或运行时路径中的任何位置。 - 没有硬编码凭据:测试使用假哨兵值。
它不能保护什么
- 一个完全妥协的上游
api.ynab.com(TLS验证已打开,但没有证书固定)。 - 完全受损的MCP客户端(客户端以明文形式看到每个工具响应)。
- 您自己机器上的对抗用户,具有对密钥环/令牌文件的读取权限。
- YNAB错误响应体中出现的裸令牌值为非-
Bearer-前缀子字符串(实践中不太可能)。
启用写入
默认情况下, mcp-ynab 是只读的。要启用写入工具,请设置 YNAB_ALLOW_WRITES=1 在MCP服务器的环境中:
{
"mcpServers": {
"ynab": {
"command": "mcp-ynab",
"env": {
"YNAB_ALLOW_WRITES": "1"
}
}
}
}
启用写入时:
- 4个写入工具出现在
tools/list除了13个阅读和任务型工具之外。 - 每次写入都会经过MCP启发确认提示(在支持它的客户端上——Claude Code会,Claude Desktop不会;env-var-gate是没有启发的客户端的唯一防御)。
- 金额>10亿美元的单位需要
amount_override_milliunits参数等于主量,迫使LLM显式重新断言该值。 - 每次写入都会在其响应中返回状态之前/之后;调用技能负责从这些响应中持久化审计跟踪(MCP本身不向磁盘写入日志)。
已知限制
- 增量同步仅未经过滤。
list_accounts未经过滤list_transactions使用last_knowledge_of_server以节省带宽。过滤list_transactions(与since_date,type,或作用域)总是进行完整的提取——YNAB在过滤端点上的增量语义记录不足。 - 增量缓存没有TTL或大小上限 在v0.2.0版本中。对于单会话MCP流程(分钟到小时),这是可以的;对于长时间运行的守护进程,它会无限增长。看
delta.go关于内存配置文件的讨论。 - 仅限英语 假设——见 docs/ASSUMPTIONS.md 对于完整列表,特别是“信用卡支付”组名称匹配
ynab_status. twiceAMonth日程表 近似为递归迭代器的15天进展,因为YNAB的API不公开用户的两个锚定日。对于7天的仪表板窗口,这最多会减少一次。看 docs/ASSUMPTIONS.md.- 金额上限与货币无关 1000万单位。更正为美元(1万美元);比不同子单位规模的货币(例如,日元~70美元等值)的预期更严格。
路线图
从v0.2推迟:
- 货币感知金额上限 --取回计划
currency_format.iso_code并使用每种货币的阈值表。 - 有界增量缓存 --LRU驱逐或基于时间的TTL长时间运行会话模式揭示了它是否重要。
twiceAMonth精确膨胀 --使用date_first和date_next得出每月两个锚定日。- 过滤读取的增量同步 --一旦YNAB的文档通过查询过滤器澄清了语义。
- 写入工具:
delete_transaction--风险最高的写作,在有强有力的用户案例之前不会发货。
发展
go test -race ./... # run tests with race detector
go vet ./...
go build ./...
staticcheck ./...
govulncheck ./...
Docker构建:
docker build -t mcp-ynab:dev --build-arg VERSION=dev .
在本地运行真正的YNAB API
echo -n "your-token" | mcp-ynab store-token # one-time, uses OS keyring
./mcp-ynab # run the server
服务器从stdin读取JSON-RPC消息,并将响应写入stdout。所有日志都会进入stderr——二进制文件永远不会从自己的代码中接触stdout,否则会损坏传输框架。
添加工具
- 在中定义输入/输出结构
tools.go和json和jsonschema标签。 - 在上添加处理程序方法
*Client. - 在中注册
registerTools与适当ToolAnnotations提示。 - 在中添加测试
tools_test.go使用testClient帮手。 - 在中添加子流程测试
subprocess_test.go如果工具有必需的参数,则确认SDK验证层拒绝缺少的字段。
MCP SDK会自动从结构类型中导出JSON模式,并在处理程序运行之前验证传入的参数。
许可证
麻省理工学院——见 许可证.