首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >麦当劳把 33 个 MCP 接口开放出来了,我用它做了个「请客卡」

麦当劳把 33 个 MCP 接口开放出来了,我用它做了个「请客卡」

原创
作者头像
用户12837321
发布于 2026-10-22 22:39:05
发布于 2026-10-22 22:39:05
10
举报

参加 1024 程序员节 · 麦当劳程序员创意开发大赛的参赛作品记录。 项目:麦麦请客卡 McTreat · https://github.com/hu-Angie/mcd-treat-card


一、先说结论:这 33 个接口里,有一条路没人走

618 之后麦当劳陆续把能力开放了出来,到 2025 年 12 月 25 日正式上线 MCP Server。 官方 README 列了 33 个工具,业务范围是麦乐送点餐、到店取餐、团餐、积分兑换券、活动日历。

把工具摊开看会发现,它把三件事挂到了一起:

代码语言:javascript
复制
读你的会员数据  →  替你写订单  →  把支付链接递回来

这在消费品牌里不常见。星巴克、瑞幸、肯德基的会员体系都还在。

但真正让我决定做这个项目的,是另一个观察。 我把当时已经上榜的 106 个作品按赛道拆了一遍:

赛道

项目数

最高 Star

省钱 / 优惠券 / 比价

24

843

趣味 / 人格 / 身份卡

26

676

综合助手 / 管家

16

592

营养 / 健身

10

636

团餐 / 派对预约

5

703

门店地图 / 时空

5

72

积分 / 商城 / 临期

4

195

前三名清一色在做省钱。这不难理解——「真的能省钱」是最强的转发理由。

于是我退了一步问自己:除了让自己这顿更便宜,这 33 个接口还能干嘛?

答案藏在工具列表里:唯一同时具备「跨人」和「写操作」属性的组合, 只有 delivery-create-address(新增收货地址)+ create-order(建单返回支付链接)这一条。 而当时 106 个作品里,没有人在用它。

那就用它做"请客",而不是"省钱"。


二、它长什么样

用户在 WorkBuddy 里说一句话:

代码语言:javascript
复制
给在上海张江上班的同事点份夜宵,预算 40,他今晚加班改 bug

然后:

代码语言:javascript
复制
你名下还没有可配送地址,我帮你加一个。请给我:省市区 + 详细地址 + 收件人 + 手机号
​
(用户提供后)
​
张江科苑店可配送,给你三套:
​
A|深夜续命组 · ¥38.00
   麦香鱼 1 + 中薯条 1 + 美式咖啡(大)1
   提神扛饿,改完 bug 正好垫一口
​
B|体面饱腹组 · ¥42.00
   板烧鸡腿堡 1 + 麦辣鸡翅 2 块 + 可乐(中)1
   热食送到手还是热的,吃得饱
​
C|轻量夜宵组 · ¥26.00
   麦旋风 1 + 薯条(小)1 + 热牛奶 1
   不重,睡前吃没负担
​
(本单不为你凑满减——送人送得干净比省 8 块重要。)

确认后建单、给支付链接,钱由用户自己扫。最后给一张 1080×1440 的卡片,直接发微信。


三、最难的部分不是写代码,是"不凑单"

这是整个项目我最想讲的一点。

省钱类工具的目标函数是总价最小。所以它们的典型做法是: 满 40 减 8,你只想吃 30 的,它让你凑到 40——多买 10 块钱的东西填满减。

请客不能这么算。

因为收卡的人看得见卡片上的订单明细。 为了用掉一张券,硬塞两个甜筒进去—— 送的人省了 8 块,收的人看到的是"敷衍"。

所以引擎里有一条硬规则:

若用某张券需要加购,只有当加购物本身是合理组成部分(小食/饮料)时才保留该券, 否则弃券,保持组合干净。

同样的逻辑还带来另外两条:

  1. 主食必选 —— 送的是"一顿饭",不是一把零食
  2. 套餐不再加配 —— 三件套/四件套本身已含小食饮料,再加配就是浪费

第 2 条一开始我没想到,是真实菜单数据打醒我的: 114 个菜品里有一大半是"XX 三件套""XX 四件套"这类套餐, 如果照搬"主食 + 小食 + 饮料"的公式往套餐上套,送出去的东西会荒谬地重叠。


四、踩坑记录(文档里一个字都没有)

这部分是我觉得最值钱的。

坑 1:工具实际是 35 个,不是 33 个

官方 README 说 33 个。实测 tools/list 返回 35 个。 文档没收录的有:query-promotions、query-survey-coupon。

坑 2:文档里的工具名是拼错的

文档写的

实际是

query-partystore-date

query-party-store-date

query-partystore-session

query-party-store-session

照着文档抄,必然失败。

坑 3:query-nearby-stores 的 city 和 keyword 必须同时传

