mcpField
B
billing-doctor

billing-doctor

本地服务
github.com/lazytitan30开发工具06 周前更新

关于 billing-doctor

Billing Doctor 是面向自建 Google Play Billing 后端开发者的本地命令行工具。它按有文档依据的规则分析购买时间线并展示证据,默认不发送数据。

主要功能

  1. 01按 97 条规则诊断时间线
  2. 02验证并脱敏时间线数据
  3. 03解释订阅状态和 RTDN 消息
  4. 04筛选规则并输出机器可读结果
  5. 05可选获取 Google 状态

适用场景

  1. 01根据日志和支持记录排查订阅故障
  2. 02在 CI 中检查时间线的高严重性问题
  3. 03解码 RTDN 消息并确定后续步骤

MCP 相关

它可通过标准输入输出运行 MCP 服务,提供时间线诊断、状态解释、RTDN 解码、文本脱敏和规则查询等六种工具。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"lazytitan30-billing-doctor": {
"command": "npx",
"args": [
"-y",
"billing-doctor"
]
}
}
}
启动命令npx -y billing-doctor

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

安装包
npmbilling-doctor0.1.1

工具

6

收录的工具列表 · 更新于 3 周前

参数类型必填说明
rulesarray否仅运行这些规则 ID
timelineany是时间线,可以是对象或 JSON 文本

详细介绍

账单诊断

Billing Doctor 会读取 Google Play 购买交易的处理情况,并告诉你问题出在哪里。它在你的机器上运行,不会调用任何服务,也不会更改 Google 中的任何内容,并会展示依据。与 Google 无关。

它面向使用 Node、Python、PHP、Go 或 Java 自建 Google Play Billing 后端的开发者,前端使用 Capacitor、Flutter、React Native 或原生 Android,且没有选择订阅平台。当订阅在晚上 11 点出了问题时,你就可以运行这个工具。

二十秒上手

下面的 fixture 随仓库一同发布,因此请从代码检出目录开始:

git clone https://github.com/lazytitan30/billing-doctor && cd billing-doctor
npx billing-doctor diagnose fixtures/rules/G2-void-then-active.json

(相同的 fixture 也随 npm 包一同发布:执行 npm install -g billing-doctor 后,它们位于 $(npm root -g)/billing-doctor/fixtures/ 下。)

billing-doctor 0.1.1: fixtures/rules/G2-void-then-active.json, 11 events, 1 finding: 1 high

HIGH
  G2  Voided purchase, then a fetch reading ACTIVE, and no revoke  [certain]
      evidence  #8 rtdn voidedPurchase tok_a1 [m-2] answered 200 (2026-09-04T10:00:00Z)
                #9 api subscriptionsv2.get tok_a1 → 200 SUBSCRIPTION_STATE_ACTIVE ack ACKNOWLEDGED (2026-09-04T10:00:01Z)
      mechanism tok_a1 was voided at #8 (the money went back); the fetch at #9 still answered ACTIVE and the ledger never revoked, so the refunded user keeps the tier.
      Google    "(1) REFUND_TYPE_FULL_REFUND - The purchase has been fully voided."
                RTDN reference: VoidedPurchaseNotification, read 2026-09-09: https://developer.android.com/google/play/billing/rtdn-reference
      observed  Seen in a live app, 2026-08: after the voided-purchase notification, purchases.subscriptionsv2.get still answered SUBSCRIPTION_STATE_ACTIVE ...
      next      Revoke tok_a1 now. In the handler, act on voidedPurchaseNotification directly: mark refunded and revoke, regardless of what subscriptionsv2.get answers afterwards.
      fix       runbook G2 (billing-doctor rule G2)

1 finding: 1 high
exit 1: a high finding is present

每项发现都包含其依据的事件、问题机制、带日期链接的 Google 规则原文、置信度(certain、likely、possible)以及下一步要检查的内容。退出码 1 表示存在高优先级发现,因此该命令可用于拦截 CI。

功能

