深入浅出 MCP 系列教程(一):协议基础与架构设计

本系列共 5 篇,系统拆解 Model Context Protocol(MCP):从协议基础、三大原语、传输层、进阶能力到生产工程与选型。本篇是第一篇,讲清楚 MCP 是什么、为什么诞生、底层消息模型和会话全生命周期。

一、为什么诞生 MCP:N × M 的集成困境

在 MCP 出现之前,Agent 和外部系统集成是典型的 N × M 复杂度问题。

假设市面上有一批 AI Host(运行 Agent 的上层应用):Claude Desktop、Claude Code、Cursor、各类自研企业 Agent 平台。同时有一批外部系统:Git、本地文件系统、PostgreSQL、Slack、Jira、Notion、内部 OA、监控平台。

如果没有统一标准,每一个 Host 对接一个外部系统都要单独写一套连接器。Host 数量 = N,外部系统数量 = M,总集成工作量 ≈ N × M。举个数字例子:5 个 Agent 客户端、8 个外部系统,需要 40 套独立对接代码。

并且每套连接器各自定义规范:工具描述有的放 YAML、有的硬编码;没有统一的资源读取方式、变更推送、用户授权确认机制、错误码、会话握手和权限边界。

Function Calling 的天然局限

很多集成只是简单封装了 LLM 的 Function Calling,但 Function Calling 本身只解决一件事:让模型输出结构化 JSON 参数调用函数。它不规定:

  1. 工具如何被发现、列表如何同步;
  2. 外部只读数据如何作为上下文送入模型;
  3. 数据变更如何主动推送;
  4. 用户如何统一授权、审批高危操作;
  5. 服务端反过来请求模型做推理;
  6. 不同 Agent 客户端复用同一套外部能力。

LSP 的启发:从 N × M 到 N + M

MCP 的思路借鉴了 LSP(Language Server Protocol)。LSP 解决了不同编辑器(VS Code、Neovim、JetBrains)对接不同语言服务的问题。MCP 把这个范式搬到 AI Agent 领域:外部能力提供者只实现一次 MCP Server;所有 AI Host 只要内置 MCP Client 就可以直接接入。复杂度从 N × M → N + M。

关键认知:MCP 是”有线协议”

MCP 不是框架,不是 SDK,不是编程语言库,它是有线协议。”有线协议”的含义:规定两个进程之间通过通道传递什么格式的消息、消息字段含义、交互顺序、握手规则。任何语言,只要按报文规范实现,就可以互通。SDK 只是降低实现成本的封装。

MCP 由 Anthropic 在 2024 年 11 月发布,目标是标准化 AI Agent 和外部系统之间的上下文交换、工具调用、资源读取、提示模板加载。

顶层设计原则

  1. 模型中立:不绑定任何大模型,Host 可以接入任意后端 LLM;
  2. 传输中立:可以跑在子进程 stdio,也可以跑在 HTTP / SSE;
  3. 默认安全,显式授权:每个 Server 连接 Host 都需要用户主动确认授权,权限遵循最小可用;
  4. 可组合:同一个 Host 可以同时挂载多个互相独立的 MCP Server;
  5. 向后兼容、版本化演进:通过能力协商而不是强制版本号锁死;
  6. 区分读、写、模板三类能力:原生区分只读资源、带副作用工具、提示模板。

二、三大核心角色:Host、MCP Client、MCP Server

这是整个 MCP 模型的骨架,也是所有报文、会话逻辑的依托。很多初学者容易混淆 Client 和 Host,这里严格区分。

Host(主机)

Host 是面向用户的顶层 AI 应用,是整个会话的拥有者和决策者。典型例子:Claude Desktop、Claude Code、自研企业 Agent 平台、集成 MCP 的 IDE。

Host 的职责清单:

  1. 持有用户会话、身份、信任边界:所有授权弹窗、高危操作确认都由 Host 展示给用户。Server 无权直接弹出确认窗口;
  2. 管理多个 MCP Client 实例:连接 3 个 MCP Server 就启动 3 个独立 Client,一一对应;
  3. 持有 LLM 推理入口:采样(sampling)请求由 Server 发起,Host 调用大模型完成推理再回传,Host 掌握模型密钥与配额;
  4. 安全策略总控:黑名单、白名单、资源读取大小限制、超长返回截断;
  5. 聚合上下文:把各 Server 的 Resources、工具返回结果整理成上下文送入 LLM。

一句话概括:Host = 用户侧的 AI 应用,拥有最终决策权。

MCP Client(协议客户端)

Client 不是独立软件,它是 Host 内部的一个协议实例,一对一绑定一个 MCP Server。这个 1:1 隔离是强制设计。

Client 职责:建立底层传输通道;发起 initialize 握手完成能力协商;转发双向消息;维护订阅关系和会话状态;隔离会话——A Server 的消息、凭据、状态完全不会混入 B Server。

❌ 错误理解:一个 Client 可以同时连接多个 Server。
✅ 正确理解:一个 Client ↔ 一个 Server;多服务接入需要多个 Client。这个隔离设计是为了防止权限逃逸、消息串扰。

MCP Server(能力服务端)

Server 是独立的能力提供者,可以是本地子进程,也可以是云端远程服务。它向外暴露 Tools、Resources、Prompts,负责声明自身能力、执行业务逻辑、推送变更通知、发起反向采样请求,并严格遵守 Host 下发的权限边界(roots)。

典型 Server:filesystem(文件读写)、postgres(数据库查询)、git(提交/diff)、jira(工单管理)。

角色关系图

1
2
3
4
[ Host(AI应用) ]
├─ Client 1 ↔ Server A(文件)
├─ Client 2 ↔ Server B(数据库)
└─ Client 3 ↔ Server C(工单)

