Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md
麦麦省钱助手 — mcd-coupon-strategist

tests deps Python Token License MCP

市面上的省钱工具都在回答「这一单怎么点最省」。 我们多回答一个问题:「你正在白扔多少钱?」

快速体验 · 真实例子 · 核心亮点 · 架构 · 设计原则


同一个账号,两种问法:省这一单 vs 你正在白扔多少钱

基于麦当劳中国 MCP 打造的点餐成本助手,做两件事:

短期 —— 这一单怎么点最省

  • 拉取当前门店的实时菜单与价格
  • 拉取你账户里当前门店可用的优惠券
  • 枚举「单品 / 套餐 / 券组合 / 加购凑单」的候选方案
  • 用 MCP 的 calculate-price 逐方案真实计价(而不是猜)
  • 输出最省钱的方案,以及为什么不推荐更便宜但吃不饱的选项

长期 —— 你白扔了多少钱

  • 券的沉默成本:你手里有几张券即将过期?那就是正在流失的钱
  • 消费习惯画像:近 N 个月花了多少、客单价是否偏高、哪些单品该改成套餐
  • 数据来自 order-list 历史订单 + query-my-coupons 券存量
🍟 一次点餐平均省💸 沉默成本发现🧮 价格来源🔑 使用门槛
3 ~ 13 元一次几十元MCP 真实计价无需 Token 即可跑测试

快速体验(30 秒)

git clone https://github.com/Ayzzz123/mcd-coupon-strategist.git
cd mcd-coupon-strategist
python demo.py

零第三方依赖(只用标准库)、不需要 MCP Token、不联网。 demo.py 读取 fixtures/ 里录制的真实 MCP 响应,跑通两条链路:

链路 A · 单次省钱
门店:麦当劳南京东城汇餐厅(1990622)(到店自取)
需求:想吃「汉堡 + 薯条 + 可乐」,预算 40 元

推荐方案
  组合:套餐:麦辣鸡腿汉堡三件套
  实付 33.5 元

超预算(仅供对照)
  · 单点:麦辣鸡腿汉堡 + 薯条 + 可乐 —— 实付 46.5 元,比推荐方案贵 13.0 元

  → 这个价差来自套餐结构本身,不需要任何优惠券 —— 这是最稳的省法。

链路 B · 消费审计
券:当前门店可用 2 张,卡包里持有 9 张 —— 沉默成本按后者算

【一】券的沉默成本
  你的券有风险:9 张将在 7 天内陆续过期(面值 21.1 元);
  另有 7 张的券面价值无法从菜单推算,未计入面值。

  优先处理这几张:
    · 大脆鸡扒堡早餐两件套  价值未知(菜单中无对应商品,未估算)  还剩 1 天
      仅 05:00-10:29 可用 · 到店专用
    · 中薯条买一送一  省 14.5 元  还剩 2 天
    · 王牌小食拼  省 6.6 元  还剩 2 天
    …… 另有 6 张(为控制篇幅未展开)

【二】消费习惯
  订单数:8 单(其中 2 笔 0 元)
  总支出:103.5 元
  客单价:17.25 元(按 6 笔有支出的订单计算)

  时段分布:
    早餐 · 4 单(2 笔有支出) · 支出 58.9 元 · 样本不足 3 笔,未估算客单价
    下午 · 1 单 · 支出 1.0 元 · 样本不足 3 笔,未估算客单价
    晚市 · 3 单 · 支出 43.6 元 · 客单价 14.53 元

本月最该做的事:先把 21.1 元的券用掉,
这笔钱不用就是纯损失。
另外 7 张券同样要过期,但券面价值还没算出来 —— 看清它们的时间和限制,别让它们悄悄走掉。

券包体检
  名义总额 ¥21.1(9 张) → 可实现 ¥21.1
【顺手可用】2 张 · 净省 ¥21.1
  · 中薯条买一送一    净省 14.5 元    还剩 2 天
  · 王牌小食拼    净省 6.6 元    还剩 2 天

