<div>
一、MCP是什么? 为什么需要它?

想象一下,你正在开发一个 AI 编程助手,它需要:
-
读取和修改项目文件
-
查询数据库Schema
-
搜索代码仓库
-
执行Git操作
传统做法是为每个数据源写一套专用代码,不同团队重复造轮子。Model Context Protocol(MCP) 就是为了解决这个问题而生的开放标准协议。
通俗理解: MCP就像是「AI应用的USB接口标准」。就像USB让不同设备都能接入电脑一样,MCP让不同的数据源和工具都能以统一方式接入AI应用。
实际案例: 在Claude Desktop中,你可以配置多个官方MCP服务器:
-
Filesystem服务器: 安全地读写本地文件,有权限控制
-
SQLite服务器: 查询和分析SQLite数据库,自动生成SQL
-
GitHub服务器: 搜索仓库、创建Issue、管理PR
你的AI应用只需实现一个MCP客户端,就能连接所有服务器,无需为每个服务器写专用代码。
二、架构设计: 三个角色的分工
MCP采用宿主-客户端-服务器三层架构,就像一家公司的组织结构:
宿主(Host) = 总经理
-
管理所有客户端
-
控制安全策略和权限
-
负责AI模型的调用
客户端(Client) = 部门经理
-
客户端负责连接服务器
-
负责双方的沟通协调
-
转发消息和通知
服务器(Server) = 业务专员
-
提供具体功能(资源、工具、提示模板)
-
可以是本地程序或远程服务
-
不知道其他服务器的存在
三、协议约定:统一规范与个性化扩展
每个MCP服务器提供的工具、资源都不一样,但它们都遵循相同的MCP协议规范。
3.1 协议的分层设计
MCP采用 基础协议 + 功能扩展 的设计,就像HTTP协议一样:
核心层(所有实现必须支持):
-
JSON-RPC 2.0消息格式
-
初始化握手流程(initialize/initialized)
-
基本错误处理
功能层(按需选择):
-
Resources、Prompts、Tools(服务器端)
-
Roots、Sampling、Elicitation(客户端)
这样设计的好处:
统一的基础协议 → 保证互操作性
+
灵活的功能选择 → 满足不同场景需求
↓
既标准化又可扩展
3.2 协议约定的过程
步骤1: 基础协议是固定的
所有MCP服务器和客户端都遵循相同的JSON-RPC 2.0格式:
<span>// 请求格式(固定)</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span> <span>// 必须是2.0</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span> <span>// 唯一标识</span>
<span>"method"</span>
<span>:</span> <span>"方法名"</span>
<span>,</span> <span>// 要调用的方法</span>
<span>"params"</span>
<span>:</span> <span>{</span>...<span>}</span> <span>// 参数对象</span>
<span>}</span>
<span>// 响应格式(固定)</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span> <span>// 对应请求的ID</span>
<span>"result"</span>
<span>:</span> <span>{</span>...<span>}</span> <span>// 成功结果</span>
<span>// 或 "error": {...} // 错误信息</span>
<span>}</span>
步骤2: 能力在初始化时协商
<span>// 客户端发起初始化</span>
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"initialize"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
<span>,</span>
<span>"capabilities"</span>
<span>:</span> <span>{</span>
<span>"sampling"</span>
<span>:</span> <span>{</span>
<span>}</span>
<span>,</span> <span>// 我支持LLM采样</span>
<span>"roots"</span>
<span>:</span> <span>{</span>
<span>}</span> <span>// 我支持根目录</span>
<span>}</span>
<span>,</span>
<span>"clientInfo"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"MyClient"</span>
<span>,</span> <span>"version"</span>
<span>:</span> <span>"1.0"</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>// 服务器响应</span>
<span>{</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
<span>,</span>
<span>"capabilities"</span>
<span>:</span> <span>{</span>
<span>"tools"</span>
<span>:</span> <span>{</span>
<span>}</span>
<span>,</span> <span>// 我提供工具</span>
<span>"resources"</span>
<span>:</span> <span>{</span>
<span>}</span> <span>// 我提供资源</span>
<span>}</span>
<span>,</span>
<span>"serverInfo"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"SQLiteServer"</span>
<span>,</span> <span>"version"</span>
<span>:</span> <span>"2.0"</span>
<span>}</span>
<span>}</span>
<span>}</span>
协商完成后,双方都知道对方支持什么功能,只使用交集部分。
步骤3: 方法名称是标准化的
MCP规范定义了标准方法名:
| 功能 | 方法名 | 说明 |
|---|---|---|
| 列出资源 | resources/list |
固定方法名 |
| 读取资源 | resources/read |
固定方法名 |
| 列出工具 | tools/list |
固定方法名 |
| 调用工具 | tools/call |
固定方法名 |
| 列出提示 | prompts/list |
固定方法名 |
| 获取提示 | prompts/get |
固定方法名 |
步骤4: 具体内容是个性化的
虽然方法名固定,但每个服务器返回的具体数据不同:
<span>// SQLite服务器的工具</span>
<span>{</span>
<span>"tools"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"执行SQL查询"</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"list_tables"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"列出所有表"</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>// Filesystem服务器的工具</span>
<span>{</span>
<span>"tools"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"read_file"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"读取文件"</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"write_file"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"写入文件"</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"search_files"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"搜索文件"</span>
<span>}</span>
<span>]</span>
<span>}</span>
3.3 协议发现机制
客户端如何知道服务器有哪些工具?
第一步:列举
客户端 → 服务器<span>:</span> <span>{</span>
<span>"method"</span>
<span>:</span> <span>"tools/list"</span>
<span>}</span>
服务器 → 客户端<span>:</span> <span>{</span>
<span>"tools"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"执行SQL查询"</span>
<span>,</span>
<span>"inputSchema"</span>
<span>:</span> <span>{</span> <span>// JSON Schema定义输入格式</span>
<span>"type"</span>
<span>:</span> <span>"object"</span>
<span>,</span>
<span>"properties"</span>
<span>:</span> <span>{</span>
<span>"sql"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"string"</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
第二步:调用
客户端 → 服务器<span>:</span> <span>{</span>
<span>"method"</span>
<span>:</span> <span>"tools/call"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span> <span>// 使用第一步获得的工具名</span>
<span>"arguments"</span>
<span>:</span> <span>{</span>
<span>"sql"</span>
<span>:</span> <span>"SELECT * FROM users"</span>
<span>}</span>
<span>}</span>
<span>}</span>
关键点:通过JSON Schema,客户端知道如何正确调用工具,无需硬编码。
四、协议基础:如何通信?
MCP基于JSON-RPC 2.0构建,这是一个成熟的远程过程调用协议。理解这一层对掌握MCP至关重要。
4.1 JSON-RPC 2.0基础
消息类型
MCP中有三种基本消息类型。
1. 请求(Request) – 期待响应
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span> <span>// 协议版本,必须是"2.0"</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span> <span>// 请求唯一标识(字符串或数字)</span>
<span>"method"</span>
<span>:</span> <span>"tools/list"</span>
<span>,</span> <span>// 要调用的方法名</span>
<span>"params"</span>
<span>:</span> <span>{</span> <span>// 可选的参数对象</span>
<span>"cursor"</span>
<span>:</span> <span>"page2"</span>
<span>}</span>
<span>}</span>
2. 响应(Response) – 对请求的回复
<span>// 成功响应</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span> <span>// 必须与请求的id相同</span>
<span>"result"</span>
<span>:</span> <span>{</span> <span>// 成功结果</span>
<span>"tools"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"执行查询"</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>}</span>
<span>// 错误响应</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"error"</span>
<span>:</span> <span>{</span> <span>// 错误对象</span>
<span>"code"</span>
<span>:</span> <span>-32602</span>
<span>,</span> <span>// 错误码(整数)</span>
<span>"message"</span>
<span>:</span> <span>"参数无效"</span>
<span>,</span> <span>// 错误描述</span>
<span>"data"</span>
<span>:</span> <span>{</span> <span>// 可选的额外信息</span>
<span>"field"</span>
<span>:</span> <span>"cursor"</span>
<span>,</span>
<span>"reason"</span>
<span>:</span> <span>"格式错误"</span>
<span>}</span>
<span>}</span>
<span>}</span>
3. 通知(Notification) – 单向消息,无需响应
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"notifications/resources/updated"</span>
<span>,</span> <span>// 通知方法名</span>
<span>"params"</span>
<span>:</span> <span>{</span> <span>// 通知参数</span>
<span>"uri"</span>
<span>:</span> <span>"file:///project/data.json"</span>
<span>}</span>
<span>// 注意:没有id字段</span>
<span>}</span>
标准错误码
MCP使用JSON-RPC 2.0的标准错误码:
| 错误码 | 含义 | 说明 |
|---|---|---|
| -32700 | Parse error | JSON解析错误 |
| -32600 | Invalid Request | 无效的请求格式 |
| -32601 | Method not found | 方法不存在 |
| -32602 | Invalid params | 参数无效 |
| -32603 | Internal error | 服务器内部错误 |
| -32002 | Resource not found | 资源未找到(MCP扩展) |
4.2 能力协商详解
能力协商是MCP连接建立的第一步,决定了整个会话中可用的功能。
初始化流程详解
阶段1: 客户端发起初始化
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"initialize"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
<span>,</span> <span>// 客户端支持的协议版本</span>
<span>"capabilities"</span>
<span>:</span> <span>{</span> <span>// 客户端能力声明</span>
<span>"roots"</span>
<span>:</span> <span>{</span> <span>// 支持根目录</span>
<span>"listChanged"</span>
<span>:</span> <span>true</span> <span>// 支持根目录变更通知</span>
<span>}</span>
<span>,</span>
<span>"sampling"</span>
<span>:</span> <span>{</span>
<span>}</span>
<span>,</span> <span>// 支持LLM采样</span>
<span>"elicitation"</span>
<span>:</span> <span>{</span>
<span>}</span>
<span>,</span> <span>// 支持用户询问</span>
<span>"experimental"</span>
<span>:</span> <span>{</span> <span>// 实验性功能</span>
<span>"customFeature"</span>
<span>:</span> <span>{</span>
<span>}</span> <span>// 自定义功能</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>"clientInfo"</span>
<span>:</span> <span>{</span> <span>// 客户端信息</span>
<span>"name"</span>
<span>:</span> <span>"MyAIApp"</span>
<span>,</span> <span>// 程序名(必填)</span>
<span>"version"</span>
<span>:</span> <span>"1.2.0"</span>
<span>,</span> <span>// 版本号(必填)</span>
<span>"title"</span>
<span>:</span> <span>"我的AI应用"</span> <span>// 显示名称(可选)</span>
<span>}</span>
<span>}</span>
<span>}</span>
阶段2: 服务器响应能力
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
<span>,</span> <span>// 服务器选择的协议版本</span>
<span>"capabilities"</span>
<span>:</span> <span>{</span> <span>// 服务器能力声明</span>
<span>"resources"</span>
<span>:</span> <span>{</span> <span>// 支持资源</span>
<span>"subscribe"</span>
<span>:</span> <span>true</span>
<span>,</span> <span>// 支持资源订阅</span>
<span>"listChanged"</span>
<span>:</span> <span>true</span> <span>// 支持资源列表变更通知</span>
<span>}</span>
<span>,</span>
<span>"tools"</span>
<span>:</span> <span>{</span> <span>// 支持工具</span>
<span>"listChanged"</span>
<span>:</span> <span>true</span>
<span>}</span>
<span>,</span>
<span>"prompts"</span>
<span>:</span> <span>{</span> <span>// 支持提示模板</span>
<span>"listChanged"</span>
<span>:</span> <span>false</span> <span>// 不支持列表变更通知</span>
<span>}</span>
<span>,</span>
<span>"logging"</span>
<span>:</span> <span>{</span>
<span>}</span> <span>// 支持日志输出</span>
<span>}</span>
<span>,</span>
<span>"serverInfo"</span>
<span>:</span> <span>{</span> <span>// 服务器信息</span>
<span>"name"</span>
<span>:</span> <span>"sqlite-mcp-server"</span>
<span>,</span>
<span>"version"</span>
<span>:</span> <span>"2.1.0"</span>
<span>,</span>
<span>"title"</span>
<span>:</span> <span>"SQLite MCP服务器"</span>
<span>}</span>
<span>,</span>
<span>"instructions"</span>
<span>:</span> <span>"此服务器提供SQLite数据库访问能力"</span> <span>// 可选的使用说明</span>
<span>}</span>
<span>}</span>
阶段3: 客户端确认就绪
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"notifications/initialized"</span> <span>// 无id,这是通知</span>
<span>}</span>
协议版本协商规则
客户端请求版本: "2024-11-05"
↓
服务器支持?
↙ ↘
支持 不支持
↓ ↓
返回相同版本 返回服务器支持的最新版本
↓ ↓
协商成功 客户端检查是否支持
↙ ↘
支持 不支持
↓ ↓
协商成功 断开连接
实际示例:
<span>// 场景1: 版本匹配</span>
客户端<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
服务器<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span> ✅ 成功
<span>// 场景2: 服务器版本更新</span>
客户端<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2024-06-01"</span>
服务器<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
→ 客户端检查是否支持<span>2024</span>
<span>-11</span>
<span>-05</span> → 如果不支持则断开
<span>// 场景3: 客户端版本更新</span>
客户端<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2025-01-01"</span>
服务器<span>:</span> <span>"protocolVersion"</span>
<span>:</span> <span>"2024-11-05"</span>
→ 客户端检查是否支持<span>2024</span>
<span>-11</span>
<span>-05</span> → 如果支持则降级使用
能力交集计算
初始化后,双方只能使用共同支持的能力:
客户端能力: {roots, sampling, elicitation}
服务器能力: {resources, tools, prompts}
↓
可用功能集合
├─ 客户端 → 服务器: resources, tools, prompts
└─ 服务器 → 客户端: roots, sampling, elicitation
示例:
<span># 客户端代码示例</span>
<span>if</span> server_capabilities<span>.</span>get<span>(</span>
<span>"tools"</span>
<span>)</span>
<span>:</span>
<span># 服务器支持工具,可以调用</span>
tools <span>=</span> <span>await</span> session<span>.</span>list_tools<span>(</span>
<span>)</span>
<span>else</span>
<span>:</span>
<span># 服务器不支持工具,跳过</span>
<span>print</span>
<span>(</span>
<span>"服务器不提供工具功能"</span>
<span>)</span>
<span>if</span> client_capabilities<span>.</span>get<span>(</span>
<span>"sampling"</span>
<span>)</span>
<span>:</span>
<span># 客户端支持采样,服务器可以请求</span>
<span># (服务器端会检查这个能力)</span>
<span>pass</span>
4.3 连接生命周期深入
完整的消息时序图
客户端 服务器
│ │
│ 1. initialize (请求) │
├──────────────────────────────────────>│
│ {protocolVersion, capabilities} │
│ │
│ 2. initialize (响应) │
│<──────────────────────────────────────┤
│ {protocolVersion, capabilities} │
│ │
│ 3. initialized (通知) │
├──────────────────────────────────────>│
│ │
│═══════════ 正常操作阶段 ════════════ │
│ │
│ 4. tools/list (请求) │
├──────────────────────────────────────>│
│ │
│ 5. tools/list (响应) │
│<──────────────────────────────────────┤
│ {tools: [...]} │
│ │
│ 6. tools/call (请求) │
├──────────────────────────────────────>│
│ {name: "query", arguments: {...}} │
│ │
│ 7. notifications/progress (通知) │
│<──────────────────────────────────────┤
│ {progress: 50, total: 100} │
│ │
│ 8. tools/call (响应) │
│<──────────────────────────────────────┤
│ {content: [...]} │
│ │
│ 9. notifications/resources/updated │
│<──────────────────────────────────────┤
│ {uri: "file://..."} │
│ │
│═══════════ 关闭阶段 ═══════════ │
│ │
│ 10. 关闭stdin │
├─────────────X │
│ │
│ 服务器退出
初始化前的限制
在initialized通知发送前:
客户端只能发送:
-
✅
initialize请求 -
✅
ping请求(用于保活) -
❌ 其他任何请求
服务器只能发送:
-
✅
initialize响应 -
✅
ping请求 -
✅
logging通知(日志) -
❌ 其他任何消息
违反限制的后果:
<span>// 客户端在初始化前调用tools/list</span>
请求<span>:</span> <span>{</span>
<span>"method"</span>
<span>:</span> <span>"tools/list"</span>
<span>}</span>
响应<span>:</span> <span>{</span>
<span>"error"</span>
<span>:</span> <span>{</span>
<span>"code"</span>
<span>:</span> <span>-32600</span>
<span>,</span>
<span>"message"</span>
<span>:</span> <span>"会话未初始化"</span>
<span>}</span>
<span>}</span>
超时和重试机制
请求超时:
<span>import</span> asyncio
<span># 设置30秒超时</span>
<span>try</span>
<span>:</span>
result <span>=</span> <span>await</span> asyncio<span>.</span>wait_for<span>(</span>
session<span>.</span>call_tool<span>(</span>
<span>"slow_operation"</span>
<span>,</span> <span>{</span>
<span>}</span>
<span>)</span>
<span>,</span>
timeout<span>=</span>
<span>30.0</span>
<span>)</span>
<span>except</span> asyncio<span>.</span>TimeoutError<span>:</span>
<span># 发送取消通知</span>
<span>await</span> session<span>.</span>send_notification<span>(</span>
<span>"notifications/cancelled"</span>
<span>,</span>
<span>{</span>
<span>"requestId"</span>
<span>:</span> <span>"123"</span>
<span>,</span> <span>"reason"</span>
<span>:</span> <span>"超时"</span>
<span>}</span>
<span>)</span>
进度通知重置超时:
<span># 当收到进度通知时,可以重置超时计时器</span>
timeout <span>=</span> <span>30</span> <span># 基础超时</span>
max_timeout <span>=</span> <span>300</span> <span># 最大超时(5分钟)</span>
<span>while</span> <span>True</span>
<span>:</span>
<span>try</span>
<span>:</span>
msg <span>=</span> <span>await</span> wait_for_message<span>(</span>timeout<span>)</span>
<span>if</span> msg<span>.</span>method <span>==</span> <span>"notifications/progress"</span>
<span>:</span>
<span># 收到进度,重置超时</span>
timeout <span>=</span> <span>30</span>
<span>except</span> TimeoutError<span>:</span>
<span># 超时处理</span>
<span>break</span>
4.4 传输方式对比
stdio传输详解
优点:
-
✅ 简单直接,适合本地开发
-
✅ 进程隔离,安全性好
-
✅ 自动管理生命周期
-
✅ 无需网络配置
缺点:
-
❌ 只能本地使用
-
❌ 不支持多客户端
-
❌ 调试相对困难
消息格式:
消息1\n
消息2\n
消息3\n
每个JSON对象占一行,以\n分隔。
HTTP传输详解
架构:
┌─────────┐ HTTP POST ┌─────────┐
│ ├──────────────────────────>│ │
│ 客户端 │ 请求/通知/响应(JSON-RPC) │ 服务器 │
│ │<──────────────────────────┤ │
└─────────┘ HTTP 响应/SSE流 └─────────┘
(application/json 或
text/event-stream)
发送消息(POST):
<span><span>POST</span> <span>/mcp</span> <span>HTTP/1.1</span></span>
<span><span>Host</span>
<span>:</span> <span>localhost:8080</span></span>
<span><span>Content-Type</span>
<span>:</span> <span>application/json</span></span>
<span><span>Accept</span>
<span>:</span> <span>application/json, text/event-stream</span></span>
<span><span>Mcp-Session-Id</span>
<span>:</span> <span>abc123</span></span>
<span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span>
<span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span>
<span>1</span>
<span>,</span>
<span>"method"</span>
<span>:</span>
<span>"tools/list"</span>
<span>}</span>
</span>
立即响应(JSON):
<span><span>HTTP/1.1</span> <span>200</span> <span>OK</span></span>
<span><span>Content-Type</span>
<span>:</span> <span>application/json</span></span>
<span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span>
<span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span>
<span>1</span>
<span>,</span>
<span>"result"</span>
<span>:</span>
<span>{</span>
<span>"tools"</span>
<span>:</span>
<span>[</span>
<span>...</span>
<span>]</span>
<span>}</span>
<span>}</span>
</span>
流式响应(SSE):
<span><span>HTTP/1.1</span> <span>200</span> <span>OK</span></span>
<span><span>Content-Type</span>
<span>:</span> <span>text/event-stream</span></span>
<span><span>Mcp-Session-Id</span>
<span>:</span> <span>abc123</span></span>
<span><span>id</span>
<span>:</span> <span>1</span></span>
<span><span>data</span>
<span>:</span> <span>{"jsonrpc":"2.0","method":"notifications/progress","params":{"progress":25}}</span></span>
<span><span>id</span>
<span>:</span> <span>2 </span></span>
<span><span>data</span>
<span>:</span> <span>{"jsonrpc":"2.0","method":"notifications/progress","params":{"progress":50}}</span></span>
<span><span>id</span>
<span>:</span> <span>3</span></span>
<span><span>data</span>
<span>:</span> <span>{"jsonrpc":"2.0","id":1,"result":{"content":[...]}}</span></span>
接收服务器消息(GET):
<span><span>GET</span> <span>/mcp</span> <span>HTTP/1.1</span></span>
<span><span>Host</span>
<span>:</span> <span>localhost:8080</span></span>
<span><span>Accept</span>
<span>:</span> <span>text/event-stream</span></span>
<span><span>Mcp-Session-Id</span>
<span>:</span> <span>abc123</span></span>
<span><span>Last-Event-ID</span>
<span>:</span> <span>42</span></span>
会话管理:
<span># 服务器端设置会话ID</span>
<span>@app<span>.</span>post</span>
<span>(</span>
<span>"/mcp"</span>
<span>)</span>
<span>async</span> <span>def</span> <span>handle_mcp</span>
<span>(</span>request<span>)</span>
<span>:</span>
<span>if</span> request<span>.</span>method <span>==</span> <span>"initialize"</span>
<span>:</span>
session_id <span>=</span> generate_session_id<span>(</span>
<span>)</span>
<span>return</span> Response<span>(</span>
content<span>=</span>json<span>.</span>dumps<span>(</span>result<span>)</span>
<span>,</span>
headers<span>=</span>
<span>{</span>
<span>"Mcp-Session-Id"</span>
<span>:</span> session_id<span>}</span>
<span>)</span>
<span># 客户端后续请求携带会话ID</span>
<span>@client<span>.</span>request</span>
<span>async</span> <span>def</span> <span>send_request</span>
<span>(</span>method<span>,</span> params<span>)</span>
<span>:</span>
headers <span>=</span> <span>{</span>
<span>}</span>
<span>if</span> self<span>.</span>session_id<span>:</span>
headers<span>[</span>
<span>"Mcp-Session-Id"</span>
<span>]</span> <span>=</span> self<span>.</span>session_id
<span>return</span> <span>await</span> http<span>.</span>post<span>(</span>
<span>"/mcp"</span>
<span>,</span>
json<span>=</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span> <span>"method"</span>
<span>:</span> method<span>,</span> <span>"params"</span>
<span>:</span> params<span>}</span>
<span>,</span>
headers<span>=</span>headers
<span>)</span>
断线重连:
<span>async</span> <span>def</span> <span>connect_sse</span>
<span>(</span>last_event_id<span>=</span>
<span>None</span>
<span>)</span>
<span>:</span>
headers <span>=</span> <span>{</span>
<span>"Accept"</span>
<span>:</span> <span>"text/event-stream"</span>
<span>}</span>
<span>if</span> last_event_id<span>:</span>
headers<span>[</span>
<span>"Last-Event-ID"</span>
<span>]</span> <span>=</span> last_event_id
<span>async</span> <span>with</span> httpx<span>.</span>stream<span>(</span>
<span>"GET"</span>
<span>,</span> <span>"/mcp"</span>
<span>,</span> headers<span>=</span>headers<span>)</span> <span>as</span> stream<span>:</span>
<span>async</span> <span>for</span> line <span>in</span> stream<span>.</span>aiter_lines<span>(</span>
<span>)</span>
<span>:</span>
<span>if</span> line<span>.</span>startswith<span>(</span>
<span>"id:"</span>
<span>)</span>
<span>:</span>
last_event_id <span>=</span> line<span>[</span>
<span>3</span>
<span>:</span>
<span>]</span>
<span>.</span>strip<span>(</span>
<span>)</span>
<span>elif</span> line<span>.</span>startswith<span>(</span>
<span>"data:"</span>
<span>)</span>
<span>:</span>
data <span>=</span> json<span>.</span>loads<span>(</span>line<span>[</span>
<span>5</span>
<span>:</span>
<span>]</span>
<span>)</span>
<span>yield</span> data<span>,</span> last_event_id
4.5 实际通信示例
让我们看一个完整的SQLite查询场景:
<span>// 1. 列出工具</span>
客户端 → 服务器<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"tools/list"</span>
<span>}</span>
服务器 → 客户端<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"tools"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"执行SQL查询"</span>
<span>,</span>
<span>"inputSchema"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"object"</span>
<span>,</span>
<span>"properties"</span>
<span>:</span> <span>{</span>
<span>"sql"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"string"</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>"required"</span>
<span>:</span> <span>[</span>
<span>"sql"</span>
<span>]</span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>}</span>
<span>// 2. 调用查询工具</span>
客户端 → 服务器<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>2</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"tools/call"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"query"</span>
<span>,</span>
<span>"arguments"</span>
<span>:</span> <span>{</span>
<span>"sql"</span>
<span>:</span> <span>"SELECT COUNT(*) FROM users WHERE active = 1"</span>
<span>}</span>
<span>,</span>
<span>"_meta"</span>
<span>:</span> <span>{</span>
<span>"progressToken"</span>
<span>:</span> <span>"query-123"</span> <span>// 请求进度通知</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>// 3. 服务器发送进度(异步通知)</span>
服务器 → 客户端<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"notifications/progress"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"progressToken"</span>
<span>:</span> <span>"query-123"</span>
<span>,</span>
<span>"progress"</span>
<span>:</span> <span>50</span>
<span>,</span>
<span>"total"</span>
<span>:</span> <span>100</span>
<span>,</span>
<span>"message"</span>
<span>:</span> <span>"正在扫描users表..."</span>
<span>}</span>
<span>}</span>
<span>// 4. 返回查询结果</span>
服务器 → 客户端<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>2</span>
<span>,</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"content"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>"查询结果: 1,234个活跃用户"</span>
<span>}</span>
<span>]</span>
<span>,</span>
<span>"isError"</span>
<span>:</span> <span>false</span>
<span>}</span>
<span>}</span>
<span>// 5. 如果查询出错</span>
服务器 → 客户端(错误情况)<span>:</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>2</span>
<span>,</span>
<span>"error"</span>
<span>:</span> <span>{</span>
<span>"code"</span>
<span>:</span> <span>-32603</span>
<span>,</span>
<span>"message"</span>
<span>:</span> <span>"SQL语法错误"</span>
<span>,</span>
<span>"data"</span>
<span>:</span> <span>{</span>
<span>"sql"</span>
<span>:</span> <span>"SELECT COUNT(*) FROM users WHERE active = 1"</span>
<span>,</span>
<span>"error"</span>
<span>:</span> <span>"near \"WHERE\": syntax error"</span>
<span>,</span>
<span>"position"</span>
<span>:</span> <span>35</span>
<span>}</span>
<span>}</span>
<span>}</span>
这就是MCP通信的完整过程!通过JSON-RPC 2.0,客户端和服务器可以进行结构化、类型安全的通信。
五、服务器能力:三种核心功能
MCP服务器可以提供三种功能。
5.1 Resources(资源):应用决定用什么
资源就是数据,比如文件内容、数据库记录、API响应。
谁控制: 应用程序决定把哪些资源提供给AI
如何使用:
<span>// 列出所有可用资源</span>
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"resources/list"</span>
<span>}</span>
<span>// 读取某个资源</span>
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"resources/read"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"uri"</span>
<span>:</span> <span>"file:///project/main.py"</span>
<span>}</span>
<span>}</span>
资源URI示例:
-
file:///project/src/main.py– 文件 -
db://schema/users– 数据库表结构 -
git://commits/main– Git提交历史 -
https://api.example.com/data– Web API
订阅变更: 可以订阅资源,当它变化时自动收到通知。
实际案例: Filesystem服务器暴露资源
<span>{</span>
<span>"uri"</span>
<span>:</span> <span>"file:///Users/alice/project/src/main.py"</span>
<span>,</span> <span>// Python源文件</span>
<span>"name"</span>
<span>:</span> <span>"main.py"</span>
<span>,</span> <span>// 文件名</span>
<span>"mimeType"</span>
<span>:</span> <span>"text/x-python"</span>
<span>,</span> <span>// 文件类型</span>
<span>"text"</span>
<span>:</span> <span>"import os\ndef main()..."</span> <span>// 文件内容</span>
<span>}</span>
客户端AI可以读取这个资源,理解代码结构后提供重构建议或生成测试。
5.2 Prompts(提示模板):用户选择用什么
什么是Prompt?
Prompt就像是「对话模板」或「快捷指令」,把常用的复杂指令预设好,用户一键调用。用生活中的例子类比,就像微信的「快捷回复」或IDE中的「代码片段(Snippet)」。
为什么需要Prompt?
场景1:没有Prompt时
用户每次都要输入:
"请分析这个Git仓库最近一周的提交,统计:
1. 总提交次数
2. 每个作者的贡献
3. 修改的主要文件
4. 是否有破坏性变更
请用表格格式输出"
场景2:有Prompt后
用户只需:
1. 点击 "/analyze-commits" 命令
2. 选择分支 "main"
3. AI自动执行完整分析
Prompt的数据结构
定义一个Prompt:
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"analyze_commits"</span>
<span>,</span> <span>// Prompt的唯一标识</span>
<span>"title"</span>
<span>:</span> <span>"提交历史分析"</span>
<span>,</span> <span>// 用户界面显示的名称</span>
<span>"description"</span>
<span>:</span> <span>"分析Git提交并生成报告"</span>
<span>,</span> <span>// 功能说明</span>
<span>"arguments"</span>
<span>:</span> <span>[</span> <span>// 需要的参数列表</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"branch"</span>
<span>,</span> <span>// 参数名</span>
<span>"description"</span>
<span>:</span> <span>"要分析的分支名"</span>
<span>,</span> <span>// 参数说明</span>
<span>"required"</span>
<span>:</span> <span>true</span> <span>// 是否必填</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"since"</span>
<span>,</span> <span>// 时间范围</span>
<span>"description"</span>
<span>:</span> <span>"起始日期(如:7 days ago)"</span>
<span>,</span>
<span>"required"</span>
<span>:</span> <span>false</span> <span>// 可选参数</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"author"</span>
<span>,</span> <span>// 作者过滤</span>
<span>"description"</span>
<span>:</span> <span>"只看某个作者的提交"</span>
<span>,</span>
<span>"required"</span>
<span>:</span> <span>false</span>
<span>}</span>
<span>]</span>
<span>}</span>
实际使用示例
步骤1: 列出所有可用的Prompt
<span>// 客户端请求</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"prompts/list"</span>
<span>}</span>
<span>// 服务器响应</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>1</span>
<span>,</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"prompts"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"analyze_commits"</span>
<span>,</span>
<span>"title"</span>
<span>:</span> <span>"📊 提交历史分析"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"分析指定分支的提交历史,生成统计报告"</span>
<span>,</span>
<span>"arguments"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"branch"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>true</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"since"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>false</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"review_code"</span>
<span>,</span>
<span>"title"</span>
<span>:</span> <span>"🔍 代码审查"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"对代码进行质量审查和改进建议"</span>
<span>,</span>
<span>"arguments"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"file_path"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>true</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"focus"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>false</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"explain_error"</span>
<span>,</span>
<span>"title"</span>
<span>:</span> <span>"🐛 错误诊断"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"解释错误信息并提供修复建议"</span>
<span>,</span>
<span>"arguments"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"error_message"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>true</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>}</span>
步骤2: 用户在界面上看到这些选项
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
可用命令:
📊 /analyze-commits
分析指定分支的提交历史
🔍 /review-code
对代码进行质量审查
🐛 /explain-error
解释错误信息并修复
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
步骤3: 用户选择并填写参数
用户输入: /analyze-commits
系统弹窗:
┌─────────────────────────┐
│ 提交历史分析 │
├─────────────────────────┤
│ 分支名 *: [main ] │
│ 时间范围: [7 days ago] │
│ 作者: [ ] │
│ │
│ [取消] [确定] │
└─────────────────────────┘
步骤4: 获取完整的Prompt内容
<span>// 客户端请求</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>2</span>
<span>,</span>
<span>"method"</span>
<span>:</span> <span>"prompts/get"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"analyze_commits"</span>
<span>,</span> <span>// 使用哪个模板</span>
<span>"arguments"</span>
<span>:</span> <span>{</span> <span>// 用户填写的参数</span>
<span>"branch"</span>
<span>:</span> <span>"main"</span>
<span>,</span>
<span>"since"</span>
<span>:</span> <span>"7 days ago"</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>// 服务器响应 - 返回完整的对话消息</span>
<span>{</span>
<span>"jsonrpc"</span>
<span>:</span> <span>"2.0"</span>
<span>,</span>
<span>"id"</span>
<span>:</span> <span>2</span>
<span>,</span>
<span>"result"</span>
<span>:</span> <span>{</span>
<span>"description"</span>
<span>:</span> <span>"分析main分支最近7天的提交"</span>
<span>,</span>
<span>"messages"</span>
<span>:</span> <span>[</span> <span>// 发送给AI的完整对话</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span> <span>// 用户角色</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>"请分析main分支在过去7天的Git提交历史。\n\n需要统计:\n1. 总提交次数\n2. 每个作者的贡献次数和代码行数\n3. 主要修改的文件列表\n4. 是否包含breaking changes\n5. 提交消息的规范性\n\n请用表格格式输出结果,并在最后给出改进建议。"</span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>}</span>
步骤5: 客户端将消息发送给AI
用户看到AI正在分析...
AI返回:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 main分支提交分析报告(最近7天)
总提交次数: 23
作者贡献统计:
┌────────────┬────────┬──────────┐
│ 作者 │ 提交数 │ 代码行数 │
├────────────┼────────┼──────────┤
│ Alice │ 12 │ +543/-89│
│ Bob │ 8 │ +234/-45│
│ Charlie │ 3 │ +123/-12│
└────────────┴────────┴──────────┘
主要修改文件:
- src/api/users.py (8次修改)
- src/models/user.py (5次修改)
- tests/test_user.py (4次修改)
Breaking Changes: 无
提交规范性: 良好 (91%符合Conventional Commits)
改进建议:
1. 建议增加单元测试覆盖率
2. 部分提交消息过于简短
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Prompt的内容类型
Prompt消息中可以包含多种内容:
1. 纯文本
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>"请审查这段代码..."</span>
<span>}</span>
<span>}</span>
2. 嵌入图片
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"image"</span>
<span>,</span>
<span>"data"</span>
<span>:</span> <span>"base64-encoded-image-data"</span>
<span>,</span> <span>// 图片数据</span>
<span>"mimeType"</span>
<span>:</span> <span>"image/png"</span> <span>// 图片类型</span>
<span>}</span>
<span>}</span>
3. 嵌入资源(引用MCP资源)
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"resource"</span>
<span>,</span>
<span>"resource"</span>
<span>:</span> <span>{</span>
<span>"uri"</span>
<span>:</span> <span>"file:///project/src/user.py"</span>
<span>,</span> <span>// 资源URI</span>
<span>"mimeType"</span>
<span>:</span> <span>"text/x-python"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>"class User:\n def __init__..."</span> <span>// 资源内容</span>
<span>}</span>
<span>}</span>
<span>}</span>
4. 多轮对话
<span>{</span>
<span>"messages"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span> <span>"text"</span>
<span>:</span> <span>"我想优化这段代码"</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"assistant"</span>
<span>,</span> <span>// AI的回复</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span> <span>"text"</span>
<span>:</span> <span>"请提供代码内容"</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"resource"</span>
<span>,</span> <span>// 用户提供代码</span>
<span>"resource"</span>
<span>:</span> <span>{</span>...<span>}</span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
Prompt vs Tool vs Resource 对比
特性 Prompt Tool Resource
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
控制者 用户主动选择 AI自动决定 应用程序控制
触发方式 用户点击命令 AI判断需要调用 应用自动附加
/analyze 或用户选择
返回内容 对话消息 执行结果 数据内容
(给AI的指令) (函数返回值) (上下文信息)
典型用途 工作流模板 执行操作 提供背景信息
快捷指令 查询数据 文件内容
示例 代码审查模板 执行SQL查询 项目README
错误诊断向导 发送邮件 数据库Schema
用户感知 ✅ 明显 ❓ 可能不知道 ❓ 透明的
(用户点击) (AI决定) (自动加载)
Prompt是预设的对话模板,通过参数化实现灵活应用,提升用户体验,并能与MCP其他能力组合形成完整工作流。
代码实现示例
<span># 服务器端:注册Prompt</span>
<span>@server<span>.</span>list_prompts</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>list_prompts</span>
<span>(</span>
<span>)</span>
<span>:</span>
<span>return</span> <span>[</span>
Prompt<span>(</span>
name<span>=</span>
<span>"analyze_commits"</span>
<span>,</span>
title<span>=</span>
<span>"📊 提交历史分析"</span>
<span>,</span>
description<span>=</span>
<span>"分析Git提交历史并生成统计报告"</span>
<span>,</span>
arguments<span>=</span>
<span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"branch"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"分支名"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>True</span>
<span>}</span>
<span>,</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"since"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"时间范围"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>False</span>
<span>}</span>
<span>]</span>
<span>)</span>
<span>]</span>
<span>@server<span>.</span>get_prompt</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>get_prompt</span>
<span>(</span>name<span>:</span> <span>str</span>
<span>,</span> arguments<span>:</span> <span>dict</span>
<span>)</span>
<span>:</span>
<span>if</span> name <span>==</span> <span>"analyze_commits"</span>
<span>:</span>
branch <span>=</span> arguments<span>[</span>
<span>"branch"</span>
<span>]</span>
since <span>=</span> arguments<span>.</span>get<span>(</span>
<span>"since"</span>
<span>,</span> <span>"7 days ago"</span>
<span>)</span>
<span># 构建完整的提示消息</span>
prompt_text <span>=</span> <span><span>f"""
请分析</span>
<span><span>{</span>branch<span>}</span></span>
<span>分支在</span>
<span><span>{</span>since<span>}</span></span>
<span>的Git提交历史。
需要统计:
1. 总提交次数
2. 每个作者的贡献
3. 主要修改的文件
4. 是否有breaking changes
请用表格格式输出。
"""</span></span>
<span>return</span> <span>{</span>
<span>"messages"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span> <span>"text"</span>
<span>:</span> prompt_text<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span># 客户端:使用Prompt</span>
<span>async</span> <span>def</span> <span>use_prompt</span>
<span>(</span>session<span>,</span> prompt_name<span>,</span> arguments<span>)</span>
<span>:</span>
<span># 获取Prompt内容</span>
prompt <span>=</span> <span>await</span> session<span>.</span>get_prompt<span>(</span>
name<span>=</span>prompt_name<span>,</span>
arguments<span>=</span>arguments
<span>)</span>
<span># 将消息发送给AI</span>
<span>for</span> message <span>in</span> prompt<span>.</span>messages<span>:</span>
ai_response <span>=</span> <span>await</span> send_to_ai<span>(</span>message<span>)</span>
<span>print</span>
<span>(</span>ai_response<span>)</span>
5.3 Tools(工具):AI 自己决定用什么
Tool就是可执行的函数,比如查询数据库、调用API、写文件。
谁控制:AI模型根据对话内容自己决定调用哪个工具
如何使用:
<span>// 列出可用工具</span>
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"tools/list"</span>
<span>}</span>
<span>// AI调用工具</span>
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"tools/call"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"name"</span>
<span>:</span> <span>"get_weather"</span>
<span>,</span>
<span>"arguments"</span>
<span>:</span> <span>{</span>
<span>"city"</span>
<span>:</span> <span>"北京"</span>
<span>}</span>
<span>}</span>
<span>}</span>
返回结果:
<span>{</span>
<span>"content"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>"北京天气:晴,温度22°C"</span>
<span>}</span>
<span>]</span>
<span>,</span>
<span>"isError"</span>
<span>:</span> <span>false</span>
<span>}</span>
5.4 其他功能
MCP提供标准化的参数自动补全功能,支持为提示和资源URI提供上下文相关的建议,实现类似IDE的交互体验。服务器通过声明completions能力,支持对ref/prompt和ref/resource两种引用类型的补全,每次最多返回100个按相关性排序的建议值,并可通过completion/complete请求获取补全结果。
MCP提供结构化日志消息传递机制,允许服务器向客户端发送包含严重性级别、可选记录器名称和任意JSON可序列化数据的日志通知。服务器需声明logging能力,支持遵循RFC 5424标准的日志级别(从debug到emergency),客户端可通过logging/setLevel请求配置最低日志级别,服务器通过notifications/message通知发送日志消息。
MCP支持对可能返回大量结果集的列表操作进行分页处理,使用基于不透明游标的分页模型而非数字页码。服务器在响应中包含当前页结果和可选的nextCursor字段(表示更多结果存在),客户端可通过在请求中包含游标继续分页。支持分页的操作包括resources/list、resources/templates/list、prompts/list和tools/list,客户端必须将游标视为不透明令牌。
六、客户端能力:反向请求
客户端不仅接收服务器的数据,也可以提供能力给服务器使用:
6.1 Sampling(采样):服务器请求客户端调用AI
场景: 服务器在处理任务时,需要AI帮忙分析中间结果。
如何使用:
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"sampling/createMessage"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"messages"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span> <span>"text"</span>
<span>:</span> <span>"这个数据正常吗?"</span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>,</span>
<span>"modelPreferences"</span>
<span>:</span> <span>{</span>
<span>"hints"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"claude-3-sonnet"</span>
<span>}</span>
<span>]</span>
<span>,</span> <span>// 建议用的模型</span>
<span>"intelligencePriority"</span>
<span>:</span> <span>0.8</span>
<span>,</span> <span>// 要求智能程度</span>
<span>"speedPriority"</span>
<span>:</span> <span>0.5</span> <span>// 速度要求</span>
<span>}</span>
<span>}</span>
<span>}</span>
实际案例:Filesystem服务器在搜索大量文件时,请求AI判断哪些文件最相关。
6.2 Roots(目录):告诉服务器工作范围
场景: 让服务器知道可以访问哪些目录。
如何使用:
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"roots/list"</span>
<span>}</span>
返回:
<span>{</span>
<span>"roots"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"uri"</span>
<span>:</span> <span>"file:///home/user/project"</span>
<span>,</span>
<span>"name"</span>
<span>:</span> <span>"我的项目"</span>
<span>}</span>
<span>]</span>
<span>}</span>
服务器知道只能在这个目录里操作,保护其他文件安全。
6.3 Elicitation(引导):服务器向用户询问信息
场景: 服务器需要用户提供额外信息才能继续。
如何使用:
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"elicitation/create"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"message"</span>
<span>:</span> <span>"请提供您的GitHub用户名"</span>
<span>,</span>
<span>"requestedSchema"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"object"</span>
<span>,</span>
<span>"properties"</span>
<span>:</span> <span>{</span>
<span>"username"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"string"</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>}</span>
用户响应:
<span>{</span>
<span>"action"</span>
<span>:</span> <span>"accept"</span>
<span>,</span> <span>// 或"decline"拒绝, "cancel"取消</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"username"</span>
<span>:</span> <span>"octocat"</span>
<span>}</span>
<span>}</span>
实际案例: Git服务器需要知道提交信息格式,弹窗问用户:”请选择提交规范:Conventional Commits/Angular/Custom?”
七、完整实战:从零构建天气查询MCP
下面让我们从头到尾构建一个完整的MCP系统,包含服务器和客户端。
7.1 需求分析
目标: 构建一个天气查询MCP服务器,提供:
-
资源: 城市列表
-
工具: 查询天气、获取预报
-
提示: 天气分析模板
7.2 服务器实现(Python)
第一步: 安装MCP SDK
pip <span>install</span> mcp
第二步: 创建服务器 (weather_server.py)
<span>from</span> mcp<span>.</span>server <span>import</span> Server
<span>from</span> mcp<span>.</span>types <span>import</span> Resource<span>,</span> Tool<span>,</span> Prompt<span>,</span> TextContent
<span>import</span> mcp<span>.</span>server<span>.</span>stdio
<span>import</span> httpx
<span># 创建MCP服务器实例</span>
server <span>=</span> Server<span>(</span>
<span>"weather-server"</span>
<span>)</span>
<span># 1. 定义资源:支持的城市列表</span>
<span>@server<span>.</span>list_resources</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>list_resources</span>
<span>(</span>
<span>)</span>
<span>:</span>
<span>"""返回可用的资源列表"""</span>
<span>return</span> <span>[</span>
Resource<span>(</span>
uri<span>=</span>
<span>"weather://cities"</span>
<span>,</span>
name<span>=</span>
<span>"支持的城市列表"</span>
<span>,</span>
mimeType<span>=</span>
<span>"application/json"</span>
<span>,</span>
description<span>=</span>
<span>"查询天气支持的所有城市"</span>
<span>)</span>
<span>]</span>
<span>@server<span>.</span>read_resource</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>read_resource</span>
<span>(</span>uri<span>:</span> <span>str</span>
<span>)</span>
<span>:</span>
<span>"""读取具体资源内容"""</span>
<span>if</span> uri <span>==</span> <span>"weather://cities"</span>
<span>:</span>
cities <span>=</span> <span>[</span>
<span>"北京"</span>
<span>,</span> <span>"上海"</span>
<span>,</span> <span>"广州"</span>
<span>,</span> <span>"深圳"</span>
<span>,</span> <span>"杭州"</span>
<span>]</span>
<span>return</span> <span>{</span>
<span>"contents"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"uri"</span>
<span>:</span> uri<span>,</span>
<span>"mimeType"</span>
<span>:</span> <span>"application/json"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span>str</span>
<span>(</span>cities<span>)</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span># 2. 定义工具:天气查询</span>
<span>@server<span>.</span>list_tools</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>list_tools</span>
<span>(</span>
<span>)</span>
<span>:</span>
<span>"""返回可用的工具列表"""</span>
<span>return</span> <span>[</span>
Tool<span>(</span>
name<span>=</span>
<span>"get_current_weather"</span>
<span>,</span>
description<span>=</span>
<span>"获取指定城市的当前天气"</span>
<span>,</span>
inputSchema<span>=</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"object"</span>
<span>,</span>
<span>"properties"</span>
<span>:</span> <span>{</span>
<span>"city"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"string"</span>
<span>,</span>
<span>"description"</span>
<span>:</span> <span>"城市名称,如'北京'"</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>"required"</span>
<span>:</span> <span>[</span>
<span>"city"</span>
<span>]</span>
<span>}</span>
<span>)</span>
<span>,</span>
Tool<span>(</span>
name<span>=</span>
<span>"get_forecast"</span>
<span>,</span>
description<span>=</span>
<span>"获取未来3天天气预报"</span>
<span>,</span>
inputSchema<span>=</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"object"</span>
<span>,</span>
<span>"properties"</span>
<span>:</span> <span>{</span>
<span>"city"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"string"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"城市名称"</span>
<span>}</span>
<span>,</span>
<span>"days"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"number"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"预报天数(1-3)"</span>
<span>,</span> <span>"default"</span>
<span>:</span> <span>3</span>
<span>}</span>
<span>}</span>
<span>,</span>
<span>"required"</span>
<span>:</span> <span>[</span>
<span>"city"</span>
<span>]</span>
<span>}</span>
<span>)</span>
<span>]</span>
<span>@server<span>.</span>call_tool</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>call_tool</span>
<span>(</span>name<span>:</span> <span>str</span>
<span>,</span> arguments<span>:</span> <span>dict</span>
<span>)</span>
<span>:</span>
<span>"""执行工具调用"""</span>
<span>if</span> name <span>==</span> <span>"get_current_weather"</span>
<span>:</span>
city <span>=</span> arguments<span>[</span>
<span>"city"</span>
<span>]</span>
<span># 实际项目中这里调用真实的天气API</span>
<span># 示例:使用模拟数据</span>
weather_data <span>=</span> <span>{</span>
<span>"city"</span>
<span>:</span> city<span>,</span>
<span>"temperature"</span>
<span>:</span> <span>22</span>
<span>,</span>
<span>"condition"</span>
<span>:</span> <span>"晴"</span>
<span>,</span>
<span>"humidity"</span>
<span>:</span> <span>45</span>
<span>}</span>
<span>return</span> <span>{</span>
<span>"content"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span><span>f"</span>
<span><span>{</span>city<span>}</span></span>
<span>当前天气:\n温度: </span>
<span><span>{</span>weather_data<span>[</span>
<span>'temperature'</span>
<span>]</span>
<span>}</span></span>
<span>°C\n天气: </span>
<span><span>{</span>weather_data<span>[</span>
<span>'condition'</span>
<span>]</span>
<span>}</span></span>
<span>\n湿度: </span>
<span><span>{</span>weather_data<span>[</span>
<span>'humidity'</span>
<span>]</span>
<span>}</span></span>
<span>%"</span></span>
<span>}</span>
<span>]</span>
<span>}</span>
<span>elif</span> name <span>==</span> <span>"get_forecast"</span>
<span>:</span>
city <span>=</span> arguments<span>[</span>
<span>"city"</span>
<span>]</span>
days <span>=</span> arguments<span>.</span>get<span>(</span>
<span>"days"</span>
<span>,</span> <span>3</span>
<span>)</span>
<span># 模拟预报数据</span>
forecast <span>=</span> <span><span>f"</span>
<span><span>{</span>city<span>}</span></span>
<span>未来</span>
<span><span>{</span>days<span>}</span></span>
<span>天预报:\n第1天: 晴,20-25°C\n第2天: 多云,18-23°C\n第3天: 小雨,16-20°C"</span></span>
<span>return</span> <span>{</span>
<span>"content"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span> <span>"text"</span>
<span>:</span> forecast<span>}</span>
<span>]</span>
<span>}</span>
<span># 3. 定义提示模板:天气分析</span>
<span>@server<span>.</span>list_prompts</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>list_prompts</span>
<span>(</span>
<span>)</span>
<span>:</span>
<span>"""返回可用的提示模板"""</span>
<span>return</span> <span>[</span>
Prompt<span>(</span>
name<span>=</span>
<span>"analyze_weather"</span>
<span>,</span>
description<span>=</span>
<span>"分析天气趋势并给出建议"</span>
<span>,</span>
arguments<span>=</span>
<span>[</span>
<span>{</span>
<span>"name"</span>
<span>:</span> <span>"city"</span>
<span>,</span> <span>"description"</span>
<span>:</span> <span>"城市名称"</span>
<span>,</span> <span>"required"</span>
<span>:</span> <span>True</span>
<span>}</span>
<span>]</span>
<span>)</span>
<span>]</span>
<span>@server<span>.</span>get_prompt</span>
<span>(</span>
<span>)</span>
<span>async</span> <span>def</span> <span>get_prompt</span>
<span>(</span>name<span>:</span> <span>str</span>
<span>,</span> arguments<span>:</span> <span>dict</span>
<span>)</span>
<span>:</span>
<span>"""获取提示模板内容"""</span>
<span>if</span> name <span>==</span> <span>"analyze_weather"</span>
<span>:</span>
city <span>=</span> arguments<span>[</span>
<span>"city"</span>
<span>]</span>
<span>return</span> <span>{</span>
<span>"messages"</span>
<span>:</span> <span>[</span>
<span>{</span>
<span>"role"</span>
<span>:</span> <span>"user"</span>
<span>,</span>
<span>"content"</span>
<span>:</span> <span>{</span>
<span>"type"</span>
<span>:</span> <span>"text"</span>
<span>,</span>
<span>"text"</span>
<span>:</span> <span><span>f"请分析</span>
<span><span>{</span>city<span>}</span></span>
<span>的天气情况,并给出出行建议。包括:\n1. 温度是否适宜\n2. 是否需要带伞\n3. 穿衣建议"</span></span>
<span>}</span>
<span>}</span>
<span>]</span>
<span>}</span>
<span># 启动服务器</span>
<span>if</span> __name__ <span>==</span> <span>"__main__"</span>
<span>:</span>
<span># 使用stdio传输(本地)</span>
mcp<span>.</span>server<span>.</span>stdio<span>.</span>run_stdio_server<span>(</span>server<span>)</span>
7.3 配置服务器(Claude Desktop)
创建配置文件 ~/Library/Application Support/Claude/claude_desktop_config.json:
<span>{</span>
<span>"mcpServers"</span>
<span>:</span> <span>{</span>
<span>"weather"</span>
<span>:</span> <span>{</span>
<span>"command"</span>
<span>:</span> <span>"python"</span>
<span>,</span>
<span>"args"</span>
<span>:</span> <span>[</span>
<span>"/path/to/weather_server.py"</span>
<span>]</span>
<span>}</span>
<span>}</span>
<span>}</span>
7.4 客户端实现(Python)
如果要自己实现客户端:
<span>from</span> mcp <span>import</span> ClientSession
<span>from</span> mcp<span>.</span>client<span>.</span>stdio <span>import</span> stdio_client
<span>import</span> asyncio
<span>async</span> <span>def</span> <span>main</span>
<span>(</span>
<span>)</span>
<span>:</span>
<span># 连接到服务器</span>
<span>async</span> <span>with</span> stdio_client<span>(</span>
command<span>=</span>
<span>"python"</span>
<span>,</span>
args<span>=</span>
<span>[</span>
<span>"/path/to/weather_server.py"</span>
<span>]</span>
<span>)</span> <span>as</span> <span>(</span>read<span>,</span> write<span>)</span>
<span>:</span>
<span>async</span> <span>with</span> ClientSession<span>(</span>read<span>,</span> write<span>)</span> <span>as</span> session<span>:</span>
<span># 1. 初始化连接</span>
<span>await</span> session<span>.</span>initialize<span>(</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span>"✅ 连接成功!"</span>
<span>)</span>
<span># 2. 列出可用资源</span>
resources <span>=</span> <span>await</span> session<span>.</span>list_resources<span>(</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n📁 可用资源: </span>
<span><span>{</span>
<span>len</span>
<span>(</span>resources<span>.</span>resources<span>)</span>
<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span>for</span> r <span>in</span> resources<span>.</span>resources<span>:</span>
<span>print</span>
<span>(</span>
<span><span>f" - </span>
<span><span>{</span>r<span>.</span>name<span>}</span></span>
<span>: </span>
<span><span>{</span>r<span>.</span>uri<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 3. 读取城市列表资源</span>
cities_resource <span>=</span> <span>await</span> session<span>.</span>read_resource<span>(</span>
uri<span>=</span>
<span>"weather://cities"</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n🌍 城市列表: </span>
<span><span>{</span>cities_resource<span>.</span>contents<span>[</span>
<span>0</span>
<span>]</span>
<span>.</span>text<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 4. 列出可用工具</span>
tools <span>=</span> <span>await</span> session<span>.</span>list_tools<span>(</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n🔧 可用工具: </span>
<span><span>{</span>
<span>len</span>
<span>(</span>tools<span>.</span>tools<span>)</span>
<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span>for</span> t <span>in</span> tools<span>.</span>tools<span>:</span>
<span>print</span>
<span>(</span>
<span><span>f" - </span>
<span><span>{</span>t<span>.</span>name<span>}</span></span>
<span>: </span>
<span><span>{</span>t<span>.</span>description<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 5. 调用工具查询天气</span>
result <span>=</span> <span>await</span> session<span>.</span>call_tool<span>(</span>
name<span>=</span>
<span>"get_current_weather"</span>
<span>,</span>
arguments<span>=</span>
<span>{</span>
<span>"city"</span>
<span>:</span> <span>"北京"</span>
<span>}</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n🌤️ 查询结果:\n</span>
<span><span>{</span>result<span>.</span>content<span>[</span>
<span>0</span>
<span>]</span>
<span>.</span>text<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 6. 获取预报</span>
forecast <span>=</span> <span>await</span> session<span>.</span>call_tool<span>(</span>
name<span>=</span>
<span>"get_forecast"</span>
<span>,</span>
arguments<span>=</span>
<span>{</span>
<span>"city"</span>
<span>:</span> <span>"上海"</span>
<span>,</span> <span>"days"</span>
<span>:</span> <span>3</span>
<span>}</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n📅 天气预报:\n</span>
<span><span>{</span>forecast<span>.</span>content<span>[</span>
<span>0</span>
<span>]</span>
<span>.</span>text<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 7. 列出提示模板</span>
prompts <span>=</span> <span>await</span> session<span>.</span>list_prompts<span>(</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n💡 提示模板: </span>
<span><span>{</span>
<span>len</span>
<span>(</span>prompts<span>.</span>prompts<span>)</span>
<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span>for</span> p <span>in</span> prompts<span>.</span>prompts<span>:</span>
<span>print</span>
<span>(</span>
<span><span>f" - </span>
<span><span>{</span>p<span>.</span>name<span>}</span></span>
<span>: </span>
<span><span>{</span>p<span>.</span>description<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span># 8. 获取提示内容</span>
prompt <span>=</span> <span>await</span> session<span>.</span>get_prompt<span>(</span>
name<span>=</span>
<span>"analyze_weather"</span>
<span>,</span>
arguments<span>=</span>
<span>{</span>
<span>"city"</span>
<span>:</span> <span>"广州"</span>
<span>}</span>
<span>)</span>
<span>print</span>
<span>(</span>
<span><span>f"\n📝 生成的提示:\n</span>
<span><span>{</span>prompt<span>.</span>messages<span>[</span>
<span>0</span>
<span>]</span>
<span>[</span>
<span>'content'</span>
<span>]</span>
<span>[</span>
<span>'text'</span>
<span>]</span>
<span>}</span></span>
<span>"</span></span>
<span>)</span>
<span>if</span> __name__ <span>==</span> <span>"__main__"</span>
<span>:</span>
asyncio<span>.</span>run<span>(</span>main<span>(</span>
<span>)</span>
<span>)</span>
7.5 运行效果
$ python weather_client.py
✅ 连接成功<span>!</span>
📁 可用资源: <span>1</span>
- 支持的城市列表: weather://cities
🌍 城市列表: <span>[</span>
<span>'北京'</span>, <span>'上海'</span>, <span>'广州'</span>, <span>'深圳'</span>, <span>'杭州'</span>
<span>]</span>
🔧 可用工具: <span>2</span>
- get_current_weather: 获取指定城市的当前天气
- get_forecast: 获取未来3天天气预报
🌤️ 查询结果:
北京当前天气:
温度: <span>22</span>°C
天气: 晴
湿度: <span>45</span>%
📅 天气预报:
上海未来3天预报:
第1天: 晴,20-25°C
第2天: 多云,18-23°C
第3天: 小雨,16-20°C
💡 提示模板: <span>1</span>
- analyze_weather: 分析天气趋势并给出建议
📝 生成的提示:
请分析广州的天气情况,并给出出行建议。包括:
<span>1</span>. 温度是否适宜
<span>2</span>. 是否需要带伞
<span>3</span>. 穿衣建议
八、其他部分:MCP基础协议的另一半
8.1 授权(Authorization)
MCP授权规范定义了基于HTTP传输的安全授权机制,使MCP客户端能够代表资源所有者向受限制的MCP服务器发出请求。该规范基于OAuth 2.1及相关标准,实现了授权服务器发现、动态客户端注册和访问令牌管理。例如,客户端通过resource参数明确指定目标MCP服务器(如https://mcp.example.com),服务器则验证令牌是否专门为其颁发,确保令牌不会被误用于其他服务,从而防止”令牌传递”安全漏洞。
8.2 取消(Cancellation)
MCP取消机制允许通过通知消息中止正在进行的请求,任何一方都可以发送notifications/cancelled通知来终止先前发出的请求。例如,当用户取消长时间运行的操作时,客户端可以发送包含请求ID和可选原因的取消通知,接收方应停止处理、释放资源且不发送响应。该机制考虑了网络延迟导致的竞态条件,允许接收方在请求已完成或无法取消时忽略通知,同时建议双方记录取消原因以便调试。
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"notifications/cancelled"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"requestId"</span>
<span>:</span> <span>"123"</span>
<span>,</span>
<span>"reason"</span>
<span>:</span> <span>"用户取消"</span>
<span>}</span>
<span>}</span>
8.3 Ping机制
MCP提供了可选的ping机制,允许任何一方验证对方是否仍然响应且连接存活。该机制通过简单的请求/响应模式实现,例如客户端发送{"jsonrpc":"2.0","id":"123","method":"ping"},服务器必须立即响应{"jsonrpc":"2.0","id":"123","result":{}}。如果在合理超时时间内未收到响应,发送方可以将连接视为陈旧并终止连接或尝试重新连接。实现应定期发送ping以检测连接健康状况,但应避免过度ping以减少网络开销。
8.4 进度跟踪(Progress)
MCP支持通过通知消息对长时间运行的操作进行可选的进度跟踪。请求方可以在请求元数据中包含唯一的progressToken(如字符串”task123″)来接收进度更新,接收方则可以发送包含进度值、可选总值和消息的notifications/progress通知。例如,文件上传操作可以发送{"progress":50,"total":100,"message":"正在上传文件..."}来指示完成百分比。进度值必须随每个通知递增,双方应实现速率限制以防止消息泛滥,并在操作完成后停止发送进度通知。
<span>{</span>
<span>"method"</span>
<span>:</span> <span>"notifications/progress"</span>
<span>,</span>
<span>"params"</span>
<span>:</span> <span>{</span>
<span>"progressToken"</span>
<span>:</span> <span>"task123"</span>
<span>,</span>
<span>"progress"</span>
<span>:</span> <span>50</span>
<span>,</span> <span>// 当前进度</span>
<span>"total"</span>
<span>:</span> <span>100</span>
<span>,</span> <span>// 总量</span>
<span>"message"</span>
<span>:</span> <span>"正在上传文件..."</span>
<span>}</span>
<span>}</span>
九、安全实践:必须重视
9.1 核心原则
1. 用户同意优先
-
所有数据访问必须经用户明确同意
-
所有工具调用前必须让用户确认
2. 数据隐私保护
-
服务器只能看到必要的信息
-
完整对话历史保留在宿主,不发给服务器
3. 工具安全
-
工具代表代码执行,必须谨慎
-
显示工具要做什么,让用户批准
4. 输入验证
-
服务器必须验证所有输入
-
客户端必须验证工具返回的结果
9.2 实际建议
服务器开发者:
-
验证所有输入参数
-
实现访问控制和速率限制
-
记录操作日志供审计
客户端开发者:
-
显示清晰的权限请求界面
-
在调用工具前展示参数
-
实现工具调用超时机制
十、MCP生态:谁开发客户端?
关键认知: 在MCP生态中,客户端通常不是由下游开发者开发的,而是内置在AI应用平台中。
开发者开发MCP服务器
↓
配置到AI平台(Claude/Cursor等)
↓
AI平台内置的MCP客户端自动连接
对于软件开发者来说,在MCP生态中的位置如下。
角色定位:
┌─────────────────────────────────────────┐
│ AI平台开发者(Anthropic, Cursor等) │
│ ──────────────────────────────── │
│ 职责: │
│ ✅ 开发MCP客户端SDK │
│ ✅ 集成到自己的AI应用中 │
│ ✅ 提供配置界面 │
│ ✅ 管理MCP服务器生命周期 │
│ ✅ 处理AI与MCP的交互逻辑 │
└─────────────────────────────────────────┘
↓ 提供平台
┌─────────────────────────────────────────┐
│ MCP服务器开发者(你、我、社区) │
│ ──────────────────────────────── │
│ 职责: │
│ ✅ 开发MCP服务器 │
│ ✅ 实现Resources/Tools/Prompts │
│ ✅ 编写使用文档 │
│ ✅ 发布到npm/PyPI │
│ ❌ 不需要开发客户端 │
│ ❌ 不需要关心AI如何调用 │
└─────────────────────────────────────────┘
↓ 使用服务
┌─────────────────────────────────────────┐
│ 最终用户(开发者、分析师等) │
│ ──────────────────────────────── │
│ 职责: │
│ ✅ 安装需要的MCP服务器 │
│ ✅ 配置到AI平台 │
│ ✅ 使用AI完成任务 │
│ ❌ 不需要写代码 │
└─────────────────────────────────────────┘
后记
MCP 让 AI 应用开发变得更简单、更安全、更强大。它不是银弹,但为构建可靠的AI系统提供了坚实基础。本文全部内容基于提示编写,欢迎交流讨论!
参考文献
-
MCP官方规范: https://modelcontextprotocol.io/specification/2025-06-18
-
JSON-RPC 2.0: https://www.jsonrpc.org/