coding小白参加金拱门项目接餐饮MCP时踩过的 4 个坑

接餐饮 MCP 踩的 4 个坑:前导空格、null ≠ 0、不能 split(','),以及「限流竟是 HTTP 200」

代码取自 github.com/smallchrist...(src/toon.ts,331 行,可跑)。 说明:为篇幅计,代码块删去了注释与部分类型标注,逻辑与仓库一致;需要逐字对照可看源文件。


先说结论 :TOON 看着像"带表头的 CSV",看着好解析。实际有四个坑, 其中最后一个最阴------被限流时 HTTP 照样返回 200, 只判状态码的代码会把"被拦截"当成"查询成功",然后把空数据当成"这家店没菜"。

一、先看一段真实返回

我用麦当劳中国的 MCP 做了一个营养搭配 CLI。四个工具里,list-nutrition-foods 返回的营养表长这样:

复制代码

TOON(Token-Oriented Object Notation)------比 JSON 省 token,人也读得懂。第一眼看上去很好解析:表头声明了 [160] 行、9 列,下面就是逗号分隔的行。

我一开始也这么想。然后连踩四个坑。


二、坑 1:每一行首字段带 2 个前导空格

数据行的第一个字段是 " 猪柳麦满分",不是 "猪柳麦满分"。

后果不是报错,是"看起来没数据" :你按名字去查,查不到;打印出来一看,营养表里明明有这条。

复制代码

这类 bug 的排查成本特别高,因为报错信息会把你带错方向------你会先怀疑"官方营养表里没有这个商品",而不是"我把名字读脏了"。


三、坑 2:null、"null"、0 是三件事,不是两件

营养字段里:

  • null = 缺失(不知道)
  • 0 = 真的是 0(比如矿泉水的热量确实是 0 千卡)
  • "null"(带引号)= 字面字符串,不是缺失

第三条最容易忽略。所以判断"是不是 null"必须看原始字段有没有被引号包住:

复制代码

为什么较这个真:如果缺失被填成 0,你的程序不会崩,它会安静地算出一份「0 千卡套餐」------这比崩溃危险得多。崩溃你会去修,错答案你会拿去用。

这条也决定了整个产品的口径:营养数据分 A/B/C/D 四级可信度,缺失一律留白,绝不填 0 。实测 121 项餐品里,可用(非 D 级)的只有 38 项(31.4%) ,其余 83 项就老实标「D 级 · 无法验证」。


四、坑 3:不能 split(',')------字段里可能有逗号

TOON 复用 CSV 的引号规则:字段含逗号、换行、双引号时,整段用双引号包起来,内部的双引号写两遍。

复制代码

三十行,替换掉一行 split。值不值得?值得------列错位是静默错误,它不会抛异常,只会让"卡路里"那一列装着"蛋白质"的数字。


五、坑 4:被限流时,HTTP 还是 200

这条最阴。

我做过一次压测(305 次请求,2026-10-12)。所有响应都是 HTTP 200,包括被限流的那些:

复制代码

也就是说:只看 HTTP 状态码,你永远发现不了自己被限了。 你会把限流当成功,把空数据当"这家店没这个菜"。

所以拆包必须检查业务信封,而不是只看有没有 data:

复制代码

注意最后那个 businessCode 参数------业务码必须带出到上层,否则客户端只能统一当"服务端异常",既不会退避重试,也不会止损。

我在这条上栽过一次:早期版本只检查"有没有 price 字段",于是 {"success":false,"code":500,"data":{"price":0}} 被解析成"官方已核实 ¥0"。 失败响应里有残留数据,是这类 API 的常态。


六、结构自检:声明 160 行,就得真的是 160 行

表头写着 [160],那就校验一遍:解析出来的行数必须也是 160,列数必须等于表头列数。

我的默认策略是严格模式直接抛错 ,只有显式传 { strict: false } 才降级为"记警告继续":

复制代码

列数同理:fields.length !== columns.length ⇒ 严格模式抛 COLUMN_COUNT_MISMATCH,宽松模式记 warnings。

为什么默认严格:解析层的容错,会把"数据变了"这件事悄悄吃掉。宁可让程序在启动时炸给我看,也不要它在三个月后给我一份少了两行的报表。


七、附赠:中文表格在终端里永远是歪的

这是做终端演示时发现的,属于同一个"宽度"家族的问题:

复制代码

实测修复前,同一列在不同行落到第 35~38 列;修复后全部对齐到第 76 列。

顺带一提 :数值列右对齐时,表头也得右对齐------否则表头和数字会错开一个单元格。这种细节,用户说不出哪里不对,但会觉得"这工具不精致"。


八、怎么自己验

复制代码

解析器本体:src/toon.ts(331 行)|踩坑记录:docs/API_PROBE_NOTES.md|匹配实测:docs/MATCHING_NOTES.md


九、四条结论

坑 现象 后果 修法
前导空格 名称带缩进 匹配全部落空,报错误导 每格 trim()
null / "null" / 0 三态混同 缺失变 0,算出"0 卡套餐" 记 quoted,未加引号的才算缺失
split(',') 字段含逗号 整行列错位(静默) 引号感知的状态机
限流 HTTP 200 + code:508 把限流当成功,把空当"没有" 校验业务信封,把业务码带出去

一句话总结:解析层的每一处"容错",都要想清楚它会不会把"数据变了"变成一个更安静的错误。

相关推荐
Danny转行做跨境5 小时前
AI 搜索时代选品数据采集: MCP 与爬虫实战对比
跨境电商·mcp·sorftime
壹米饭7 小时前
手搓 MCP 到最简 Agent,我都做了什么?
agent·ai编程·mcp
Sakura_j_h_7 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
xrlfreedom8 小时前
MCP 面试高频考点:企业内网统一管理多个 MCP Server,Tools 权限与审计怎么落地?
tools·mcp·最小权限与审计日志·typescript mcp sdk
风雨中的小七10 小时前
解密Prompt系列73. 爆改对话框:揭秘 Intelligent UI 的动态界面魔法
llm·agent·mcp
正在走向自律1 天前
AI Agent 落地这一年:从“能跑起来”到“敢放出去”
大数据·人工智能·ai agent·智能体·mcp·a2a
VIP_CQCRE1 天前
视频任务显示‘已提交’之后:别让异步生成变成黑盒
异步任务·工作流·ai视频·mcp
xrlfreedom1 天前
MCP 面试高频考点:为团队沉淀可复用 Prompts 工作流,Tools、Resources、RAG 怎么分工?
tools·resources·mcp·rag 知识库
vjmap2 天前
MCP 实战:在 WorkBuddy 里一句话让 AI 生成红军长征地图动画(唯杰 AI 地图动画 MCP 接入教程)
aigc·gis·mcp
Bayze2 天前
让两个模型吵一架,再用第三个裁决——我把多 AI 协作磨成了五种模式,六轮真实测试修出七个 Bug
mcp