2026-03-23
0. 太长不读
MCP 和 Skills 是 Claude Code 生态里最容易混淆的两个概念。一句话版本:MCP 管连接,Skills 管流程。但真正让人困惑的不是这句话,而是 Skills 里可以带脚本,脚本可以调 API、操作数据库------这不就是 MCP 能干的事吗?
本文从协议层、运行时、工程实践三个维度拆清楚两者的边界,核心结论:
- Skills 脚本和 MCP 在能力上确实有重叠,但运行机制完全不同
- MCP 是持久化服务进程,Skills 脚本是按需执行的一次性命令
- 选择标准不是"能不能做",而是"该用什么姿势做"
- 大多数生产场景需要两者协同,而不是二选一
1. MCP 到底是什么
一句话定义
MCP(Model Context Protocol)是 Anthropic 于 2024 年 11 月推出的开源标准协议,用于将 AI 应用连接到外部系统。可以理解为 AI 世界的 USB-C 接口。
架构三件套
arduino
┌─────────────────────────────────────────────┐
│ MCP Host(Claude Code / IDE / 任意 AI 应用) │
│ │
│ ┌───────────┐ JSON-RPC 2.0 ┌────────┐ │
│ │ MCP Client │ ◄──────────────► │ MCP │ │
│ │(内置于Host)│ stdio / SSE │ Server │ │
│ └───────────┘ └────────┘ │
│ │ │
│ ┌──────┴─────┐ │
│ │ 外部系统 │ │
│ │ DB / API / │ │
│ │ Notion / GH │ │
│ └────────────┘ │
└─────────────────────────────────────────────┘
三个组件各司其职:
| 组件 | 职责 | 类比 |
|---|---|---|
| MCP Host | 承载 LLM 的应用环境 | 电脑 |
| MCP Client | 管理 Host 与 Server 之间的通信 | USB 控制器 |
| MCP Server | 连接外部系统,暴露工具和数据 | USB 设备 |
运行时特征
MCP Server 是一个独立的、持久运行的服务进程。启动后:
- 向 Host 注册自己提供的所有工具(自动发现)
- 维持长连接,保持状态(认证、会话、缓存)
- 通过 JSON-RPC 2.0 接收调用请求,返回结构化结果
- 生命周期跟随 Host,不是用完就退出
关键词:持久、有状态、结构化通信、自动注册、跨应用复用。
一个具体例子
Notion MCP Server 启动后,Claude 自动获得这些工具:
sql
notion-search
notion-create-pages
notion-update-page
notion-query-database-view
notion-get-comments
...(共 15+ 个工具)
不需要任何额外配置,Claude 直接知道自己能搜索 Notion、创建页面、查询数据库。工具定义、参数约束、返回格式全部由 Server 结构化声明。
2. SKILLS 到底是什么
一句话定义
Skills 是 Claude Code 的本地扩展机制,本质是一组存放在 .claude/skills/ 目录下的指令文件,教 Claude 怎么做事。
文件结构
bash
.claude/skills/
└── my-skill/
├── SKILL.md # 必须:指令定义(YAML frontmatter + Markdown)
├── scripts/ # 可选:可执行脚本
│ ├── lint.sh
│ └── deploy.py
└── templates/ # 可选:模板文件
└── pr-template.md
SKILL.md 的两段式结构
yaml
---
name: code-review
description: "Use when reviewing PRs or code changes. Don't use for writing new code."
---
## 审查流程
1. 先读取变更文件列表
2. 对每个文件检查以下维度:
- 安全性:是否引入 OWASP Top 10 漏洞
- 性能:是否有 N+1 查询、不必要的循环
- 可读性:命名是否清晰,逻辑是否直接
3. 如果发现问题,运行 `scripts/lint.sh` 验证
4. 输出结构化审查报告
Frontmatter 配置触发条件(什么时候用),Markdown 定义操作流程(怎么做)。
运行时特征
Skills 的加载是延迟的、按需的:
- 启动时,Claude 只加载所有 Skill 的 name + description(约 30-50 tokens/skill)
- 用户输入到达后,Claude 扫描可用 Skills,匹配最相关的
- 匹配成功才读取完整 SKILL.md 到上下文
- 如果指令引用了脚本,Claude 通过 Bash 工具执行
- 执行完毕,脚本进程退出
关键词:延迟加载、无状态、纯文本指令、通过 Bash 执行脚本、仅限 Claude Code。
3. 能力重叠:SKILLS 脚本也能调 API
这是大多数人困惑的地方。看个例子:
用 MCP 查 GitHub Issues
php
// MCP Server(持久运行)
// Claude 自动获得 list-issues、create-issue、close-issue 等工具
// 调用时:
await mcp.callTool("list-issues", { repo: "owner/repo", state: "open" });
// 返回:结构化 JSON,包含 issue 列表
用 Skill 脚本查 GitHub Issues
bash
#!/bin/bash
# scripts/list-issues.sh
gh issue list --repo "$1" --state open --json number,title,labels
yaml
# SKILL.md
---
name: github-issues
description: "Use when user asks about GitHub issues"
---
查看 issues 时,运行 `scripts/list-issues.sh <repo>`。
两种方式都能拿到 GitHub Issues。那到底有什么区别?
4. 核心区别:不是能不能,是怎么做
4.1 生命周期
arduino
MCP Server:
启动 ──────────── 运行中(持久) ──────────── 随 Host 关闭
注册工具 处理请求 维持连接
Skill 脚本:
触发 → 执行 → 返回 → 退出
触发 → 执行 → 返回 → 退出
(每次都是全新进程)
MCP Server 启动一次,服务整个会话。Skill 脚本每次调用都是一个新进程,执行完就退出。
实际影响:MCP Server 可以维持数据库连接池、缓存查询结果、保持 OAuth 会话。Skill 脚本每次执行都需要重新建连、重新认证。
4.2 工具发现
| 维度 | MCP | Skill 脚本 |
|---|---|---|
| 发现方式 | 启动时自动注册所有工具 | Claude 读 SKILL.md 才知道有脚本 |
| 参数定义 | JSON Schema,结构化声明 | 脚本参数,靠自然语言描述 |
| 返回格式 | 结构化 JSON | stdout 文本 |
| 错误处理 | 结构化错误码 + 修正建议 | exit code + stderr |
MCP 的工具是结构化注册的,Claude 在调用前就精确知道每个工具的参数类型、约束、返回结构。Skill 脚本的"工具发现"依赖 Claude 阅读自然语言指令,然后自行构造 Bash 命令。
4.3 通信方式
arduino
MCP:
Claude ←── JSON-RPC 2.0 ──→ Server
双向、结构化、可流式、支持回调
Skill 脚本:
Claude → Bash("scripts/xxx.sh arg1 arg2") → stdout
单向、纯文本、一次性
4.4 跨应用复用
MCP 是协议级标准。一个 Notion MCP Server 可以同时被 Claude Code、VS Code Copilot、Cursor、ChatGPT 使用------任何实现了 MCP Client 的应用都能接。
Skill 是 Claude Code 专属。换一个 AI 工具,Skill 文件就是一堆普通 Markdown。
4.5 一张表总结
| 维度 | MCP Server | Skill 脚本 |
|---|---|---|
| 本质 | 独立服务进程 | Bash 执行的脚本文件 |
| 生命周期 | 持久运行 | 按需启停 |
| 状态 | 有状态(连接池、缓存、会话) | 无状态(每次重来) |
| 通信 | JSON-RPC 2.0 双向结构化 | stdin/stdout 纯文本 |
| 工具发现 | 自动注册 | 读指令后才知道 |
| 参数 | JSON Schema 强类型 | 命令行参数,自然语言描述 |
| 返回 | 结构化 JSON | 文本输出 |
| 错误 | 结构化错误 + 建议 | exit code + stderr |
| 复用 | 跨所有 MCP 兼容应用 | 仅 Claude Code |
| 开发成本 | 较高(需实现 Server) | 较低(写个脚本就行) |
5. 那 SKILLS 的真正价值是什么
如果 MCP 在"外部连接"上严格优于 Skill 脚本,那 Skills 存在的意义是什么?
5.1 Skills 的核心是知识,不是能力
Skills 最重要的部分不是 scripts/ 目录,而是 SKILL.md 里的指令。它定义的是:
- 什么时候做:触发条件和反例
- 怎么做:步骤、流程、判断标准
- 做到什么程度:验收标准
yaml
# 示例:数据库迁移 Skill
---
name: db-migrate
description: "Use when creating or modifying database migrations. Don't use for queries."
---
## 迁移流程
1. 检查当前迁移状态:`scripts/check-migration-status.sh`
2. 生成迁移文件前,确认:
- 是否有未应用的迁移
- 字段命名是否符合 snake_case 约定
- 是否需要数据回填
3. **禁止**在迁移中使用 `DROP COLUMN`,改用 `ALTER COLUMN ... SET NOT VISIBLE`
4. 生成后必须运行 `scripts/validate-migration.sh` 检查语法
5. 迁移文件名格式:`YYYYMMDD_HHMMSS_description.sql`
这里面 90% 的价值在流程规范和团队约定,脚本只是辅助验证的工具。
5.2 Skills 脚本擅长确定性计算
LLM 不擅长的事:
- 精确的正则匹配和文本处理
- 数值计算和统计
- 文件格式转换(CSV → JSON、Markdown → HTML)
- 本地文件系统批量操作
这些交给脚本做,Claude 只需要调用和解读结果。
markdown
## 代码统计 Skill
当用户问项目规模时:
1. 运行 `scripts/count-lines.sh`
2. 解读输出,给出概要
bash
#!/bin/bash
# scripts/count-lines.sh
cloc --json . | jq '{
languages: [.header.n_lines],
total_code: .SUM.code,
total_comments: .SUM.comment,
total_blank: .SUM.blank
}'
这类任务不需要持久服务,不需要结构化通信,一个脚本足够。
5.3 Skills 是上下文管理的载体
回到上下文工程的视角,Skills 的延迟加载机制本身就是一种优化:
yaml
系统提示(常驻,约 30-50 tokens/skill)
├── skill-1: name + description
├── skill-2: name + description
└── skill-n: name + description
匹配触发后才加载完整指令(几百到几千 tokens)
100 个 Skills 在系统提示里只占 3000-5000 tokens。完整指令只在需要时才进入上下文,用完可以释放。这种渐进式加载是 MCP 工具定义做不到的------MCP 的 55,000 tokens 工具定义是启动时全量注入的。
6. 实战:什么场景用什么
6.1 决策树
objectivec
需要连接外部系统?
├── 是 → 需要持久连接/状态/会话?
│ ├── 是 → MCP
│ └── 否 → 调用频率高?
│ ├── 是 → MCP(连接复用、缓存)
│ └── 否 → Skill 脚本就够
└── 否 → 需要定义工作流程?
├── 是 → Skill
└── 否 → 既不需要外部连接也不需要流程定义
→ 可能 CLAUDE.md 就够了
6.2 场景对照表
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 读写 Notion 页面 | MCP | 需要 OAuth 会话、频繁交互 |
| 查询生产数据库 | MCP | 连接池、事务、持久会话 |
| 操作 Figma 设计稿 | MCP | 双向通信、状态同步 |
| 按团队规范审查代码 | Skill | 核心是流程知识,不是外部连接 |
| 提交前跑 lint 检查 | Skill 脚本 | 一次性执行,无需持久化 |
| 统计代码行数 | Skill 脚本 | 确定性计算,LLM 做不好 |
| 格式化 Markdown 表格 | Skill 脚本 | 文本处理,脚本更准确 |
| 部署到 Cloudflare | Skill + MCP | Skill 定义部署流程,MCP 连接 CF API |
| 每日早报推送到 Slack | Skill + MCP | Skill 定义内容格式,MCP 负责发送 |
6.3 协同使用的典型模式
最有价值的用法往往是两者配合:
Skill(流程层) MCP(能力层)
┌──────────────┐ ┌──────────────┐
│ 1. 读取 PR 变更 │──────────► │ GitHub MCP │
│ 2. 按规范审查 │ │ │
│ 3. 查关联 Issue │──────────► │ Linear MCP │
│ 4. 写审查报告 │ │ │
│ 5. 发通知 │──────────► │ Slack MCP │
└──────────────┘ └──────────────┘
Skill 编排"做什么、按什么标准做",MCP 提供"连接到哪、怎么通信"。两层各管各的,互不侵入。
7. 常见误区
| 误区 | 事实 |
|---|---|
| "MCP 就是高级版 Skill" | 不是。两者解决不同层面的问题 |
| "有了 MCP 就不需要 Skills" | 不对。MCP 不管流程定义和团队约定 |
| "Skill 脚本能替代 MCP" | 能力上部分重叠,但缺少持久连接、状态管理、跨应用复用 |
| "MCP 很难,先用 Skill 脚本顶着" | 对于简单场景确实可以,但别把它当长期方案 |
| "工具越多越好" | 5 个 MCP Server 就 55,000 tokens。工具多了 Claude 反而选不对 |
| "Skill 只是花哨的 Prompt" | Skill 支持脚本、模板、子 Agent 调度,远不止 Prompt |
8. 工程落地建议
8.1 从 Skill 开始,按需引入 MCP
大多数团队的初始需求是"让 Claude 按我们的方式做事",这正是 Skills 擅长的。不要上来就搭 MCP Server。
启动顺序:
- 先写
CLAUDE.md,定义项目级约定 - 重复出现的流程抽成 Skill
- 需要外部系统交互时,评估是 Skill 脚本够用还是需要 MCP
- 高频、有状态、跨应用的场景上 MCP
8.2 Skill 脚本转 MCP 的信号
当你发现 Skill 脚本出现以下情况,该考虑迁移到 MCP 了:
- 每次执行都要重新认证(OAuth token 过期、重建连接)
- 脚本里有大量错误处理和重试逻辑
- 多个 Skill 依赖同一个外部服务
- 需要维持长连接(WebSocket、数据库连接池)
- 其他 AI 工具也需要同样的能力
8.3 控制 MCP 工具数量
前面提到,5 个 MCP Server 就占 55,000 tokens,约 200K 上下文的三成。工具定义过多直接导致:
- Claude 选错工具的概率上升
- Prompt Caching 命中率下降
- 上下文留给实际任务的空间变少
原则:只接真正需要的 MCP Server,不要贪多。
9. 划重点
- MCP 是协议级标准,提供持久化的外部系统连接;Skills 是 Claude Code 本地扩展,提供流程知识和确定性脚本。两者解决不同层面的问题。
- Skills 脚本确实能干 MCP 能干的部分事情,但机制完全不同:一个是持久服务进程,一个是按需执行的一次性命令。
- 选择标准不是"能不能做"而是"该怎么做":需要持久连接、状态管理、跨应用复用时用 MCP;需要定义流程、团队约定、确定性计算时用 Skills。
- 最有价值的用法是两者协同:Skill 编排"做什么、怎么做",MCP 提供"连到哪、怎么通信"。
- 从 Skill 开始,按需引入 MCP。不要一上来就搭 Server,也不要用 Skill 脚本硬撑需要持久连接的场景。
- 控制 MCP 工具数量。5 个 Server 就 55,000 tokens,工具越多 Claude 越容易选错。
参考资料
- Anthropic, Introducing the Model Context Protocol
- Anthropic, Extend Claude with skills
- Anthropic, Introducing Agent Skills
- Model Context Protocol, What is MCP?
- Tw93, 你不知道的 Agent:原理、架构与工程实践
- IntuitionLabs, Claude Skills vs. MCP: A Technical Comparison
- morphllm, Claude Code Skills vs MCP vs Plugins: Complete Guide