三、底层基础:JSON-RPC 2.0 消息模型

MCP 所有通信报文都基于 JSON-RPC 2.0,完全沿用其三类消息分类:

  1. Request(请求):需要对方返回响应;
  2. Response(响应):对应一个请求,成功或失败;
  3. Notification(通知):单向消息,不需要应答,没有 id。

Request 报文

1
2
3
4
5
6
{
"jsonrpc": "2.0",
"id": "req-001",
"method": "tools/list",
"params": {}
}
  • id:唯一标识,后续 Response 必须带上完全一样的 id 用来配对;
  • method:MCP 预定义标准方法,如 initialize、tools/list、tools/call。

Response 报文

成功用 result,失败用 error:

1
2
3
4
5
6
7
8
{
"jsonrpc": "2.0",
"id": "req-001",
"error": {
"code": -32601,
"message": "Method not found"
}
}

Notification 报文

通知没有 id,接收方不需要回复。典型例子:握手完成的 initialized 通知、资源变更通知、日志推送。

MCP 在 JSON-RPC 之上追加的约束

  1. 所有消息是独立 JSON 对象;stdio 传输时每条消息单独一行(JSONL);
  2. method 有命名空间:工具 tools/*,资源 resources/*,提示 prompts/*;
  3. 不允许批量消息(JSON-RPC 原生支持 batch,但 MCP 规范不鼓励);
  4. 同一通道消息按发送顺序处理,但响应返回顺序不一定严格匹配。

新手坑:凡是需要等待返回结果的,一定带 id;事件推送、状态告知,不带 id。

四、会话完整生命周期(核心流程)

MCP 是有状态会话,不是无状态的单次 HTTP 请求。流程是协议强制顺序,不能颠倒:

  1. 建立传输通道(stdio spawn 子进程 / HTTP 连接);
  2. Client → Server:initialize 请求(交换协议版本、能力、客户端信息);
  3. Server 返回 initialize 响应,公布自身能力;
  4. Client 发送 initialized 通知,握手完成;
  5. 正常交互阶段(工具调用、资源读取、订阅、采样);
  6. 会话关闭(优雅 shutdown 或异常断开)。

握手报文示例

Client 请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"jsonrpc": "2.0",
"id": "init-001",
"method": "initialize",
"params": {
"protocolVersion": "0.1.0",
"capabilities": {
"sampling": {},
"roots": {}
},
"clientInfo": {
"name": "my-agent-host",
"version": "1.0.0"
}
}
}

Server 响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"jsonrpc": "2.0",
"id": "init-001",
"result": {
"protocolVersion": "0.1.0",
"capabilities": {
"tools": {},
"resources": { "subscribe": true },
"prompts": {}
},
"serverInfo": {
"name": "demo-file-server",
"version": "0.1.0"
}
}
}

关键点

  • 协商之后,交集才是可用能力:Client 支持 sampling、Server 不支持 → 整个会话不能使用 sampling;
  • initialized 通知不能忘:Server 收到之前不能主动推送通知、不能处理业务调用。很多 Demo 握手后忘记发送 initialized,导致 Server 不响应后续调用;
  • 会话断开,协商结果全部作废:重新通信必须完整重新握手,不能复用上次协商结果;
  • 权限边界一直生效:例如 roots 约束 Server 任何资源读取不能越界。

五、Capability(能力集)的设计思想

协议把能力分成两大类:

  1. 强制基础能力:JSON-RPC 消息、initialize 握手;
  2. 可选扩展能力:tools、resources、prompts、sampling、roots、订阅、日志等,靠握手协商开启。

为什么这样设计?

  • 轻量化:极简 Server 可以只暴露资源,完全不实现工具;
  • 向前向后兼容:协议新增能力时,老客户端不会崩掉;对方没声明支持,直接不调用;
  • 职责分离:纯只读知识库 Server 不需要实现 tools。

常见 capability 含义:

Capability 含义
tools 支持工具调用
resources 支持资源读取,subscribe: true 表示支持变更订阅
prompts 支持提示模板
sampling Server 可以请求 Host 的模型
roots Host 可以下发访问根路径限制
logging 接收日志推送通知

重要:capabilities 只是”声明我具备这个能力”,不是权限开关。就算 Server 声明支持 tools,Host 依然可以在应用层策略上拒绝调用其中某些工具。协商只是协议层面的互通可能性,最终放行权在 Host。

六、第一篇小结与高频误区

核心要点

  1. MCP 是有线通信协议,在 Function Calling 之上标准化 Agent 和外部系统对接;
  2. 三层角色:Host(决策者)、Client(一对一协议通道)、Server(能力提供者);
  3. 底层报文基于 JSON-RPC 2.0,分为 Request / Response / Notification;
  4. 会话固定顺序:建通道 → initialize 交换能力 → initialized 通知 → 业务交互 → 关闭;
  5. 能力协商是版本兼容与轻量化扩展的核心,只有双方都声明支持的能力才能使用;
  6. 隔离约束:一个 Client 只绑定一个 Server。

高频误区(面试常考)

误区 正解
MCP = Function Calling Function Calling 只是模型输出结构化参数;MCP 是完整的服务发现、上下文、权限、双向通信标准
一个 Client 连多个 Server 强制一对一
建立连接后直接调用工具 必须走完 initialize + initialized 握手
stdout 可以随便打印日志 stdio 模式下 stdout 只能输出 JSON-RPC,日志走 stderr
capability 协商 = 授权 协商只代表协议上可互通,用户授权、工具审批是 Host 上层安全策略

下一篇:《深入浅出 MCP 系列教程(二):三大核心原语实战》,将详解 Resources / Tools / Prompts 的完整规范、调用链路与踩坑点。