【无法判断】7 张
  · 大脆鸡扒堡早餐两件套    菜单中无对应商品,未估算    还剩 1 天
  ……

用券排程
  窗口 2 天(券全部过期前) · 点单频率 0.089 单/天
  → 这期间你大概只会点 1 单,最多用掉 1 张券
    第 1 单 → 中薯条买一送一    净赚 14.5 元
  排不上(1 张 · 可实现 ¥6.6)
    · 王牌小食拼    净价值 6.6 元    还剩 2 天
  券包可实现 ¥21.1,但机会只够用掉 ¥14.5 —— 剩下 ¥6.6 注定随券过期浪费。

  麦麦省共 7 条券记录:已领取 4 条、可领取 3 条(同名去重后)

可领取的券
  你还有 3 张券没领(领取免费)

【无法判断】3 张
  · 免费脆薯饼    菜单中无对应商品,未估算
  · 人气麦旋风买一送一    菜单中无对应商品,未估算
  · 9.9元中杯冰美式    菜单中无对应商品,未估算

  3 张的价值无法从券面推算 —— 我们不猜;领取后可以用「带券计价」实测出精确价值。
  另外别忘了机会有限:上面排程算出,窗口内的点单机会已被你手里的券占满 ——
  券不是越多越好,用得上才算数。

活动节奏
  10 月日历里有 14 天有活动:已过 2 天 · 今天 1 天 · 之后 11 天
  最近一次:10月15日(明天)
    · 麦当劳 X PEACEMINUSONE

  说明:「有活动」不等于「更便宜」。
       活动内容里的价格是营销文案,无法核实,本工具不拿它做计算。
       所以这里只给时间线,值不值得等要你结合活动内容自己判断。

  你手里的券撑得到 10月15日 吗(纯日期比较):
    · 中薯条买一送一    10月16日到期(还剩 2 天)    → 等得到
    · 王牌小食拼    10月16日到期(还剩 2 天)    → 等得到

积分体检
  可用 376.3 积分 · 累计 581.3 · 已用 188
  ⚠️ 已过期 17 积分 —— 已发生的损失

  积分商城 24 个商品:9 个仍在兑换期内(其中 6 个换得起),15 个已过兑换期

【现在就能换】
  · 6.9元可乐麦炫酷    需 50 积分    还剩 77 天
  · 3.9元圆筒冰淇淋    需 100 积分    还剩 77 天
  · 16.9元2份麦辣鸡翅    需 200 积分    还剩 77 天

【同款不同价 · 换便宜的那个】
  · 10.9元指定小食任选 —— 一个要 200 积分,一个只要 100 积分,差 100

【已过兑换期】15 个
  这些商品的接口状态仍标着「上架」,但兑换截止日已经过去 ——
  只看状态会以为还能换。

上面那 3 张全是「价值未知」不是解析失败,是数据事实:这份菜单快照采集于 21:59,而脆薯饼、冰美式并不在该时段的菜单里。我们没有为了让 demo 好看 而往菜单里塞一个能匹配上的商品名 —— 原因与验证方式见 fixtures/README.md。

上面这段输出为便于阅读做了删减(省略了分隔线、以及「积分还不够」等重复项), 完整输出请直接跑 python demo.py。

真实运行时,这些响应由 MCP 实时返回,业务逻辑一字未改 —— 所以这个 demo 同时也是整套数据流水线的端到端回归测试。 数据来源与采集时间见 fixtures/README.md。


一个真实例子

同一个账号,同一个门店,两种问法:

问「今天怎么点最省」 →

推荐方案
  组合:套餐:麦辣鸡腿汉堡三件套
  实付 33.5 元

超预算(仅供对照)
  · 单点:麦辣鸡腿汉堡 + 薯条 + 可乐 —— 实付 46.5 元,比推荐方案贵 13.0 元

同样吃到「汉堡 + 薯条 + 可乐」:套餐 33.5 元,单点 46.5 元,差 13 元 —— 而单点那条已经超出 40 元预算,所以它是对照,不是备选。

问「我最近在麦当劳花了多少」 →

