前阵子在给团队做 AI Agent 能力扩展方案调研时,我一直在想一个问题:大模型本身只会“对话”,它究竟靠什么去查数据库、操作浏览器、调用设计稿、执行本地脚本?网上资料大多把“MCP 配置一下就能用”说得特别简单,但真正落地时协议结构、Skill 组织方式、客户端配置、鉴权边界,每一步都有坑。这篇文章我会把 AI Agent 的两大扩展手段讲透,并给出可以直接复用的实战代码,覆盖概念、原理、搭建过程和排错思路,适合正在做 Agent 应用开发、也想了解 MCP 与 Skill 到底是什么的读者。
1. AI Agent 为什么需要能力扩展:从“会聊天”到“能干活”
1.1 AI Agent 的核心组成
AI Agent(智能体)并不是一个神秘的概念。从工程视角来看,一个完整可用的 Agent 至少包含四个核心模块:
- 大模型,负责理解用户意图、规划任务、生成文本或工具调用参数;
- 上下文管理器,负责承载多轮对话、记忆、检索结果和工具返回内容;
- 工具层,负责把模型“想做”的动作真正执行到外部系统;
- 执行与反馈回路,负责把执行结果重新喂给模型,形成“规划—执行—观察—再规划”的循环。
只有一个大模型的程序不能叫 Agent,它只是聊天机器人。真正的 Agent 必须有“行动能力”,而行动能力几乎全部来自工具层。在我实际做的项目里,纯粹让模型自己推理、自己写答案的应用只占少数,绝大多数业务需求最后都落在“帮我查一下订单”“把这份报表发到群里”“根据设计稿生成前端页面”这类需要对接真实资源的任务上。所以工具层怎么设计,基本决定了 Agent 能干什么活。
1.2 模型能力边界:为什么单靠 Prompt 不够
我们在项目初期也走过一段“靠 Prompt 打天下”的弯路。当时为了控制模型输出格式,把工具描述、字段说明、调用约束全部写进系统提示词,结果模型动不动就把参数编错,或者触发了根本不存在的工具。
这里面的问题在于,大模型本质上是概率推理器,它只能“按照文字描述猜测”工具的调用方式,并没有办法保证它与真实接口永远一致。一旦工具数量增加,系统提示词会迅速膨胀,模型对每个工具的关注度会被稀释,出现工具名混淆、参数类型错误、应答格式不稳定等一连串问题。而且,工程上还有一个更现实的问题:很多能力不在模型的知识范围内,比如某个内部数据库的 schema、某套设计稿的节点结构、某个浏览器的真实 DOM 状态,模型根本没有训练数据。这时候再好的 Prompt 也无济于事,必须通过机制化的方式把“外部世界”接入进来。
这也是我为什么强烈建议做 AI Agent 开发的同学认真研究 MCP 和 Skill 的原因。它们不是同一层的事物,但都在解决“模型如何安全、规范、可复用地下达和执行动作”的问题。
1.3 MCP 与 Skill 的能力扩展定位
先给一个整体结论,方便后面理解:
- MCP 解决的是“Agent 如何连接外部工具和数据源”的协议问题,它把各种服务能力抽象成统一接口,让 Agent 可以像“即插即用”一样接入数据库、浏览器、设计工具、文件系统等。
- Skill 解决的是“Agent 如何复用一套成熟的行为流程”的知识问题,它把完成一类任务所需的指令、经验、脚本和参考资料打包成一个可复用的技能包,Agent 遇到对应场景时可以直接加载执行。
可以这样类比:MCP 是 Agent 的“手”,帮助 Agent 碰到真实系统和数据;Skill 是 Agent 的“操作手册”,告诉 Agent 在某个场景里应该按什么步骤把活干完。两者经常配合使用——Skill 负责描述流程和策略,MCP 负责具体执行动作。理解了这层关系,再去读后面的架构和代码就不会觉得混乱。
2. 环境准备与工具链选型
2.1 基础运行环境
本文的实战部分会同时用到 Python 和 Node.js,原因很简单:目前 MCP SDK 对这两种语言支持最成熟。
版本需要根据实际项目情况调整,本文示例以常见环境为例,重点演示配置思路:
- 操作系统:macOS / Linux / Windows(Windows 建议使用 PowerShell 或 WSL 2);
- Python 3.10 及以上;
- Node.js 18 及以上;
- 一个支持 MCP 的 Agent 客户端,常见的有 Claude Desktop、Claude Code、Cursor、Cline、Windsurf 等,示例中会以 JSON 配置文件的方式演示,基本兼容大多数客户端;
- 编辑器推荐 VS Code 或 Cursor,主要为了方便查看 JSON 配置和 Python 日志。
2.2 核心工具链清单
- MCP Python SDK,包名为
mcp; - MCP TypeScript SDK,包名为
@modelcontextprotocol/sdk; - Agent 客户端各自的 Skill 目录约定,不同产品命名可能不同;
- 若干参考类 MCP Server,例如官方仓库中提供的 PostgreSQL、Git、Selenium、文件系统等示例实现。
工具链版本变化较快,我没有在本文写死某个小版本号。如果你的环境安装报错,优先去对应官方仓库看 README 和 release note,不要盲目把网上别人用的版本号复制到生产环境。
2.3 概念辨析:MCP、Skill、Function Calling、Computer Use
很多读者会把 MCP、Skill、Function Calling、Computer Use 混为一谈,这里我用尽量直白的方式区分:
- Function Calling 是模型厂商提供的一种结构化输出能力,它让模型按 JSON 格式输出“要调用哪个函数、参数是什么”。它是一套模型侧的约定,不是一个跨系统协议。
- MCP 是统一的工具接入协议。它不仅有“模型输出函数调用参数”这一层,还解决了工具的发现、连接、鉴权、生命周期管理、资源访问等更完整的工程问题。可以把 MCP 理解成“工具层的 USB-C 接口”。
- Skill 是面向场景的行为封装。它把“什么时候用、按什么步骤做、需要什么脚本、有哪些经验注意点”写成一个包,让 Agent 遇到适配场景时自动加载。
- Computer Use 是让模型直接操作图形界面(看屏幕、模拟鼠标键盘)的一类能力,可以理解为一种特殊的工具,但与 MCP 的定位不同,两者可以共存,也可以单独使用。
把这几个概念区分清楚,能避免很多入职面试和方案评审时的尴尬问题。
3. MCP 核心原理拆解
3.1 MCP 协议是什么
MCP 全称 Model Context Protocol,是一个开放协议,目标是为“大模型应用接入外部工具与数据源”建立一套统一规范。它由 Anthropic 在 2024 年底提出,随后迅速被各类 Agent 客户端和工具厂商支持。
从传输角度看,MCP 支持多种传输方式,开发中最常用的是 stdio(标准输入输出),也就是 Agent 客户端启动一个本地子进程,通过标准输入和标准输出与 MCP Server 通信。另一种常见方式是 SSE(Server-Sent Events)或 HTTP 流式传输,用于连接远程服务。
协议本身定义了三类核心原语:Tools(工具)、Resources(资源)、Prompts(提示模板)。Tools 是绝大多数人最先接触的,它让模型可以调用一个具体动作;Resources 让模型可以读取一段数据内容;Prompts 则是可供复用的提示词模板。在实际业务中,我们通常先从一个 Tools 类型的 Server 入手。
3.2 Host、Client、Server 三层架构
MCP 的架构可以清晰地分为三层:
- Host(宿主):用户直接面对的 Agent 程序,例如 Claude Desktop、Cursor 等。它负责收集用户意图,调度模型,并管理多个 Client。
- Client(客户端):Host 进程内与某个 MCP Server 建立一对一连接的组件。它的职责是维护连接状态、转发工具调用请求、把 Server 返回结果交给模型。
- Server(服务端):独立的进程,可能是本地脚本,也可能是远程服务,负责暴露工具、资源和提示模板。它可以封装数据库、浏览器、设计稿工具、内部 API 等各种能力。
这套架构的好处是解耦。开发者只需要按协议实现一个 Server,任何支持 MCP 的客户端都能直接使用,不需要为每个 Agent 产品单独开发插件。
3.3 一次完整的 MCP 调用流程
我们以“模型查询订单状态”为例,梳理一次完整调用:
- Host 收到用户问题:“订单 10086 现在什么状态?”
- Host 将问题交给大模型,模型根据 Server 暴露的工具描述,决定调用
query_order工具,并生成参数{"order_id": "10086"}。 - Client 通过协议把工具调用请求发送给 MCP Server。
- Server 执行真实查询逻辑,从数据库或 API 获取数据。
- Server 把结果返回给 Client,再被拼接到模型上下文。
- 模型阅读结果,生成最终回答:“订单 10086 已发货,物流单号是 JD00123456。”
这个流程里,MCP 的价值在于第 2 步到第 5 步的“标准化通信”。工具描述如何暴露、参数如何解析、结果如何返回,都有约定,开发者不用关心客户端是哪一家,只要协议对得上,就能跑通。
3.4 常见 MCP Server 应用场景
我在选题调研时梳理了一下社区里比较热的 MCP 应用方向,几乎覆盖了日常开发的所有高频操作:
- 数据库 MCP:让 Agent 直接查询 PostgreSQL、MySQL、SQLite。
- 浏览器自动化 MCP:例如 Playwright MCP,让 Agent 打开网页、点击按钮、抓取数据。
- 设计工具 MCP:Figma、MasterGo、蓝湖的 MCP 插件,可以让 Agent 读取设计稿结构,辅助生成前端代码。
- 3D 与游戏引擎 MCP:Blender、Unity、Cocos Creator 等,让 Agent 操作场景、生成资源。
- 版本库 MCP:封装 Git 操作,让 Agent 读取代码、创建分支、提交变更。
- 日常效率工具 MCP:日历、邮件、飞书/钉钉机器人、任务管理工具等。
这些案例说明,MCP 已经从“尝鲜”走向了“基础设施”。接下来我直接带大家搭建一个自己的 Server。
4. Skill 核心原理拆解
4.1 Skill 的本质
Skill 在中文里常被翻译成“技能”,但它并不是指某个单一的工具函数,而是一整套“完成某类任务的经验包”。一个典型的 Skill 可以包含任务说明、使用步骤、输入输出约定、辅助脚本、数据文件和注意事项。
它解决的核心问题是:让 Agent 不再依赖用户每次手写详细指令,而是遇到某个场景时,自动从技能库中加载对应的行为规范。比如,团队内部经常要做数据周报,那我们可以把“取数—清洗—统计—生成图表—写成周报”的完整流程封装成一个周报 Skill。以后任何成员只要说一句“生成本周数据周报”,Agent 就会加载这个 Skill,按步骤执行。
Skill 的出现,本质上是为了让 Agent 的行为可编排、可复用、可沉淀。这是从“写 Prompt”升级到“建设 Agent 能力资产”的关键一步。
4.2 Skill 与 Prompt、Function Calling 的关系
这个问题很容易被面试官追问:Skill 和 Prompt 有什么区别?
我的理解是,Prompt 是一次性或嵌入在系统提示中的文字指令,它没有独立的生命周期,改起来需要动整个系统配置;而 Skill 是一个结构化、可独立版本管理的单元,它不仅有描述文本,还能带脚本和资源。Skill 最终确实是靠“加载后变成 Prompt 或指导上下文”起作用的,但从工程管理角度看,资产边界完全不同。
Skill 也和 Function Calling 不同。Function Calling 是“模型决定调用哪个函数”,Skill 是“模型决定按哪套流程处理问题”。Skill 内部完全可以包含多个 Function Calling 动作,甚至包含多个 MCP 工具调用。可以理解为:Skill 是更高阶的行为封装,Function Calling 和 MCP 是底层的执行能力。
4.3 Skill 的通用结构与加载机制
虽然不同客户端的 Skill 实现有差异,但大体遵循一种通用结构。下面是我在项目中比较常用的一种组织方式:
skills/ weekly-report/ SKILL.md scripts/ generate_report.py references/ template.md assets/ logo.png其中SKILL.md是入口文件,通常包含两大部分:头部元信息(技能名称、描述、适用场景)和正文(任务步骤、规则、示例、注意事项)。加载机制一般是:Agent 根据当前用户意图与所有 Skill 的 description 做匹配,当匹配度足够高时,将对应 Skill 的内容注入上下文,必要时执行其中的辅助脚本。
这种设计让 Agent 的“知识”和“能力”可以像积木一样叠加,而不是每次都在一个巨大的 Prompt 里手写所有规则。
5. 实战:用 Python 快速搭建 MCP Server
5.1 安装依赖
我们使用 Python 版本搭建一个“订单查询 + 销售统计”的 MCP Server。首先创建项目目录并安装依赖。
mkdir mcp-demo cd mcp-demo python -m venv .venv source .venv/bin/activate # Windows 使用 .venv\Scripts\activate pip install mcp如果你的网络环境安装较慢,可以切换为镜像源。安装完成后,可以用下面的命令确认 SDK 是否可用:
python -c "import mcp; print('mcp ok')"5.2 编写核心 Server 代码
新建文件order_server.py。我们使用mcp.server.fastmcp.FastMCP来快速创建一个 Server。为了演示方便,这里先使用内存数据代替真实数据库。
# mcp-demo/order_server.py from mcp.server.fastmcp import FastMCP # 创建 MCP Server,名字会显示在客户端配置中 mcp = FastMCP("order-demo") # 模拟的订单数据 ORDERS = { "10086": {"status": "已发货", "carrier": "顺丰", "tracking_no": "SF1234567890"}, "10087": {"status": "待付款", "carrier": "", "tracking_no": ""}, "10088": {"status": "已完成", "carrier": "中通", "tracking_no": "ZT987654321"}, } @mcp.tool() def query_order(order_id: str) -> str: """根据订单号查询订单状态、物流公司和运单号。 Args: order_id: 订单号,例如 10086。 """ info = ORDERS.get(order_id) if not info: return f"未找到订单 {order_id}" return ( f"订单 {order_id} 当前状态:{info['status']};" f"物流公司:{info['carrier'] or '暂无'};" f"运单号:{info['tracking_no'] or '暂无'}" ) @mcp.tool() def count_orders() -> str: """统计当前订单总数以及各状态订单数量。""" total = len(ORDERS) status_count = {} for info in ORDERS.values(): status_count[info["status"]] = status_count.get(info["status"], 0) + 1 return f"订单总数:{total};状态分布:{status_count}" if __name__ == "__main__": # 启动 Server,默认使用 stdio 传输 mcp.run()这段代码里有两个关键点:
@mcp.tool()装饰器把函数注册成一个可供模型调用的工具,函数的 docstring 会被当作工具描述,模型就是靠这段描述决定何时调用以及传什么参数的,所以描述要写得尽量清晰。mcp.run()默认以 stdio 方式启动,适合作为本地子进程被 Agent 客户端拉起。
5.3 运行方式验证
在终端运行:
python order_server.py如果 SDK 安装正常,你会发现终端看起来“卡住”了,没有任何输出。这是正常的,因为程序正在等待从标准输入读取协议消息。你可以按Ctrl+C结束。
如果想快速验证工具函数本身的逻辑,可以加一行测试代码临时运行,但更推荐直接在后续的客户端配置中验证,因为那样能验证完整的 MCP 通信链路。
5.4 在客户端中配置 MCP
大部分支持 MCP 的客户端都支持通过 JSON 文件声明 MCP Server。下面是一个通用的配置片段,文件名可能是.mcp.json或客户端偏好设置中的 MCP Servers 区域,具体入口因产品而异。
{ "mcpServers": { "order-demo": { "command": "python", "args": ["/absolute/path/to/mcp-demo/order_server.py"] } } }配置完成后,重启客户端。然后向 Agent 提问:“订单 10086 现在什么状态?” 模型应该会自动调用query_order工具并返回如下结果:
订单 10086 当前状态:已发货;物流公司:顺丰;运单号:SF1234567890如果客户端有“工具列表”或“MCP 资源”面板,你也能看到query_order和count_orders两个工具已经注册成功。此时第一个 MCP 服务就算跑通了。
5.5 补充:连接真实数据库时的注意事项
热词里经常看到“claude code 安装 mcp 读取数据库”,说明很多人希望让 Agent 直接读库。这里补充一条重要经验:
- 不要把生产库的写权限直接暴露给 Agent;
- 应先为 Agent 创建只读账号,并限定 schema 和表;
- 查询语句要走参数绑定,避免让模型生成的字符串直接拼接 SQL;
- 在测试环境验证所有工具的行为,再考虑发布到生产。
连接 MySQL 时,需要在 Server 端引入数据库驱动,并在工具函数内部完成连接创建、查询、关闭。数据库密码不要写死在代码里,建议通过环境变量或密钥管理服务注入。
6. 实战:创建并调试一个 Agent Skill
6.1 Skill 设计目标
先规划一个技能:运营数据周报分析 Skill。当用户说“生成这周运营周报”时,Agent 能按固定流程做四件事:
- 从数据源加载本周订单数据;
- 清洗并统计核心指标;
- 生成趋势图表;
- 按固定模板输出周报内容。
这套流程如果每次都用对话方式临时指挥,既容易遗漏环节,结果格式也会不稳定。封装成 Skill 后,Agent 会稳定地按步骤执行。
6.2 目录结构与 SKILL.md
在 Agent 的 skills 目录下新建weekly-report技能包。先看目录结构:
skills/ weekly-report/ SKILL.md scripts/ build_report.py references/ report_template.md编写SKILL.md作为技能入口。这里采用比较通用的 Markdown 头信息格式,不同客户端字段略有差异,请以你的客户端文档为准。
--- name: weekly-report description: 当用户需要生成运营数据周报、统计本周订单、分析销售趋势时使用该技能,可以自动完成数据统计、图表生成和报告输出。 --- # 运营数据周报 Skill ## 适用场景 - 用户要求“生成本周周报”“汇总本周数据”“分析订单趋势”。 ## 执行步骤 1. 调用订单统计工具,获取本周订单量、销售额、退款率等基础指标。 2. 调用趋势分析脚本,计算环比变化。 3. 调用图表生成脚本,输出 PNG 趋势图。 4. 按照 references/report_template.md 的模板填充内容。 ## 注意事项 - 数据时间范围默认是本周一至今天,用户另有说明时以用户为准。 - 如果某项指标无法获取,不要猜测,明确标注“数据缺失”。 - 输出报告时保留两位小数。这里的关键是:把任务步骤写得足够具体,让模型能稳定地按流程执行,同时留下处理异常的规则。
6.3 编写辅助脚本
build_report.py是一个辅助脚本,负责把原始数据转成 Markdown 报告片段。这里不连接真实数据库,用模拟数据演示处理逻辑。
# skills/weekly-report/scripts/build_report.py import json import sys def compute_metrics(orders_data: list[dict]) -> dict: """根据订单列表计算核心运营指标。 Args: orders_data: 订单列表,每个订单包含 amount、status 等字段。 """ total_amount = sum(float(o.get("amount", 0)) for o in orders_data) total_orders = len(orders_data) success_orders = [o for o in orders_data if o.get("status") == "success"] return { "total_orders": total_orders, "total_amount": round(total_amount, 2), "success_orders": len(success_orders), "success_rate": round(len(success_orders) / total_orders, 4) if total_orders else 0, } def format_report(metrics: dict) -> str: """把指标格式化成周报 Markdown 片段。""" return ( "## 本周核心指标\n\n" f"- 订单总量:{metrics['total_orders']}\n" f"- 成交金额:{metrics['total_amount']}\n" f"- 成交订单数:{metrics['success_orders']}\n" f"- 订单成功率:{metrics['success_rate'] * 100:.2f}%\n" ) if __name__ == "__main__": # 从命令行接收 JSON 字符串,方便 Agent 调用 raw = sys.argv[1] data = json.loads(raw) result = compute_metrics(data) print(format_report(result))这个脚本体现了 Skill 的一个重要设计原则:复杂计算不要依赖模型心算,而是尽量放进脚本里执行,模型只负责调度和解读结果。这样能大幅提升结果准确率。
6.4 让 Agent 按 Skill 执行
当 Skill 包被正确放入目录后,重启 Agent 客户端,然后输入:
生成这一周运营数据周报,数据文件在 data/weekly_orders.jsonAgent 应当自动加载weekly-reportSkill,按SKILL.md里的步骤执行,最终输出包含「本周核心指标」的报告。如果你的客户端支持显示“加载了某个 Skill”,你应该能看到技能名称出现在调用信息里。
如果你在验证时发现 Agent 没有自动加载该 Skill,可以检查:
- Skill 目录是否放在客户端约定的根目录下;
description是否写清楚适用场景,模型匹配能力有限时,可以主动提示“使用 weekly-report 技能生成本周周报”;- 脚本是否有执行权限,Windows 系统下要注意 Python 命令的可执行路径。
7. 开发中常见问题与排查思路
下面整理一份高频问题清单,覆盖我实践和社区反馈中常见的坑。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 配置 MCP 后客户端未识别 Server | 命令路径或参数写错,或 Server 启动即崩溃 | 先在终端手动运行命令,确认能进入等待状态;检查 JSON 中command和args是否为绝对路径 |
| 模型总是编造工具名 | 工具说明不清晰,或工具数量过多 | 精简工具数量,docstring 写清楚“何时调用”,必要时为每组工具增加命名前缀 |
| 调用 MCP 工具后返回值格式异常 | Server 返回了非文本内容,或模型未按结构解析 | 先保证 Server 返回纯文本 Markdown;生产环境可以统一 JSON 结构返回,并让模型按 JSON 读取 |
| Skill 没有被自动加载 | description 匹配不上,或者目录结构不对 | 检查 Skill 目录层级、文件名是否为SKILL.md;在对话中显式指定技能名验证 |
| 脚本执行报编码错误 | Windows 下默认编码不是 UTF-8 | 在脚本入口处加# -*- coding: utf-8 -*-,或设置环境变量PYTHONUTF8=1 |
| 数据库 MCP 查询超时 | 查询未加 LIMIT,或连接池失效 | 在工具函数内强制加 LIMIT,设置连接超时;生产环境建议使用只读账号 |
| 修改 Server 代码后客户端仍走旧逻辑 | 客户端缓存了 Server 进程 | 重启客户端,或先杀死残留的 MCP 子进程再测试 |
排查问题的基础方法论是“分层定位”:先确认 Server 端能独立运行,再确认配置能被客户端读到,最后确认模型是否真的发起了正确的工具调用。这个顺序能过滤掉大部分低级错误。
安全提醒:如果你在 MCP Server 里实现了数据库删除、更新、文件写入等操作,务必先做好备份和最小授权。不要在未确认数据影响范围的情况下,把高风险操作直接暴露给模型,更不要在生产环境用管理员账号直接连接 MCP Server。
8. 最佳实践与工程建议
8.1 安全与权限边界
Agent 的能力越强,安全风险越高。基于我踩过的坑,建议所有人在上线前都做一次安全审查:
- 最小权限原则:MCP Server 连接的数据库、文件目录、API 都要限制到“完成任务所需的最小范围”。
- 危险操作确认机制:删除、覆盖、转账、发送消息等高危动作,不要由模型单独决定,至少在客户端侧增加人工确认步骤。
- 输入校验:模型生成的参数不一定安全,Server 端必须对长度、格式、枚举范围做校验,防止注入和异常输入。
- 密钥管理:所有密码、Token 通过环境变量或密钥服务注入,严禁硬编码到代码和配置里。
- 审计日志:记录每次工具调用的发起人、参数、返回结果和时间,方便事后追溯。
8.2 配置与版本管理
MCP Server 和 Skill 本质上都是代码资产,要像业务代码一样管理。
- 用 Git 管理 MCP Server 代码和 Skill 目录,每个技能一个独立目录,提交信息写清楚变更原因。
- Server 和 Skill 的配置尽量做到环境隔离,开发、测试、生产使用不同的配置文件和鉴权信息。
- 为 MCP Server 固定依赖版本,使用
requirements.txt或package.json锁定版本,避免协议升级导致不兼容。 - Skill 的
SKILL.md也建议带版本号字段,方便比较不同版本的执行效果。
8.3 稳定性与可观测性
MCP Server 是独立进程,稳定性问题通常比较隐蔽。建议从三方面入手:
- 日志:在工具函数入口和出口分别打印日志,记录参数和耗时;
- 心跳与超时:远程 MCP Server 要设置连接超时和请求超时,避免模型等待过久;
- 回归测试:为每个工具准备一组测试用例,定期运行,防止工具行为被无意修改。
下面是一个简单的日志装饰器示例,可以直接用到你的 Server 里。
import functools import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger("mcp-server") def log_tool(func): @functools.wraps(func) def wrapper(*args, **kwargs): logger.info("call %s args=%s kwargs=%s", func.__name__, args, kwargs) result = func(*args, **kwargs) logger.info("done %s result=%s", func.__name__, result) return result return wrapper然后把装饰器加到工具函数上:
@mcp.tool() @log_tool def query_order(order_id: str) -> str: ...8.4 测试与迭代方法
Agent 应用的测试与普通后端不同,它包含两层不确定性:模型调不准参数?工具执行出错?两层需要分开验证。
建议建立“三层测试”体系:
- 单元层:直接调用工具函数,传合法和非法参数,确保函数本身逻辑正确。
- 协议层:模拟 MCP 客户端发起工具调用,校验协议消息往返是否正常。
- 模型层:用典型用户问题驱动完整 Agent 流程,记录成功率、错误类型和模型决策原因,分析失败样本后持续优化工具描述和 Skill 步骤。
每次迭代只改一个变量:要么改工具描述,要么改 Skill 步骤,要么改脚本逻辑,避免多个改动混合在一起导致无法定位是哪个变化影响了效果。
9. 总结与学习路线
这篇文章从概念上讲清楚了 AI Agent 能力扩展的两条主线:MCP 负责统一接入外部工具与数据源,Skill 负责沉淀可复用的任务流程。实战部分我们亲手搭建了一个 Python MCP Server,并创建了一个带脚本的 Skill 包,也整理了开发中最高频的排错问题和工程落地的安全、稳定性建议。
下一步建议按下面的顺序继续深入:
- 先把你常用的内部服务(数据库、文件系统、内部 API)封装成自己的 MCP Server,跑通“配置—调用—结果回流”的完整链路;
- 再从高频重复任务中提炼 3 到 5 个 Skill,让 Agent 从“会调用工具”升级为“会按规范完成业务”;
- 然后关注客户端产品对 MCP 的差异化支持,结合你实际使用的编辑器或平台做配置优化;
- 最后建立一套针对工具调用和 Skill 效果的评估集,用数据驱动 Agent 持续迭代。
AI Agent 的能力边界,本质上是由你能安全、规范接入多少真实能力决定的。与其反复在 Prompt 里堆砌规则,不如把工具协议做好、把技能包做厚。这个方向值得深挖,欢迎在实践中多踩坑、多总结,也欢迎在评论区交流你的 MCP 与 Skill 落地经验。