一个跑在 WorkBuddy 上的麦当劳 Agent Skill:把一顿饭点明白,把优惠用到位,把积分算清楚,把抽奖守规矩。
麦当劳的坑很具体:积分什么时候过期?30 积分到底能换什么?点餐时哪张券真的能用、这一单怎么付最省? 积分不够换礼品,要吃到什么时候?接口说「积分不足」是真的不足吗?抽奖没反应,是没抽成还是扣了分?
McLottery Alchemist 用三层结构回答这些问题:
| 层 | 负责 | 不负责 |
|---|---|---|
| Skill(提示词 + 能力模块) | 理解意图、组织对话、决定调哪个工具、按需加载点餐/券/营养/计划模块 | 算数、记账 |
确定性计算层(src/mclottery) |
到期分类、兑换筛选、成本试算、带券算价比较、热量组合、积分缺口计划、下单金额复核 | 访问网络 |
| MCP 工具(麦当劳官方 33 个) | 门店、菜单、算价、下单、取消、券、积分、抽奖、活动、营养 | 判断该不该买、该不该抽 |
- 想点餐但懒得算的人:想知道「这单用哪张券最省、实付多少」,而不是一堆券名。
- 积分快过期但懒得算的人:想被告知「先换哪个、别拖到月末」。
- 想抽奖但怕被坑的人:希望先看到「单次 24 分、你只有 20.5 分、差 3.5 分」再决定。
- 想换礼品但积分不够的人:需要一张按截止时间、到店频率、预算排出来的计划表。
- 想控制热量的人:按目标热量组合一餐,而不是凭印象点。
- 被接口字段坑过的开发者:需要一份把真实返回、真实坑位写清楚的 MCP 集成参考。
这些不是设想,是接真实 MCP 后实测到的:
point = "0"不等于免费。 积分商城列表里混着生日派对、读书会等付费活动,point是 0、price是 45/58/138 元。直接按「所需积分排序」会推荐一堆要花钱的东西。status = 2(上架)不等于能换。 实测列表里存在downTime已过期的商品,状态仍为上架。必须同时校验upTime / downTime。- 积分是小数,且按月汇总。
availablePoint = 20.5;到期字段只有currentMouthExpirePoint(注意是Mouth)与nextMouthExpirePoint,没有具体到期日期。所以「你的 120 积分将在 10 月 23 日过期」这种话,接口根本支撑不了。 - 能不能抽只看
drawDecision.resourceEligible。availableTimes = 0不代表不能抽(混合规则下会改扣积分),drawTypeText也只是文案。 draw-lottery无入参、一次一抽、无幂等键。 抽 3 次 = 3 次串行调用;超时重试就是重复扣分的风险。- 奖池没有概率。 接口只给奖品名与类型,任何「期望收益」都是编的。
- 点餐全流程:门店 → 菜单 → 详情 → 算价 → 用券 → 六项确认卡 → 下单 → 支付链接 → 查单 → 取消;结果未知时禁止重复下单,先查订单列表。
- 优惠最大化:先领麦麦省券,再用门店券判断可用性,一单选最省;不为凑门槛加购。
- 营养与热量:按目标热量组合 1–3 件餐品,只做算术,不做医疗或减重建议。
- 积分缺口计划:按截止时间、到店频率、预算区间算「够不够、要几周、总共花多少」,同时给替代路径。
- 积分体检:余额、本月/下月将过期、已过期,全部带数据来源与精度声明。
- 兑换筛选与预检:只留「状态上架 + 积分 > 0 + 在兑换窗口内」的商品,被排除的每个都给出原因;下单前校验 skuId、实物地址、积分 + 现金双金额,并说明「待支付」而非「兑换成功」。
- 三类方案:A 止损 / B 稳健兑换 / C 娱乐抽奖;不可执行的方案直接写明为什么,不凑数。
- 抽奖守卫:意图 → 明确授权 → 单次执行 → 未知状态冻结 → 对账解除,台账落盘、可审计。
- 活动与福利:当月活动日历、主题活动四级预约链、可领券,只推进行中与即将开始。
- MCti 人格 / 娱乐运势:八种吃堡人格与今日签文,纯娱乐,且明确「不影响中奖概率」。
- 中奖追踪:只展示接口返回的状态与提醒文案,不补期限。
- Agent 工作台:口令启动「麦门欧气补给站」,十三个面板覆盖点餐、福利、营养、计划、账户、兑换、活动、奖品与娱乐;宿主支持 UI Bridge 时渲染,不支持就降级成文字摘要。
- 单文件 Demo:不联网、不扣分、不需要 Token,打开就能点着体验上述全部面板。
-
打开 WorkBuddy → 左侧栏【专家·技能·连接器】→【连接器】→ 右上角【自定义连接器】→【配置MCP】。
-
在手动配置页填入(把
${MCD_MCP_TOKEN}换成你自己的 Token):{ "mcpServers": { "mcd-mcp": { "type": "streamablehttp", "url": "https://mcp.mcd.cn", "headers": { "Authorization": "Bearer ${MCD_MCP_TOKEN}" } } } } -
保存后回到【自定义连接器】启用
mcd-mcp。 -
把
skills/mclottery-alchemist/整个目录放进你的技能目录(项目级.workbuddy/skills/,或用户级~/.workbuddy/skills/)。 -
如需计算和真实抽奖,在 Python 3.10+ 环境执行
python -m pip install -e <本仓库绝对路径>,确认mclottery --help可运行。仅复制 Skill 支持只读查询与娱乐互动,不能运行守卫。默认台账为~/.mclottery/ledger.jsonl;旧版相对路径台账需先核实未结算状态并迁移,不能以新建空台账绕过冻结。 -
直接对话:「我要吃麦当劳」「这单用哪张券最省」「帮我配一餐 700 卡」「积分不够换礼盒,帮我排个计划」「我积分怎么样」「现在有什么抽奖」。
Token 申请:麦当劳 MCP 站点右上角登录 → 控制台 → 激活,阅读并同意服务协议后复制。 本仓库不含任何真实 Token,
mcp-config.example.json只有占位符。
git clone https://github.com/Bryce-border/-.git mclottery-alchemist
cd mclottery-alchemist
python run.py --help # Python 3.10+,零第三方依赖可选安装为命令:
pip install -e . # 之后可直接用 mclottery 命令不想先配 Token、也不想读代码?直接打开随 Skill 附带的单文件工作台:
skills/mclottery-alchemist/assets/demo.html
双击用浏览器打开即可(也可以交给 WorkBuddy 直接预览)。单文件、零依赖、不联网、不调用 MCP、不需要 MCP Token。
在 Agent 里说出下面任一句,也可以启动同一个工作台(是否渲染成面板取决于宿主是否支持 UI Bridge):
启动麦门炼金台 · 打开麦门欧气补给站 · 麦门积分管家,开工 · 我要吃麦当劳
十三个面板:
| 面板 | 能体验什么 | 背后用的工具 |
|---|---|---|
| 炼金总览 | 能力介绍、今日活动播报、账户摘要、到期风险、快捷入口 | 账户 + 活动 + 券(只读) |
| 点餐台 | 选门店/取餐方式、菜单加购、带券算价比较试算、六项确认卡 | 门店、菜单、算价、下单(意图) |
| 活动日历 | 进行中/即将开始的活动、主题活动四级预约链 | campaign-calendar、query-party-* |
| 福利中心 | 可领券、门槛与带券算价比较、领券授权说明 | available-coupons、query-store-coupons |
| 营养实验室 | 目标热量输入、1–3 件组合、蛋白质/脂肪/碳水/钠汇总 | list-nutrition-foods + 本地算术 |
| 积分计划 | 缺口、每次约得、预计周期、预计总支出、逐周进度 | query-my-account + 商城 + 本地计算 |
| 积分体检站 | 余额与月度到期、固定成本试算、规划入口 | query-my-account |
| 积分兑换研究所 | 搜索、筛选、候选与排除原因、商品详情 | mall-points-products、mall-product-detail |
| 麦麦抽奖活动站 | 状态、成本、drawDecision 资格、奖池、前置核验、模拟仪式 |
query-lottery-info + 账户 |
| 中奖收藏柜 / 我的麦享卡包 | 奖品状态与接口提醒、卡券与可用性边界 | query-my-prizes、query-my-coupons |
| MCti 人格实验室 | 八型人格、逐题/快测、多选、跳题、自选、改答、分享、搭子建议 | 纯本地,不查账户 |
| 今日麦气 | 1–5 星麦签、宜/忌、签文、幸运单品灵感 | 纯本地,不做中奖预测 |
数据口径:页面默认是示例数据,只有宿主真正推送
mclottery:state后才可能变成「实时数据」。页里的余额、价格、消耗、奖品、概率都是演的,不会扣任何积分。 页面没有「直接下单 / 直接支付 / 直接抽奖 / 直接领券」按钮:有副作用的动作只产生意图,必须回到对话完成成本说明、确认与授权。 宿主不支持内嵌时,Skill 会降级成文字摘要,不会假装已经打开面板。UI 契约见agent-ui-integration.md,页面/意图映射见demo-feature-map.md。
真实能力请在对话里用:「我积分多少」「现在有什么抽奖」「积分快过期了怎么办」。
你:我积分怎么样,快过期了吗
炼金术士:账本看完了—— 可用 20.5 积分(累计 34,已过期 13.5)。 本月将过期 0,下月将过期 0,暂时没有到期风险。 一句实话:接口只给「按月汇总」的到期数,没有具体到某一天,所以我没法告诉你「10 月 23 日过期多少」。 想花的话,目前门槛最低的可兑换项要 50 积分,还差 29.5 分。
你:直接帮我抽一次
炼金术士:先对账再动手——活动「麦麦积分抽奖」,单次 24 积分,你的可用 20.5,差 3.5 分,服务端也标了「积分不足」。 这次不抽,也不替你「试试看」。等积分够了再说,抽奖不会跑。
python run.py plan \
--account tests/fixtures/account_expiring.json \
--products tests/fixtures/products_mixed.json \
--activity tests/fixtures/lottery_running_ok.json \
--now "2026-10-19 12:00:00"—— 积分盘点 ——
· 本月将过期:120(接口仅返回月度汇总)
· 下月将过期:80(接口仅返回月度汇总)
· 提醒窗口为产品侧阈值,不是麦当劳官方积分有效期政策;实际有效期以麦当劳官方渠道为准。
【方案 A】优先止损(防止积分作废)
· 优先处理即将过期的 200 积分(本月 120 + 下月 80)
· 可兑换:6.9元可乐麦炫酷(50 积分,类目:到店专用)
...
【方案 B】稳健兑换(确定性优先)
· 按「用途 + 兑换门槛」选择,不按门槛低就认定性价比高
【方案 C】娱乐抽奖(体验随机结果)
· 麦麦积分抽奖:单次 24 积分
· 只在你明确同意的次数内执行,抽完即止,不追加
注:抽奖是概率事件,接口未返回中奖概率,任何「期望收益」都不成立。
python run.py guard propose --activity-code dtx2 --activity-name 麦麦积分抽奖 --draws 1 --cost 24 --preflight-ok
python run.py guard authorize --intent-id intent_xxx --explicit # 没有 --explicit 会被拒
python run.py guard begin --auth-id auth_xxx # 登记一次执行
python run.py guard settle --attempt-id draw_xxx --result draw_timeout.json
python run.py guard status # 未知状态 → 冻结,禁止重试你:今天欧气怎么样
炼金术士:今日干饭运势:★★★☆☆ 麦门签文:薯条趁热,积分趁早,欧气随缘,快乐为王。 今日宜:先看一眼积分有效期。 今日忌:为了证明自己是欧皇而连抽三次。 (纯娱乐,跟真实中奖概率没关系,我也不会去动你的账户。)
你:我要吃麦当劳,公司附近有什么店?帮我点个巨无霸套餐,用最省的券。
管家:先确认一下:你要到店自取还是外送?我查到 2 家店:人民广场店(320m,营业中)、南京东路店(860m)。
你:到店自取,人民广场店。
管家: 【下单确认】 门店:人民广场店(S-DEMO-01) 取餐方式:到店自取 商品:巨无霸 ×1 ¥25.5|中薯条 ×1 ¥12 优惠:满 30 减 5(-¥5) 配送费:¥0 实付:¥32.5(calculate-price 返回) 确认后我创建订单,支付在官方页面完成,我不代付。
你:确认。
管家:订单已创建:
ORD20261021001,待支付。支付链接:<接口返回的链接>。未支付订单可能自动取消,具体时限以订单页为准。
你:帮我配一餐 700 大卡左右的。
管家:按
list-nutrition-foods的默认份数据,最接近的是: 巨无霸(550 kcal)+ 中杯可乐(150 kcal)= 700 kcal 蛋白质 25g|脂肪 30g|碳水 78g|钠 910mg 偏差 0;另有 1 个餐品缺热量字段,没算进来(麦旋风)。 这是热量搭配,不是营养处方;特殊人群建议咨询专业人士。
你:我想换那个 3000 分的礼盒,现在只有 2350 分,帮我看看还来得及吗?
管家:先确认三件事:你大概每周去几次、单次预算多少、想在什么时候之前换到?
你:每周 2 次,一顿 25–40,年底前。
管家: 缺口 650 分。按你给的规则(1 元 = 1 分,单次取中位 32.5 元): 每次约 32.5 分,需要约 20 次,约 10 周。 距 12 月 31 日约 10.1 周 → 刚好能达成,预计总支出约 ¥650。 提醒:积分按规则到账、礼盒在截止前仍有库存,这两个前提不成立就要重算。 如果不想花这么多,也可以换 2000 分以内的目标,或用现有积分直接换小件。
用户
│
▼
WorkBuddy Agent ── 加载 ──▶ skills/mclottery-alchemist/SKILL.md
│ │ 意图路由 / 授权红线 / 话术边界
│ ▼
│ references/*.md(工具契约、人格、算法)
│
├── 只读查询 ──▶ mcd-mcp(门店、菜单、券、积分、活动、营养 …)
│
├── 需要算数 ──▶ python run.py <cmd> ──▶ src/mclottery(纯函数,无网络)
│ │
│ ├── nutrition / mealplan / coupon / order
│ └── guard:ledger.jsonl(授权 / 执行 / 对账)
│
└── 想先体验 ──▶ assets/demo.html(十三面板工作台,默认示例数据)
│
└── 宿主支持 UI 时 ──▶ mclottery:state / agent-intent 桥接
(不支持则降级为文字摘要,不假装打开)
.
├── README.md # 本文件
├── CONTEST_DECLARATION.md # 参赛声明(官方原文,未改动)
├── MCP_INTEGRATION.md # MCP Server / Tool / 调用流程 / 业务价值
├── mcp-config.example.json # 脱敏配置示例(仅环境变量占位符)
├── workbuddy.md # WorkBuddy 开发对话上下文(专项奖励核验用)
├── run.py # 零安装 CLI 入口
├── pyproject.toml
├── skills/mclottery-alchemist/
│ ├── SKILL.md
│ ├── assets/demo.html # 单文件离线演示页(可直接打开体验)
│ ├── references/
│ │ ├── tool-workflows.md # 33 个工具契约与调用链
│ │ ├── ordering-workflow.md # 点餐/外送/下单/取消全流程
│ │ ├── coupon-strategy.md # 领券与一单最省
│ │ ├── nutrition-health.md # 热量与营养边界
│ │ ├── points-meal-plan.md # 积分缺口 → 饮食计划
│ │ ├── campaigns.md # 活动日历与福利推荐
│ │ ├── points-calculation.md mcti-personalities.md output-templates.md
│ │ └── agent-ui-integration.md demo-feature-map.md
│ └── tests/{intent-routing,mcti-experience,safety-cases,regression-cases,demo-acceptance}.md
├── src/mclottery/
│ ├── models.py expiry.py value.py
│ ├── lottery.py guard.py plan.py cli.py
│ ├── nutrition.py mealplan.py coupon.py order.py redemption.py
└── tests/ # 170 个单元测试 + fixtures
python -m unittest discover -s tests -v # 170 tests, OK
pytest -q # 可选,已配置 pythonpath=src覆盖:积分充足/不足/临期、活动结束/未登录、商品售罄/下架/预热/窗口过期/付费活动、 中奖/未中奖/超时未知、授权缺失、额度耗尽、单日上限、台账持久化与脱敏、 热量组合与缺字段排除、积分缺口与零频率、券门槛/封顶/不叠加、订单金额复核与重复提交指纹、 兑换预检(实物缺地址/积分不足/现金+积分)与「待支付」返回解析。
draw-lottery没有幂等键。守卫的防重复只能做到「本地台账 + 未知即冻结」,无法阻止在另一台设备上同时操作。请勿多端并发抽奖。create-order同样没有幂等键。本地只做购物车指纹提示,不能阻止其他设备重复下单;结果未知时必须先查order-list。- 接口不返回中奖概率,因此期望价值功能默认锁死,只输出定性结论。
- 接口不返回分批到期明细,到期风险只能到「月」粒度。
- 接口不返回积分获取速度(消费 1 元得多少分),积分计划的到账速度必须由官方规则或用户输入提供。
- 不提供商品参考价值,因此不做「元/积分」性价比排名。
- 点餐/券/营养域已按官方文档(2026-10-21)对齐字段,但未做真实网络联调;
party-session.price与party-order-create.amount的单位仍待确认。 - 券接口不返回门槛与面额:门店券只能判断适用性,券后金额必须由
calculate-price计算;麦麦省与卡包是 Markdown 文本。 - 算价单位是分、下单单位是元,代码已分别处理,调用时不要混用。
- 本 Skill 只影响对话与本地台账,不能替服务端做风控、库存或支付校验。
- 本项目为麦当劳程序员节创意开发大赛参赛作品,由参赛者独立开发,非麦当劳官方产品。
- 项目输出仅供参考,不构成营养、医疗或投资建议;餐品信息、价格与供应状态以麦当劳官方渠道为准。
- 项目不含真实 Token、密钥、账号凭证或他人个人信息;配置文件仅使用环境变量占位符。
- 抽奖内容为娱乐性记录与流程协助,不承诺中奖,不鼓励追加投入,不构成任何赌博性引导。
MIT
默认三轮情景题,也支持一次答完。每题覆盖不同偏好,八种人格都有明确计分依据;支持改答、跳题、打平认领和重测。结果卡引用真实答案,附专属宣言、娱乐搭配和积分建议。可继续生成分享文案或搭子互动,全程不自动查询账户或抽奖。
开发过程记录见 workbuddy.md。