【一】券的沉默成本
  你的券有风险:9 张将在 7 天内陆续过期(面值 21.1 元);
  另有 7 张的券面价值无法从菜单推算,未计入面值。
  优先处理这几张:
    · 大脆鸡扒堡早餐两件套  价值未知  还剩 1 天
      仅 05:00-10:29 可用 · 到店专用
    · 中薯条买一送一  省 14.5 元  还剩 2 天
    · 王牌小食拼  省 6.6 元  还剩 2 天

【二】消费习惯
  订单数:8 单(其中 2 笔 0 元)
  总支出:103.5 元
  客单价:17.25 元(按 6 笔有支出的订单计算)
  洞察:
    · 近 3 个月你在麦当劳共消费 103.5 元,其中 6 笔有实际支出,平均每单 17.25 元。
    · 另有 2 笔 0 元订单(多为券核销或积分兑换)—— 不计入客单价,但算作一次点单机会。
    · 还有 2 笔「部分退款」订单 —— 接口不返回退款金额,无法确认 realTotalAmount 是退款前还是退款后的口径,上面的支出可能略偏高。

本月最该做的事:先把 21.1 元的券用掉,这笔钱不用就是纯损失。

第二个问题的价值不在这一次的数字大小,而在于它是持续性的: 第一个问题每单只影响一次;第二个问题每次都会告诉你又有什么在悄悄过期 —— 而这是一次性工具永远给不出的答案。

注意「王牌小食拼」那个 6.6 元:这张券的标题里没有数字,菜单里也没有对应商品, 靠反查原价这条路根本走不通。它的价值是把券的商品码传给 calculate-price 实测出来的 —— 而不是估一个「差不多」的数。

这两段输出与 python demo.py 的结果逐字一致 —— 你可以自己跑一遍验证。


我们做对了什么别人没做的

省钱类工具已经很多了,多到这次比赛报名里就有好几支在做同一件事。所以先说清楚我们的不同点到底在哪:

常见做法我们的做法差别
让模型估算价格所有金额由 MCP calculate-price 回填模型给不出真实价格,只能猜
只说「推荐买这个」说清省在哪:哪张券、哪个套餐、加了什么用户才能学会,而不是依赖工具
为用券鼓励凑单主动检测凑单陷阱并劝退凑单常常反而更贵
只看这一单同时看历史订单 + 券存量一次性工具看不到长期结构
券是「可用资源」券是有保质期的钱过期即损失,这是本项目独有的视角
积分是「攒够就换」积分也是有保质期的钱,且**status 不等于可兑换**实测 24 个兑换品里 15 个已过兑换期,接口状态却仍标「上架」
「有券就建议用」算净价值,该劝退就劝退名义 ¥150 的券包,可实现的可能只有 ¥60
教你「怎么用券」还提醒你**「还有券没领」**未领取的券是唯一一种零成本的省钱来源
用「平均客单价」一刀切分清消费口径 / 点单口径、全时段 / 分时段口径错,后面所有券的判定都会跟着偏
券 = 「门店里能用的」券分两种口径:门店可用的 vs 卡包里持有的实测差 2 张 vs 9 张 —— 拿门店券算沉默成本,会把 7 张即将过期的早餐券整个漏掉
拿活动文案里的价格当依据只取活动的日期与标题,文案价格一概不用营销文案无法核实,拿它算钱等于编
——券的沉默成本别处见不到这个指标

差异化内核:别处都在帮用户花钱,我们在帮用户止损。 下单前省的那几块钱是「收益」,快过期的券是「损失」—— 人对损失的敏感度是对收益的两倍,而这个数字从来没人给他算过。

关键实现:怎么知道一张券真值多少钱

「券的沉默成本」要成立,前提是得知道每张券真实值多少钱。而 MCP 返回的券通常只有名字,没有面值:

「中薯条买一送一」  →  值多少钱?
「9.9元中杯冰美式」 →  值多少钱?
「王牌小食拼」      →  值多少钱?

首选:直接问收银台。 把券自带的商品码连同 couponId 传给 calculate-price, 返回的 discount 就是这张券的精确价值,price 就是用券实付:

