Skills 并未杀死 MCP:Goose 中 Agent Skills 与 MCP 的能力分工与协作边界
导读:每当 AI 圈出现新概念,技术社区总喜欢宣布某个旧技术"已死"——这一次的标题党主角是 "Agent Skills 刚刚杀死了 MCP"。本文以 goose 开源项目为背景,从 MCP 的"能力层"与 Agent Skills 的"流程/知识层"入手,讲清楚两者为何是互补而非替代关系;同时结合 goose 仓库中 Skills 的文件发现机制、
load_skill工具的源码实现与 Developer MCP 扩展的真实配置,给出可落地的分层认知与配置方法。
一、一个并不新鲜的"标题党"命题
"Skills 刚刚杀死了 MCP"——这句话听起来很大胆,也很笃定,但它是错的。
把它翻译成另一句话你就立刻明白了:说"GitHub Actions 杀死了 Bash"和它有差不多同等的准确性。Bash 至今活得很好,而且实际上正在干着真正的活。GitHub Actions 改变的是表达方式(expression),而不是执行方式(execution)——它给了我们一种更清晰、更易共享的方式来描述"我们如何构建、测试和部署",但底层跑的还是同一批 shell 命令。YAML 组织的是执行,不是取代执行。
这正是 Agent Skills 与 MCP 之间的关系。一旦你从这个视角看问题,"Skills 杀死 MCP"的说法自己就塌了。
在继续阅读之前,建议先对照 goose 官方对这两项能力的完整指南:Agent Skills 使用指南 与 Developer MCP Server(Developer 扩展)。
二、MCP 是"能力层":让 Agent 真正动手
MCP 承载的是能力(capability)。正是它让 AI Agent 真正"做成事",而不只是"讨论事"。当一个 Agent 能够执行 shell 命令、编辑文件、调用 API、查询数据库、读取磁盘、存取记忆、拉取实时数据时,背后基本都是 MCP 在工作。
MCP Server 是代码。它们以服务形式运行,对外暴露可调用的工具(tools)。只要 Agent 想以任何有意义的方式与现实世界交互,几乎必然有 MCP 参与。
举几个具体例子:Agent 需要查询 GitHub API、发送一条 Slack 消息、拉取生产环境指标——这些都要求真实的集成、真实的权限和真实的执行。光靠"指令"本身做不到这些。指令无法凭空获得网络访问权,也无法替你完成一次带认证的 API 调用。
在 goose 仓库中,这一点有非常清晰的落地形态:Developer 扩展(即内置的 Developer MCP Server)向 Agent 提供了 shell、write、edit、tree、read_image 等真实执行工具(见 documentation/docs/mcp/developer-mcp.md)。其中:
| 工具 | 作用 | 风险等级 |
|---|---|---|
shell |
执行 shell 命令(跑测试、装包、git 操作) | 高:可以以你的用户权限运行任意系统命令 |
write |
创建或覆盖文件 | 高:可以修改任何可访问的文件 |
edit |
精确替换文件中的文本 | 高:可以修改任何可访问的文件 |
tree |
列出目录树与行数,帮助理解项目结构 | 低:只读 |
read_image |
读取本地或远程图片供模型查看 | 低:只读 |
这正是"MCP 提供 runner"的仓库证据:真正的读写执行,落在这些由 MCP Server 暴露的工具上。
三、Agent Skills 是"流程与知识层":教 Agent 把事情做对
Skills 生活在另一个层级。Skills 关乎流程与知识(process and knowledge)。它们是 markdown 文件,编码了"工作应该怎么做":团队约定、工作流、领域经验。一个 Skill 可以描述部署应该如何进行、代码评审如何处理、事故如何分级响应——这是把制度性知识显性化(institutional knowledge made explicit)。
goose 官方对 Skills 的定义是:"可复用的指令与资源集合,用于教会 goose 如何执行特定任务。一个 Skill 可以简单到一份清单,也可以复杂到一份包含领域专长的详细工作流,并且可以附带脚本或模板等支撑文件。"(见 using-skills.md)。典型使用场景包括部署流程、代码评审清单、API 集成指南。
原博客中给出了一个教 Agent 接入 Square 账户的示例 Skill,它完整展示了一个 Skill 的真实结构(YAML frontmatter + Markdown 正文):
---
name: square-integration
description: How to integrate with our Square account
---
# Square Integration
## Authentication
- Test key: Use `SQUARE_TEST_KEY` from `.env.test`
- Production key: In 1Password under "Square Production"
## Common Operations
### Create a customer
const customer = await squareup.customers.create({
email: user.email,
metadata: { userId: user.id }
});
### Handle webhooks
Always verify webhook signatures. See `src/webhooks/square.js` for our handler pattern.
## Error Handling
- `card_declined`: Show user-friendly message, suggest different payment method
- `rate_limit`: Implement exponential backoff
- `invalid_request`: Log full error, likely a bug in our code
注意上例中的 frontmatter 只有两个必填字段:name 与 description。goose 源码对这两个字段做了严格校验与解析——在 crates/goose/src/skills/mod.rs 中定义了 SkillFrontmatter 结构:name 可选(缺失时跳过该 Skill 并告警)、description 必填、额外的自由元数据放入 metadata 嵌套映射(遵循 agentskills.io 规范,避免与保留字段冲突)。而 validate_skill_name(mod.rs)进一步约束了命名规则:
- 名称不能为空;
- 长度不超过 64 个字符;
- 只允许小写字母、数字与连字符
-; - 不能以连字符开头或结尾。
违反以上任何一条,该 Skill 都会在发现阶段被跳过或直接报错——这些约束从侧面说明:Skill 的 name 是运行时被精确索引与调用的标识符,而不只是给人看的标题。
四、为什么 Skill "看起来会执行"却不会?
Skills 可以包含看起来可执行的东西——这也是大量混淆的来源。一个 Skill 可能展示代码片段、引用脚本、甚至打包模板或脚本文件,这很容易让人觉得"是 Skill 自己在干活"。
但事实并非如此。
即使一个 Skill 文件夹里带着可运行的脚本,执行它们的也不是 Skill 本身。Agent 是靠调用"别处提供的工具"(例如通过 Developer MCP Server 暴露的 shell 工具)来执行这些文件的。Skill 打包的是指导与素材(guidance and assets),而运行代码、访问网络、修改系统的能力来自工具——这些工具通常正是通过 MCP 暴露的。
goose 中的一条关键证据:Skill 目录与支撑文件如何被"执行"
在 goose 中,Skills 功能由内置的 Skills 平台扩展提供(默认启用,扩展名 skills,常量定义见 crates/goose/src/skills/client.rs)。深挖实现会发现一个很有意思的事实:Skills 扩展本身也是以 MCP Client 的方式实现的——它向 Agent 暴露了一个名为 load_skill 的工具(工具定义与参数 schema 见 client.rs),参数只有两个:
name:要加载的 Skill 名称;支持用"skill-name/路径"的形式加载某个支撑文件;args:加载 Skill 时可选的参数(会被注入正文中的$ARGUMENTS占位符,相关渲染逻辑见 mod.rs)。
也就是说:Skill 的正文内容通过 load_skill 注入 Agent 的上下文,让模型"学会怎么做";而 Skill 内引用的脚本、模板等支撑文件,要么同样通过 load_skill(name: "skill-name/relative/path") 读取内容,要么依赖 Developer 扩展的文件工具去读写。用源码注释里的话说:"shell 工具运行在会话工作目录中,因此相对路径会从 Skill 目录解析;如果要运行支撑脚本,请使用解析后的完整路径或先 cd 进 Skill 目录"(见 mod.rs 的 supporting files 拼接逻辑)。
这在代码层面再次印证了博客的核心论断:Skill 只负责"把指导送进上下文",真正的跑命令、改文件永远由工具完成。
五、GitHub Actions 类比:YAML 不执行任何东西
让我们回到 GitHub Actions 的类比,把话讲透:
一个 workflow 文件可以引用脚本、命令和可复用的 action,看上去威力十足。但 YAML 本身不执行任何东西——执行它的是 runner。没有 runner,workflow 只是一份计划。
对应到 Agent 世界:
- Skills 描述工作流,MCP 提供 runner。
- Skills 没有 MCP:只是一份写得不错的说明书。
- MCP 没有 Skills:是没有任何指引的"裸能力"。
- 一个告诉 Agent 应该发生什么;另一个让 任何事情都有可能发生。
能力与指引必须双全
把两者放在一起,生态才算完整。举一个 goose 用户每天都在经历的对比:
- 要让 Agent 在新会话中自主选择正确方法:需要 Skill 提供的名称与描述被自动注入系统指令。goose 在每次会话启动时,会把发现的 Skill 名称与描述加入指令(见 using-skills.md 与 client.rs 附近的
get_instructions逻辑)。当你的请求明确匹配某个 Skill 的用途、或你显式要求"用 code-review skill 评审这个 PR"时,goose 才会把完整指令加载进来。 - 要让 Agent 真正把这些步骤跑完:需要 Developer MCP 提供的
shell、write、edit工具来安装依赖、创建文件、执行测试。
只给 Agent 一把刀(MCP 工具)而没有任何操作手册,它会乱砍;只给手册(Skill)而没有任何工具,它什么都做不了。
六、在 goose 中实际使用 Skills:位置、命令与发现机制
存放位置与发现优先级
goose 会从多个位置递归发现 SKILL.md。推荐位置有三类:
~/.agents/skills/—— 全局 Skill,所有会话可用;.agents/skills/—— 项目级 Skill,仅当前项目可见;~/.agents/plugins/<plugin-name>/—— 由已安装插件提供的 Skill。
同时为向后兼容,goose 也会扫描 .goose/skills/、.claude/skills/、~/.claude/skills/ 以及平台相关的配置目录,但官方推荐统一使用 agents/skills/ 标准。
源码 mod.rs 中的 all_skill_dirs_with_config 精确描述了发现顺序与优先级:项目目录在前(.agents/skills → .goose/skills → .claude/skills → 项目插件 Skill 目录),全局目录在后(~/.agents/skills → 配置目录 skills → ~/.claude/skills → 用户插件 Skill 目录)。递归遍历时会跳过 .git/.hg/.svn 等目录,并在遇到同名 Skill 时只保留优先级更高(先被扫描到)的那一个——测试用例 project_plugin_skill_precedes_global_skill_with_same_name 对此有专门验证。实际目录结构如下:
~/.agents/skills/
└── code-review/
└── SKILL.md
会话内的操作命令
你可以直接向 goose 询问有哪些 Skill 可用,也可以运行 goose skills list,或在 CLI 中用 /skills 命令一次性按名称加载多个 Skill:
/skills code-review edge-case-finder
需要支持文件的 Skill(例如附带脚本、模板的 api-setup)建议把素材放进 Skill 目录中与 SKILL.md 并列:
~/.agents/skills/
└── api-setup/
├── SKILL.md
├── setup.sh
└── templates/
└── config.template.json
内置 Skill 示例:web-search
goose 自带一个无需安装即可用的内置 Skill web-search(内容见 crates/goose/src/skills/builtins/web_search.md)。注意它的实现方式非常能说明问题:这个 Skill 描述的是"用哪些命令行去搜索",而真正联网抓取靠的是 shell 工具与 uvx/curl 这些程序在运行。它内部按优先级选择后端:
- 默认 DuckDuckGo:
uvx ddgs text -q "your query here" -m 5(无需 API key,仅需安装uv); - 设置
TAVILY_API_KEY时改用 Tavily(结果更丰富); - 设置
SEARXNG_URL时改用自托管 SearXNG。
它甚至写明了"若返回登录墙或 CAPTCHA,报告 URL 并停止,不要尝试绕过"这样的使用规则——规则属于 Skill,执行仍属于工具。这就是"流程层"与"能力层"同框工作的最小示例。
七、为什么"两者并存"恰恰是生态成熟的表现
如果非要说 Skills 取代了 MCP,那逻辑就变成了"说明书取代了执行引擎",这本身就不成立。反过来说:
- MCP 给 Agent 以能力(abilities)。
- Skills 教 Agent 如何用好这些能力(how to use them well)。
- Bash 仍在运行命令;GitHub Actions 仍在定义工作流。同一套系统、不同的层级,没有谁被谋杀。
更进一步,两者的并存是一个积极的信号:它意味着 Agent 生态正在走向成熟——我们不再争论"Agent 该有工具还是该有指令",而是在构建默认"两者都需要"的系统。工具负责让"做"成为可能,指令负责让"做对"成为大概率事件。
这正是进步,而不是替代。
给读者的分层实践建议
- 凡是涉及真实副作用的操作(联网、写文件、执行命令、访问外部系统),优先以 MCP Server 的形式提供工具能力,参考 Developer MCP Server 的配置方式与权限控制;
- 凡是涉及"怎么做的知识"(部署流程、评审规范、事故响应、API 集成手册),写成带
name/descriptionfrontmatter 的SKILL.md,放入~/.agents/skills/或项目.agents/skills/,参考 using-skills.md 中的部署工作流、测试策略等完整范例; - Skill 需要引用脚本或模板时,把文件放进 Skill 目录,正文用相对路径指引,Agent 会通过
load_skill(name: "skill-name/文件路径")或 Developer 扩展的文件工具访问它们; - 命名遵守 goose 约束:小写字母、数字与连字符,不超过 64 字符,且不以连字符开头结尾,否则 Skill 会被跳过。
把握好"Skills 描述工作流、MCP 提供 runner"这条分界线,你就不会再被"X 杀死 Y"的标题党带走节奏——你会更关心如何让两者在自己的工程里各司其职。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
