内容
# 今天麦什么
[](https://github.com/ftxcgwf/mcd-solver/actions/workflows/ci.yml)
**给我预算、热量上限和一个心情,我给你麦当劳的最优解。**
基于麦当劳 MCP 能力的点单决策求解器。不是菜单查询,不是领券脚本——它把「怎么点」建模成一个带约束的优化问题:预算、热量、钠、蛋白质是约束,目标函数是**满足感**,而不是「最便宜」。
> **WorkBuddy 原生项目**:本项目从方向选型、MCP 接入、求解器实现到参赛文档,全程在 WorkBuddy 智能体中完成,并可通过 `SKILL.md` 被 WorkBuddy 直接加载调用。`workbuddy.md` 即 WorkBuddy 专项奖励凭证(作品进入前 100 名额外 +3000 积分)。
> **为什么不是又一个「算最便宜」的工具?** 榜单前十里已有多个省钱 / 卡路里 / 预算类方案。本项目的差异点在于把 **控钠(盐)** 与 **口感层次 / 温度反差(满足感)** 也建模进目标函数——目前公开作品里**独一份**这么做。
>
> 同一预算、同一门店,三种取向解出的钠含量差异明显(单位 mg):
>
> | | 省钱派 | 嘴馋派 | 均衡派 |
> |---|---|---|---|
> | 钠 | **768** | **1245** | **768** |
>
> 最便宜的和最贵的钠一样,夹在中间的反而高 62%——多花钱不等于吃得更健康。一个反直觉事实:板烧鸡腿堡钠 1041mg,比巨无霸的 961mg 还高。
---
## 先说一个可能颠覆你认知的数据
你可能以为鸡腿堡比牛肉堡健康。但麦当劳官方营养数据是这样的:
| 餐品 | 热量 | 钠 |
|---|---|---|
| 板烧鸡腿堡 | 392 kcal | **1041 mg** |
| 巨无霸 | 513 kcal | 961 mg |
**板烧鸡腿堡比巨无霸还咸。**
中国居民膳食指南建议每日钠摄入不超过 2000mg。一份板烧鸡腿堡就吃掉了一半还多。而几乎所有控卡工具都只看热量,不看钠——这是本项目强调控钠的原因,`--max-sodium` 是一等公民参数。
---
## 它长什么样
```
约束:预算 45 元 热量 ≤ 1200 kcal (价格经 MCP 官方结算价校准)
【省钱派】满足感 -1.79 合计 ¥35.0 516kcal 钠 768mg
主食 麦香鸡 1个 ¥17.0 370kcal 钠 731mg [—]
小食 玉米杯 小 ¥13.0 53kcal 钠 1mg [清爽·温热]
甜品 圆筒冰淇淋 1个 ¥5.0 94kcal 钠 36mg [冰爽·奶香·甜]
【嘴馋派】满足感 37.41 合计 ¥41.0 632kcal 钠 1245mg
主食 麦辣鸡腿汉堡 1个 ¥23.0 485kcal 钠 1208mg [嚼劲·酥脆·多汁·咸香·嫩滑]
小食 玉米杯 小 ¥13.0 53kcal 钠 1mg [清爽·温热]
甜品 圆筒冰淇淋 1个 ¥5.0 94kcal 钠 36mg [冰爽·奶香·甜]
【均衡派】满足感 16.27 合计 ¥44.5 664kcal 钠 768mg
主食 麦香鸡 1个 ¥17.0 370kcal 钠 731mg [—]
小食 玉米杯 小 ¥13.0 53kcal 钠 1mg [清爽·温热]
饮料 可口可乐 中 ¥9.5 147kcal 钠 0mg [冰爽]
甜品 圆筒冰淇淋 1个 ¥5.0 94kcal 钠 36mg [冰爽·奶香·甜]
```
同一个约束、同一家门店,三种取向解出来的结果值得多看一眼:
| | 花费 | 热量 | **钠** |
|---|---|---|---|
| 省钱派 | ¥35.0 | 516kcal | **768mg** |
| 嘴馋派 | ¥41.0 | 632kcal | **1245mg** |
| 均衡派 | ¥44.5 | 664kcal | **768mg** |
**最便宜的和最贵的,钠含量一模一样;夹在中间的那个反而高出 62%。**
多花钱并不等于吃得更健康。省钱派和均衡派都绕开了那个 1208mg 的汉堡,钠就都压到了 769mg;嘴馋派为了口感层次选了它,钠直接跳一倍,尽管花的钱还在中间。这种事盯着菜单看是看不出来的,得把每一件的钠累加起来、放进同一个约束里比过才知道。
(各人设权重不同,且经济性惩罚项会让分数变负,满足感分数**不可横向比较**,只在同人设内比较。)
### 官方复核:让「我算的」变成「官方认的」
求解器是本地累加的,这一单到底要付多少只有麦当劳自己知道。加 `--quote` 就把方案交回 MCP `calculate-price` 复核:
```
【均衡派】
官方复核 · 麦当劳常州万象城餐厅(1990558)
官方复核(calculate-price)
原价 ¥44.5
应付 ¥44.5
与求解器估算 ¥44.5 相比:一致
明细:
麦香鸡 x1 ¥17.0
小杯玉米杯 x1 ¥13.0
可乐 x1 ¥9.5
圆筒冰淇淋 x1 ¥5.0
取餐方式:堂食(eat-in)、外带(take-in-store)
```
复核不只是回显数字,它会真的拿这套商品去该门店验一次能否结算:遇到售罄自动剔除并重新报价,遇到门店打烊自动切到同城还在营业的门店。这次结果是「一致」——价格层事先被同一套 `calculate-price` 校准过,两边自然对齐。
> **一个容易看反的地方**:`--quote` 复核**不带券**,而求解器用的是**券后价**。
> 所以方案里有可用券的商品时,复核金额会**高于**求解器估算(例如冰美式求解器按券后
> ¥9.9、复核按原价 ¥11.9)。这不是求解器算少了,恰恰相反——它已经算到了用券之后的最低价,
> 而复核是按不含券报的。要让官方连同券一起确认,加 `--coupons`,它会逐张带着 `couponId`
> 试算并挑出最划算的那张。
---
## 为什么目标函数不是「最便宜」
人点麦当劳时的真实心理是:**这顿吃完我不能后悔**。后悔通常来自四种情况:
- 花了钱但没吃到想吃的(口味单调)
- 吃完发现这顿咸得离谱(钠超标)
- 结构不完整,吃了跟没吃一样(没主食、没喝的)
- 明明有更划算的组合,自己没发现
所以满足感被拆成六项:
```
S = 固有满足度 # 单品口感愉悦分,来自口味先验,按边际递减累加
+ 口感层次奖励 # 酥脆/多汁/冰爽/奶香…覆盖维度越多越爽,边际递减
+ 温度反差奖励 # 热汉堡配冰可乐 > 全是热食
+ 结构完整奖励 # 主食/小食/饮料/甜品齐备度;没主食不成一顿饭
- 同类堆叠惩罚 # 三个汉堡不叫一顿饭
- 健康软惩罚 # 钠与脂肪,渐进扣分
+ 性价比愉悦 # 省得越多越开心(需价格)
```
其中**口感层次**和**温度反差**来自经验,不来自数据库——MCP 能给你热量和钠,但它永远不会告诉你「一份餐里同时有酥脆、多汁、冰爽三种口感时,满足感远高于三样都是软塌塌的」。这部分先验在 `solver/taste.py`,可用 `data/taste_override.json` 手工精修。
有三个反直觉但必要的修正,不加就会给出蠢方案:
- **固有满足度按边际递减累加**(第 n 件的愉悦 × 0.8ⁿ)。不衰减的话,五件小食的分数之和永远压过三件正餐,模型就会输出「脆薯饼 + 苹果片 + 薯条」这种凑数组合。
- **撑不起正餐的「主食」直接降级**。官网把脆薯饼(146kcal)、脆香油条(202kcal)挂在早餐分类下,而早餐算主食——于是它们会和汉堡抢主食名额,还经常因为便宜而胜出。只在评分里扣分不够,求解器照旧拿它们凑数,所以低于 300kcal 的一律降为小食。
- **钠要渐进惩罚,不能只罚超限**。一餐吃掉每日推荐(2000mg)的 78% 已经很咸了,但「只罚超 2000mg」的写法会给它满分——结果是均衡派选出钠 1555mg 的组合,和嘴馋派一模一样,控钠人设形同虚设。现在从占每日推荐一半起就开始罚,超限后斜率翻倍。
---
## 快速开始
零第三方依赖,Python 3.9+,**不需要 MCP Token 就能跑**。
```bash
git clone https://github.com/ftxcgwf/mcd-solver.git
cd mcd-solver
# 一行到底(会自动建营养快照并跑三个示例)
python scripts/quickstart.py
```
手工执行同样简单:
```bash
# 1. 建营养快照(约 2 分钟,抓自麦当劳官网公开营养计算器,无需 Token)
python scripts/fetch_nutrition_web.py
# 2. 直接问
python cli.py --max-kcal 750 --max-sodium 1800 --persona all
```
想让预算约束生效,需要真实价格——价格官网不提供,只能来自 MCP:
```bash
# 到 https://open.mcd.cn/mcp 登录激活,申请 MCP Token
export MCD_MCP_TOKEN=你的Token
python scripts/fetch_menu.py # 抓在售菜单与价格 -> data/menu.json
python scripts/verify_prices.py # 校准官方结算价 -> data/prices_verified.json
python scripts/coupons.py --calibrate # 折算券后价 -> data/prices_coupon.json
python cli.py --budget 45 --max-kcal 1200 --persona all
```
券数据是可选的:没有券时求解照常,只是少一层价格优惠。
### 参数
| 参数 | 说明 |
|---|---|
| `--budget` | 预算上限(元)。需先跑 `scripts/fetch_menu.py`;启用后只在有确定价格的单品中求解 |
| `--max-kcal` | 热量上限(千卡) |
| `--max-sodium` | 钠上限(毫克),每日推荐不超过 2000mg |
| `--min-protein` | 蛋白质下限(克),健身场景 |
| `--max-items` | 最多几件,默认 5 |
| `--persona` | `value` 省钱派 / `indulge` 嘴馋派 / `balance` 均衡派 / `all` |
| `--coupons` | 逐张试算卡包里的券,输出本单最优用券与加购建议(需 Token) |
| `--quote` | 用 MCP `calculate-price` 做官方券后价复核(需 Token) |
| `--place` | 复核后创建真实订单(需 Token,且需交互确认) |
| `--city` / `--store-code` | 复核与下单用的城市 / 指定门店 |
| `--json` | 机器可读输出,便于接入其他 Agent |
更多例子:
```bash
python cli.py --min-protein 30 --max-sodium 1500 # 健身增肌且控钠
python cli.py --budget 25 --persona value # 25 块怎么点最值
python cli.py --max-kcal 500 --persona balance # 500 大卡轻食
python cli.py --budget 45 --persona all --quote # 求解并让官方复核总价
```
---
## 价格校准:菜单标价 ≠ 结算价
这是接入 `calculate-price` 后最意外的发现。实测某商品:
| 商品 | 菜单列表标价 | `calculate-price` 结算价 |
|---|---|---|
| 燕麦奶铁 | ¥9.9 | **¥23.0** |
| BFF 四宫格小食盘双人餐 | ¥62.9 | **¥122.5** |
菜单里的 `price` 有两处不能被直接当成应付价,成因还不一样:
- **条件性优惠价**。燕麦奶铁菜单标 ¥9.9,但那是 `随单购麦金卡优惠`(要凑单或持麦金卡才成立),通用结算价仍是 ¥23.0。按 ¥9.9 做预算,没满足条件的人到店要多付一倍多。
- **组合餐起价**。BFF 四宫格小食盘双人餐菜单 ¥62.9,实际结算 ¥122.5——¥62.9 是"起",配齐算的是实价。(该组数字来自早期实测;当前版本已按 `category` 把组合餐整类排除在价格来源之外,不再参与求解。)
拿菜单 `price` 当预算约束会系统性低估总价。本项目早期版本就因此踩过坑:求解器算 ¥44.4,官方复核 ¥57.5。
所以有了 `scripts/verify_prices.py`——用 `calculate-price` 逐个校准,把结算价写到 `data/prices_verified.json`,且优先级高于菜单标价。常州门店实测:53 个非套餐单品里 51 个拿到结算价,另 2 个当时售罄、自动退回菜单标价。
这里有个坑值得单独说:**它必须一件一件地查,不能把商品塞进同一个购物车批量问。**
抹茶阿芙佳朵单独买单是 ¥15.0,但和燕麦奶出现在同一张单里会立减 ¥7.5(整单 `discount=750`)。这类「随单购」优惠只在特定组合下成立,而批量查询会把整单优惠摊进明细,让这一步记下「¥7.5」。后果很实在:求解器以为它是性价比极高的饮品,把它塞进了每一个预算方案,直到 `--quote` 整单复核才发现实际是 ¥15.0。改回逐件查询后,凑单优惠留给整单复核去兑现——那时只会更便宜,不会让预算失守。副作用是请求数从 6 次变成 54 次,换来的是单价口径干净。
另外,逐件查询顺带消灭了售罄处理逻辑:批量查询时一件售罄会拖垮整批(60006),要靠二分拆分兜;逐件查询每件独立失败,不需要任何拆分。
---
## 券优化:券的面额,只有官方知道
麦当劳 MCP 提供了五个券相关工具,但它们有个共同特点:**都不返回面额**。
券上写「¥5 优惠」是印在图片上的,接口只给一个 `couponId`。
这意味着「这张券到底值多少钱」在本地无解。唯一的办法是带着 `couponId`
去调 `calculate-price`,让官方算一遍,比一比才知道。这是全项目里 MCP
不可替代性最强的一环——不用 MCP,这件事做不了。
还有一个顺序上的坑。最初的实现是"先求解,再看手里的券能不能用",结果
几乎永远命中不了:求解出的方案里恰好没有那件商品,券就废了。正确的顺序
是先把券折算成**券后价**,让"冰美式有券只要 ¥9.9"从一开始就参与组合选择。
实测常州门店(麦当劳常州万象城餐厅):
```
门店 1990558 可用的券(query-store-coupons)(1 张)
· 9.9元中杯冰美式 适用:麦咖啡™冰美式中杯
正在用 calculate-price 折算券后价 ...
已折算 1 个券后价:
麦咖啡™美式 ¥9.90 [9.9元中杯冰美式]
```
对应商品 `麦咖啡™美式`(code 507411)菜单标价 ¥11.9,折算后 ¥9.90,直接压低 ¥2.00。
价格优先级因此定为:**券后价 > 官方结算价 > 菜单标价 > 无价格**。
方案里没命中券商品时,还会进一步回答「为用这张券加一件值不值」——它会带着券
重新试算,告诉你加购这一件实际只需多花多少。
> **安全提示**:`couponCode` 是核销凭证,等同于现金。抓取结果写入
> `data/coupons.json` 与 `data/prices_coupon.json`,两者均已加入
> `.gitignore`,请勿提交。仓库只含脱敏的结构示例
> `data/coupons.example.json`。
---
## 算法
营养快照展开后有 125 个可选项(82 个产品 × 各自的规格档位),穷举 3~5 件组合有上亿种。但一顿麦当劳有天然层次:主食 / 小食 / 饮料 / 甜品,每层数量上限很小。
于是用**分层束搜索**:逐层扩展,每层只保留 `beam_width` 个最有希望的部分解。热量、钠、花费都是单调累加的,超预算的分支当场剪掉,不必等组合完整才发现。
复杂度从 `O(C(n,k))` 降到 `O(层数 × beam × 每层组合数)`,实测秒级出解。这是高质量近似解而非精确最优——对「今天中午吃什么」这个问题,算到精确最优没有意义,快和多方案才重要。
---
## 数据来源:四源设计
| 数据 | 来源 | 是否需要 Token | 实测规模 |
|---|---|---|---|
| 营养(热量/蛋白/脂肪/碳水/钠/钙) | 麦当劳中国官网营养计算器 | 否 | 82 个产品 / 125 个规格 |
| 在售菜单与商品编码 | 麦当劳 MCP `query-meals` | 是 | 104 个条目(其中 53 个是可下单单品) |
| 官方结算价 | 麦当劳 MCP `calculate-price` | 是 | 53 个里命中 51 个(2 个当时售罄) |
| 挂载是否正确 | 麦当劳 MCP `list-nutrition-foods` | 是 | 158 条,用于倒查校验(见下文) |
| 可用券与券后价 | 麦当劳 MCP `query-store-coupons` + `calculate-price` | 是 | 1 张券(随账号与时段变化) |
预算模式下实际进入求解的是 **34 个**单品——104 个菜单条目先按组合餐标识与分类剔除掉一半,剩下的 53 个有确定编号的单品再与营养快照匹配、按规格去重,最后因多个选项争抢同一商品编码,收敛到 34 个(原因见下方第六个坑)。
> 以上为 **常州市 · 麦当劳常州万象城餐厅** 的实际快照。换一个城市重跑
> `fetch_menu.py` / `verify_prices.py` / `coupons.py --calibrate` 即可,数字会随门店变化。
官网营养数据面向公众开放,因此**营养部分无需 Token 即可构建**,这也是本项目 clone 即能跑出结果的原因。价格官网不提供,必须走 MCP。
四者以品名归一化、商品编码精确匹配后合并,优先级是「券后价 > 结算价 > 菜单标价 > 无价格」。营养以官网实验室测定数据为准(页面标注更新时间 2025-04)。
合并时有六个坑,都已处理:
1. **套餐不能当单品**。MCP 菜单里「吉士汉堡包套餐」¥26 若被子串匹配当成「汉堡包」的单价,结果会严重失真——所以带「套餐/件套/随心选/乐园餐/双人餐」的条目一律排除在价格来源之外。
2. **规格不能被平铺**。官网薯条有迷你/小/中/大四档,MCP 只有一条「薯条」¥13.5。无差别赋值会让求解器以为大份和中份同价,所以每条菜单记录的价格只给一个规格档。档位怎么定也有讲究:`calculate-price` 返回的结算明细常自带规格(菜单写「玉米杯」,结算写「**小杯**玉米杯」;菜单写「美式」,结算写「麦咖啡™**冰美式中杯**」),优先听它的;没有可读明细时才退回「热量居中」的启发式——不这么做的话,玉米杯会被挂到「大」(87kcal),而实际下到单里的是小杯(53kcal)。
3. **预算模式只在有确定价格的单品里求解**。MCP 当前门店菜单以套餐为主,过滤后能确定单价的是 34 个。若允许混入无价格单品,总价不可知,预算检查会被静默绕过——那样给出的「45 元方案」其实不知道多少钱。宁可选择面窄,也不给假答案。
4. **券不能只在求解后挑**。券接口只给 `couponId` 不给面额,必须带着它调
`calculate-price` 反推券后价,并让券后价先进入价格层再求解。
5. **一个商品编码只能被一个选项占用**。这是自查时抓出来的:两边的粒度不一样,
MCP 只有一条「美式」(code 507411),官网营养数据却拆成「冰美式」「热美式」,
「新地」对应官网的「朱古力新地」「草莓新地」。放任多个选项抢同一个编码,
会输出两个下不了单的方案,还会把「9.9 元中杯**冰**美式」的券错算到「热美式」头上。
6. **仲裁要听证据,不要比谁的名字更像**。修完上一条后又抓出一个同类的:光按
品名挑承接者,「冰浓浓抹茶牛奶」和「热牛奶」一样都含「牛奶」,谁排在前面谁
拿到编码 507394——而结算明细明确写着这个编码叫「热牛奶中杯」。牛奶被挂到冰的
那款,热量差 20kcal、冷热口感标签也反了;燕麦奶同理差 43kcal(27%)。
现在先拿结算明细名给候选打分(核心名对上 +10、冷热一致 +3、冷热冲突 -6),
没有明细名时才比品名相似度。
这套映射如今有一道独立防线:`scripts/crosscheck_nutrition.py` 拿 MCP 自己的另一份
营养数据(`list-nutrition-foods`,158 条,名字写成「热牛奶中杯」这种带规格的形式)
倒查每一个挂载——「这个编码官方叫 X,独立数据里 X 的营养是多少,和我们挂的那一项
是否一致」。常州门店实测 32 项全部吻合、0 项不符。
---
## 项目结构
```
mcd-solver/
├── cli.py 命令行入口(含复核与下单)
├── SKILL.md Skill 定义,供 AI 助手加载
├── solver/
│ ├── taste.py 口感先验:把「老饕的嘴」变成向量
│ ├── satisfaction.py 满足感模型与三种人设
│ ├── optimize.py 分层束搜索求解器
│ └── model.py 四源数据合并(营养 / 菜单 / 结算价 / 券后价)
├── scripts/
│ ├── fetch_nutrition_web.py 抓官网营养数据(无需 Token)
│ ├── fetch_menu.py 从零实现的 MCP Streamable HTTP 客户端
│ ├── verify_prices.py 用 calculate-price 校准官方结算价
│ ├── coupons.py 券查看 / 领取 / 折算券后价 / 试算
│ ├── order.py 官方复核与下单(含人工确认闸门)
│ ├── quickstart.py 一键体验(跨平台,无需 make)
│ ├── crosscheck_nutrition.py 用 MCP 独立营养表倒查挂载是否正确
│ └── selftest.py 离线自检
├── data/
│ ├── nutrition.json 营养快照(官网公开数据,无需 Token)
│ ├── menu.json MCP 在售菜单
│ ├── prices_verified.json 官方结算价(脱敏,仅商品编码与金额)
│ ├── prices_coupon.json 券后价(不入库,含真实券码)
│ └── coupons.example.json 券数据结构示例(脱敏)
├── assets/social-preview.png 分享卡面 1280×640
├── .github/workflows/ci.yml 离线自检(无需 Token,Python 3.9~3.13)
├── Makefile 常用命令薄封装
├── README.md 本文件:项目介绍 / 安装 / 使用示例 / 目标用户
├── MCP_INTEGRATION.md MCP 接入说明(Server / Tool / 调用流程 / 业务价值)
├── CONTEST_DECLARATION.md 赛事方统一参赛声明(内容不可改动)
├── mcp-config.example.json 脱敏 MCP 配置示例(仅环境变量占位符)
├── workbuddy.md WorkBuddy 联动上下文(专项奖励用)
├── NOTICE.md 服务依赖 / 商标归属 / 数据来源 / 原创明细
├── LICENSE MIT
└── CHANGELOG.md 四个阶段的演进与踩坑记录
```
## 工程
- **零第三方依赖**,只用标准库,`clone` 即能跑出结果
- **离线自检**:`python scripts/selftest.py`,26 项检查覆盖语法、数据完整性、
硬约束不可违反、JSON 结构、边界降级、无 Token 优雅退出、敏感数据未入库
- **CI**:GitHub Actions 在 Python 3.9~3.13 五个版本上跑同一套自检,无需任何密钥
- **安全**:Token 与 `couponCode` 只写进 `.gitignore` 覆盖的本地文件,提交前自检会拦截
---
## 目标用户
- **控卡 / 控钠人群**——知道热量上限,想知道怎么吃得最爽;或被要求限盐
- **健身人群**——用 `--min-protein` 保证蛋白质,同时压住钠
- **预算敏感的打工人**——这点钱怎么点最值
- **选择困难症**——不想看菜单,想要一个带理由的建议
- **开发者**——`--json` 输出可直接接入自己的 Agent 或小程序
---
## 参赛说明
本项目为「麦当劳程序员创意开发大赛」参赛作品,基于麦当劳 MCP 能力开发。
- `MCP_INTEGRATION.md` 说明了实际使用的 MCP Server、Tool、调用流程与业务价值
- `mcp-config.example.json` 为脱敏配置示例,只含环境变量占位符
- `CONTEST_DECLARATION.md` 为赛事方统一参赛声明(按规定使用官方文本、内容不可改动),
本项目的原创与合规明细见 `NOTICE.md`
- `NOTICE.md` 集中说明服务依赖、商标归属与数据来源
---
## 边界与免责
- 营养数据来自麦当劳官方公开营养计算器(更新于 2025-04),实际出品可能因原料批次、产地、工艺存在差异,以官方公布与门店实际为准
- 价格随地区、时段、活动浮动,以门店实际为准
- 服务范围为麦当劳中国大陆,不含港澳台
- **同一商品的冷热 / 口味变体可能拿不到可下单的编码**。MCP 菜单的粒度粗于官网营养数据:菜单只有「美式」「新地」「牛奶」一条记录,官网却按口味冷热分列(「冰美式/热美式」「朱古力新地/草莓新地」)。冷热这种差异能靠结算明细名(「麦咖啡™冰美式中杯」)判定;口味这种两边都对不上的,只有唯一一个代表项能挂上编码并参与带价格的求解,其余变体仍保留营养数据,会出现在不需要下单、只看营养的场景里。
- **泛称商品的规格无从判定**。有的编码连结算明细都只返回泛称:「可乐」不带杯型、「新地」不带口味。此时只能退回「热量居中」这条保守启发式,取中间档;而官网各杯型的营养差异很大(可乐小/中/大 = 107/147/224 kcal),若实际不同可能偏 ±50%。这类项目在 `crosscheck_nutrition.py` 里会被明确标为「无从核对」,不冒充已验证。
- **不是每样在售商品都有营养数据**。官方营养计算器更新于 2025-04,而菜单是实时拉取的,因此当季新品(龙焰鸡腿堡、枫糖厚松饼系列、当季口味的麦旋风等)虽有价格与编码,却配不上营养值,进不了求解——这是数据源本身的滞后,不是匹配失败。已重跑 `fetch_nutrition_web.py` 确认官网确实没更新(两次抓取结果完全一致,仍标 2025-04)。
- `--place` 会创建真实订单(仍需你在麦当劳 APP 完成支付)。默认只试算,下单须手动输入金额确认
- 本项目只做**决策辅助**,不构成医疗或营养建议;有特殊健康需求请遵医嘱
- 本项目为个人开源作品,与麦当劳官方无隶属关系。使用麦当劳 MCP 服务须遵守其《使用条款》与《MCP 服务规则》
---
## 许可
代码采用 [MIT License](LICENSE)。服务依赖、商标归属与数据来源见 [NOTICE.md](NOTICE.md)。
连接信息
猜你喜欢
暂无推荐服务器