券实测结果
中薯条买一送一14.5 元
王牌小食拼6.6 元

兜底:从菜单反查原价(拿不到券的商品码时用):

券形态价值推算本例结果
满减券 满50减12直接取减免额12.0 元
买一送一 中薯条买一送一取该商品菜单单价14.5 元
免费券 免费脆薯饼取该商品菜单单价(券面即免费)脆薯饼单价
固定价券 9.9元中杯冰美式菜单原价 − 固定价23.0 − 9.9 = 13.1 元

为什么首选实测:「王牌小食拼」标题里没有数字、菜单里也没有对应商品 —— 反查只能返回 0(价值未知),而它实际值 6.6 元。 反查不只是可能低估,还会把真实存在的价值报成 0。

两条路都走不通时,一律取 0 并在报告中标注「价值未知」, 绝不估一个「看起来合理」的数。宁可少报,不可编造。

前提:把「客单价」的口径搞对

后面的券包体检和用券排程都依赖同一个数:你的「自然消费基准」 —— 不看券的话,你本来会花多少钱。它取自历史订单的客单价。

而这个数很容易算错。真实订单里有两类订单不该按「一单消费」来算:

订单类型怎么处理
整单退款直接过滤,不计入任何统计
部分退款退款金额接口不提供 → 保持计入,但如实提示「支出可能略偏高」,不猜退款额
0 元订单多为券核销 / 积分兑换 → 不计入客单价,但仍算一次点单机会

最后一条是关键:0 元订单只在有券时才会出现,拿它当「不看券时你会花多少」是 循环论证;而且它会把基准往下拉,让所有券都显得更难用上。

真实数据里,仅这一处口径修正就让客单价从 12.94 元变成 17.25 元, 结论随之从「两张券都得凑单」变成「两张都顺手可用」, 可实现金额从 ¥17.58 变成 ¥21.1。

于是本项目区分两个口径 —— 混用会让结论系统性失真:

  • 消费口径(算钱、当基准):只算有实际支出的订单 → avg_per_order
  • 点单口径(算机会):全部订单都算 → 推算「券过期前你还会点几单」

更进一步:券包体检

知道「你正在白扔多少钱」之后,下一个问题自然是:这笔钱该怎么不白扔?

答案取决于一个反直觉的事实 —— 券的名义面值,从来不是它对你的真实价值:

净价值 = 券面价值 − 为用这张券、你本来不会花的那部分钱

一张「满50减12」的券,如果客单价是 13 元 —— 为了用它得点到 50 元, 名义省 12,实际多花 37,净亏 25。

按这个公式,券包会被切成四类:

类别判定条件建议
顺手可用你本来就会花到门槛直接用,净价值 = 券面价值
努一把差额 < 券面价值凑单后仍净赚,标出净赚多少
纸面富贵差额 ≥ 券面价值明确劝退,算出硬用会亏多少
无法判断券面反查不到原价如实标注,不估算

最后汇总成一句可以直接行动的话:

券包名义 ¥150 → 按你的消费习惯只拿得到 ¥60。

第三类是全篇最反直觉的地方 —— 别的工具都在说「你有券,快去用」, 我们说「这几张别用」。这与「别处帮用户花钱,我们帮用户止损」的立场一致。

⚠️ 判定用的「自然消费基准」取自历史订单的客单价,是一个保守近似、 而非精确值。这个假设写在报告里,不藏在代码里。

再进一步:用券排程

「可实现 ¥60」有个隐含前提 —— 这些券你都有机会用掉。 但券会过期,而你点单的次数有限。

于是有了第二层:先推算「券全部过期前你还会点几单」,再在这个约束下分配券。

窗口 20 天 · 点单频率 0.09 单/天
→ 这期间你大概只会点 1 单,最多用掉 1 张券

建议安排
  第 1 单 → 满20减12    净赚 5.0 元

排不上(1 张 · 可实现 ¥5.0)
  · 免费脆薯饼    净价值 5.0 元    还剩 20 天

券包可实现 ¥10.0,但机会只够用掉 ¥5.0 —— 剩下 ¥5.0 注定随券过期浪费。

「可实现的券,未必用得上」 —— 这是比「券面价值加总」更硬的一层。 大多数省钱工具连第一层都没做,这一层基本没人碰。

三个假设都写在代码注释里,不藏着:你在窗口内本来就会点 K 单、 每单最多用 1 张券、用券不改变你的点单次数。

最后一层:还没领的券

前面三步看的都是你已经领到手的券。但你的券源不止这些 —— available-coupons 会同时返回「已领取」和还没领的券:

麦麦省共 7 条券记录:已领取 4 条、可领取 3 条
可领取:免费脆薯饼 / 人气麦旋风买一送一 / 9.9元中杯冰美式

别的工具都在帮你「用」券,没人提醒你「还有券没领」。 未领取的券是唯一一种零成本的省钱来源,所以我们把它也做进了体检 —— 沿用同一套净价值框架,但问的是不同的问题:

券包体检问可领取券问类别文案
这张券该不该用这张券该不该领领了就能用 / 领了要凑一点 / 领了也用不上

「领了也用不上」是这里最反直觉的一类:领券本身免费, 但你为了用它而消费不是 —— 这跟券包体检是同一套标准。

还有一处必须诚实的地方:这批券拿不到 couponId(工具不返回), 所以上一节那套「带券计价实测」走不通,只能靠菜单反查; 反查不到时如实标「价值未知」,不猜。如上面 demo 输出的 3 张全是未知 —— 原因是那份菜单快照采集于 21:59,脆薯饼与冰美式并不在该时段的菜单里。

⚠️ 不擅自替用户领券。 领取(auto-bind-coupons)会改动账号状态, 必须先取得用户明确同意。工具负责把「有哪些没领、值不值」摆清楚, 领不领由用户决定。

另外,这批券没有有效期,所以它们不进用券排程(排程的窗口天数是靠有效期算的)。 渲染时也刻意不输出剩余天数 —— 把「未知」说成「无期限」就是编造。


目标用户

  • 学生党 / 打工人:预算固定,希望同样吃饱的前提下花得更少
  • 持券用户:手里攒了一堆券,但不知道哪张快过期、哪张该用
  • 选择困难用户:不想在菜单里反复横跳,希望直接得到一个明确答案
  • 想知道自己花了多少钱的人:从没算过在麦当劳的月度开销

核心能力

能力说明
门店菜单感知价格与供应状态随门店实时变化,不写死菜单
券面价值解析从菜单反查原价,算出这张券真实值多少钱(买一送一 = 商品单价;9.9元券 = 原价 − 9.9)
方案枚举计价所有候选方案都经 MCP 真实计价,不复用历史价格
省钱归因明确告诉用户「省在哪」:用了哪张券、换成了哪个套餐、加了什么凑单品
反凑单陷阱当「为用券而加购」反而更贵时,主动指出并给出更优解
券的沉默成本量化即将过期的券面值 —— 那是正在流失的钱
消费习惯画像从历史订单还原月度支出、客单价、高频单品,给出结构性省钱建议
时段口径菜单分时段供应,所以「几点点的」也是消费结构。样本不足 3 笔的时段只报单数,不给客单价
券包体检算出每张券的净价值,明确告诉你哪几张别用:名义 ¥150,可实现的可能只有 ¥60
用券排程可实现的券未必用得上 —— 在「券过期前你还会点几单」的约束下分配券,点明注定浪费多少
可领取券发现麦麦省里还没领的券。别的工具帮你用券,我们提醒你还有券没领,并判断哪张值得领
积分体检积分是另一种有保质期的钱:余额、已过期、能换什么、够不够,以及同一件商品哪个 SPU 更省积分
活动节奏活动时间线 × 券的有效期:回答「等活动再买」等不等得起。只做纯日期比较,不拿营销文案里的价格说话

快速开始

1. 申请麦当劳 MCP Token

前往麦当劳 MCP 开放平台 https://open.mcd.cn/mcp ,使用手机号登录后在控制台激活并复制 MCP Token。

2. 配置 MCP 连接

本项目提供脱敏示例配置 mcp-config.example.json:

{
  "mcpServers": {
    "mcd-mcp": {
      "type": "streamablehttp",
      "url": "https://mcp.mcd.cn",
      "headers": {
        "Authorization": "Bearer ${MCD_MCP_TOKEN}"
      }
    }
  }
}

将 ${MCD_MCP_TOKEN} 替换为你自己的 Token 后,写入 MCP Client 的配置。请勿将真实 Token 提交到任何公开仓库。

3. 在 WorkBuddy 中启用

  1. 打开 WorkBuddy,左侧边栏进入【专家 · 技能 · 连接器】→【连接器】页签
  2. 点击右上角【自定义连接器】→【配置 MCP】
  3. 粘贴上面的 JSON(替换 Token),点击【保存】
  4. 回到【自定义连接器】,将 mcd-mcp 设为【启用】

4. 开始使用

直接对话即可,例如:

我在麦当劳点外卖,门店选好之后帮我算一下:
我手里有券,想吃一个汉堡 + 一份薯条 + 一杯饮料,预算 40 元,
怎么点最省钱?给我两个方案对比。

使用示例

示例一:预算内吃饱

你:预算 35 元,想吃鸡类主食 + 一个配餐,帮我选。

助手:已查询当前门店菜单与你名下可用券,为你计价了 3 个候选方案:

方案组合实付预算 35 元
✅ 推荐麦辣鸡腿汉堡三件套(汉堡 + 薯条 + 可乐)33.5预算内
超预算单点:麦辣鸡腿汉堡 + 薯条37.0超 2 元
超预算单点:麦辣鸡腿汉堡 + 薯条 + 可乐46.5超 11.5 元

只推荐三件套:33.5 元拿到三样,比只买两样的单点组合(37 元,已超预算)还便宜 3.5 元, 比同内容的单点组合省 13 元。这是套餐结构本身带来的价差,不必再叠加优惠券。

示例二:凑单陷阱提醒

你:我有一张「满 50 减 12」的券,是不是该凑单?

助手:不建议。你当前想买的商品合计 46.5 元,为触发门槛需要再加 3.5 元商品, 实付变为 46.5 + 3.5 - 12 = 38 元;而直接买三件套只要 33.5 元。 也就是说,凑单用券后反而比直接买套餐贵 4.5 元。 除非你本来就想吃那个凑单品,否则不划算。

这是一个演示场景(该账户当前没有满减券),用于说明凑单陷阱的判定逻辑。 逻辑本身由 src/test_saver.py 覆盖。

以上金额均来自 MCP calculate-price 的真实返回,非估算值。


架构

架构图:MCP 数据底座 → 适配层 → 链路 A 单次省钱 / 链路 B 消费审计

两条链路共用同一套 MCP 数据底座,但回答的是完全不同的问题:

  • 链路 A(短期):saver.py —— 枚举候选组合,每个组合都交给 calculate-price 真实计价,输出这一单的最省方案
  • 链路 B(长期):auditor.py —— 读 order-list 历史订单与 query-my-coupons 券存量,输出结构性浪费报告

衔接两者的是 mcd_adapter.py:它负责唯一一次的「分 → 元」换算、字段映射、退款过滤,以及券面价值反查。算法层不接触原始响应,因此不会出现单位错乱的幻觉。


项目结构

mcd/
├── README.md                  # 本文件
├── CONTEST_DECLARATION.md     # 参赛声明(官方文本,未做改动)
├── MCP_INTEGRATION.md         # MCP 集成说明:Server / Tool / 调用流程 / 业务价值
├── SKILL.md                   # Skill 定义与工作流说明
├── mcp-config.example.json    # 脱敏 MCP 配置示例(仅环境变量占位符)
├── .env.example               # 环境变量占位符
├── .gitignore
├── LICENSE                    # MIT
├── demo.py                    # 零配置演示:跑通两条链路(不需要 Token)
├── assets/                    # README 展示图
│   ├── banner.svg             #   头图
│   ├── demo-dual-view.svg     #   两种问法对比
│   ├── architecture.svg       #   双链路架构
│   └── social-preview.png     #   GitHub 社交预览图(1280×640)
├── fixtures/                  # 录制的真实 MCP 响应(供 demo 复现)
│   ├── README.md              #   数据来源、采集时间与补充方法
│   ├── menu.json              #   query-meals
│   ├── coupons.json           #   query-store-coupons
│   ├── orders.json            #   order-list
│   ├── prices.json            #   calculate-price(按组合签名索引)
│   ├── coupon_probe.json      #   calculate-price 带券计价(实测券的精确价值)
│   ├── available_coupons.json #   available-coupons(⚠️ 该工具返回 Markdown 文本)
│   ├── my_coupons.md          #   query-my-coupons(账户券,⚠️ Markdown 文本)
│   ├── meal_detail.json       #   query-meal-detail(套餐内含单品)
│   ├── points_account.json    #   query-my-account(积分账户)
│   ├── points_products.json   #   mall-points-products(积分商城)
│   └── campaign_calendar.md   #   campaign-calendar(⚠️ Markdown 文本,活动时间线)
├── src/
│   ├── saver.py               # 单次省钱:方案枚举、需求约束与优化核心逻辑
│   ├── auditor.py             # 长期画像:券的沉默成本 + 消费习惯审计
│   ├── planner.py             # 券包体检 + 用券排程 + 可领取券预判
│   ├── points.py              # 积分体检:余额、有效期、可兑换性(不折算金额)
│   ├── campaign.py            # 活动节奏:活动时间线 × 券的有效期(纯日期比较)
│   ├── mcd_adapter.py         # MCP 响应适配层(单位换算 + 字段映射)
│   ├── test_saver.py          # 算法逻辑自测
│   ├── test_adapter.py        # 适配层自测
│   ├── test_auditor.py        # 审计模块自测(含日期临界值、时段口径)
│   ├── test_planner.py        # 券包体检与排程自测(四类判定 + 机会约束)
│   ├── test_order_adapter.py  # 订单/券解析自测(用真实响应片段)
│   ├── test_claimable.py      # 可领取券自测(文本解析 + 不得编造有效期)
│   ├── test_points.py         # 积分自测(按截止日过滤 + 不得折算成金额)
│   └── test_campaign.py       # 活动日历自测(只取结构化字段 + 标签不当事实)
├── scripts/
│   └── style_check.py         # 零依赖代码规范检查(CI 会跑)
├── .github/workflows/
│   └── tests.yml              # CI:规范检查 + Python 3.8/3.10/3.12/3.13 跑测试与 demo
├── workbuddy.md               # WorkBuddy 开发对话上下文(WorkBuddy 专项奖励用)
└── docs/
    ├── TOKEN_GUIDE.md         # MCP Token 申请指引
    └── SUBMIT_CHECKLIST.md    # 报名提交检查清单

测试

python demo.py                    # 端到端:两条链路的完整输出
python src/test_saver.py          # 单次省钱:枚举、排序、凑单陷阱
python src/test_auditor.py        # 长期画像:沉默成本、消费习惯
python src/test_planner.py        # 券包体检与排程:四类判定、机会约束
python src/test_adapter.py        # 适配层:单位换算、响应解析
python src/test_order_adapter.py  # 订单/券:退款过滤、券价值推算
python src/test_claimable.py      # 可领取券:文本解析、免费券券型、不编造有效期
python src/test_points.py         # 积分:按截止日过滤、同款不同积分、不折算金额
python src/test_campaign.py       # 活动日历:只取结构化字段、标签不当事实

全部为纯本地运行,不需要 MCP Token,也不需要安装任何第三方库。

代码规范

python scripts/style_check.py     # 零依赖,只用标准库

检查项:行宽 ≤ 88 列、行尾空白与制表符、文件结尾换行、所有函数的返回类型标注、 所有非双下划线函数的 docstring、未使用的导入、__all__ 与公开定义的一致性。

