1024 想请全组吃麦当劳,结果我先写了个拼单工具

1024 想请全组吃麦当劳,结果我先写了个拼单工具

起因:每次点下午茶,都有一个人在当财务

组里点下午茶基本是这样:群里接龙几十条,总有人被漏掉;门店券怎么用才最便宜,没人算得清;付完钱还得挨个说"你转我 24.9"。1024 程序员节快到了,大概又要来一遍。

刚好麦当劳中国开放了 MCP,也在办程序员节的开发比赛,我就趁机做了个小工具「麦麦拼单」(mcd-team-feast)。先说一句:我不是科班出身,这个项目基本是和 AI 一起 vibe 出来的,下面写的也都是边做边踩到的坑,大佬看了轻拍。

它做的事情很简单:开个团 → 链接丢群里,大家各点各的 → 它自己试券、挑最便宜的方案 → 每人该转多少算到分 → 出一张 git log 风格的账单卡。

接麦当劳 MCP:只读为主,金额单位是"分"

MCP 客户端是自己写的,零依赖,就是按 Streamable HTTP 走一遍 initialize → tools/list → tools/call,带上 Session Id。Token 只从本机环境变量读,不进仓库,网页版完全不需要。

真正用到的基本是只读工具:query-nearby-stores 找门店,query-meals 拉菜单,query-store-coupons 拿可用券,calculate-price 计价,另外 list-nutrition-foods 用来算热量。

几个踩到的点:

  • 金额单位是分 。calculate-price 返回的原价、优惠、实付都是整数分。这反而是好事,我整个项目内部都用分算,最后才转成元显示,浮点误差直接绕过去。
  • 券是挂在商品行上的 。不是"整单传一个券 ID",而是给某一份商品带上 couponId/couponCode。所以每张候选券都要拆出一份对应商品再去计价。
  • 活动价别重复扣 。最早的版本里,我把"菜单价和实付的差额"和券的优惠又加了一遍,结果优惠被算了两次,账单卡上省得特别夸张。后来改成以 calculate-price 的实付为准:各人菜单价之和减实付,就是能分摊的全部优惠,门店活动价单独列一行。
  • 菜单上有些价格要另外买卡才享受(随单购早餐卡之类),拼单场景一律按原价算。

券组合搜索 + 按分分账

券的数量不多,所以没上什么高级算法,就是老实枚举:最多 3 张券、整单券最多 1 张,每种组合都丢给官方 calculate-price 算一遍,取实付最低的。价格以官方为准,我自己不猜优惠规则,这样就不会出现"工具说 30,结账 35"的尴尬。

分账规则是按每人原价占比分摊优惠:每人的优惠用 Math.floor 取整到分,剩下的尾差由发起人兜底,保证每人应付加起来 = 实付,一分不差。这条守恒有单独的测试盯着。

真实跑过一次(只计价,没下单):上海一家门店 5 人下午茶,10 件咖啡甜品小食,原价 ¥159.90 ,门店活动价优惠 ¥19.20,实付 ¥140.70 ,人均 ¥28.14。

账单卡:git log、PR、小票三选一

算完总得有个能发群里的东西。我做了三种主题:git log 提交记录风、GitHub PR 风、普通小票风。卡片是纯函数生成的 SVG,CLI 和网页共用一套,字体做了子集化内嵌进去,导出 PNG 在不同设备上长得一样。中文和等宽字体混排对齐这块折腾了挺久。

PR 风 小票风

卡片底部还有一句梗签名 ,会按时段、人数、省钱比例、热量自动挑一句程序员梗,不满意可以换一句或者自己写。另外 feast blame 会评出今天的"钱包担当"和"热量担当",纯属娱乐。

实时拼单:开团 → 同步 → 锁单

一开始网页版是"链接模式":团的数据全编码在 URL 里,不经过服务器,但每个人改完都得把新链接发回群里,用起来有点累。

后来加了实时房间:团长开团拿到链接和二维码,成员填个昵称就能进来,谁在线、谁选好了、谁还在选,所有人实时看得到,团长还能设截止倒计时。到点了团长一键锁单,大家变成只读,看到最终分账;要改可以再解锁。

实现很朴素:服务端推送用 SSE,客户端操作用普通 POST,服务端是一个零依赖的 Node 文件。房间只存团名、昵称和点了什么,24 小时自动删除;断线会自动重连,同步服务连不上时自动退回链接模式,界面上会标明当前是哪种模式。想自己部署的话,仓库里有通用的部署模板。

做成 MCP Server,但故意不给下单工具

既然是 MCP 比赛,顺手把它自己也做成了一个 MCP Server(stdio),配一个 SKILL.md,在 Agent 里说一句"帮我们组拼一单麦当劳"就能开团、点餐、结算、出卡。

但这里我故意没暴露任何下单工具 。AI 帮你算账没问题,替你花钱还是算了。真要下单只能在终端手动执行 feast order --confirm <确认码>,确认码由门店、餐品和券组合哈希出来,团内容一变就失效,最后也只返回支付链接,付不付钱你自己决定。

几点体会

  1. 算钱的事交给官方接口 。自己模拟优惠规则一定会翻车,能调 calculate-price 就别猜。
  2. 金额全程用整数分,再写一条"总和守恒"的测试,能省很多心。
  3. 和 AI 一起写代码,测试比代码更重要。AI 改起东西来很勇,那个优惠算两遍的 bug 就是这么来的,后来全靠测试兜住。现在一共 30 个用例,全程不碰真实接口。
  4. 能分享的结果比功能列表好传播。大家对算法没什么兴趣,但会把一张好玩的账单卡转到群里。

链接

这是「麦当劳程序员节创意开发大赛」的参赛作品,非官方产品。网页版用的是演示菜单(虚构价格),不用登录、不用 Token 就能完整走一遍流程;命令行也可以一行跑 mock:

bash 复制代码
npx github:Jasonin2099/mcd-team-feast demo --mock --theme all

如果这周你们组也要点下午茶,可以拿去试试。觉得还行的话,顺手点个 Star 我会很开心,有问题或者新主题的点子也欢迎提 issue。

相关推荐
流烟默2 小时前
MCP第 2 篇:Java 本地实战:官方 SDK + stdio + 单能力 Server
人工智能·mcp
用户460381291942 小时前
MCP 给了 Agent 一堆“手”,Skill 才教它怎么干活:两者到底什么关系?
agent·mcp
xrlfreedom3 小时前
MCP 面试高频考点:如何给 Java MCP Server 写可重复执行的集成测试,并兼顾最小权限与审计日志
mcp·mcp server·最小权限与审计日志·java mcp sdk
Danny转行做跨境13 小时前
我给AI写作流水线装了六道发布闸门,带病文出不了门
跨境电商·mcp·sorftime
goehou16 小时前
Agent 接飞书实战:回调验签、事件去重与异步回复(附踩坑)
实战·飞书·agent·mcp·im集成
xrlfreedom17 小时前
MCP 面试高频考点:给 Tool 调用加身份认证、最小权限与 RAG 协作,你能答到第几层?
json schema·mcp·rag 知识库
跨境Jacky1 天前
选品数据采集: MCP 与爬虫的稳定性差异实测
跨境电商·mcp·sorftime
.Bryce.1 天前
三协议合一实战:用MCP+A2A+ANP搭建一个智能研究助手
网络·redis·agent·codex·mcp·a2a·anp
xrlfreedom1 天前
MCP 面试高频考点:把知识库 RAG 检索封装为 Tool,Docker 与结构化输出怎么配合不踩坑
docker·结构化输出·mcp