MCP 技能如何分发与校验
文章介绍 MCP Skills 扩展如何通过资源 URI、技能清单及文件摘要分发 SKILL.md 和依赖文件。mcpscore 1.27.0 提供 21 条检查规则,并以 Hugging Face 提供的 25 个技能作为检查样本。
AI 深度解读
MCP 工具告诉 Agent「能做什么」,Skill 告诉它「这些工具该怎么配合」。当 Skill 也能通过 MCP 分发,服务端交付的就不只是 API,还有会直接进入模型上下文的操作说明。文件能读到,远远不够。
作者用 mcpscore 1.27.0 的 21 条规则检查了 Hugging Face 提供的 25 个 Skill。结果整体不错,但更值得程序员关注的是检查边界:文件一致性、协议合规、文本风险和执行授权,是几件不同的事。
Skill 通过 MCP 分发,究竟多了什么
按原文描述,Skills 扩展 SEP-2640 在 9 月定稿后,MCP 服务端可以在工具旁边提供 Skill。一个 Skill 以 SKILL.md 为入口,再通过引用组织说明文档和脚本。
服务端先声明 io.modelcontextprotocol/skills 能力,每个文件作为 MCP resource,通过 skill:// URI 标识。skills/list 返回入口地址、frontmatter,以及完整文件清单。frontmatter 就是文件开头的名称、描述等元数据;清单还包含每个文件的 SHA-256 摘要和大小。
下面是 Hugging Face 的真实返回项,它让客户端在读取正文之前,就知道自己应该收到什么:
{
"uri": "skill://hf-mem/SKILL.md",
"frontmatter": {
"name": "hf-mem",
"description": "Hugging Face CLI to estimate the required memory to load Safetensors or GGUF model weights for inference from the Hugging Face Hub"
},
"resources": [
{
"uri": "skill://hf-mem/SKILL.md",
"digest": "sha256:ee99f9d97e084aa61a80eaec4e6de2265341e71256d918d48fb87a2ac01ce99f",
"size": 3325
}
]
}
要留意 resources 中的 digest 和 size:它们需要与实际读取的文件对应,不能只在首次发布时生成一次。
skills/get 按 URI 返回单个 Skill 的同类信息。服务端若声明 directoryRead: true,还要支持 resources/directory/read。文件命名和 frontmatter 的格式,则来自 Agent Skills specification。
扩展是可选的。没有声明能力的服务端,全部 21 条规则都按不适用跳过,不影响分数;声明了,就要接受检查。mcpscore 按规范措辞区分严重程度:MUST 通常对应 MEDIUM,导致宿主拒载或把隐藏指令送入模型的情况对应 HIGH,SHOULD 和建议对应 LOW,分别计 2、3、1 分。
为什么摘要全部匹配,也不能证明 Skill 安全
宿主,也就是加载 Skill 的客户端,必须核对文件大小和摘要,还必须逐字段比较实际 SKILL.md 与清单中的 frontmatter。任一检查失败,内容都不能使用。
所以,修改正文却忘记更新清单,并非一个无关紧要的发布疏漏。合规宿主会直接拒绝加载。
摘要匹配只能证明文件与清单一致,不能证明内容可信。
原因很直接:文件和摘要都由同一个服务端提供。恶意服务端完全可以为恶意内容生成正确摘要。
mcpscore 会读取每个列出的 SKILL.md,并在固定读取上限内,为每个 Skill 读取一个辅助文件,模拟宿主做一致性检查。这里存在采样边界,不能理解为所有辅助文件都经过了全文审计。
文本检查又是另一层。Skill 会直接进入模型上下文,因此扩展要求把它视为不可信输入。作者把用于工具描述的三类检查也用于 Skill:隐藏 Unicode、嵌入凭据、提示注入措辞。这些检查属于 Security & Auth 下独立的 HIGH 规则,覆盖 frontmatter 和每份 SKILL.md 的全部行。
但 Skill 经常包含提示词示例。Hugging Face 的一个 Skill 就在 JSON 代码块中展示了带聊天模板标记的 reranker 提示词。检查器把代码中的这类标记视为示例,不报警;其他类型的问题,即使出现在代码里,也照常记录。这个例外只针对特定语境,不能推广成「代码块里的内容都安全」。
Hugging Face 的结果,到底说明了什么
作者检查的 25 个 Skill,规模从单份约 3 KB 的 SKILL.md,到包含 31 个文件的训练指南不等。复现审计使用这条命令:
uvx mcpscore==1.27.0 'https://huggingface.co/mcp'
注意固定版本的 mcpscore==1.27.0,否则后续规则变化可能影响结果;加上 --json 可以获取包含 skills 部分的报告。
这次审计中,19 条适用的 Skill 规则通过了 18 条,另一个无状态列表就绪检查也通过了。实际读取的 41 个文件全部匹配摘要和大小,25 份 frontmatter 全部与清单一致,66 个相对链接全部指向清单内文件。每个 Skill 都符合 512 个资源、16 MiB 的上限,也满足检查器验证的 OpenAI 单个 Skill 导入限制。
唯一报告的问题是:4 份 SKILL.md 达到或超过 500 行。规范建议把入口控制在 500 行以内,将细节放进引用文件,等模型需要时再加载。这属于质量建议,并非协议硬性错误。Skill 规则为最高分增加了 41 分,Hugging Face 拿到其中 40 分,整个服务端最终得分为 194/214。这个总分还包含其他检查,不能直接当作 Skill 得分。
没有任何 Skill 使用 allowed-tools,因此 skills_allowed_tools_valid 跳过。另有 9 个 Skill 携带 Python 脚本,这项事实会被报告,但不扣分。
理由是执行权限由宿主决定:通过 MCP 收到的 allowed-tools,在用户批准授权前必须忽略;执行 Skill 附带代码,也需要逐 Skill 批准。存在脚本本身不是缺陷。
导入容量同样要区分。原文称 OpenAI 每次扫描最多导入 5 个 Skill、合计 8 MiB 的归档。25 个无法一次导完,是容量事实;单个 Skill 超出导入限制,才作为 LOW 建议处理。
协议还有一个版本差异。仅支持 2026-07-28 无状态生命周期的服务端,没有 initialize 握手,检查器改用 server/discover 发现能力,再在请求的 _meta 中声明扩展,调用 skills/list、skills/get 和 resources/read,应用同样的 20 条 Skill 规则。第 21 条涉及无状态列表缓存提示。Hugging Face 同时支持两种生命周期,其 ttlMs 和值为 public 的 cacheScope 通过了检查。
我的判断
这套检查最有价值的地方,是把「能列出来」推进到了「宿主能按规范加载」。文件变了但摘要没变、frontmatter 不一致、引用文件漏进清单,这些都适合交给自动化发现。
不过,194/214 不是安全承诺。原文提供的是一次合规与静态检查结果,没有提示注入检出的准确率、漏报率,也没有实际 Agent 执行任务的对照数据。不能据此判断这些 Skill 能否稳定完成任务,更不能把低风险文本检查当成运行隔离。
500 行建议也有合理动机:入口越集中,越容易按需加载细节。但原文没有证明拆分后能提升多少成功率或节省多少 token,它仍然是组织文档的经验建议。
工具选择上,MCP Inspector 2.6.0 及以上已经支持 --method skills/list --verify,检查合规性、摘要和 frontmatter,并提供 CI 退出码。只需要这些能力,可以先用官方免费工具。mcpscore 的额外价值,是把 Skill 与工具、传输、认证、安全放进同一次审计,再加入文本风险和质量建议。作者没有给出两者的性能或检出率对照。
能拿来做什么
- 如果你在 Node 服务里通过 MCP 提供 Skill,把文件清单、大小、摘要和 frontmatter 当成同一份发布产物维护,避免更新说明后客户端突然拒载。
- 给团队维护 AI 编程 Skill 时,先检查 SKILL.md 是否塞入过多细节。接近 500 行时,可以把参考资料移到引用文件,并确认相对链接对应的文件都进入清单。
- 将协议检查接入 CI。只验合规可以使用 MCP Inspector;需要连同服务端其他能力一起审计,再考虑固定版本的 mcpscore,并保留
--json报告。 - 开发 Skill 宿主时,把内容读取和代码执行分开处理。摘要通过后仍按不可信文本处理;
allowed-tools授权和附带脚本执行,都应落实到扩展要求的用户批准流程。