最新MCP规范解读,看这篇就够了!


                                                                                                                                                <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/promptref/resource两种引用类型的补全,每次最多返回100个按相关性排序的建议值,并可通过completion/complete请求获取补全结果。

日志

MCP提供结构化日志消息传递机制,允许服务器向客户端发送包含严重性级别、可选记录器名称和任意JSON可序列化数据的日志通知。服务器需声明logging能力,支持遵循RFC 5424标准的日志级别(从debug到emergency),客户端可通过logging/setLevel请求配置最低日志级别,服务器通过notifications/message通知发送日志消息。

分页

MCP支持对可能返回大量结果集的列表操作进行分页处理,使用基于不透明游标的分页模型而非数字页码。服务器在响应中包含当前页结果和可选的nextCursor字段(表示更多结果存在),客户端可通过在请求中包含游标继续分页。支持分页的操作包括resources/listresources/templates/listprompts/listtools/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系统提供了坚实基础。本文全部内容基于提示编写,欢迎交流讨论!

参考文献

  1. MCP官方规范: https://modelcontextprotocol.io/specification/2025-06-18

  2. JSON-RPC 2.0: https://www.jsonrpc.org/



Source link

未经允许不得转载:紫竹林-程序员中文网 » 最新MCP规范解读,看这篇就够了!

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
关于我们 免责申明 意见反馈 隐私政策
程序员中文网:公益在线网站,帮助学习者快速成长!
关注微信 技术交流
推荐文章
每天精选资源文章推送
推荐文章
随时随地碎片化学习
推荐文章
发现有趣的