代码语言:javascript
复制
# 两个都报 600058「城市名或者关键词不能为空」
{'beType':1,'searchType':2,'city':'上海'}
{'beType':1,'searchType':2,'keyword':'上海'}
​
# 只有这样才能成功
{'beType':1,'searchType':2,'city':'上海','keyword':'上海'}

坑 4:外送场景 beCode 必传,虽然 schema 标着"选填"

入参 schema 里 beCode 是 required: [] 里的,但 description 写着 「得来速(beType=5)/外送(orderType=2)/团餐场景必传,到店自取(beType=1)场景不传」。

只看必填标记就传参,外送会挂。

坑 5:响应根本不是 JSON

这条最要命。

我默认 tools/call 会返回结构化数据,结果拿到的是一整个 Markdown 文档:

代码语言:javascript
复制
每个门店的基本信息按单行展示:
- **门店名称**: data[].storeName
- **门店编号**: data[].storeCode
...
{"success":true,"code":200,"data":{...}}

先给模型看展示指令,再把真 JSON 塞在后面。

更麻烦的是:JSON 的位置不固定。 有的响应有 ## Original Response 标记,有的没有,直接跟在指令后面。

所以我最后没用 split,而是写了括号平衡扫描:

代码语言:javascript
复制
def _scan_json_object(text: str) -> dict | None:
    start = text.find('{"')
    while start >= 0:
        depth = 0
        in_str = False
        esc = False
        for i in range(start, len(text)):
            ...
        start = text.find('{"', start + 1)
    return None

外层还统一裹着 {"success","code","message","traceId","data"}, success:false 时 message 是中文原因,traceId 可追溯。

坑 6:单位不一致

  • query-meals:currentPrice 是字符串、单位「元」,如 "34.5"
  • calculate-price:返回「分」

混用会差 100 倍。

坑 7:会话是无状态的

initialize 不返回 Mcp-Session-Id。每次请求独立,别依赖会话头。


五、一条我自己定的规矩:钱永远由人扫

全流程只有两个写操作:delivery-create-address 和 create-order。

create-order 我把它放在了一道闸门后面:

代码语言:javascript
复制
def create_order(self, confirmed: bool = False):
    if not confirmed:
        raise TreatSafetyError(
            "下单需要用户明确确认。请在用户说出「确认」「下单」等明确指令后再调用。"
        )

Agent 只建单,付款永远是人扫。

这不是技术限制,是刻意的设计。支付一旦交给 Agent, 误下单、比价跑偏、prompt 注入导致的非预期消费,全都会变成平台的责任。 现在的切分很干净:单是 Agent 建的,钱是人付的。


六、关于验证

没有真实可调的环境也能验证传输层。我起了个本地假 MCP 服务, 把握手、会话 ID 透传、JSON/TOON/SSE 三种响应形态、401 中止、429 退避都验了一遍。

最终 43 项离线自测全绿,不消耗任何调用额度,随时可重跑。

代码语言:javascript
复制
python -m tests.test_mcp_client_offline   # 传输层 21 项
python -m tests.test_recommender          # 组单引擎 15 项
python -m tests.test_pipeline             # 端到端 7 项

顺带说一句,这套 mock 测试当场抓出了我三个 bug: _biz_error 缩进掉进类里、_extract_mcd_envelope 漏 self、 以及 initialize 把 401 当普通错误白试 3 个协议版本。


七、写在最后

这个比赛比的表面是代码,实际是传播——排名只认 GitHub Star。

一个 Star 都没有,代码写得再好也等于没参赛。这个我是在报名成功之后才查明白的, 规则里写着「Star数为0的项目不进入排行榜」。

所以如果你看到这里觉得这个项目还有点意思, 帮我点个 Star 吧,这可能是整场比赛里投入产出比最高的一次点击。

https://github.com/hu-Angie/mcd-treat-card


本项目为独立参赛作品,非麦当劳官方产品。文中数据均来自麦当劳中国 MCP 接口返回, 价格与供应状态以官方渠道实时结果为准。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先说结论:这 33 个接口里,有一条路没人走
  • 二、它长什么样
  • 三、最难的部分不是写代码,是"不凑单"
  • 四、踩坑记录(文档里一个字都没有)
    • 坑 1:工具实际是 35 个,不是 33 个
    • 坑 2:文档里的工具名是拼错的
    • 坑 3:query-nearby-stores 的 city 和 keyword 必须同时传
    • 坑 4:外送场景 beCode 必传,虽然 schema 标着"选填"
    • 坑 5:响应根本不是 JSON
    • 坑 6:单位不一致
    • 坑 7:会话是无状态的
  • 五、一条我自己定的规矩:钱永远由人扫
  • 六、关于验证
  • 七、写在最后
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档