我把麦当劳官方 MCP 的 35 个工具全测了一遍,几个坑文档里没写

15 阅读5分钟

先说结论:能跑通,能真下单,但和读文档时的想象差得挺远。

我本来只想做个小工具,替自己决定每天早上吃什么。结果一周里有三天在跟自己前一天写的代码较劲——因为文档没写的东西,接口不会告诉你。

下面这些全是真机跑出来的,价格来自 calculate-price,不是我自己算的。


一、返回体不是纯 JSON,是 Markdown 混 JSON

https://mcp.mcd.cn 是无状态 JSON-RPC,Bearer token 认证。但返回体长这样:

## 查询成功

以下是门店菜单...(一大段给模型看的说明文字)

{"success":true,"data":{...}}

直接 json.loads 会炸。我一开始按行找 { 开头的那一行,遇到说明文字里有花括号就又炸了。最后用 raw_decode 从 {"success" 的起点开始解:

idx = text.find('{"success"')
obj, _ = json.JSONDecoder().raw_decode(text[idx:])

这个细节不重要,但它决定了你后面所有调试信息能不能拿到。我在这上面浪费了半天。


二、营养库只给了名字,没给 code

list-nutrition-foods 返回大概 160 条,字段是纯中文商品名 + 热量,没有商品 code。

也就是说,菜单里的商品(有 code)和营养库里的条目(有名字)之间,没有可直接 join 的键。

只能按名字匹配。而按名字匹配就必然踩坑——我第一版用的是"子串包含",结果「北非蛋风味卷」被匹配成了「猪柳蛋麦满分」,热量 387 算成了别人的。后来改成只做变体精确匹配,匹配不上就说没有,宁可缺数据也不要错数据。

宁可返回 null,也别返回一个错的数。 这句话在营养计算里是底线,我是在算错过一次之后才真信的。


三、套餐热量必须拆开算,拆的时候要取 quantity > 0

query-meal-detail 的参数是 code,不是 mealCode(这个我猜错过一次)。

它返回 rounds[].choices[],每一轮是一组可选项。要把套餐热量算对,得取每一轮被选中的那项,查单品热量,再加总。

坑在于"哪一项算默认选中"。结构里有两个字段看起来都像:isDefault 和 quantity。

要取 quantity > 0 的那项,不是 isDefault = 1 的那项。 真机下单之后的订单明细证明了这一点——两者在某些套餐里指向不同商品。

改之前我算出的官方热量覆盖率是 46%,改之后是 30%。也就是说前一个数字虚高了 16 个百分点,全是默认项取错导致的。


四、优惠券不在顶层,在 items[] 里

这一条我错得最彻底。

create-order 的 schema 我读了,顶层没看到 couponId,于是得了个结论:券用不了,只能原价下单。

第二天不死心,把 schema 的 items[] 子结构完整展开,couponId 和 couponCode 就在里面。

实测:19.00 的订单,带券 9.90。

教训不是"要仔细读 schema",是"顶层没有不等于没有"。 嵌套结构里藏字段,这类错误在给模型写工具封装时会反复出现,因为模型看到的是你喂给它的那份摘要,它不知道你漏了什么。


五、加价 ¥0 的默认饮品,往往是最不能改的那个

这条纯粹是意外发现,也是我最想写出来的一条。

早餐套餐默认配一杯「鲜萃冰咖」(code 521327),diffPrice 是 +¥0。看着像白送。

但它的 supportModify 是 false——没有 modification,也就是说它根本没有"去冰"这个选项。

想要一杯能去冰的,得整杯换掉。而换掉之后价格是这样的(同一份猪柳蛋麦满分套餐 9900003458):

饮品方案实付
默认 鲜萃冰咖(无冰量选项)¥25.50
优品豆浆大杯(热饮)¥25.50
可乐中杯 / 无糖可乐中杯 / 雪碧中杯 · 去冰¥24.00
麦咖啡冰美式中杯 · 去冰¥29.50
麦咖啡冰美式中杯 · 标准冰(对照组)¥29.50

最后两行是我的对照组:同一杯冰美式,标准冰和去冰一个价。去冰本身不加价,贵出来的钱是"换饮品"的 diffPrice。

而那个 +¥0 的默认款,是唯一一个你改不了的。

顺便说一句,diffPrice 不是数字,是 "+ ¥4" 这种展示字符串。直接拿去比较会抛 ValueError,得先标准化成"分"。


六、每日下单有硬上限,取消也占额度

返回 code=600039,「今日下单数已经上限」。

我第一天拿真实下单去试接口,四次额度半天用完。而且取消订单不退还额度——这一点没有任何文档提到,是我把额度耗光之后才确认的。

所以如果你也想接这个 MCP,写测试的时候把 --execute 这种开关做出来,默认只跑到 calculate-price。核价是免费的,下单不是。


七、支付只有 15 分钟窗口,这决定了架构

create-order 会返回支付链接,实测到店和外卖都是 15 分钟内有效(预约次日早晨的单,窗口是 09:52→10:07 这种)。

这意味着自动化没法"早上到了再下单"。我最后改成了两段式:

  • 决策前置:前一晚把计划算好、存进数据库,不下单
  • 执行后置:早上定时任务读计划 → 重跑 calculate-price 复核价格 → 偏离超过 10% 或超预算就不下单 → 否则下单并推支付链接

中间那步复核很重要。菜单价和券的状态都会变,前一晚算的价到早上可能已经不对了。


最后

没有自动支付工具,所以这条链路的天花板就是"预填到支付前一步"。我把终点定在这里,不再往下猜。

项目在这:github.com/157991/mcd-…

不是推荐大家去用,是上面这几个坑如果没人写出来,下一个做麦当劳 MCP 的人会一模一样再踩一遍。尤其是第三条和第四条——它们不会报错,只会让你得出一个看起来很合理的错误结论。