之所以自己写而不用 ruff / flake8:项目定位是零第三方依赖, 连开发期的 linter 依赖也不引入。CI 上会跑这个脚本,规范不达标直接失败。 CI 会在 Python 3.8 / 3.10 / 3.12 / 3.13 上自动跑这一整套(见 tests.yml)。


这个项目可能对你有用,如果……

  • 🌱 你在做 MCP 相关的项目 —— MCP_INTEGRATION.md 里记录了官方文档没写、但跑通链路必需的 12 条实测调用契约(门店查询的必传参数、calculate-price 的字段名、「分 vs 元」两个接口方向相反的坑),可以帮你少踩不少坑。
  • 🍔 你想知道自己在外卖上花了多少 —— 链路 B 给出的是可以直接执行的结论:「你有 2 张券将在 4 天内陆续过期,面值 14.5 元」。
  • 🧩 你在写 Agent / Skill 的评测 —— 这个项目是一个完整的、双链路的 MCP 编排示例,saver.py + auditor.py + mcd_adapter.py 分层清晰,可直接作为参考实现。
  • 💡 你也在做麦当劳 MCP 的省钱工具 —— 欢迎对比,也欢迎来 issue 里讨论「券的沉默成本」这个视角。

如果它对你有帮助,一个 star 就是最好的反馈。 ⭐

本项目为麦当劳程序员创意开发大赛参赛作品,非麦当劳官方产品。


设计原则

  1. 绝不猜测价格 —— 所有金额均来自 MCP calculate-price 的返回结果。
  2. 宁可少报,不可编造 —— 券的价值若无法从菜单反查到原价,取 0 并在报告中标注,而不是估一个看起来合理的数。
  3. 省在哪要说清 —— 每个推荐都附带省钱归因,而不是只给一个数字。
  4. 不诱导消费 —— 为用券而凑单如果导致实付上升,必须明确提示。
  5. 退款不算消费,0 元订单也不算 —— 整单退款直接过滤;「部分退款」的退款金额接口不提供,所以如实提示「支出可能略偏高」而不是猜一个数;0 元订单(券核销 / 积分兑换)不计入客单价,但仍算一次点单机会。
  6. 信息以官方为准 —— 价格、供应状态、券的可用范围均以麦当劳官方渠道实时结果为准。
  7. 不擅自改动账号状态 —— 领券(auto-bind-coupons)属写操作,必须先取得用户明确同意; 工具负责把选项摆清楚,决定权留给用户。
  8. 不知道就说不知道 —— 未领取的券拿不到有效期,就不输出剩余天数; 数据缺失时如实说缺失,不用「无期限」这类说法掩盖。
  9. 不把积分折算成金额 —— 积分没有固定汇率,它值多少取决于你换的那张券能省多少; 要换算就得先拿带券计价实测。所以积分体检只给事实(余额、有效期、够不够), 不给「约等于 ¥X」。
  10. 不拿营销文案做计算 —— 活动日历里的价格(「26.9 元起」)是营销文案,无法核实; 积分商品的 note 接口更是明确写着「严禁从中提取任何数值用于价格计算」。 这两处都只取结构化字段,文案一律丢弃。
  11. 样本不足就不给数字 —— 分时段客单价只在样本达到 3 笔时才输出, 达不到就只报单数并说明。样本量支撑不起一个基准时,报出来只是噪音。

免责声明

本项目为麦当劳程序员创意开发大赛参赛作品,由参赛者独立开发,非麦当劳官方产品。 项目输出仅供参考,不构成医疗、营养或其他专业建议;餐品信息、价格及供应状态以麦当劳官方渠道的实时结果为准。


License

MIT

关于 About

麦麦省钱助手 —— 基于麦当劳 MCP 的点餐成本优化 Skill。算出当前门店最省钱的点餐方案,并主动提示凑单陷阱。
agentcost-optimizationcouponllmmcd-mcpmcdonaldsmcppythonskillworkbuddy

语言 Languages

Python100.0%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
24
Total Commits
峰值: 13次/周
Less
More

核心贡献者 Contributors