第 34 章

MCP 协议原理:Host / Client / Server 三角架构与 JSON-RPC 2.0 消息格式

第三十四章:MCP 协议详解:架构、传输层与能力声明

34.1 MCP 的诞生背景

在 MCP(Model Context Protocol)出现之前,每一个希望给 AI 模型提供工具能力的开发者都面临同样的困境:工具集成是碎片化的、不可复用的。OpenAI 有自己的 Function Calling 格式,Anthropic 有 Tool Use 规范,LangChain 有自己的 Tool 抽象,各家格式互不兼容。一个优秀的数据库查询工具,如果想同时支持 ChatGPT 和 Claude,就需要维护两套完全不同的代码。

2024年11月,Anthropic 发布了 MCP(Model Context Protocol),这是一个开放的、供应商中立的协议标准,目标是成为 AI 模型与外部工具之间的 USB-C 接口——一个统一的连接标准,让工具的开发者只需实现一次,就能被所有支持 MCP 的 AI 客户端使用。

MCP 的设计哲学核心是关注点分离

34.2 MCP 整体架构

34.2.1 三层架构模型

┌─────────────────────────────────────────┐
│           Host Application              │
│  (Claude Desktop / Claude Code / 自定义) │
│                                         │
│  ┌──────────────┐  ┌──────────────┐    │
│  │  MCP Client  │  │  MCP Client  │    │
│  │  (连接 A)    │  │  (连接 B)    │    │
│  └──────┬───────┘  └──────┬───────┘    │
└─────────┼─────────────────┼─────────────┘
          │                 │
    MCP Protocol      MCP Protocol
    (stdio / HTTP)    (stdio / HTTP)
          │                 │
   ┌──────▼──────┐  ┌──────▼──────┐
   │  MCP Server │  │  MCP Server │
   │  (文件系统) │  │  (数据库)   │
   └─────────────┘  └─────────────┘

Host 可以同时维护多个 MCP Client 连接,每个 Client 连接一个 MCP Server。Claude 模型通过 Host 的 Client 层访问 Server 提供的能力,整个过程对模型透明——模型看到的只是抽象化的工具调用接口。

34.2.2 核心概念关系图

概念 由谁提供 作用
Tools(工具) MCP Server 可执行的函数,模型可以调用
Resources(资源) MCP Server 可读取的数据,类似文件或 URL
Prompts(提示) MCP Server 预定义的提示模板,供用户选择
Roots(根路径) MCP Client 告知 Server 当前工作目录范围
Sampling(采样) MCP Client Server 请求 Host 调用 LLM

34.3 传输层详解

MCP 定义了两种标准传输层,分别适用于不同的部署场景。

34.3.1 stdio 传输(本地进程通信)

stdio 是最简单也最常用的传输方式,适用于 Server 和 Client 在同一台机器上运行的场景。

工作原理:

Host Process
    │
    ├── stdin  →  [JSON-RPC Request]  →  MCP Server Process
    │
    └── stdout ←  [JSON-RPC Response] ←  MCP Server Process

stdio 的优势

stdio 的限制

Claude Desktop 的 stdio 配置示例(~/Library/Application Support/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Documents"],
      "env": {}
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
      }
    }
  }
}

34.3.2 HTTP + SSE 传输(远程服务通信)

HTTP + SSE(Server-Sent Events) 是为远程部署设计的传输层,支持 Server 和 Client 分离部署,适合多用户、云端服务场景。

通信模式:

MCP Client                    MCP Server (远程)
    │                               │
    ├─── HTTP POST /message ────────▶│  发送请求
    │                               │
    │◀── SSE /sse ──────────────────│  接收响应/通知(长连接)
    │                               │
    │     GET /sse  →  建立 SSE 连接  │

HTTP+SSE 的优势

HTTP+SSE 的限制

2025年新增的 Streamable HTTP 传输:Anthropic 在 2025年3月更新的规范中,引入了 Streamable HTTP 作为更灵活的 HTTP 传输变体,允许在单个 HTTP 请求中以流式方式返回多个响应消息,同时保持对 SSE 的向后兼容。