你需要提供一条时间线:一个 JSON 文件,记录某一笔购买发生的情况,由你的日志、数据库、Cloud Console 和支持工单整理而成。其中包括 Google 发送的通知、API 响应、后端写入的内容,以及用户所说的话。令牌使用假名;文件中不会包含任何真实信息。

它会根据 97 条规则,分成十一组,对时间线进行检查。每条规则都基于 Google 官方文档中的一句话,逐字引用,并附有 URL 和阅读日期:

分组检查内容
A. 配置与权限完全没有通知、401/403、主题位于其他项目、否定确认、未经过身份验证的端点、在 2026-08-31 门槛后仍使用低于 Billing Library 8 的版本、未启用一次性购买通知
B. 购买与确认Google 已退款但尚未确认的购买、在 PENDING 期间进行确认或发放权益、已确认但未消耗的消耗型商品、验证前发放权益、重复发放权益、客户端未收到通知的确认失败、预付周期、将多数量购买当作一件处理、因订阅尚未确认而阻止方案变更、文件中尚未退款且始终未确认的购买
C. 通知同一消息被应用两次、通知乱序、未重新获取数据就写入、收到无 ID 的消息时撤销、未处理的类型、将拒付审查当作退款、应用测试通知、始终未确认且未应用的消息
D. 状态解读从错误来源读取到期时间、将 CANCELED 和宽限期视为无访问权限、将暂停和暂停续订视为仍可访问、EXPIRED 仍发放权益、忽略行项目、使用已弃用的 v1 资源、将测试购买计入、将预付购买视为自动续订、令牌使用时间超过六十天窗口
E. 生命周期事件RECOVERED 后未重新发放权益、将 RESTARTED 视为新令牌、DEFERRED 后仍使用旧到期时间、硬编码宽限期和暂停期、将计划取消和计划暂停视为立即生效、已弃用的类型 8、实际上由未接受的涨价导致的流失
F. 升级与关联令牌旧令牌仍在发放权益、提前为 DEFERRED 替换项发放权益、重新注册关联到了错误的令牌、按比例计费后未重新读取到期时间、应用外重新订阅后未建立关联、升级时丢失混淆账户 ID、对单位时间价格更低的方案使用按比例收费模式
G. 退款与作废购买REVOKED 后仍发放权益、作废记录与读取到的状态不一致、将部分退款当作全额退款处理、未扫描作废购买、退款时未撤销、应撤销时却取消、退款涉及的订单不是最新订单
H. 账户绑定与恢复无法映射的通知、原始账户 ID、对共享令牌使用 findOne、恢复时未调用 queryPurchasesAsync、未查询已暂停的订阅、Google 账户不一致
I. 测试与 Console测试续订间隔几分钟就发生、生产环境中存在测试行、已获批准但尚未发布、12 位测试人员规则、已验证但未写入任何内容、测试人员购买后在三分钟后退款
J. 账本完整性发放权益时未使用幂等键、到期后仍保留令牌、时间线中包含真实数据、以本地时间记录到期时间、以订单 ID 作为行的键
K. 设备与 Play Billing Library商品目录为空、断开连接时仍发起调用、无人排查已拥有的购买、可恢复的失败从未重试、不可恢复的失败仍被重试、DEVELOPER_ERROR、商品详情过期、回调重复、查询重叠、将基本方案 ID 用作商品 ID、购买从未到达服务端、将失败报告为成功、将取消视为错误、购买时因商品不可用而被拒绝、Billing Library 8 后仍依赖设备恢复已消耗购买

billing-doctor rules 会列出这些规则;billing-doctor rule B1 会完整打印其中一条规则。

安装

需要 Node 20 或更高版本。

npm install -g billing-doctor

也可以直接运行,无需安装:npx billing-doctor <command>。

命令

命令功能
billing-doctor init根据几个问题填写策略区块,并写入一个空的 timeline.json
billing-doctor validate timeline.json根据架构检查文件;如果令牌、用户 ID 或邮箱看起来是真实的,则发出警告
billing-doctor diagnose timeline.json运行所有规则;使用 --json 输出供机器处理的结果,使用 --rules B1,C3 运行部分规则,使用 --kit <path> 指定运行手册
billing-doctor state sub.json用通俗语言解释 purchases.subscriptionsv2 资源;--policy timeline.json 用于指出你的策略与 Google 不一致之处
billing-doctor rtdn message.json解码 Pub/Sub 推送正文:整数对应的类型名称、令牌和下一步操作
billing-doctor redact < logs.txt将购买令牌替换为稳定的 tok_ 化名,移除邮箱,遮蔽订单 ID,并删去私钥和 bearer 令牌
billing-doctor rules 和 billing-doctor rule <id>规则目录;以及单条规则的 Google 引文和运行手册条目(若提供了工具包)
billing-doctor mcp通过 stdio 提供与六个 MCP 工具相同的功能

退出代码:0 表示没有需要报告的内容;1 表示发现高风险问题(或无法解码输入);2 表示用法或文件错误。

时间线

docs/timeline-format.md 是格式规范。事件分为六种:app(设备报告的内容)、api(对 Play Developer API 的调用及其应答)、ledger(后端写入的内容)、rtdn(收到的通知)、support(用户所说的内容)、console(发布和配置更改)。policy 区块说明后端应如何运作,以便规则区分策略问题与 Bug。

