mcd-experience-atlas
Health Gecti
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 16 GitHub stars
Code Uyari
- network request — Outbound network request in src/build_atlas.py
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
麦当劳体验活动地图 —— 生日派对/亲子读书会/品鉴会在全国281城3664家门店哪里能办,一张地图查完。基于官方MCP只读采集与可视化。
麦当劳体验活动地图 · mcd-experience-atlas
「我在成都,能办麦当劳生日派对吗?哪家店?多少钱?这周六还有位吗?」——一次查询就有答案。
基于麦当劳中国官方 MCP 的只读采集与可视化:生日派对、主题派对、亲子读书会、品鉴会、体验营在全国哪些城市、哪些门店、什么时段可以预约。
🗺️ 在线体验(无需安装,打开即用):https://johnny37.github.io/mcd-experience-atlas/

全国体验活动分布总览 —— 圆点大小 = 可体验的活动款数,右侧为数据洞察(含 2 款全国零城市可约的下架活动、体验丰富度中位数 18 款等独家指标)
一、项目介绍
一句话定位
「我在成都,能办麦当劳生日派对吗?哪家店?多少钱?这周六还有位吗?」——一次查询就有答案。
麦当劳的体验活动(生日派对 / 主题派对 / 品鉴会 / 亲子读书会 / 体验营)分散在 App 的深层路径里,
用户需要逐级确认「城市有没有 → 哪家门店能办 → 哪天可约 → 几点有场 → 还剩多少位」。
本项目把这条链路的数据一次拉通,做成一张可以点开的全国地图。
核心数据(2026-10-13 实测快照)
| 指标 | 数值 |
|---|---|
| 可预约城市 | 281 个(含行政区划码 + 经纬度) |
| 可办活动门店 | 3664 家 |
| 场次样本 | 157 个(覆盖 79 个城市) |
| 体验品类 SPU | 26 款(商城 SPU 合计 50 款) |
| MCP 工具(实测) | 35 个 |
| 餐品营养表 | 160 项 |
| 当月营销活动 | 13 天 / 27 个事件 |
| 门店数 TOP5 城市 | 北京 365 · 上海 219 · 天津 136 · 佛山 118 · 成都 97 |
它解决什么问题
官方 App 里,上述五个问题需要逐级点开、逐个城市试才能回答,且没有任何横向对比视角。
本项目把这些数据一次拉通后,可以直接回答:
- 我所在的城市能办哪些麦当劳体验活动?
- 哪家门店能办?这周还有没有场次?多少钱?几个人起订?
- 全国范围内,哪些活动其实「一个城市都约不了」?
- 同样叫「生日派对」,不同城市能办到的款式差多少?
最后一条是本项目独有的指标——体验丰富度(按可体验 SPU 款数计):
全国中位数 18 款,最少 8 款,最多 23 款(福州 / 龙岩 / 泉州并列第一)。
二、安装方法
环境要求
| 项 | 要求 |
|---|---|
| Python | 3.8 及以上(实测 3.13) |
| 第三方依赖 | 无。全部使用标准库实现 |
| Node / 构建工具 | 不需要 |
| 操作系统 | Windows / macOS / Linux 均可 |
| MCP Token | 仅采集时需要;查看地图和运行测试不需要 |
安装步骤
# 1. 获取代码
git clone https://github.com/johnny37/mcd-experience-atlas.git
cd mcd-experience-atlas
# 2. (可选)验证安装 —— 无需 Token,纯本地运行
python tests/test_toon.py # 19 项
python tests/test_data_pack.py # 20 项
python tests/test_booking_gates.py # 35 项
python tests/test_contest_compliance.py # 24 项
# → 共 98 项,全部通过即说明环境就绪
# 3. 查看地图(无需 Token)
python -m http.server 8000
# 浏览器打开 http://localhost:8000/web/
在线预览(GitHub Pages)
仓库根目录的 index.html 是数据完全内联的单文件版本,
因此可以直接用 GitHub Pages 托管,访客打开链接即可看到地图,无需 clone:
Settings → Pages → Build and deployment → Source: Deploy from a branch
→ Branch: main / (root) → Save
本仓库已启用 GitHub Pages,在线地址:https://johnny37.github.io/mcd-experience-atlas/。
本仓库的 dist/index.html 与根目录 index.html 内容相同,均可单独分享。
配置 MCP Token(仅采集新数据时需要)
Token 在 https://open.mcd.cn/mcp 用手机号登录后申请。本项目按以下优先级读取,不接受也不生成任何本地凭证文件:
- 环境变量
MCD_MCP_TOKEN; - WorkBuddy 的
~/.workbuddy/mcp.json中mcd-mcp连接器已配置的凭证
(在 WorkBuddy 中接入过自定义连接器时自动生效,零额外配置)。
# 方式 A:环境变量
export MCD_MCP_TOKEN="你的 Token"
# 方式 B:在 WorkBuddy 中接入连接器(推荐)
# 左侧边栏 → 连接器 → 自定义连接器 → 配置 MCP,填入:
# { "mcpServers": { "mcd-mcp": {
# "type": "streamablehttp",
# "url": "https://mcp.mcd.cn",
# "headers": { "Authorization": "Bearer YOUR_MCP_TOKEN" } } } }
# 之后直接运行采集脚本即可,无需再设置环境变量。
配置模板见 mcp-config.example.json(仅含 ${MCD_MCP_TOKEN} 占位符)。
作为 Agent Skill 安装
本仓库同时是一个可被任意 MCP 客户端加载的 Agent Skill。将仓库路径加入客户端的技能目录即可,SKILL.md 已按 WorkBuddy 标准格式声明了所需的 9 个只读工具与使用约束。
三、使用示例
示例 1:查看地图(最常用,无需 Token)
三种方式任选:
# A. 本地起服务(数据走 data/atlas.json)
python -m http.server 8000
# 打开 http://localhost:8000/web/
# B. 直接双击根目录的单文件版(数据已内联,无需服务器、无需 Token)
# index.html
# C. 在线访问(零安装):
# https://johnny37.github.io/mcd-experience-atlas/
页面上可以做的事:
- 切换视图:「体验丰富度」看各城市能办多少款活动;「可办门店数」看门店密度;
- 筛选品类:下拉选择「生日类派对 / 主题类派对 / 品鉴会 / 读书会」,
地图即时高亮该品类可约的城市,不可约的缩为灰点; - 点选城市:右侧显示该城全部可办门店、7 天可约日期与每日场次数、场次时段与余位;
- 搜索:输入「东单」可直接定位到麦当劳北京东单北大街餐厅;
- 离线分享:直接双击根目录
index.html或dist/index.html,数据已内联,不需要服务器。
示例 2:采集最新数据(需要 Token)
python src/collect.py # 全量:281 城门店 + 79 城场次抽样
python src/collect.py --deep # 深采:每个城市首店都取日期与场次
python src/collect.py --resume # 中断后续采,跳过已完成的城市
python src/build_atlas.py # 打包成 web/ 使用的 data/atlas.json
实际输出:
[0/7] tools/list → 35 个工具
[1/7] mall-points-products → 50 个 SPU
[2/7] 体验品类城市覆盖 {'读书会': 281, '生日类派对': 281, '主题类派对': 279, '品鉴会': 36} → 去重后 281 城
[3/7] 门店采集完成 → 3664 家
[4/7] 场次抽样 → 79 城 / 157 个场次
[5/7] list-nutrition-foods → 160 项(TOON 已解析)
[6/7] query-lottery-info → 麦麦积分抽奖,10 项奖品,单次 24 积分
[7/7] campaign-calendar → 13 天 / 27 个事件
示例 3:作为 Agent Skill 对话使用
加载本仓库为 Skill 后,可以直接这样问:
用户:我在成都,想给孩子办个麦当劳生日派对,这周六还有位吗?多少钱?
Skill 会依次调用 mall-points-products → query-party-city → query-party-store
→ query-party-store-date → query-party-store-session,回答:
成都可以办 6 款生日派对(开心鸭尊享版、迪士尼疯狂动物城主题尊享版等),
全市有 97 家门店可办,你能体验的活动共 20 款,高于全国中位数(18 款)。以成都高新区大魔方餐厅的采样场次为例,10-14 至 10-22 连续 9 天可约,
这周六(10-17)有 2 个场次:10:30–12:00 和 14:00–15:30,
5~12 人,当前各余 12 位。注意这是「亲子读书会」品类的场次与价格(¥45.00),
生日派对的场次时间与价格需按具体 SPU 再查一次。实际下单请在麦当劳 App 或门店完成。
Skill 内置的硬约束(见 SKILL.md):只读,禁止调用任何写操作工具;
金额单位为分需自行换算;涉日期必须实时调用 now-time-info;不得编造未返回的门店。
示例 4:运行测试
python tests/test_toon.py
python tests/test_data_pack.py
四、地图功能
| 功能 | 说明 |
|---|---|
| 体验丰富度视图 | 圆点大小 = 该城市可体验的活动款数(按 SPU 计)。官方渠道没有这个指标 |
| 可办门店数视图 | 圆点大小 = 该城市可办活动的门店数 |
| 品类筛选 | 下拉或点击覆盖条形图切换品类,地图即时高亮;不可约城市缩为灰点 |
| 7 天场次日历 | 选中城市后显示一周内每日可约场次数量,零场次的日子标灰 |
| 门店搜索与筛选 | 支持按城市名或门店名全局搜索;可按「仅可预约」过滤门店 |
| 数据洞察面板 | 自动算出「全国零城市可约的活动」「覆盖最窄的在售活动」「门店集中度」等结论 |
五、预约功能(带确认闸,默认关闭)
地图与查询全部只读;src/book.py 额外提供了可真实下单的能力,但默认关闭,
只在满足下列全部条件时才创建订单:
- 用户精确说出「确认创建订单」——「试试看」「可以就下单」等模糊措辞一律视为未确认;
- 用户核对过完整回显(活动 / 门店 / 日期 / 场次 / 人数 / 单价 / 预估总额);
- 用户提供的订单指纹与当前参数算出的一致(防止「确认的是 A、下单的是 B」);
- 前置校验通过:人数在
[partyMin, partyMax]内、余位 > 0、shopId == 5、partyType与商品规则一致、满足提前预订天数。
# 第一步:只读,任何时候都安全,可反复运行
python src/book.py --spu-id 8516 --city 南宁市 --store 3570247 \
--date 2026-10-17 --session 36915550 --count 6
# 第二步:写操作,真实创建订单
python src/book.py --spu-id 8516 --city 南宁市 --store 3570247 \
--date 2026-10-17 --session 36915550 --count 6 \
--confirm 确认创建订单 --fingerprint <第一步给出的指纹>
实测回显效果(南宁水晶城餐厅,生日派对):
活动名称 :麦当劳一起开心鸭尊享版生日派对
派对类型 :包场 人数规则:5-12 人(年龄 4-12)
门店 :麦当劳南宁水晶城餐厅(青秀区金湖路61号)
预约日期 :2026-10-17 场次:12:00 – 13:30 余位 12
参与人数 :6 人 单价 ¥138.00/位 预估总额 ¥828.00
订单指纹 :74E14B2F22B1
三条不可妥协的安全约束:
- 绝不重试
party-order-create——若订单已创建但响应未读回,重试会产生重复订单,
这是金钱相关的不可逆操作。mcp_client.call()对写操作工具强制retries=0。 - 默认黑名单——
mcp_client.WRITE_TOOLS默认拦截全部 7 个写操作工具,
须显式allow_write=True才放行,且只有book.py会这么做。 - 审计留痕——每次下单尝试写入
data/booking_audit.log,便于事后核对。
这些约束由 tests/test_booking_gates.py(35 项)锁定,全部离线运行、不发真实请求。
六、地图合规说明
默认视图是纯 SVG 散点图:只绘制城市坐标点与经纬网格,不描绘任何行政边界、不加载任何在线底图瓦片,
因此不涉及领土表示,可安全托管到 GitHub Pages 等任意静态空间。
如果你需要带底图的视图,请自行接入腾讯地图 / 高德 / 百度 / 天地图这四家具备资质的服务商,
并遵守《中华人民共和国测绘法》及相关地图合规要求。请注意:
- 禁止使用 Google Maps、Apple Maps、Bing 海外版、OpenStreetMap 及 Mapbox 等未取得境内测绘资质的来源;
- 前端代码中不要硬编码任何地图 Key,应通过自己的后端代理或域名白控;
- 本项目
data/中的经纬度来源于麦当劳 MCP 返回值,坐标系以官方为准,
接入不同底图前请自行核对是否存在 GCJ-02 / BD-09 偏移。
七、技术要点
这个项目的技术含量不在前端,而在摸清一条没有文档的链路。
1. 链路入口是积分商城,不是「派对工具」
query-party-city 这类工具的入参 spuId 来自 mall-points-products——
也就是说,体验活动预约的入口是积分商城选商品,而不是某个独立的派对查询工具。
官方门户文档完全没有记载 query-party-* 系列,只读门户文档的开发者不会发现这条链路。
完整链路:
mall-points-products → query-party-city → query-party-store
→ query-party-store-date → query-party-store-session
→(party-order-create,写操作,本项目不调用)
2. 接口返回不是纯 JSON
所有 tools/call 返回的是「Markdown 说明 + 内嵌一行原始 JSON」混合体。
不能取「第一行看起来像 JSON 的内容」——说明文档里也有 JSON 示例。
本项目从 {"success" 起用 JSONDecoder.raw_decode 找边界(见 src/mcp_client.py)。
3. 营养表是自研的 TOON 格式
list-nutrition-foods 返回的不是 JSON 数组,而是:
[160]{productName,nutritionDescription,energyKj,energyKcal,protein,fat,carbohydrate,sodium,calcium}:
猪柳麦满分,null,1288,308,16,16,24,781,213
巨无霸,null,2145,513,27,28,44,1010,190
坑在于:在原始 HTTP 响应文本中,行分隔符是两字符序列 \n(反斜杠 + n),不是真实换行,
直接 split('\n') 会得到 0 行。本项目 src/toon.py 对两种形态都做了归一化,并有回归测试锁定。
4. 其他实测确认的接口特性
详见 MCP_INTEGRATION.md 第 5 节的 10 条清单,包括:query-nearby-stores 单次只回 5 家且坐标返回 0.0、available-coupons 不返回 couponId、
鉴权失败返回 403 + 业务错误信封、协议仅支持 ≤2025-06-18 等。
八、目录结构
mcd-experience-atlas/
├── README.md 项目介绍 / 安装 / 使用示例 / 目标用户
├── MCP_INTEGRATION.md 实际调用的 Server/Tool/流程/业务价值(参赛必需)
├── CONTEST_DECLARATION.md 参赛声明(官方原文,未做任何改动)
├── mcp-config.example.json 脱敏配置示例,仅含 ${MCD_MCP_TOKEN} 占位符
├── workbuddy.md 使用 WorkBuddy 开发的对话上下文
├── SKILL.md Agent 技能描述(可被任意 MCP 客户端加载)
├── LICENSE MIT
├── index.html 单文件地图页(数据内联,供 GitHub Pages 根目录托管)
├── data/
│ ├── atlas.json 前端使用的打包数据(build_atlas.py 生成)
│ ├── cities.json 281 城 + 经纬度 + 品类覆盖矩阵
│ ├── stores.json 各城市可办门店全量
│ ├── sessions.json 场次抽样(79 城 / 157 场次)
│ ├── experiences.json 50 个商城 SPU
│ ├── nutrition.json 160 项营养表(TOON 已解析)
│ ├── lottery.json 积分抽奖活动与奖池
│ ├── campaign_calendar.json 当月营销活动日历
│ ├── live_verification.json 通过 WorkBuddy 连接器的全链路实时验证记录
│ ├── tools_snapshot.json tools/list 实测元数据
│ └── tools_reference.md 35 个工具的完整描述与入参 Schema
├── src/
│ ├── mcp_client.py MCP 客户端(混合响应解析、429 退避、写操作黑名单)
│ ├── toon.py TOON 解析器(含字面量 \n 归一化)
│ ├── collect.py 采集脚本(支持 --deep / --resume)
│ ├── build_atlas.py 数据打包 + 单文件版本生成(同时输出根 index.html)
│ └── book.py 体验活动预约:带确认闸的下单流程(默认只读)
├── web/
│ ├── index.html 图谱页面(零依赖)
│ └── atlas.js 投影 + 视图切换 + 品类筛选 + 搜索交互
├── dist/
│ └── index.html 单文件版本(数据内联,可离线双击打开)
├── docs/
│ └── map-overview.png README 首屏截图(在线演示实拍)
└── tests/
├── test_toon.py 19 项:TOON 解析与混合响应提取
├── test_data_pack.py 20 项:数据包结构与自洽性
└── test_contest_compliance.py 24 项:参赛要求逐项合规校验
九、测试
python tests/test_toon.py # 19 项:TOON 解析与混合响应提取
python tests/test_data_pack.py # 20 项:数据包结构与自洽性
python tests/test_booking_gates.py # 35 项:下单确认闸的安全属性
python tests/test_contest_compliance.py # 24 项:参赛要求逐项合规校验
# → 共 98 项,全部通过
三个测试各自锁定一类风险:
test_toon.py——TOON 的字面量\n陷阱、混合响应中「不能误取说明文档里的 JSON 示例」;test_booking_gates.py——锁住「默认只读 + 显式确认 + 写操作不重试」三条安全属性:
只读客户端必须拒绝全部 7 个写操作工具、模糊确认串不构成确认、
订单指纹随任一要素变化、越界人数与零余位被拦截。全部离线运行,不发真实请求。test_data_pack.py——data/atlas.json的计数一致性、城市字段完整性、
覆盖矩阵的cityCodes可解析、门店索引无孤立键、场次价格单位为分;test_contest_compliance.py——按官方参赛要求逐项校验:四个必需文件名未改动、
README 四个必备章节齐全、CONTEST_DECLARATION.md与官方原文 MD5 一致(内容未改动)、mcp-config.example.json仅含环境变量占位符、仓库内无任何真实凭证。
最后一个测试存在的意义:参赛要求里有「文件名不可改动」「内容不可修改」这类硬约束,
一旦日后重构目录或误改文档,它会立即失败,避免到报名截止前才发现问题。
十、采集的健壮性
长任务中断是真实会发生的事(实测遇到过代理 502)。采集脚本为此做了三件事:
- 增量落盘:每 25 个城市写一次
stores.json,中途失败不丢已采数据; - 断点续采:
--resume复用上次已完成的城市,不从头再来; - 网络错误与业务错误分离:连接层故障(
URLError)上抛重试,
服务端错误码(401/429)按语义处理,两者不会混为一谈。
十一、目标用户
- 家长:想给孩子办一场麦当劳生日派对,先确认自己城市有没有、哪家店、什么价位;
- 行政 / HR:筹备团建或品鉴会,需要横向对比可选门店与时段;
- 亲子社群 / 本地生活内容创作者:需要「哪里能办」的确定性答案;
- 麦当劳 MCP 开发者:需要一条完整的体验活动链路参考实现与踩坑记录。
十二、参赛文件清单
按《麦当劳程序员创意开发大赛》要求逐项对照:
| # | 文件 | 官方要求 | 本项目状态 |
|---|---|---|---|
| 1 | README.md |
必须,文件名不可改动;含项目介绍、安装方法、使用示例、目标用户 | ✅ 四项分别为第一、二、三、十一节 |
| 2 | CONTEST_DECLARATION.md |
必须,文件名及内容均不可改动 | ✅ 官方原文件,MD5 与官方仓库一致 |
| 3 | MCP_INTEGRATION.md |
必须,文件名不可改动;说明 MCP Server、Tool、调用流程和业务价值 | ✅ 见该文件第 1~6 节 |
| 4 | 源代码 | 必须,形式不限 | ✅ src/ 4 个 Python 模块 + web/ 前端 + tests/ |
| 5 | workbuddy.md |
参加 WorkBuddy 专项奖励必须 | ✅ 开发过程、决策与安全自查 |
| — | mcp-config.example.json |
活动规则另列,仅允许环境变量占位符 | ✅ 仅含 ${MCD_MCP_TOKEN} |
| — | 项目创建时间 | 2025-12-25 ~ 2026-10-25 | ✅ |
| — | 真实使用麦当劳 MCP | 必须 | ✅ 9 个只读工具,35 个工具清单已实测 |
| — | 真实使用腾讯 WorkBuddy | 拿专项奖励必须 | ✅ 通过 WorkBuddy 连接器开发与验证 |
十三、免责声明
本项目为独立参赛作品,由参赛者独立开发,非麦当劳官方产品,也未获得麦当劳品牌背书。
项目展示的所有数据来源于麦当劳中国 MCP 的只读接口返回,仅供参考;
活动规则、价格、余位及供应状态以麦当劳官方渠道的实时结果为准。
本项目不执行任何下单、领券、抽奖或积分消费操作。
对「麦当劳」「麦麦省」「麦乐送」等名称的使用仅限描述性指代,
不构成对麦当劳及其关联方商标的任何授权,亦不暗示官方背书。
License
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi