Skill 和 MCP 有什么区别:实测上下文开销与选法

Agent Skill 和 MCP 都能给 Claude Code、Codex、OpenCode 这类编码 Agent 加能力,所以常有人问该写 Skill 还是接 MCP。两者装进去的东西不同,加载时机也不同。我们在沙箱里把同一个「中文排版检查」功能分别做成 Skill 和 MCP 服务器,再用一个假的模型接口把 Claude Code 2.1.309 发出的请求体全部记下来,看它们各自往上下文里塞了多少。
Skill 是一份说明书,MCP 是一个服务
Skill 是一个文件夹,核心是 SKILL.md:顶部 YAML 写 name(不超过 64 个字符)和 description(不超过 1024 个字符),下面是 Markdown 写的步骤和规则,旁边可以放 scripts/、references/。Agent Skills 规范把加载分成三层:开局只读每个 Skill 的名字和描述(约 100 token),决定要用时才读整份 SKILL.md(建议控制在 5000 token 以内),脚本和参考资料用到再读。Skill 本身不运行任何东西,要跑脚本,靠的是 Agent 自己的 Bash 工具。
MCP 是一套协议。工具方写一个服务器进程(本地走 stdio,远程走 HTTP),通过 JSON-RPC 对外提供工具、资源和提示词模板。规范里工具是「模型控制」的:模型看到工具列表,自己决定调用哪个,代码在服务器进程里执行。查数据库、调 SaaS 接口、带 OAuth 登录的服务,都更适合做成 MCP。
| 对比项 | Agent Skill | MCP 服务器 |
|---|---|---|
| 形态 | 文件夹:SKILL.md + 脚本 + 参考资料 | 独立进程或远程服务,JSON-RPC 通信 |
| 开局进上下文 | 名字 + 描述(本文实测 210 字节) | 默认只给工具名;关掉 tool search 后每个工具 425–875 字节 |
| 代码在哪执行 | Agent 用自己的 Bash 跑,需要 shell 权限 | 服务器进程里,Agent 不需要 shell |
| 擅长 | 流程、规范、模板、团队约定 | 外部系统、凭证、长连接和状态 |
| 编写成本 | 写 Markdown,脚本可选 | 写服务器代码,维护依赖和版本 |
| 跨工具 | Agent Skills 开放规范 | MCP 开放协议 |
实测:同一个功能,两种做法各占多少上下文
测试环境:Debian 沙箱,Claude Code 2.1.309,模型名填 claude-sonnet-4-5,ANTHROPIC_BASE_URL 指向我们写的一个假接口。它把每次请求的完整 JSON 记到文件里,再按脚本回一个 tool_use 或一句 done。这样能看清 Claude Code 往上下文里放了什么,但它不代表真实模型会怎么判断,真模型触发 Skill 的准确率本文未实测。每次运行都用全新的 CLAUDE_CONFIG_DIR 和 --strict-mcp-config,避免本机已有的配置混进来。
Skill 是 zh-spacing-check,SKILL.md 1215 字节,带一个检查脚本;MCP 一侧是把同一个检查函数包成工具的 Python 服务器(MCP Python SDK 2.3.0),外加官方 filesystem 服务器 2.0.0(14 个工具)做规模对照。

几个结论:
- 装 1 个 Skill 但不调用,请求体只多 210 字节,内容就是系统提醒里的一行「名字: 描述」。
- 假接口让模型调用 Skill 后,下一轮多出 1,726 字节:整份
SKILL.md正文作为一条消息塞进来,${CLAUDE_SKILL_DIR}已经换成了绝对路径。 - 给同一个 Skill 加上
disable-model-invocation: true,请求体回到 84,027 字节,和基线一字节不差,描述完全不进上下文。 - 接上 filesystem 服务器、保持默认的 tool search,只多 357 字节,是 14 个工具名的列表;设
ENABLE_TOOL_SEARCH=false后多出 38,360 字节,其中 14 个工具定义共 8,467 字节,单个 425–875 字节。

默认设置下两者开局都很省。关掉 tool search 以后,MCP 工具定义每轮都要全量发一遍,差距从这里出来。
MCP 要多走一步。默认情况下,模型要先调 ToolSearch(我们让它发 select:mcp__zh-spacing__check_zh_spacing),拿到一个 tool_reference 和「Tool loaded.」,下一轮请求里才出现这个工具的定义(356 字节,带 defer_loading 标记),然后才能调用。Skill 这边是一步:调 Skill 工具,正文直接进来。
怎么选:问自己三个问题
- 要不要连外部系统、带凭证或保持状态?要的话用 MCP。数据库连接、公司内部 API、需要 OAuth 的 SaaS,我们更建议放在服务器进程里管,别让 Agent 拿着 token 自己拼 curl。
- 是不是一套做事的方法,本机命令就能完成?是的话写 Skill。发布检查清单、代码评审规范、周报模板、排版规则,写成 Markdown 加一个小脚本就够了,不用维护服务器。
- Agent 有没有 shell 权限?Skill 里的脚本要靠 Agent 的 Bash 执行。如果所在环境不给 Agent shell 权限,就只能用 MCP,或者写纯说明型、不带脚本的 Skill。
两者可以一起用:用 MCP 负责「连得上」,Skill 负责「怎么做」。比如接一个工单系统的 MCP 服务器,再写一个 Skill 规定「先查工单、按模板写复现步骤、结论写回工单」。Skill 正文里直接写要调用哪个 MCP 工具即可。
常见坑
- ENABLE_TOOL_SEARCH=false 不只影响 MCP。我们不接任何 MCP、只设这个变量,请求体就多了 30,164 字节,工具从 12 个变成 24 个,原本延迟加载的内置工具(Cron、Task、WebFetch 等)也被一起提前加载了。用网关或第三方模型接口时如果碰到
defer_loading报错,先看官方文档的网关说明,别急着全局关掉。 - Python SDK 2.x 删了 FastMCP。沿用老教程
from mcp.server.fastmcp import FastMCP,服务器启动就报 ModuleNotFoundError,Claude Code 这边只显示服务器连接失败(CONNECTION_CLOSED)。改成from mcp.server.mcpserver import MCPServer即可,细节见我们的 40 行写 MCP 服务器接进 OpenCode 实测。 - disable-model-invocation 会让 Skill「隐身」。描述不进上下文,模型就不会自己用它,只能你手动输入
/zh-spacing-check。部署、发消息这类有副作用的 Skill 适合这么设,规范类 Skill 别加。 - Skill 正文加载后一直留在上下文里。官方文档写明正文不会在后续轮次重读,而是常驻;压缩后每个 Skill 最多保留前 5,000 token,所有 Skill 合计 25,000 token。所以
SKILL.md要短,长资料放进references/。
完成标准
- 能说出你手上的需求属于「连系统」还是「讲方法」,并据此选了 Skill 或 MCP。
- Skill 的 description 写清了做什么、什么时候用,在 Claude Code 里问「有哪些 Skill 可用」能看到它。
- MCP 服务器在
claude mcp list里显示已连接,且没有为了省事全局关掉 tool search。
最后
如果你还没写过 Skill,先照着 10 分钟写出第一个 Agent Skill 做一个;MCP 的配置和作用域,见 MCP 是什么、怎么配置。两边各跑通一次,再对照上面的表来选。