{
  "schema": "billing-doctor-timeline/1",
  "app": { "packageName": "com.example.app", "billingLibrary": "8.0.0", "backend": "node" },
  "policy": { "grantOn": ["SUBSCRIPTION_STATE_ACTIVE", "SUBSCRIPTION_STATE_IN_GRACE_PERIOD", "SUBSCRIPTION_STATE_CANCELED"], "ackWithinHours": 72 },
  "events": [
    { "t": "2026-09-01T10:00:00Z", "kind": "app", "type": "purchase_result", "token": "tok_a1", "productId": "basic_monthly", "purchaseState": "PURCHASED" },
    { "t": "2026-09-01T10:00:02Z", "kind": "api", "call": "subscriptionsv2.get", "token": "tok_a1", "status": 200, "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "acknowledgementState": "ACKNOWLEDGEMENT_STATE_PENDING", "expiryTime": "2026-10-01T10:00:00Z" },
    { "t": "2026-09-01T10:00:03Z", "kind": "ledger", "op": "grant", "token": "tok_a1", "userId": "u_1", "idempotencyKey": "tok_a1:grant" }
  ]
}

fixtures/ 文件夹为每条规则存放一个最简时间线、三个符合实际情况的周记录,以及五个不会产生任何结果的正确生命周期。这些文件既是测试套件,也是了解此格式的最佳方式:fixtures/README.md。

使用编码 Agent

同一引擎也可通过 stdio 作为 MCP 服务运行,因此 Claude Code、Codex、Gemini CLI 或 Cursor 可以在你修复 Bug 时调用它。工具:diagnose_timeline、explain_subscription_state、decode_rtdn、redact_text、list_rules、get_rule。

将其配置为命令 npx,参数为 ["-y", "billing-doctor", "mcp"]。对于 Claude Code,此仓库也可作为插件使用(在检出目录中运行 claude --plugin-dir .,并使用技能 /billing-doctor:diagnose);对于 Gemini CLI,运行 gemini extensions install https://github.com/lazytitan30/billing-doctor。

Incident Kit

免费工具本身就已完整。付费版 Incident Kit 是一个文件夹,可帮助你更快修复问题:每条规则对应一个运行手册条目(用户报告的症状、问题机制、修复方法、需要添加的回归测试)、一组可在 CI 中针对你自己的处理程序重放的真实事件时间线、一个用于验证端点的 TypeScript 参考实现、一个 RTDN 处理程序和一个对账任务,以及适用于 Play Console、Cloud 设置、许可测试和 Billing Library 8 与 9 迁移的检查清单。将该文件夹放在工具旁边,命名为 ./billing-doctor-kit(或设置 BILLING_DOCTOR_KIT),然后运行 billing-doctor rule G2 即可打印运行手册。没有许可证服务器,也不会向外发送数据;工具包就是一组文件。

billingdoctor.dev — 每条规则对应一个运行手册页面、四十条事件时间线、参考后端和检查清单。

具体包含:

运行手册每条规则对应一个页面:用户报告的症状、问题机制、注明查阅日期的 Google 规则原文、修复方法,以及需要添加的回归测试
事件四十条根据真实故障整理的时间线,每条都附有它会产生的调查结果,另有五种必须保持静默的正确生命周期。在 CI 中针对你自己的处理程序重放
参考后端TypeScript:采用失败时关闭原则的账本验证端点、具备消息 ID 幂等性的 RTDN 处理程序、确认看门狗、已撤销购买扫描任务、对账任务、HMAC 账号绑定、数据保留清理任务和 Postgres 架构。可通过全部四十五条时间线
检查清单Play Console 和 Cloud 设置、许可测试、托管发布、Data Safety,以及 Billing Library 8 和 9 迁移

在十二个月内更新;当 Google 的规则发生变化或新增规则时,提供新的下载版本。

唯一的可选联网功能

diagnose --fetch 会使用你自己的服务账号密钥,针对时间线中的每个令牌读取 purchases.subscriptionsv2.get,并将 Google 的回复作为 api 事件附加到时间线中,这样根据日志构建的时间线就能反映 Google 对每笔购买的当前视图。此功能默认关闭;数据只会发送给 Google。

billing-doctor diagnose timeline.json --fetch --service-account ./key.json --token-map ./tokens.json --out augmented.json

时间线会保留其化名:tokens.json 将 tok_a1 映射到真实购买令牌,并保存在你的设备上;附加的事件携带化名,写入的文件绝不会包含真实令牌。该密钥需要在 Play Console 中拥有“查看财务数据”权限。仅获取订阅;不会获取一次性商品。

隐私

默认不进行网络调用。绝不收集遥测数据。你的日志绝不会离开你的设备。上文提到的唯一可选联网功能使用你自己的密钥,且只与 Google 通信。

它不是什么

它不是 SDK、托管服务、订阅平台、仪表板,也不提供法律或财务建议。它绝不会确认、消耗、退款、撤销、取消或延期任何内容。它无法诊断 Apple 的问题。

这些内容的来源

这些规则来自 Google 自己的文档,并被转化为机器可执行的检查。97 条规则中的每一条都引用了 Google 发布的一句话,并注明页面、章节和查阅日期;全部 97 条规则都放在一个文件(src/google/docs.ts)中,因此文档变更只需修改一个文件,旁边还有对应的失败测试。资料来源包括 Android 开发者网站、Play Developer API 参考文档、Play Console 帮助中心和 Pub/Sub 文档。

另有 8 条规则附带了来自线上应用的现场观察,注明日期并标记为观察记录,始终放在 Google 的原文旁边,绝不替代原文。这些记录之所以存在,是因为文档说明了应该发生什么,而支持收件箱揭示了实际发生的情况:某个封装层从不显示响应代码、某个插件将基础方案 ID 作为商品 ID 返回、某个 Web 回退流程解析为空,却看起来像是完成了销售。

每条规则都有一个能证明其触发的测试样例,以及 5 个必须完全不产生发现的正确生命周期样例;误报是发布阻断项。如果规则漏掉了你的某起事件,请提交一个附带脱敏时间线的 issue(good first incident);目录就是这样逐步扩充的。

贡献

npm test 会构建并运行所有测试;测试运行器需要 Node 20.9 或更高版本才能使用 --test-concurrency,而工具本身可在 Node 20.0 上运行(已在该版本检查)。有一个文件可以单独运行:node --test tests/rules-B.test.js。添加一条新规则,需要将规则文件放入 src/engine/rules,将对应的 Google 事实加入 src/google/docs.ts(唯一存放 Google 事实的文件,每条都注明日期),提供带有 expected.json 的测试样例,并在 src/engine/catalogue.ts 中添加一行。5 个干净的测试样例必须始终保持零发现;误报是发布阻断项。

许可证和商标

MIT。Google Play 是 Google LLC 的商标。Billing Doctor 是独立项目,与 Google 无关联,也未获得 Google 的认可或赞助。

评论

支持 Markdown

第一次接触 MCP?

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

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