mcd-saver-strategist: the coupon combo search behind a McDonald's China agent skill
麦当劳省钱点餐助手(麦门精算师)|麦当劳优惠券组合优化 Skill:拉取麦当劳菜单与全部可用优惠券,算出最省的点餐组合,巨无霸套餐 ¥47 → ¥21.9(省 53%)。McDonalds MCP(麦当劳 MCP)coupon optimizer · McDonalds China MCP Server · Agent Skill for WorkBuddy · 麦当劳程序员创意开发大赛参赛作品
At a glance
- What is it?
- A Python agent skill for WorkBuddy that fetches McDonald's China menus and coupons over MCP, then enumerates order combinations to find the cheapest legal basket. Useful as a reference design for deterministic pricing agents, less useful as a production ordering system because its menu and coupon values are demo snapshots.
- Who is it for?
- Adopt this skill if you are building a WorkBuddy agent against the McDonald's China MCP and want coupon handling done by code rather than by model arithmetic. Skip it if you need live production pricing, since menu prices and coupon faces in the repository are demo snapshots that the README says defer to the store response.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Splitting the MCP fetch from the arithmetic
The design line that matters here is the division of labour: data collection goes to the McDonald's China MCP server at mcp.mcd.cn, combination arithmetic goes to scripts/optimizer.py, and the agent handles wording. The README calls this the core insight of the project, and the architecture diagram shows the flow. The agent queries tools such as now-time-info, query-meals and list-nutrition-foods, the MCP response is normalised into a menu/coupons/request.json structure, and the optimizer runs over that structure and returns Top-N solutions with the lowest total price.
Why separate them? Because coupon optimisation is a combinatorial pricing problem. Menus run to dozens of items, a user may hold a dozen coupons, and each coupon carries its own stacking rule. The README is blunt about the reason for the split: large language models get price, discount and stacking arithmetic wrong when they do it in their head. Put the enumeration in Python and the answer stops depending on how the model feels about the prompt. The same division also means the agent never has to re-derive a total, it only has to explain one that the code already produced.
Every non-stackable coupon disqualifies the others
The optimiser takes a deliberately conservative line on coupon conflicts. Any coupon carrying stackable:false is treated as mutually exclusive with every other coupon, and the README states the reason plainly: it guarantees the quoted price never exceeds the amount actually paid. This is the rule that makes a result safe to hand to a customer, and it is also the rule that throws away combinations.
The trade-off is worth naming. A user who holds a free-delivery coupon and a percentage-off coupon may be able to combine them at the counter, but this optimiser will not consider that. The result will be a valid order, priced slightly worse than what a careful human at the till could assemble. The README's own coupon audit example makes the point from the other side: a 'spend 35, save 7' coupon looks cheap on its own, but using it blocks the 1+1 combination and costs 18 extra yuan.
The project accepts that cost on purpose. A pricing assistant that quotes an unavailable stack is worse than one that quotes a safe, slightly higher basket. Whether that is right depends on your tolerance for under-promising.
Four coupon pools must be drained before optimizing
The field observations section records a finding that any implementer of a coupon agent should read first: coupons have to be collected from several places, and querying one source alone produces a worse answer. query-my-coupons returns coupons already in the account. Claimable coupons require auto-bind-coupons to be called before they appear. Store-level coupons live in query-store-coupons. The diagram describes this as a three-way coupon pool plus automatic binding.
Coupons also carry a channel property. Some store coupons were found to be valid for in-store use only, so the optimiser supports pickup, delivery and any, and the delivery mode removes coupons that cannot be used for delivery before searching.
There is also an empty-state trap. order-list returns an empty list for an account with no order history, so anything that leans on past orders needs a fallback. The nutrition side is easier: list-nutrition-foods returns nutrition data for roughly 160 menu items in one call, which is what makes calorie constraints workable without estimation.
Installing the skill and running the offline sample data
Setup has three parts. First, obtain an MCP token by signing in with a phone number on the McDonald's MCP open platform at open.mcd.cn/mcp and activating it in the console. Second, add a custom MCP connector inside WorkBuddy using the contents of mcp-config.example.json, which contains only a Bearer token placeholder for the MCD_MCP_TOKEN environment variable. Third, copy the skill directory into the WorkBuddy user skills folder:
cp -r skills/mcd-saver-strategist ~/.workbuddy/skills/On Windows the target path is %USERPROFILE%\.workbuddy\skills\. A one-line clone covers both the clone and the copy from a fresh checkout:
git clone https://github.com/hujjun/mcd-saver-strategist.git && cp -r mcd-saver-strategist/skills/mcd-saver-strategist ~/.workbuddy/skills/Before you spend a token, run the offline sample data. The bundled scripts work with no MCP connection at all:
cd skills/mcd-saver-strategist/scripts
python optimizer.py --json
python optimizer.py --objective lightest
python optimizer.py --party 3
python optimizer.py --budget 25
python optimizer.py --mode delivery --fee 9
python selftest.py
python bench.pyThe README states that selftest.py runs 46 self-test cases and that CI pairs those with a front-end parity check and a benchmark across menu sizes from 10 to 160 items. Run the self-test after any change to the logic.
Budget, calories and party size as solver inputs
The optimiser accepts the request parameters a caller actually cares about, which is what makes it more than a cheapest-item picker. A budget constraint turns the search into a bounded problem, as in the example where a 30 yuan request returns the best combination that fits inside it. A calorie cap uses the nutrition feed directly, so a 800 calorie request can return something like a grilled chicken burger, a McCafe item and a cone rather than a default burger meal.
The objective flag switches the ranking target between cheapest, balanced, lightest and fewest. The distinction matters because the cheapest basket and the lightest basket are rarely the same basket, and a user who says 'I want to eat well' is not asking for the cheapest thing on the menu.
For groups, party_size changes the problem shape. The agent computes a total and a per-person figure, and applies a single discount to the whole order rather than per head, which the README calls conservative pricing. The team scenario is deliberately conservative so the quoted per-person number cannot be an artefact of counting the same discount several times.
The project also computes a Pareto frontier over price and calories, so a user who suspects the cheap option and the light option cannot both be had can see exactly where the boundary sits.
The coupon audit exposes the small coupon that costs more
Two features sit outside the main search loop, and they address the questions a plain optimiser cannot answer.
The audit mode, run as optimizer.py --audit, evaluates each coupon on three axes: its nominal face value, the actual saving it produces, and its opportunity cost. The third axis is the interesting one, because the README found in live testing that the most expensive coupon is not a fake or a dud. It is a small coupon that crowds out a much larger bundle. Each coupon on its own looks worthwhile, but applying it removes the 1+1 combination from consideration. The audit exists to make that trade-off visible before the user commits.
The gap suggestion uses a subset-sum dynamic program to find the cheapest add-on that pushes the order over a threshold. The worked answer says the order is 7 yuan short of a promotion, that adding a taro pie at 7.5 yuan triggers 12 yuan off, and that the net effect is a saving of 4.5 yuan. The gap helper also reports the net change, which can be negative, so an add-on that only seems useful is labelled as such instead of being quietly recommended.
Sample prices are a snapshot, not live store pricing
This is the limitation that governs every claim the project makes. The README's own truthfulness table marks menu prices and calories as an example snapshot whose structure matches the MCP response but whose values are for demonstration, with the store's live return taking precedence. Coupon content carries the same caveat, since availability depends on the real account state. The claims the table does mark as real are the optimisation logic, the 53 percent saving figure, which the README says is computed by the algorithm on the sample data rather than written by hand, the stacking rule, the MCP data path, and the ordering path.
Ordering deserves a specific note. Price verification happens through calculate-price, then create-order produces a payment link after the user confirms. The repository's own web pages do not place orders, so the online calculator at the project homepage is a replay of the same algorithm for exploration, not a checkout.
In other words, the useful part of this repository is the algorithm and the agent wiring. The prices are demonstration inputs, and a team putting this in front of customers needs a live data contract with the MCP server before the savings numbers mean anything.
MIT licence, contest entry, and the last push date
The licence is MIT and the repository is public. The README carries a contest compliance section that records a self-check against the rules of a McDonald's programmer creative development competition, dated 2026-10-19, stating that the repository was created on 2026-10-09 within the required window, that CONTEST_DECLARATION.md is byte for byte identical to the official text by md5, that mcp-config.example.json contains only an environment variable placeholder, and that a scan of the full git history found no real token or key. The project is explicitly described as a non-official entry, so nobody should read its outputs as statements from McDonald's.
The repository is not archived and the last push was on 2026-10-19, four days before the current date, so the code is moving. It also has no GitHub releases, which means there is no tagged version to pin. The skills directory is copied into place rather than installed from a package index, so upgrading means re-copying the directory and re-running the 46 self-test cases. For a project this young, that is a normal amount of upgrade work, but it is real work and it happens by hand.
Editorial conclusion
Adopt this skill if you are building a WorkBuddy agent against the McDonald's China MCP and want coupon handling done by code rather than by model arithmetic. Skip it if you need live production pricing, since menu prices and coupon faces in the repository are demo snapshots that the README says defer to the store response. Before depending on it, verify three things: that your account can pull all four coupon pools, that the 46 self-test cases and the 17 parity checks still pass against your copy, and that the non-stackable exclusivity rule does not block a combination you actually want.
Frequently asked questions
Does mcd-saver-strategist need a McDonald's MCP token to try it out?
Only for live data. The bundled sample data lets optimizer.py, demo.py, selftest.py and bench.py run offline, and the MCP token is needed for now-time-info, menu, coupon and ordering calls.
How much does the coupon optimizer save on a Big Mac combo in the example?
In the README's example, a Big Mac with medium fries and a drink costs 47.00 yuan when ordered directly, and 21.90 yuan with a 1+1 combination applied, which is 25.10 yuan saved, or 53 percent.
Can mcd-saver-strategist place a McDonald's order for me?
Ordering runs through the MCP server, with calculate-price verifying the basket and create-order producing a payment link after the user confirms. The repository's own web calculator never places orders.
Does the optimizer handle delivery orders and delivery fees?
Yes. In delivery mode it counts the delivery fee in the total price and only considers coupons whose channel allows delivery, so a pickup-only store coupon cannot lower the quoted cost.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hujjun-mcd-saver-strategist)Was this useful?