Part 6:MCP协议与Skills系统详解 - 工具化AI应用的基石
学习目标:理解MCP(Model Context Protocol)如何实现LLM与外部系统解耦,掌握Skills系统设计与开发方法,能构建工具化、可扩展的AI应用
一、为什么要MCP?—— 工具碎片化的痛点
1.1 问题:每个框架都有自己的工具定义方式
现实困境:
- LangChain有Tool定义格式
- LlamaIndex有Tool定义格式
- OpenAI有Function Calling格式
- 每个平台(Coze/Dify)都有自己的插件系统
痛点:
- ❌ 为一个平台开发的工具,不能在其他平台复用
- ❌ 企业开发内部工具,要适配多个AI应用 → 重复劳动
- ❌ 工具提供方(如天气API)要对接N个AI框架 → 维护成本爆炸
1.2 MCP的愿景:统一标准
类比:USB接口
- 电脑(AI应用)只需要一个USB口
- U盘、键盘、鼠标(各种工具)都通过USB连接
- USB芯片厂商(工具开发方)不用关心电脑品牌
MCP的目标:
- ✅ 工具定义一次, everywhere可用
- ✅ AI应用只需对接MCP标准,不关心工具实现细节
- ✅ 工具在独立沙箱运行,安全可控
二、MCP核心概念:三要素
2.1 架构总览
┌─────────────┐ JSON-RPC over STDIO ┌─────────────┐
│ Client │◄────────────────────────────────►│ Server │
│ (AI App) │ (Client-Server消息协议) │ (Tool) │
└─────────────┘ └─────────────�
│ │
LLM交互 执行业务逻辑
(调用工具) (访问DB/API)
角色:
- Client:AI应用(如Claude Code、OpenCode)
- Server:工具提供方(文件操作、数据库查询、自定义业务)
- Protocol:JSON-RPC 2.0 over STDIO(本地)或 SSE(远程)
2.2 Resources(资源):只读数据源
定义:文件、数据库记录、API响应的只读访问。
特点:
- 只读(不能写)
- 可以有URI标识(如
file:///path/to/doc.txt) - 可列出(list)和读取(read)
例子:
资源类型:
- 文件:file:///home/user/readme.md
- 数据库行:postgres://table/users/id=123
- API响应:http://api.company.com/employees?dept=sales
场景:
- AI问:"用户123的个人信息?"
- Client向MCP Server请求资源
user://123 - Server返回JSON数据
- AI基于数据回答
2.3 Tools(工具):可执行操作
定义:能改变状态或执行计算的函数。
与Resources区别:
- Resources:只读(查)
- Tools:可写(增删改查 + 执行动作)
Tool定义结构:
{
"name": "create_ticket",
"description": "创建客服工单",
"inputSchema": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "用户ID"},
"issue": {"type": "string", "description": "问题描述"},
"priority": {"type": "string", "enum": ["low", "medium", "high"]}
},
"required": ["user_id", "issue"]
}
}
Client调用流程:
1. Client获取Server支持的Tool列表
2. LLM决定调用哪个Tool,生成参数
3. Client发送 "tools/call" JSON-RPC消息
4. Server执行,返回结果
5. Client把结果喂给LLM,继续对话
2.4 Prompts:可复用的Prompt模板
定义:预定义的Prompt片段,带参数,可被LLM调用。
场景:
Developer写好了常用Prompt:
- "review_code":审查代码,参数(file_path, language)
- "explain_error":解释错误信息,参数(error_log)
AI在对话中:
用户:"帮我看看这段Python代码有没有bug"
AI:→ (自动触发)调用Prompt "review_code" + 代码作为参数
→ 返回审查结果
价值:
- 非技术用户写的Prompt,技术用户复用
- 标准化输出格式
- Prompt版本管理
三、Skills系统:MCP的应用实践
3.1 什么是Skill?
Skill = 一组Tools + Resources + Prompts + 权限定义
类比:
- MCP是"USB接口标准"
- Skill是"插在USB口的实际设备"(U盘、键盘)
Skill定义文件(SKILL.md或YAML):
name: file-operator
description: 文件读写操作工具集
version: 1.0.0
permissions:
- file_read
- file_write
tools:
- name: read_file
description: 读取文件内容
inputSchema:
type: object
properties:
filePath: {type: string, description: 文件路径}
required: [filePath]
- name: write_file
description: 写入文件(覆盖)
inputSchema: ...
permissions: [file_write]
resources:
- name: local_files
uri: file:///**
description: 本地文件系统(只读列举)
3.2 权限模型与安全沙箱
声明式权限:
Skill运行前声明:
我需要:file_read、file_write、network_access
用户确认:Yes/No
沙箱隔离:
- 限制文件访问范围:只能访问
/workspace/目录 - 禁止危险操作:删系统文件、fork炸弹、无限循环
- 资源限制:CPU时间、内存、网络带宽
审计日志:
时间戳 | 用户 | 工具调用 | 参数 | 结果 | 耗时
────────┼──────┼──────────┼──────┼──────┼──────
10:23:01| Alice| write_file|path=...|成功| 50ms
便于追溯和合规。
四、工具定义规范最佳实践
4.1 参数类型系统
支持类型(JSON Schema子集):
string:文本number:数字boolean:布尔array:数组(如文件路径列表)object:对象(支持嵌套)
必需 vs 可选:
{
"required": ["filePath", "content"], ← 必须提供的参数
"properties": {
"filePath": {"type": "string"},
"content": {"type": "string"},
"encoding": {"type": "string", "default": "utf-8"} ← 可选,有默认值
}
}
4.2 描述的最佳实践
坏例子:
"description": "打开文件"
问题:不知道是读还是写?会不会覆盖?
好例子:
"description": "读取文件内容,返回字符串。如果文件不存在,抛出错误。注意:文件编码必须为UTF-8。"
- ✅ 明确操作(读)
- ✅ 明确副作用(无副作用,只读)
- ✅ 明确错误处理(抛异常)
- ✅ 给出约束(UTF-8)
给LLM看的描述要具体:
"description": "搜索Git commit历史。参数:author(作者邮箱)、since(起始日期,格式YYYY-MM-DD)、until(结束日期)。返回:最近10次提交的hash和message。"
LLM看到这个,就知道什么时候该用、怎么填参数。
4.3 设计模式
原子工具:单一功能,无副作用的工具
read_file:只读write_file:只写delete_file:只删
复合工具:封装多个原子操作为"高级功能"
refactor_code:内部调用 read→修改→writedeploy_service:build→push→kubectl apply
工具链:顺序调用完成复杂任务
"deploy_fullstack_app" =
[build_frontend, build_backend, push_docker,
update_kubernetes, notify_slack]
选择原则:
- 权限隔离严格的场景 → 原子工具(细粒度控制)
- 业务流程固定 → 复合工具(简化调用)
- 需要灵活编排 → 工具链(可配置顺序)
五、MCP服务器开发实战
5.1 用Python实现一个文件操作Server
目标:实现一个MCP Server,支持:
read_filewrite_filelist_directory
Step 1:定义工具
tools = [
{
"name": "read_file",
"description": "读取文件内容",
"inputSchema": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径(相对于workspace)"}
},
"required": ["path"]
}
},
# ... 其他工具
]
Step 2:实现回调函数
def read_file_callback(path: str) -> str:
"""读取文件,返回内容"""
full_path = os.path.join(WORKSPACE, path)
if not os.path.exists(full_path):
raise FileNotFoundError(f"文件不存在: {path}")
with open(full_path, 'r', encoding='utf-8') as f:
return f.read()
Step 3:启动服务器(STDIO模式)
#!/usr/bin/env python3
import sys, json
def main():
# 1. 读取Client消息(stdin)
for line in sys.stdin:
request = json.loads(line)
# 2. 根据方法路由
if request["method"] == "tools/list":
response = {"tools": tools}
elif request["method"] == "tools/call":
tool_name = request["params"]["name"]
args = request["params"]["arguments"]
if tool_name == "read_file":
result = read_file_callback(**args)
response = {"content": result}
# ... 其他工具
# 3. 写回响应(stdout)
print(json.dumps(response))
sys.stdout.flush()
if __name__ == "__main__":
main()
Step 4:处理错误
try:
result = tool_callback(**args)
response = {"content": [{"type": "text", "text": result}]}
except Exception as e:
response = {
"content": [{"type": "text", "text": f"错误: {str(e)}"}],
"isError": True
}
Step 5:测试
# 用mcp-cli工具手动测试
echo '{"method":"tools/call","params":{"name":"read_file","arguments":{"path":"test.txt"}}}' | python my_server.py
六、实际开发案例
案例1:文件操作Skill(OpenCode同款)
场景:在Claude Code / OpenCode中让AI读写本地文件。
工具列表:
read_file(filePath):读文件write_file(filePath, content):写文件(覆盖)list_directory(path):列目录search_files(pattern):正则搜索文件
权限设计:
permissions:
- file_read
- file_write
- file_delete # 高危,需要双重确认
安全措施:
- 只能访问
workspace/目录(chroot-like) ../路径穿越检测- 删除操作:先软删(.trash),7天后真删
调试技巧:
- 在Claude Code中调用:
/read_file path/to/file.py - 看输出:文件内容是否正常?
- 查看Server日志:工具执行是否成功?
案例2:企业CRM查询工具
场景:AI客服需要查询客户信息、订单历史。
工具定义:
{
"name": "query_customer",
"description": "查询CRM系统中的客户信息",
"inputSchema": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"fields": {"type": "array", "items": {"type": "string"}} // 指定返回字段
},
"required": ["customer_id"]
}
}
实现:
def query_customer(customer_id: str, fields: list = None) -> dict:
# 1. 验证权限(当前用户是否有权查这个客户?)
# 2. 连接CRM数据库(SQL)
# 3. 只返回allowed fields(隐私字段屏蔽)
# 4. 记录审计日志
return {"name": "张三", "order_count": 5, "vip_level": "gold"}
隐私保护:
- 敏感字段(手机号、身份证)默认不返回
- 需额外权限
view_pii才能查 - 每次查询记录日志,可追溯
七、实践任务
任务1:用Python实现"文件操作"MCP Server
要求:
- 支持3个工具:
read_file、write_file、list_directory - 工作目录限制在
./workspace/(防止路径穿越) - 错误处理:文件不存在 → 友好提示
- 日志:记录每次工具调用的参数和结果
测试:
echo '{"method":"tools/list"}' | python server.py
echo '{"method":"tools/call","params":{"name":"read_file","arguments":{"path":"test.txt"}}}' | python server.py
任务2:为"项目进度查询"设计Tool Schema
场景:项目经理问"项目A进度如何?"
工具:query_project_status(project_id, include_tasks, include_milestones)
任务输出:
- 完整的JSON Schema(含描述、类型、required)
- 参数说明:
project_id:项目唯一标识include_tasks:是否返回任务列表(布尔,默认False)include_milestones:是否返回里程碑(布尔,默认False)
- 描述写清楚:"查询JIRA系统中的项目进度,返回当前状态、完成率、风险等级。如果include_tasks=True,额外返回最近10个任务的状态。"
任务3:在OpenCode中注册自定义Skill并测试
步骤:
- 将任务1的Server放到OpenCode技能目录(
~/.opencode/skills/) - 确保SKILL.md定义完整
- 重启OpenCode
- 在对话中测试:"读取当前目录的README.md文件"
- 截图并记录:Server日志、OpenCode输出是否正常
✅ 学习检查点
完成Part 6后,您应该能:
-
解释MCP三要素的区别
- Resources(只读数据) vs Tools(可执行操作) vs Prompts(Prompt模板)
- 每个要素的典型使用场景
-
设计符合JSON Schema规范的工具定义
- 必填/可选字段
- 类型系统(string/number/boolean/array/object)
- 描述写清楚"做什么+副作用+错误"
-
理解"解耦"思想,设计可复用的Skill
- 工具定义与LLM应用分离
- 一个工具可以被多个应用复用
- 权限隔离、审计日志
-
用Python实现一个简单的MCP Server
- 响应
tools/list和tools/call - 路由到不同的工具函数
- 错误处理
- 响应
-
评估MCP的价值和局限
- 为什么是大势所趋(生态整合)
- 当前不足(复杂度、调试难)
- 适用场景(企业内部工具标准化)
📚 延伸阅读
- MCP规范文档:https://github.com/context-labs/mcp (GitHub官方)
- Claude Code Skill开发:https://docs.anthropic.com/en/docs/claude-code/skills
- OpenCode Skills:https://github.com/opencodeai/opencode/tree/main/docs/skills
- JSON-RPC 2.0:http://www.jsonrpc.org/specification
- MCP Server示例集:https://github.com/modelcontextprotocol/servers
Part 6 结束!
MCP是AI应用基础设施的"USB标准",理解它才能构建可扩展、可复用的工具生态。
下一部分 Part 7:微调技术通俗解析 —— 什么场景真正需要微调?如何用LoRA低成本定制领域专家模型?学习节奏:Part 6建议1.5周,动手实现至少一个MCP Server(哪怕最简单的),理解Client-Server消息流。
系列进度:
- ✅ Part 1:Transformer原理大白话
- ✅ Part 2:分词与词向量详解
- ✅ Part 3:提示词工程实战
- ✅ Part 4:RAG检索增强生成
- ✅ Part 5:Agent智能体架构
- ✅ Part 6:MCP协议与Skills系统(当前)
- 🔄 Part 7:微调技术通俗解析
- 🔄 Part 8:推理优化与工程部署
- 🔄 Part 9:综合项目实战与职业发展
工程思维:Part 6是"基础设施层"。在企业落地AI时,工具分散在不同系统(CRM/ERP/DB),MCP提供统一接入层,是规模化应用的前提。值得深入!
评论区