34.4 MCP 消息格式:JSON-RPC 2.0

MCP 基于 JSON-RPC 2.0 规范定义消息格式。所有消息都是 JSON 对象,分为三种类型:

34.4.1 请求(Request)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": {
      "path": "/home/user/document.txt"
    }
  }
}

34.4.2 响应(Response)

成功响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "文件内容..."
      }
    ],
    "isError": false
  }
}

错误响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request",
    "data": "文件路径不存在"
  }
}

34.4.3 通知(Notification)

通知是无需响应的单向消息(无 id 字段):

{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed",
  "params": {}
}

34.5 能力声明:初始化握手

MCP 连接建立时,Client 和 Server 通过能力协商(Capability Negotiation)互相声明自己支持的功能。

34.5.1 初始化流程

Client                          Server
  │                               │
  ├──── initialize ──────────────▶│
  │     (clientCapabilities)      │
  │                               │
  │◀─── initialize response ──────│
  │     (serverCapabilities)      │
  │                               │
  ├──── initialized ─────────────▶│
  │     (通知:初始化完成)          │
  │                               │
  │         [正常工作]             │

34.5.2 完整的初始化消息

Client 发送的 initialize 请求

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "roots": {
        "listChanged": true
      },
      "sampling": {}
    },
    "clientInfo": {
      "name": "claude-code",
      "version": "1.0.0"
    }
  }
}

Server 返回的初始化响应

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {
        "listChanged": true
      },
      "resources": {
        "subscribe": true,
        "listChanged": true
      },
      "prompts": {
        "listChanged": false
      },
      "logging": {}
    },
    "serverInfo": {
      "name": "my-filesystem-server",
      "version": "2.1.0"
    }
  }
}

34.6 工具能力(Tools)详解

34.6.1 工具列表查询

Client 通过 tools/list 方法获取 Server 提供的所有工具:

// 请求
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "read_file",
        "description": "读取指定路径的文件内容",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": {
              "type": "string",
              "description": "文件的绝对或相对路径"
            },
            "encoding": {
              "type": "string",
              "enum": ["utf-8", "base64"],
              "default": "utf-8",
              "description": "文件编码格式"
            }
          },
          "required": ["path"]
        }
      },
      {
        "name": "write_file",
        "description": "将内容写入指定路径的文件",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": {"type": "string"},
            "content": {"type": "string"},
            "create_dirs": {
              "type": "boolean",
              "default": false,
              "description": "是否自动创建不存在的父目录"
            }
          },
          "required": ["path", "content"]
        }
      }
    ]
  }
}

34.6.2 工具调用

// 调用请求
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": {
      "path": "/Users/alice/notes.md",
      "encoding": "utf-8"
    }
  }
}

// 成功响应
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "# 我的笔记\n\n今天学习了 MCP 协议..."
      }
    ],
    "isError": false
  }
}

工具响应的 content 数组支持多种内容类型:

类型 用途 示例
text 纯文本内容 文件内容、执行结果
image 图像数据(base64) 截图、图表
resource 资源引用 嵌入的资源 URI

34.7 资源能力(Resources)详解

Resources 是 MCP 中用于暴露数据的机制,类似于"虚拟文件系统"。每个 Resource 有一个 URI 标识符,Client 可以读取其内容。

34.7.1 资源列表查询

// 请求
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "resources/list",
  "params": {}
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "resources": [
      {
        "uri": "file:///home/user/project/README.md",
        "name": "项目 README",
        "description": "项目说明文档",
        "mimeType": "text/markdown"
      },
      {
        "uri": "db://myapp/users/schema",
        "name": "用户表结构",
        "description": "users 表的完整 DDL",
        "mimeType": "application/sql"
      }
    ]
  }
}

34.7.2 资源内容读取

// 请求
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "resources/read",
  "params": {
    "uri": "file:///home/user/project/README.md"
  }
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "contents": [
      {
        "uri": "file:///home/user/project/README.md",
        "mimeType": "text/markdown",
        "text": "# 项目名称\n\n..."
      }
    ]
  }
}

34.7.3 资源订阅与变更通知

如果 Server 声明了 resources.subscribe 能力,Client 可以订阅资源变更:

// 订阅请求
{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "resources/subscribe",
  "params": {
    "uri": "file:///home/user/project/config.json"
  }
}

// Server 主动推送的变更通知
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "file:///home/user/project/config.json"
  }
}

34.8 提示能力(Prompts)详解

Prompts 是 Server 预定义的提示模板,允许用户在 Host 中直接选择并使用。这是 MCP 中一个容易被忽略但非常实用的能力。

34.8.1 提示列表

// 响应示例
{
  "result": {
    "prompts": [
      {
        "name": "code_review",
        "description": "对选中的代码进行全面的代码审查",
        "arguments": [
          {
            "name": "code",
            "description": "需要审查的代码",
            "required": true
          },
          {
            "name": "language",
            "description": "编程语言",
            "required": false
          }
        ]
      }
    ]
  }
}

34.8.2 获取提示内容

// 请求
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "code": "def fibonacci(n):\n    if n <= 1: return n\n    return fibonacci(n-1) + fibonacci(n-2)",
      "language": "Python"
    }
  }
}

// 响应:返回完整的消息列表
{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "description": "Python 代码审查",
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "请对以下 Python 代码进行全面的代码审查,关注性能、可读性和潜在 bug:\n\n```python\ndef fibonacci(n):\n    if n <= 1: return n\n    return fibonacci(n-1) + fibonacci(n-2)\n```"
        }
      }
    ]
  }
}

34.9 Sampling(采样):Server 调用 LLM

Sampling 是 MCP 中最高级的能力,它允许 MCP Server 请求 Host 去调用 LLM。这实现了一种反向调用——原本是 Client 调 Server,现在 Server 也可以反向发起 LLM 推理请求。

// Server 发送的 sampling/createMessage 请求
{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "请总结这段日志中的错误模式:ERROR: connection timeout..."
        }
      }
    ],
    "modelPreferences": {
      "hints": [{"name": "claude-sonnet-4-5"}],
      "intelligencePriority": 0.8,
      "speedPriority": 0.5
    },
    "maxTokens": 500
  }
}

Sampling 的典型应用场景:一个文件系统 Server 在发现代码错误时,可以请求 Host 的 LLM 生成修复建议,然后作为工具调用结果的一部分返回给用户。

34.10 协议版本与向后兼容

MCP 协议使用日期版本号(如 2024-11-05)进行版本管理。当前稳定版本为 2024-11-05,2025年3月发布了包含 Streamable HTTP 支持的更新规范。

版本协商规则:

  1. Client 在 initialize 请求中声明支持的最高协议版本
  2. Server 在响应中返回其使用的协议版本(不高于 Client 声明的版本)
  3. 如果版本不兼容,连接失败

实现 MCP Server 或 Client 时,建议使用官方 SDK 而非手动实现协议,以获得自动版本协商和未来兼容性保障。


小结

MCP 协议通过清晰的三层架构(Host/Client/Server)和两种传输层(stdio/HTTP+SSE),为 AI 工具生态提供了一个统一的标准接口。其核心设计理念——关注点分离能力声明协议中立性——使得工具开发者只需实现一次,即可在所有支持 MCP 的 AI 应用中使用。

关键要点:

  1. stdio 适合本地工具,HTTP+SSE 适合远程服务
  2. 初始化握手时双方声明各自的能力集合
  3. Tools(工具)、Resources(资源)、Prompts(提示)三种核心能力
  4. JSON-RPC 2.0 是协议的消息基础
  5. Sampling 允许 Server 反向请求 LLM 推理

下一章将进入实战,完整地构建一个自定义 MCP Server。

本章评分
4.5  / 5  (3 评分)

💬 留言讨论