
先说一个我最近经常被问到的问题“Agent Skills是不是要取代MCP”问的人多了我发现大家其实是被两个概念的命名带偏了——都带“Agent/模型”的影子都像是给AI加能力很容易被当成同一类东西。实际上在真实项目里这俩完全不在一个层面上也没法互相替代。我最早把两者彻底区分开是在一次Agent平台的技术方案评审上。当时团队想做一个内部数据库巡检助手既能查元数据、拉慢查询又希望AI按固定流程输出报告。一开始我们只接了一个MCP Server结果发现工具是能调了但AI每次调用的顺序、报告的结构、异常的判断标准都不稳定今天一个样明天一个样。后来引入Agent Skills把流程固化成标准作业程序才真正把“能调工具”变成了“会干活”。这篇文章就以“Agent Skills和MCP的关系”为主线把两者的定位差异、协作方式、落地踩坑一次性讲透。适合正在做Agent平台、写MCP Server或者刚被Agent Skills这个概念搞晕的开发者。看完你至少能分清什么时候该写Skill什么时候该做MCP Server以及它们是怎么在同一个Agent里配合的。1. 先搞清楚两个概念到底在解决什么问题1.1 Agent SkillsAgent的“行为模块化”Agent Skills最早由Anthropic在2025年10月推出后来Claude Code、Cline、Roo Code这些主流Agent工具都跟进了类似机制。它的本质很简单把一段做事的方法固化成一个可复用的技能包当Agent遇到匹配的场景时按需读取这个技能包并按里面的步骤执行。一个标准的Skill目录长这样skills/ code-review/ SKILL.md # 技能定义 scripts/ # 可选辅助脚本 assets/ # 可选模板、文档 database-inspection/ SKILL.md assets/ report_template.mdSKILL.md是关键文件用YAML frontmatter声明name和description正文写具体的执行指令。模型会先读description判断“当前任务是否匹配这个技能”匹配后才会加载正文——这也就是所谓的按需加载靠近使用时注入上下文而不是把所有技能一股脑塞进系统提示词里。举个例子我一个代码审查Skill的description会写当用户要求检查代码质量、审查Pull Request、找潜在Bug时使用。典型触发语帮我review一下这段代码、这PR有没有问题。正文则规定先看整体逻辑、再查错误处理、最后给分级建议。这套东西解决的核心问题是同样的任务每次让Agent自由发挥结果就会漂移。有了Skill能把最佳实践固定下来让Agent的行为稳定、可复制、可审计。1.2 MCPAgent的“外部世界连接标准”MCPModel Context Protocol是Anthropic在2024年11月开源的协议全称是模型上下文协议。它的目标非常明确标准化AI应用与外部工具、数据源、文件系统之间的交互方式。很多人把它类比成“AI界的USB-C”我觉得这个类比很贴切——以前每个工具都要单独给AI做私有集成现在只要实现MCP接口任何支持MCP的Agent都能即插即用。MCP的架构包含四个角色Host是宿主应用比如Claude Desktop、IDE插件Client负责在Host里管理连接Server是工具提供方把能力包装成标准接口Transport负责底层通信本地常用stdio远程用HTTP/SSE。这个体系里有三个核心原语Tools可被AI调用的操作比如查询数据库、打开浏览器、发送消息Resources可被AI读取的数据比如配置文件、日志文件、数据库SchemaPromptsServer端预置的提示模板告诉AI“这个工具通常怎么用”MCP解决的是工具接入碎片化的问题。你想想光是浏览器自动化就有Playwright MCP、Chrome DevTools MCP、Browser Use MCP好几个选择数据库类MCP更是数不清。每个都走标准协议Agent接起来成本就低很多。热词里提到的同花顺MCP、Burp Suite MCP、蓝湖MCP、Cheat Engine桥接MCP、通义灵码连Oracle本质上都是把某个域的能力包装成MCP Server让AI能调用。1.3 一张表说清定位差异维度Agent SkillsMCP定位Agent内部的行为能力封装Agent与外部系统之间的连接协议解决的问题“怎么思考、怎么组织动作”“怎么触达外部工具和数据”载体SKILL.md 可选脚本、模板Server Client Transport是否需要网络不需要纯本地指令需要Server在对应环境运行加载方式Agent按需注入上下文工具列表动态发现、远程调用所属层次认知层 / 行为层连接层 / 协议层典型场景代码审查、报告生成、多步工作流查数据库、操作浏览器、文件读写看完这张表你就能明白这俩根本不是竞争关系。Skills管的是Agent“内在的如何做”MCP管的是Agent“外在的用什么做”。一个解决聪明的问题一个解决连接的问题。2. 两个东西不是二选一而是互补关系2.1 Skills决定“怎么做”MCP决定“拿什么做”我先说一个没有MCP时Skills的局限。写一个“生成数据库巡检报告”的Skill如果底下没有任何真实工具Agent能做的只是基于它的训练知识“编”一份报告字段可能是编的、数据可能是编的、结论更是编的。Skill再规范也改变不了“巧妇难为无米之炊”的事实。MCP就是那口锅里的米它让Agent真正能拿到外部数据。反过来只有MCP没有Skills也有困境。我见过一些团队把MCP Server接好之后满怀期待让AI操作结果发现AI确实会调用工具但调用得很随意说好了先查元数据再判断结果它上来就拉全表数据说要聚焦慢查询结果它把每个表都扫一遍token烧得飞快。这时候你就明白工具是能力但能力不等于稳定的工作方法。谁来决定先做什么后做什么、做到什么程度算完成这是Skills的活。一个健康的分工是Skills负责“工作流编排”MCP负责“原子能力供给”。Skill里的instructions写明步骤和判断标准MCP的工具负责具体的执行细节。2.2 真正的协同Skill做编排MCP做执行下面这段是两者实际的协同逻辑。以数据库巡检为例一个Skill的instructions里会写先调用db-inspection_list_tables获取全部表判断表数量是否异常超出基线数量一般意味着有临时表没清理对核心业务表调用db-inspection_table_schema检查是否有主键、字段类型是否合理、索引是否缺失调用db-inspection_slow_query_check获取最近30分钟慢查询重点关注执行时间超过2秒的SQL按照assets/report_template.md的格式输出巡检报告发现问题时调用db-inspection_notify发送告警注意第1、2、3、5步全部是MCP工具。但决定“什么时候调用哪个工具、调用顺序如何、结果怎么解读”的是SKILL.md里的指令。这就是两者的交汇方式Skill是剧本MCP是演员。还有一个关键机制叫allowed-tools。Skill定义里可以声明白名单只允许Agent在技能执行期间调用指定的那几个工具防止跑偏。比如“数据库巡检”技能只允许操作db-inspection这个Server下的工具绝不允许去调用什么浏览器工具、文件删除工具。这是安全设计上非常重要的一道闸门。2.3 最容易踩的3个误区误区一用Skills替代MCP把工具逻辑写进SKILL.md。有人图省事不写MCP Server直接在Skill里写“你需要模拟运行一条SQL”让模型凭空猜测查询结果。这非常不可靠生成的数据没人敢信而且白白消耗大量token。凡是需要真实访问外部系统的老老实实走MCP。误区二用MCP替代Skills把所有业务流程封装成一个个MCP Tool。这个方向也错。如果业务流程全写在工具实现里意味着每改一次流程就要改一次代码、重启一次Server。而且工具会越堆越多Agent挑选工具的难度也急剧上升。业务规则放Skills层工具保持原子化才是正确的拆法。误区三混淆MCP的Prompts和Agent Skills。MCP的Prompts是Server端提供的提示模板告诉你“某工具通常怎么用”Agent Skills是Agent端的行为定义告诉你“某类任务该怎么完成”。前者是说明书后者是操作手册不是一个层面的东西别混着谈。3. 实操搭建一个会查数据库的自动化运维助手3.1 需求拆解与分层方案我拿一个真实的内部工具举例这个方案我实际跑过在团队里用了挺长时间。需求大概是让AI在收到“帮我做数据库巡检”“看看数据库有没有问题”这类请求时自动连上MySQL、查表结构、查慢查询、生成一份格式固定的巡检报告并在发现问题时告警。按上一节的思路拆成两层。MCP层一个Python写的数据库巡检Server暴露五个原子工具——server_status、list_tables、table_schema、slow_query_check、notify。Skills层一个名为database_inspection的技能负责明确触发条件、编排调用顺序、规定报告格式、限定允许使用的工具列表。3.2 用FastMCP实现数据库Server实现MCP Server我用的是FastMCP它把底层协议细节封装得很好写起来跟装饰一个普通函数差不多。下面是一个简化版的核心代码# db_server.py from fastmcp import FastMCP import pymysql mcp FastMCP(db-inspection-server) # 数据库连接统一走这里避免重复创建连接 def get_conn(db: str): return pymysql.connect( host127.0.0.1, port3306, userreadonly_user, password******, databasedb, charsetutf8mb4, connect_timeout5, read_timeout10 ) mcp.tool() def server_status() - dict: 返回MCP Server运行状态及数据库连通性Agent在任务开始前应优先调用此工具确认环境可用。 try: conn get_conn(information_schema) conn.close() return {status: ok, database: reachable} except Exception as e: return {status: error, message: str(e)} mcp.tool() def list_tables(db: str) - list[str]: 列出指定数据库中所有业务表名。入参db为目标数据库名。 conn get_conn(db) with conn.cursor() as cur: cur.execute( SELECT table_name FROM information_schema.tables WHERE table_schema%s ORDER BY table_name, (db,) ) rows [r[0] for r in cur.fetchall()] conn.close() return rows[:200] # 截断最多返回200个表 mcp.tool() def table_schema(db: str, table: str) - str: 返回单张表的字段、类型、主键和索引信息。入参db为数据库名table为表名。 conn get_conn(db) with conn.cursor() as cur: cur.execute(SHOW CREATE TABLE %s % table) # 实际请用参数化方式 row cur.fetchone() conn.close() return row[1] if row else table not found mcp.tool() def slow_query_check(db: str, minutes: int 30) - list[dict]: 查询最近N分钟慢查询日志默认30分钟窗口。重点关注执行时间超过2秒的SQL。 conn get_conn(db) with conn.cursor() as cur: cur.execute( SELECT start_time, query_time, sql_text FROM slow_log WHERE start_time NOW() - INTERVAL %s MINUTE ORDER BY query_time DESC LIMIT 50, (minutes,) ) rows [{time: r[0], duration: r[1], sql: r[2]} for r in cur.fetchall()] conn.close() return rows mcp.tool() def notify(channel: str, message: str) - str: 发送告警消息到指定渠道。channel为渠道名message为消息正文。 # 实际对接企业微信/钉钉机器人 return fnotification sent to {channel}这段代码有些细节值得说明。第一所有工具都做了结果截断list_tables最多返回200个表slow_query_check最多返回50条记录。为什么要截断因为工具返回的所有内容都会进Agent的上下文如果不设上限一张超大表或几百条慢查询日志就能把上下文撑爆反过来影响模型理解。第二server_status这个工具看着多余实际非常有用。Agent在做任何复杂操作之前先调它确认Server和数据库都活着能把一大半“工具没反应”的排查时间省下来。3.3 编写database_inspection技能MCP Server写完了下面是Skill部分。目录结构很简单skills/database-inspection/ SKILL.md assets/report_template.mdSKILL.md的核心内容是这样设计的--- name: database_inspection description: 对指定MySQL数据库执行健康巡检生成巡检报告。当用户要求检查数据库状态、慢查询、表结构异常、做数据库巡检时使用。典型触发语帮我检查一下订单库、数据库有没有问题、做一次巡检。 allowed-tools: - db-inspection_server_status - db-inspection_list_tables - db-inspection_table_schema - db-inspection_slow_query_check - db-inspection_notify --- # 数据库巡检流程 1. 先调用 db-inspection_server_status 确认MCP Server和数据库连通性如果返回 status 不为 ok直接向用户说明环境不可用并结束。 2. 调用 db-inspection_list_tables 获取全部业务表。如果表数量超过该库基线值的120%重点关注是否存在未清理的临时表。 3. 对每张核心业务表调用 db-inspection_table_schema检查 - 是否存在主键无主键的表标记为高风险 - 是否存在明显缺失索引的字段如高频查询字段无索引 - 字段类型是否与业务语义匹配。 4. 调用 db-inspection_slow_query_check 获取最近30分钟慢查询。对执行时间超过2秒的SQL逐条分析判断是全表扫描、缺索引还是并发问题。 5. 按 assets/report_template.md 的格式输出巡检报告包含巡检时间、库名、表数量、风险项清单、慢查询统计、改进建议。 6. 如果发现任何高风险项调用 db-inspection_notify 发送告警消息内容为风险摘要。汇报模板report_template.md我会写成一个Markdown骨架包含标题、巡检时间、风险级别、明细表格这些固定结构确保每次输出的报告长得一样下游解析也方便。这里有一个必须强调的细节allowed-tools里工具名的格式是MCP Server名_工具名中间用下划线连接。比如Server在配置里叫db-inspection工具叫list_tables那白名单里就是db-inspection_list_tables。这个命名规则因客户端而异但FastMCP和Claude生态基本都遵循这个约定。写错的话Agent会报“工具不存在”这是我在群里看到问得最多的问题之一。3.4 配置接入与运行效果实录配置MCP Server的方式取决于你用的客户端。Claude Desktop是在claude_desktop_config.json里加一段{ mcpServers: { db-inspection: { command: python, args: [db_server.py], env: { DB_HOST: 127.0.0.1, DB_USER: readonly_user } } } }如果用Cline或Roo Code这类VS Code插件在配置界面里填同样的内容就行。关键是把db-inspection这个名字和代码里的Server ID保持一致否则白名单匹配不上。运行效果大致是这样。用户说“帮我检查一下订单库。”Agent会先判断这个请求匹配了database_inspection这个Skill的description于是加载SKILL.md正文然后按照流程第1步调用server_status确认正常后调用list_tables接着逐个检查表结构、查慢查询最后按模板输出报告。整个过程中模型每一步的调用顺序都被Skill的指令约束住了不会跑偏而真正取数、查询的能力来自MCP工具。两者配合行为和结果都稳定。3.5 关键参数背后的取舍逻辑有几个参数我特意调整过这里说说当时的思考过程。slow_query_check的时间窗口默认30分钟超时时间设10秒。设太短查不到有效数据设太长日志量大会拖慢响应30分钟是我们运维同事“发现异常后想先看最近情况”的合理粒度。list_tables返回上限200个表。一般业务库超过200张表已经算复杂了再高的场景应该按业务模块拆分而不是无限返回。SQL查询一律用参数绑定table_schema里我写的是SHOW CREATE TABLE实际上线时表名不能直接拼接用户输入必须做白名单校验或参数化处理。安全这块别偷懒Agent工具特别是数据库类工具一定要用只读账号权限最小化。工具返回的每条慢查询我加了时长字段方便模型快速排序不用在长文本里硬找。这个细节属于“工具设计为模型服务”的思路MCP工具不仅要实现功能还要考虑返回结构对模型友好。4. 常见问题与排查技巧实录4.1 问题排查速查表问题常见原因解决思路Skill一直不触发description写得太抽象没有典型触发语在description里加2到3个用户真实说法例句Agent调用MCP工具报not foundallowed-tools里的工具名格式不对确认工具名是“Server名_工具名”且Server名与配置一致MCP工具返回内容巨大上下文爆炸工具没做结果截断Server层对行数和字段数都设上限SKILL.md加载后Agent执行顺序还是乱instructions里没写清明确的先后顺序第一行直接写“先调用xxx然后…”别用模糊表述配置了Skill但完全不生效skills目录名或SKILL.md路径不对确认目录名是skillsSKILL.md必须放在该技能的根目录stdio模式的MCP Server启动失败依赖缺失或Python解释器路径不对先手动在终端跑一遍命令确认能启动再配给客户端Agent拿到MCP工具后乱调用工具description太宽泛每个工具的description写清楚参数含义、适用场景和典型用例远程MCP连接被拒端口或WSS地址配置错误或Token失效用MCP Inspector单独连接测试先排除Server侧问题多Skill存在时误触发description描述重叠度太高每个Skill的触发场景要写差异化必要时设互斥条件4.2 几条压箱底的避坑经验第一条MCP工具要原子化业务规则别写死在Server里。我一开始图省事把整个巡检流程写成了一个工具结果每次改报告格式都要改代码重启Server。改成Skills层之后改流程只改SKILL.md几分钟搞定效果完全不一样。第二条allowed-tools一定要写哪怕麻烦。不写白名单意味着Skill运行时Agent可以调用客户端里的任何工具一旦某个工具描述被误触发可能造成不可逆操作。白名单是低成本高收益的安全闸门。第三条给每个MCP Server配一个server_status或_health工具。这个习惯帮我省了无数排查时间。Agent每次开工前先确认Server存活错了也知道是环境问题还是逻辑问题。第四条Skill不要贪多。表面上看技能越多Agent越强大实际上Agent在并行判断哪个description匹配时技能数量太多会增加决策负担。我的经验是一个技能只干一件事description短而准正文控制在“30秒内读完”的长度。第五条定期看触发率。在Claude Code这类工具里能看Skill调用日志凡是触发率很低的Skill大概率是description写得太烂或场景没有实际需求删掉或重写别留着吃灰。最后分享一个实用的经验我在实际项目里折腾了有一阵子最后形成的判断是MCP接入要克制Skills固化要大胆。先挑两三个真正高频的外部能力做成MCP Server跑通之后再把这些能力串成Skill。起步阶段别追求数量一个库巡检Skill、一个代码审查Skill、一个通知Skill基本上就能覆盖大部分自动化场景。还有一件事值得提就是概念本身也在演进。今天聊的Agent Skills和MCP未来可能都会融合出新的形态但底层那个分工逻辑大概率不变——连接外部世界的归协议层稳定行为模式的归技能层。理解这一层比记住任何一个API细节都更重要。