kfc-cn-mcp
README.md
# kfc-cn-mcp
肯德基中国([order.kfc.com.cn](https://order.kfc.com.cn/preorder-taro/menu?label=preorder))点餐 MCP 服务器,**为 Hermes Agent 适配**,同时兼容任何支持 stdio 的 MCP 客户端(Claude Desktop、Cursor、Cherry Studio 等)。
它把肯德基中国 H5 点餐的真实接口封装成一组工具:找门店 → 看菜单 → 加购物车 → 结算预览 → 提交订单。日常点餐直接走官方 H5 的 JSON 接口(含 KBS 签名与字段加密),无需截图或置顶窗口;可选的账号连接只在首次登录时打开官方网页,由用户自行操作。
> 本项目参考了 [markswendsen-code/mcp-kfc](https://github.com/markswendsen-code/mcp-kfc) 的工具形态(search_menu / add_to_cart / view_cart / checkout …)。中国版使用重写的 HTTP 客户端;已实测登录账号提交的待支付订单可在同一账号的肯德基 App 中看到,订单状态和支付以官方页面为准。
---
## 1. 能力与边界
### 已实现
| 工具 | 作用 |
| --- | --- |
| `find_stores` | 按关键词 + 城市国标码,或经纬度找门店,返回 `storeCode` |
| `select_store` | 选定门店并加载该店实时菜单;初始化时按目标门店坐标定位,必要时走切店流程 |
| `get_menu` | 查看分类/某个分类下的餐品(`linkId`、价格、是否套餐) |
| `search_menu` | 按中文名/描述搜索餐品 |
| `get_item` | 商品详情 + 套餐可选内容(`comboRounds`)+ 规格 |
| `cart_add` | 加购;套餐可不传 `selections` 自动按最少份数选默认项 |
| `cart_set_quantity` | 修改某行数量(0 = 删除) |
| `cart_remove` | 删除某行 |
| `cart_clear` | 清空购物车 |
| `cart_view` | 查看购物车与合计 |
| `preview_order` | 服务端结算预校验,返回金额、门店、账号登录状态 `accountLoggedIn` 和 `previewToken` |
| `place_order` | 提交真实订单请求;必须 `confirm=true`、`previewToken`、用户确认的总价和手机号 |
| `resolve_uncertain_submission` | 用户在官方渠道确认上次订单未创建、已关闭或已支付后,解除重试保护 |
| `order_status` | 优先查询肯德基预点餐订单详情的状态;不返回详情中的手机号等个人信息 |
| `session_status` | 查看当前门店/购物车/会话状态,便于排障 |
提交结果不明时,`place_order` 返回 `outcomeUnknown: true` 和脱敏的 `error.details`;进入收银或结果不明时都会持久化待核实标记,之后的预览和提交会被拦截。先由用户在肯德基官方渠道核对,确认上次订单未创建、已关闭或已支付后,再调用 `resolve_uncertain_submission`。提交请求不会自动重试,预览令牌在发送前即失效。`code: 0` 或购物车编号不能单独证明订单可支付。常见手机号、地址、凭证和链接会被遮盖,未识别的敏感字段仍可能存在,分享诊断前请自行检查。
### 明确不做
- **不处理支付**:接口返回收银状态时,工具返回订单编号和实验性 H5 详情链接。免登录订单能否显示在 App、链接能否跨会话付款尚未验证;本 MCP 不接触支付密码、验证码或银行卡。
- **不保存账号密码或短信验证码**:默认免登录点餐,也可按下文连接会员账号。会员价、优惠券、大神卡、积分的专门功能未接入。
- **不绕过风控**:若肯德基触发人机验证(geetest),工具会返回提示,需要用餐人在 App/H5 内完成。
- **不做预约时段**:默认“尽快取餐”。H5 的「预约」选时间尚未封装(接口已具备,后续可加)。
---
## 2. 环境要求
- Node.js **≥ 18.17**(建议 20/22/24)
- 可选账号登录:Windows 和已安装的 Microsoft Edge;登录态使用当前 Windows 用户的 DPAPI 加密保存
- 能直连 `order.kfc.com.cn`、`store.kfc.com.cn`(如公司网络有代理,请给 Hermes 进程配置 `HTTPS_PROXY`)
- Hermes Agent(标准安装已含 MCP 支持)
---
## 3. 安装与构建
```powershell
git clone <this-repo> kfc-cn-mcp
cd kfc-cn-mcp
npm install
npm run build
```
构建产物是 `dist/index.js`,Hermes 直接用 `node` 启动它,不需要常驻服务。
自检(会真实访问肯德基接口,只读 + 加购/清空购物车,**不会下单**):
```powershell
npm run smoke
```
成功时最后一行是 `SMOKE OK`。
离线提交、购物车和账号保护测试:`npm run test:order`、`npm run test:account`。独立临时会话的真实菜单、加购、预览和清空测试:`node scripts/integration-readonly-test.mjs`,不创建订单。可用 `KFC_TEST_STORE_KEYWORD`、`KFC_TEST_CITY_CODE` 和 `KFC_TEST_STORE_NAME` 指定测试门店。
命令行 MCP 客户端:设置 `KFC_STATE_DIR` 后,将工具参数 JSON 通过 stdin 传给 `node scripts/call-mcp.mjs <工具名>`;使用独立状态目录可避免干扰 Hermes 购物车。
### 可选:连接肯德基账号(Windows)
使用**新的专用状态目录**;不要覆盖已有免登录购物车。先设置目录并启动登录:
```powershell
$env:KFC_STATE_DIR = "$env:USERPROFILE\.kfc-cn-account"
npm run account:login
```
在打开的肯德基官方网页中,自行登录与手机 App 相同的会员账号;短信验证码只填写在官方网页。连接后,`account-auth.dpapi` 和 `account-session.dpapi` 由当前 Windows 用户的 DPAPI 加密保存,切勿上传或共享。日常 MCP 点餐不需要再次打开网页;登录失效后,在另一个新目录重新连接,再把 MCP 的 `KFC_STATE_DIR` 指向该目录。`session_status.account.authenticated` 表示本地已绑定;结算预览的 `accountLoggedIn` 是服务端当次返回的登录状态。账号模式若无法确认登录会停止预览,不会自动降级为免登录。
此前通过免登录创建的订单不一定会自动关联到会员账号。绑定登录态已通过真实菜单、加购、预览和清空测试;一次登录后的真实待支付订单已由用户确认出现在同一账号的 App 中。支付仍由用户在官方渠道自行完成。
---
## 4. 接入 Hermes
### 4.1 写入 `~/.hermes/config.yaml`
把下面的片段合并进 `mcp_servers`(Windows 示例,路径改成你的实际路径):
```yaml
mcp_servers:
kfc_cn:
command: "node"
args:
- "C:/Users/你的用户名/kfc-cn-mcp/dist/index.js"
env:
KFC_STATE_DIR: "C:/Users/你的用户名/.kfc-cn-account"
# 默认城市:上海 310100;北京 110100;深圳 440300;广州 440100
KFC_CITY_CODE: "310100"
# 默认坐标(用于“附近门店”推荐,可改成你的常用位置)
KFC_LATITUDE: "31.2304"
KFC_LONGITUDE: "121.4737"
timeout: 60
connect_timeout: 20
tools:
include:
- find_stores
- select_store
- get_menu
- search_menu
- get_item
- cart_add
- cart_set_quantity
- cart_remove
- cart_clear
- cart_view
- preview_order
- place_order
- resolve_uncertain_submission
- order_status
- session_status
prompts: false
resources: false
```
完整可复制版本见 [`hermes/config.snippet.yaml`](hermes/config.snippet.yaml)。
### 4.2 或者用 `hermes mcp add`
```powershell
hermes mcp add kfc_cn --command node --args "C:\path\to\kfc-cn-mcp\dist\index.js"
```
然后编辑 `~/.hermes/config.yaml` 补上 `env` 和 `tools.include`(`hermes mcp add` 不一定支持一次写入全部字段)。
### 4.3 验证
```powershell
hermes mcp test kfc_cn
```
应能看到 15 个工具。然后在 Hermes 会话里:
```text
/reload-mcp
```
问一句:「用 kfc_cn 的工具查一下上海淮海路附近的肯德基」。
Hermes 注册后的工具名形如:
```text
mcp__kfc_cn__find_stores
mcp__kfc_cn__select_store
mcp__kfc_cn__search_menu
mcp__kfc_cn__cart_add
mcp__kfc_cn__preview_order
mcp__kfc_cn__place_order
...
```
### 4.4 收紧权限(推荐)
如果只想让 Hermes 查菜单、不想让它下单,把 `place_order` 从 `tools.include` 里删掉即可;购物车工具可以保留。
Hermes 支持 `tools.exclude`,也可以反过来只排除危险工具:
```yaml
tools:
exclude: [place_order]
```
### 4.5 装配套 Skill(可选)
`hermes/skills/kfc-cn-ordering/SKILL.md` 是一份 Hermes Skill,教模型按正确顺序调用工具、什么时候必须停下来让用户确认。复制到 Hermes 技能目录:
```powershell
# Windows
Copy-Item -Recurse hermes\skills\kfc-cn-ordering "$env:USERPROFILE\.hermes\skills\"
# macOS / Linux
mkdir -p ~/.hermes/skills
cp -r hermes/skills/kfc-cn-ordering ~/.hermes/skills/
```
之后在 Hermes 里输入 `/kfc-cn-ordering` 或直接说“帮我点肯德基”,它会按 Skill 的流程执行。
---
## 5. 使用示例
```text
你:帮我看看上海淮海路附近有哪些肯德基。
AI:(find_stores keyword=淮海路 cityCode=310100)
附近有「淮海路餐厅 SH1146」「淮海路新金钟餐厅 SH2103」…
你:选淮海路餐厅,看看有什么汉堡。
AI:(select_store storeCode=SH1146 → get_menu category=汉堡卷)
培根鸡腿肉霸堡 ¥24.90、泰夯Q虾鸡腿肉霸堡 ¥24.90…
你:来一个培根鸡腿肉霸堡,再加一个特大号鸡腿桶。
AI:(cart_add → cart_view)
购物车:培根鸡腿肉霸堡 ×1、S特大号鸡腿桶 ×1,合计 ¥64.80
AI:(preview_order)请确认门店、餐品、数量、合计 ¥64.80、堂食/外带及取餐手机号。预览不保证服务端锁价。
你:确认,手机号 138****8000,堂食。
AI:(place_order confirm=true phone=… previewToken=… expectedTotalCents=6480)
接口返回收银状态,订单号 1793…,合计 ¥64.80。
请查看返回的实验性订单详情链接,并在官方页面自行核对及支付。
```
### 套餐选择
`get_item` 会返回:
```json
{
"comboRounds": [
{
"roundId": "1",
"name": "小食",
"minCount": 2,
"maxCount": 2,
"items": [{ "linkId": "100129945", "name": "特大号鸡腿1个", "maxCount": 2 }]
}
]
}
```
加购时可以显式指定:
```json
{
"items": [
{
"linkId": "100129947",
"quantity": 1,
"selections": { "1": [{ "linkId": "100129945", "quantity": 2 }] }
}
]
}
```
不传 `selections` 时,会按每轮 `minCount` 自动选第一个可选项(与 H5 默认行为一致)。
---
## 6. 环境变量
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `KFC_STATE_DIR` | `~/.kfc-cn-mcp` | 会话 cookie、sessionId、菜单缓存、购物车状态目录 |
| `KFC_CITY_CODE` | `310100` | 默认城市国标码(`find_stores` 未传 `cityCode` 时使用) |
| `KFC_LATITUDE` / `KFC_LONGITUDE` | `31.2304` / `121.4737` | 默认坐标(上海人民广场),用于附近门店与切换门店时的距离计算 |
| `KFC_HTTP_TIMEOUT_MS` | `20000` | 单次接口超时 |
城市国标码示例:北京 `110100`、上海 `310100`、广州 `440100`、深圳 `440300`、杭州 `330100`、成都 `510100`、南京 `320100`、武汉 `420100`。
---
## 7. 状态与并发
- 状态保存在 `KFC_STATE_DIR/session.json`(cookie + sessionId + 购物车)与 `menu.json`(菜单缓存,30 分钟有效)。
- 同一时间只应有一个会话操作同一个 `KFC_STATE_DIR`,也不要并发操作同一个会话的购物车;不同进程之间没有锁,否则状态和购物车可能互相覆盖。多开时给每个进程设置不同的 `KFC_STATE_DIR`。
- `session.json` 里有肯德基会话 cookie,属于敏感文件;不要提交到 Git(项目已 `.gitignore`)。
---
## 8. 故障排查
| 现象 | 原因/处理 |
| --- | --- |
| `无法连接肯德基接口 … ECONNRESET / ETIMEDOUT` | 网络或代理问题。给 Hermes 配 `HTTPS_PROXY`,或换网络。 |
| `初始化门店菜单失败:参数错误` | 接口/版本变化,或门店不支持自取。先 `find_stores` 换门店。 |
| `会话已过期` | 已自动重建会话并重试;若仍失败,重新 `select_store`。 |
| `商品校验失败,可能已售罄` | 菜单缓存过期,`get_menu(refresh=true)` 后重新加购。 |
| `触发人机验证` | 肯德基风控,需在 App/H5 人工完成,MCP 无法绕过。 |
| `hermes mcp test` 失败 | 检查 `node` 是否在 PATH、`args` 是否是绝对路径、`dist/index.js` 是否已构建。 |
| 工具列表里没有 `place_order` | 被 `tools.include/exclude` 过滤了。 |
| 接口返回收银状态但没有支付入口 | 尝试返回的实验性 H5 订单详情链接;该链接跨会话可用性未验证。若看不到订单,先向官方渠道核实,勿重复提交。 |
---
## 9. 实现说明(给维护者)
详细接口笔记见 [`docs/API-NOTES.md`](docs/API-NOTES.md)。核心点:
- H5 入口:`https://order.kfc.com.cn/preorder-taro/menu`
- 预订单接口:`https://order.kfc.com.cn/preorder-portal`
- 门店接口:`https://order.kfc.com.cn/store-portal`
- 每个请求带 `kbck` / `kbcts` / `kbsv` 三个头;`kbsv = md5(client_key \t client_sec \t 时间戳 \t 路径 \t\t 完整 JSON body)`。
- `encodeList` 里的字段(手机号、经纬度、门店坐标等)用 DES-CBC(key=iv=`D963r1wp`,PKCS7,Base64)加密。
- `cart/update` 的 `quantity` 是**增量**而不是绝对值(已实测);删除用 `cart/clearItem`。
- 这些常量来自公开 H5 bundle,官方改版后可能需要重新提取;代码里集中在 `src/crypto.ts`,便于更新。
---
## 10. 合规与免责
- 仅供**个人学习与自用**。请遵守肯德基用户协议、门店规则与当地法律。
- 请勿用于代下单、黄牛、批量刷单、爬取价格或其他商业用途。
- 下单会产生**真实订单**(未支付也会占用门店产能),请确保用餐人确认后再调用 `place_order`。
- 项目与肯德基(Yum China)无关联;接口可能随时变更,维护者不对下单失败、价格变动、订单取消等负责。
- 参考项目:[markswendsen-code/mcp-kfc](https://github.com/markswendsen-code/mcp-kfc)(MIT)。
---
## 11. License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues