📈 GH Trending Explorer 🎲 Surprise me

← all repos

linghuchong6668 / mcd-optimizer

git clone https://github.com/linghuchong6668/mcd-optimizer.git

—

—
stars, 24h
+111
stars, 7 days · #456
+111
stars, 30 days · #2,082
111
★ total · +111% this week
8
forks · 0 open issues

Star history starts 2026-10-20; the chart appears after the second daily snapshot.

LanguagePython
LicenseMIT
Created2026-10-15 (5d ago)
Last push3d ago
Watchers0
OwnerUser

Links

README excerpt
# 麦麦最优解 · Mcd Optimizer
> 在「预算 × 热量 × 人数 × 忌口」多重约束下,求解麦当劳最优下单方案的 Skill。
> 数据全部来自麦当劳 MCP Server 的真实接口——菜单、价格、营养、优惠券一律实时拉取,不做任何硬编码。
> 它还会**先把券领了,再带着券求解**。
---
## 30 秒看懂效果
同一家门店、同一组约束(2 人 / 预算 ¥70 / 人均热量 ≤ 800 kcal),
差别只在于「有没有把券算进去」:
| | 方案 | 实付 | 原价 | 热量 | 性价比 |
| --- | --- | --- | --- | --- | --- |
| 不用券 | 那么大鸡排 ×3 | ¥42.00 | ¥42.00 | 1155 kcal | 27.5 kcal/元 |
| **用券** | **中薯条买一送一(券)×1 + 那么大鸡排 ×2** | **¥41.50** | **¥55.00** | **1348 kcal** | **32.5 kcal/元** |
**少花 ¥0.5,多吃 193 kcal,每元买到的热量高 18%,同时省下 ¥13.5。**
> 数据于 2026-10-15 由麦当劳 MCP 实时接口拉取,含真实领取的优惠券。
---
## 目录
- 它解决什么问题
- 快速开始
- 为什么必须先领券
- 输出示例
- 常用参数
- 更多场景
- 求解原理
- 项目结构
- FAQ
---
## 它解决什么问题
减肥期想吃麦当劳、两个人只有 70 块、团队下午茶要凑够 8 份还不能太咸——
这些本质上是同一个问题:**带约束的组合优化**。
菜单有上百个餐品、套餐还有隐藏的默认组成、卡包里躺着几张不知道能不能用的券,
靠人脑根本算不清。这个项目把它解出来,一次给出三套方案:
| 目标 | 含义 |
| --- | --- |
| 最省钱 | 满足热量下限前提下的最低实付,附人均花费 |
| 最扛饿 | 每元买到的千卡最高(性价比) |
| 最均衡 | 蛋白供能比接近 20%、钠更低、总热量贴近目标 |
---
## 快速开始
纯 Python 标准库,**零依赖**,不用 pip 装任何东西。
 [code] 
把 MCP 接入任意支持 Streamable HTTP 的客户端,示例见 `mcp-config.example.json`
(仅含环境变量占位符,不含任何真实凭据)。
---
## 为什么必须先领券
这是本项目和"随便挑几样"最大的区别。券链路用到三个 Tool:
 [code] 
之所以必须单独处理,是因为实测发现两个反直觉的坑——**这两个坑不修,券就等于白领**:
**坑 1:券对应的商品不在菜单里。**
「中薯条买一送一」是一个券专属商品(编码 `9900012387`),`query-meals` 里根本查不到。
不单独建模,它永远进不了候选池——而它恰恰是最划算的选项(原价 ¥27,凭券 ¥13.5)。
**坑 2:不带券核价会静默丢件。**
把券商品塞进订单但不带券,接口会**悄悄把它丢掉**,只返回其余商品的合计:
 [code] 
照 ¥28 去比较,会得出「不用券更便宜」的荒谬结论——而这单根本下不了。
代码做了三层防护:`price <= 0` 判无效、比对 `productList` 条数发现丢件、
含券商品的方案只认带券那次核价。
---
## 输出示例
 [code] 
 [code] 
### 生成可分享的 HTML 卡片
 [code] 
会输出一张带券信息、性价比、营养指标的方案卡片,浏览器直接打开 `docs/sample.html` 即可看到效果。
---
## 常用参数
| 参数 | 说明 | 默认 |
| --- | --- | --- |
| `--people` | 用餐人数 | 1 |
| `--budget` | 总预算上限(元),0 表示不限 | 0 |
| `--kcal` | 每人热量上限(kcal),0 表示不限 | 0 |
| `--min-kcal` | 每人热量下限,默认取上限的 60% | 自动 |
| `--avoid` | 忌口关键词,逗号分隔 | 空 |
| `--extra` | 除主食外允许的共享附加件数 | 1 |
| `--main` | 主食件数下限 | 等于人数 |
| `--top` | 每种目标输出的方案数 | 1 |
| `--no-claim` | 跳过一键领券,只用现有卡包 | 关闭 |
| `--html` | 输出可视化 HTML 卡片到指定路径 | 无 |
| `--json` | 额外输出结构化结果,便于接自己的前端 | 关闭 |
| `--city` / `--keyword` | 定位门店 | 上海 / 人民广场 |
| `--store-code` | 直接指定门店编码,跳过搜索 | 无 |
| `--be-type` | 1 到店自取,2 麦乐送,5 得来速,6 团餐 | 1 |
---
## 更多场景
 [code] 
---
## 求解原理
MCP 负责提供真实数据与权威核价,**重计算放本地**,两者通过约束求解衔接——
而不是把大模型当计算器反复打接口。
1. **真实数据**:门店、菜单、现价/原价、营养成分全部实时拉取,菜单换了项目不用改。
2. **套餐营养反推**:营养表只有单品维度,菜单里大量是组合餐。命中失败时用
 `query-meal-detail` 拆出套餐默认组成(主食+小食+饮料)逐项累加,
 营养覆盖率从 32% 提到接近全覆盖。
3. **券商品单独建模**:菜单里买不到的券专属商品,带券核价拿到真实到手价后强制入池;
 「买一送一」类券还会把营养翻倍,避免把两份薯条的热量算成一份。
4. **约束建模**:主食件数、预算上限、热量上下限、忌口关键词同时生效,
 避免「最省钱 = 两个冰淇淋」这种废解。
5. **多样性保留**:三个目标各自用自己的代理指标先排一遍、各贡献 1/3 名额再统一核价。
 否则先按价格砍到 N 个,最扛饿和最均衡就只能矮子里拔将军。
6. **按实付复核预算**:菜单价是「起价」,套餐真实核价往往更高
 (实测有组合菜单合计 ¥128、实付 ¥155),所以核价后必须再复核一次预算。
调用量控制在单次 80 次以内,远低于 600 次/分钟的限额;客户端内置 429 指数退避,
营养表落盘缓存 12 小时,领券后查卡包会强制回源避免读到旧缓存。
---
## 项目结构
 [code] 
---
## FAQ
**会帮我自动下单吗?**
不会。项目定位是决策辅助,只用到了查询与核价类 Tool,不用下单类 Tool,
避免自动化下单带来的资金风险。方案出来后你自己确认再下单。
**一键领券是真实操作吗?**
是。`auto-bind-coupons` 会把券真实领进你的卡包。默认开启,不想要加 `--no-claim`。
**为什么算出来的价格跟 App 里看到的不一样?**
所有金额都以 `calculate-price` 的实时返回为准