设计MCP:不是暴露API,是给AI写说明书
约 11 分钟驭光者首发于微信公众号「羲和Lab」

特别企划 · 216个工具的MCP设计复盘——六条原则、四仓架构、八个坑 《智能编码进化论》系列 · 实战复盘体 · 2026-09
会议室里、群聊里,谈AI的声音越来越多。最典型的一句口头禅,是那句对仗的玩笑——遇事不决量子力学,遇事不决写个Skill。
这个梗好笑,是因为它半真半假。Skill确实能封装很多活,但它封不了「怎么连」;缺了「连」,再好的Skill也够不着外部系统。
但把提示词、MCP、Skill放在一起,能一句话说清各自是什么的人,很少。更多的人干脆一刀切:都是「AI工具」,随便叫。分不清,不丢人——这三个词的边界,比多数人以为的更模糊:模糊到你以为自己对,其实只对了一半,而错的那一半,恰是MCP设计里最重要的工作。
先交代来路。数据三部曲收官,版本是药、数据是听诊器、规则是免疫系统,那三篇都站在「用AI」的一侧,静默失败那条暗线先记在账上。这一篇换到桌子另一边:给AI天天调用的工具,当一次作者。05篇《给AI接外线》教过你怎么把MCP挂进Claude Code——只是接外线的人,很少站到那头看一眼。
那头是什么景象?用户对智能体说「帮我建个高优缺陷」,智能体面前摆着216个工具,它靠什么选?靠你写的文字。所以本篇的核心认知只有一句:MCP Server的本质不是暴露API,是给AI写说明书。说明书是给AI读的——AI读,你写。
口径先立:本文复盘TAPD MCP两个版本线——1.x单包210工具,2.x四仓聚合216工具。TAPD是公开产品,工具数与架构是公开事实;单一项目复盘,非统计样本,结论是方向性经验。
这个认知怎么来的——先看两种写description的差距。
一、说明书,不是API
先给一张三秒地图:提示词,是说什么;Skill,是干什么;MCP,是怎么连。记住这张地图,接下来要告诉你,在「连」这个字的深处,藏着一个反转。三者分工的细节,《六层架构》篇用整章讲过,这里只给三秒版。
看代码。同一个创建需求的工具,两种写法:
// 坏版本
description: '创建需求'
iteration_id: '迭代 ID'
// 好版本(项目真实原文)
description: '创建需求。兼可创建任务:工作项类别参数传「任务型」
类别的 ID 即走任务创建(适合仅有需求创建权限而无任务创建
权限的场景)。从已有需求复制用复制工具。写操作;name 必填,
负责人缺省取环境变量 TAPD_NICK_NAME。返回新需求。'
iteration_id: '迭代 ID;必须以字符串(带引号)传递,禁止传数值,
20 位 ID 超出 JS 安全整数范围会丢精度'
第一版告诉智能体「这个工具做什么」。第二版告诉它:什么时候选它而不是相邻那个,怎么传参不踩坑,缺省行为是什么。
02篇教过给AI写岗位说明书,那是CLAUDE.md。这一篇,是给AI用的工具写说明书——同一门手艺,换个对象。
再往深一层。这些描述会经MCP的tools/list协议、连同inputSchema一起注入模型上下文。你改的不是文档,是模型看到的系统提示——说明书是给AI读的,AI读,你写,你写下的每一段都在实时塑造它眼中的世界;改一行描述,智能体下一次的工具选择就可能变,你动的是它的世界观。
于是,那个反转来了。开篇那些分不清三者的人,无意中说中了真相:在description这一层,三者的边界不是修辞上的模糊,是真实的模糊。MCP设计的核心工作,恰恰是写提示词。
《六层架构》篇判过「Skill只是提示词」这个错,判得对;这里能补下一层真相——这个混淆半对。材质层重叠,职责层各司其职:提示词、Skill文件、MCP工具描述,在「注入模型上下文的文字」这一层是同一种材质;但职责各归其位,提示词管说什么,Skill管干什么,MCP管怎么连。分不清的人蒙对的是材质;若就此说三者是一回事,就从蒙对滑向了真错。两层法也给了「分不清不丢人」最后的底气:不丢人的是材质,该较真的是职责。
分不清还有个结构性根源:一个MCP Server的工具,往往被多个Skill调用,物理同居是常态。但代码要能把两层分开——MCP层只管工具怎么描述、参数怎么序列化、错误怎么返回,活儿全在Skill层。
所以回到那句话:你写的每一行describe、每一个工具命名,就是智能体看到的全部现实。说明书人人会写,写好不容易。六条原则,条条带血。
二、六条原则
**六条原则,就是「怎么连」这一层的设计学。**连接层的核心工作落在描述、参数、错误三件事上,前四条定义写什么,后两条定义怎么服务读写。
**原则一:消歧优先于功能。**216个工具里,最容易出错的不是功能Bug,是选错工具。get与count与批量详情、create与update与copy、标准与轻协作——这些相似对,才是智能体的真正陷阱;功能Bug顶多坏一个工具,选错工具坏的是整次交付。
每对至少一侧要写清分工,最好是两侧互相指认:列表工具写「只统计数量用数量统计工具;已知多个ID要完整详情用批量详情工具」,统计工具写「与列表查询相同的过滤条件返回数量,不返回列表」——智能体站在岔路口,每条路上都立着路牌。一条实操发现(本项目实测):消歧描述里别引用相邻工具的英文全名,推荐侧会把描述里的英文token计入索引权重、污染召回排序;用中文功能指称,「数量统计工具」,不是那串英文名。
**原则二:参数描述是行为契约。**每个参数的describe不只是「是什么」,更定义了智能体怎么用。四要素:ID类标精度约束,枚举类列常用取值,默认值写清来源是环境变量还是API参数,非必填但规范要求的写明后果。比如:「关联测试用例ID,虽非必填,但缺陷源自测试执行时应带上,否则覆盖追溯断裂」。默认值来源写错的后果很具体:智能体要么反复追问,要么拿着错误缺省一路跑到底。非必填,不等于不重要。
*原则三:错误输出是接管界面。调用失败时返回什么,决定人能不能接手。错误体不是一句error message,是结构化移交清单。以一次真实的403为例:code是TAPD_HTTP_403,endpoint指向/stories,params里的workspace_id打码为;hint告诉智能体怎么修——「OAuth token缺少stories::create权限,前往开放平台权限配置」;takeover告诉人怎么接、该收什么。批量操作部分失败时不吞整批,返回summary、succeeded、failed三态聚合,每一笔都算数。
**原则四:读归一,写保真。**读侧,平台返回的HTML富文本统一归一为Markdown给智能体;写侧,智能体提交的Markdown转为平台富文本,并完成@提及、附件锚点的语义转换。再留一条raw_html旁路,给需要确定性透传的高级场景——转换层再聪明,也不该挡在确定性场景中间。方向各归各:读要归一,写要保真。
两条快答。其一,富文本字段按实体类型设计写作引导:story的description引导写「## 背景/目标、## 功能点、## 验收标准」,bug引导写「## 复现步骤、## 预期vs实际、## 根因、## 影响」——引导同样注入即系统提示,每处约50-100token(估算),篇幅必须控。其二,只读低频数据加缓存:工作项类型、工作流状态表、成员列表这类数据,allowlist加TTL加LRU,工具层零感知;这是服务端主动控制上下文体量的手段,不是05篇讲过的使用者侧避坑技巧。
说明书写好了,装它的房子呢?210个工具的时候,单包住得挺好。问题出在你要复用内核的那天。
三、210到216:从单包到四仓
版本一是单包,src下入口、HTTP客户端、按领域分文件的工具定义,各一摊;客户端兼了双认证与GET重试。它足够撑起210个工具——单包不是罪,这一点先说清楚。
撑不住的时刻,不是工具变多,是内核要复用:CLI要命令树,MCP要tools/list,底下是同一批工具定义、同一个客户端、同一个富文本转换内核——一份内核,两张脸。于是版本二拆成四仓:
markdown(纯函数)
↑
core(内核)
↑
┌───┴───┐
mcp cli
(纯接线)(入口)
两个关键决策,各有一句「为什么」。其一,基座是唯一发布入口——CI全量门禁,按依赖序编排子仓发布,聚合tag;子仓纯源码,main上零工具链依赖,构建工具链由流水线临时注入。不是为了省事,是防「子仓各自发版导致版本漂移」:一个消费者拿到旧版core、另一个拿到新版,行为不一致且无法排查。
其二,发布走npm Trusted Publishing,OIDC身份,workflow文件名、仓库名、environment三重绑定,零token。不是赶时髦,是token长期存在就等于长期风险——零token,意味着没有可泄漏的凭据。
四仓有一条写进CI的验收标准:core的mcp业务增量=0。MCP只是内核的一个消费者,内核里不该出现MCP特有的逻辑;这条标准每次改动自动核对,防的是自觉。「MCP Server里固化业务逻辑」——《六层架构》篇判过的病,这道闸就是防它的。
复盘到这里,还发现了一件事。六月的《六层架构》下篇讲容灾时提过一条原则:所有能力同时暴露为CLI(供人类)与MCP工具(供模型),AI不可用时人从日志接手。当时讲的是「设计原则」,四仓落地时我们才发现,cli和mcp正是core的并列消费者——这个结构不是「暗合」那条原则,是那条原则的自然结果。
我们把自己讲过的道理建出来了。讲过,然后做到,比「符合业界共识」更有分量;解耦的收益顺带落袋:Skill将来切换协议,代码不用改,MCP层换安全策略,Skill毫无感知。而原则三的takeover与这里的双入口,是同一哲学的两端——一个在错误信息里把人接进来,一个在架构上就备好了人的入口。
蓝图归蓝图,施工队踩过的坑才是真地图。八个坑,挑三个最疼的。
四、三个最疼的坑
先立一条总纲:MCP的坑,多半不在你的代码里,在你依赖的平台行为里。每个坑背后,是一条平台行为假设的破产。
**坑一:zod数值精度。**平台ID是19-20位数字,超出JS安全整数范围(2^53-1),用数值类型传递,精度说丢就丢。解法两层:长ID参数一律z.string(),描述写明「以字符串传递,禁止传数值」;再加preprocess防御层,安全范围内的数值自动转字符串救回。这个坑直接反哺原则二——契约写错,行为必错,参数类型就是行为。
同一族问题还有参数名形态:tcase_id与tcase_ids、id与test_plan_id——SDK路由要逐端点核对参数名与形态,本项目实测就这么错过两起。
**坑二:npx双层缓存。**MCP用npx分发,这是零安装的代价。第一层:根tag不动,整棵依赖树原样复用;第二层更隐蔽——缓存的lockfile记录的是具体版本(如1.2.3),只要依赖范围(如^1.2.0)没变,npm就复用它,不拉范围内更新的1.2.4;根包升级也撬不动——决定拉不拉新的,是依赖范围,不是根。用户以为永远最新,实际停在半年前。解法是lockstep发版加发布时精确pin——「版本永远新鲜」的承诺,靠发版纪律兑现。
**坑三:stderr当error。**以Claude Code为宿主时(不断言所有宿主如此),MCP server往stderr写的任何东西,都会被当成错误呈现。进度提示、友好警告,一律变成红色报错;提示与警告必须走MCP protocol logging notification。教训:通道语义由宿主定义,不是POSIX惯例。
剩下五个,一览带过。新版pnpm(10起)把设置收敛进pnpm-workspace.yaml,.npmrc只剩认证类设置;submodule提交前校验指针不在detached HEAD,防发旧代码;npm provenance溯源签名只收公开源仓库,私有仓需--no-provenance;unpublish要三思:撤包后同名同版本永远不可重发;整包全撤,包名还有24小时冷静期——发坏版本优先发新版修复,不要撤。
第五个要单独说:并行子代理共享同一份子仓checkout,会互相切走HEAD、未提交改动跨分支携带——每个子代理配独立worktree。这正是《从2277个子代理说起》那个多智能体日常的另一面:连git目录,都成了共享资源。
坑踩完,回头看整个项目交付了什么。不是216个工具。
五、结语:三层产品,一次交付
优雅的MCP Server,是三层产品的统一——而且三层不是先后关系,是同时成立。
对智能体,它是一份清晰的工具选型手册——就是一、二章写的那本说明书;消歧、契约、接管信息,缺一不可。往远处看一层:不给MCP端点,就等于对AI不可见——设计MCP不是炫技,是让你的能力在AI时代可见。
对用户,它是一个零安装、零配置、版本永远新鲜的npm包:npx拉起,OIDC发布,lockstep对齐——「零安装」的承诺,是拿坑二那套发版纪律换来的。
对开发者,它是一个可持续演进的工程体系:四仓聚合,全量门禁,分层回归——正是三章那套工程,从单元测试盖到发布产物。
发布前六问,自查用,任何一问答不上来,说明书就有漏页。长ID参数是否全为string且描述带引导?新增工具是否有四要素描述(功能/何时选它/约束/返回)并与相邻工具消歧?错误路径是否产出结构化错误体?round-trip契约测试(md→html→md等价)是否通过?基座聚合CI是否全绿?子仓main是否零工具链依赖?
05篇站在电话这头教你接线,这一篇站到那头——同一条外线,两端各写了一次说明书。现在轮到你:把你自己的MCP工具清单拉出来逐个问,它的描述,回答了「什么时候选它而不是相邻那个」吗?这一问,就是设计者和使用者真正的分界线。
你在这三层上做的每一个决策,最终都会体现在智能体的一次工具选择、用户的一次更新体验、或者你自己的一次深夜发布里。
治理三部曲的静默失败暗线,仍在账上——待续。
评论区试试:把你最常用的一个MCP工具的描述原文贴出来,我们一起看,它有没有回答「什么时候选它」。觉得有用,点赞、在看、转给正在写MCP的那位。
免责声明
本文内容仅供学习交流,所述方法需结合实际场景灵活运用。AI工具输出结果仅供参考,关键业务决策请结合人工判断。
文中代码示例基于TypeScript与zod实现,工程实践以npm生态为语境,其他技术栈需等价转换;工具描述均为项目真实原文,工程细节已脱敏;复盘结论来自单一项目,方向性经验供参考。
本文由AI辅助创作,经人工审核编辑后发布。
《智能编码进化论》特别企划 · 实战复盘体 · 2026-09
本文首发于微信公众号「羲和Lab」,公众号内可留言交流
阅读公众号原文