MCP 协议深度解析(一):架构设计与概念模型

1 阅读35分钟

概述

系列定位:本文是“AI 应用核心框架与协议”系列的第 5 篇,也是 MCP 协议深度解析四篇系列的第 1 篇。在前四篇建立了 LangChain 生态认知、LangChain4j 源码内核、Spring Boot 集成和 LLM 通信协议之后,本文将聚焦 AI 工具标准化的核心协议——MCP。理解 MCP 的架构设计与概念模型,是后续实现跨框架工具复用、构建 Agent 工具市场的前提。

总结性引言:作为 Java 架构师,你对“标准化”带来的价值一定深有体会——如果没有 Servlet 规范,每个 Web 服务器都需要为每种应用框架写一个适配器;如果没有 JDBC 规范,每个数据库都需要为每种 ORM 框架提供专属驱动。现在,AI 工具领域正面临同样的“前标准化”混乱局面:OpenAI 说工具的 JSON 参数要放在 function.arguments 里,Anthropic 说应该放在 input 里;LangChain 用 Python 的 @tool 装饰器定义工具,LangChain4j 用 Java 的 @Tool 注解;一个为 Claude 写的天气查询工具,无法在 GPT-4o 的 Agent 中使用。这种碎片化严重阻碍了 AI 工具的复用和生态发展。MCP(Model Context Protocol)正是为了解决这个问题而生——它定义了一套标准的 Client-Server 协议,让任何 LLM 厂商、任何 Agent 框架、任何工具开发者都可以用同一种方式描述和调用工具。MCP Server 像是一个“微服务”——它通过标准接口(tools/listtools/call)暴露自己的能力,任何支持 MCP Client 的应用都可以发现并调用它。MCP Client 像是一个“RPC Stub”——它封装了底层的通信细节,让上层 Agent 框架只需关心“这个工具有什么用、怎么调用”,而不需要关心“这个工具是本地方法还是远程 MCP Server”。本文将从 MCP 的起源与问题背景出发,系统拆解其架构设计、消息格式、四大核心概念与安全模型,帮助你建立起对 MCP 的完整认知,为后续的通信流程、Java 实现和生态应用打下坚实基础。

核心要点

  • MCP 的使命:解决 Function Calling 的巴别塔——统一不同 LLM 厂商、Agent 框架、工具开发者之间的工具描述与调用协议。
  • Client-Server 架构:Host 发起连接,Client 管理连接,Server 提供 Resources/Tools/Prompts 三大能力(加高级的 Sampling)。
  • JSON-RPC 2.0 消息格式:Request/Response/Error/Notification 四种标准消息类型,简单、语言无关、易于实现。
  • 四大核心概念:Resources(数据源,URI 标识)、Tools(可执行函数,JSON Schema 参数)、Prompts(参数化提示词模板)、Sampling(Server 委托 Host 调用 LLM)。
  • 能力协商initialize 握手交换 capabilities,Client 和 Server 互相了解对方能做什么。
  • 类比 USB-C:MCP Server = USB-C 设备,MCP Client = USB-C 接口,LLM/Agent = 主机——设备可以即插即用,不需要为每种接口准备不同的转接头。

文章组织架构图

flowchart TD
    n1["1. MCP 的起源:碎片化与标准化需求"] --> n2["2. MCP 架构设计:Host/Client/Server/Transport"]
    n2 --> n3["3. 消息格式:JSON-RPC 2.0 四种消息"]
    n3 --> n4["4. 四大核心概念:Resources/Tools/Prompts/Sampling"]
    n4 --> n5["5. 能力协商、生命周期与安全模型"]
    n5 --> n6["6. MCP 与 Function Calling 关系"]
    n6 --> n7["7. 与前後系列的衔接"]
    n7 --> n8["8. 面试高频专题"]

    classDef nodeStyle fill:#f1f5f9,stroke:#334155,stroke-width:1.5px,color:#1e293b
    class n1,n2,n3,n4,n5,n6,n7,n8 nodeStyle

架构图说明

  • 总览说明:全文 8 个模块从 MCP 的起源与问题背景出发,逐步深入到架构设计、消息格式、核心概念、安全模型,最后以与 Function Calling 的关系、系列衔接和面试题收尾。
  • 逐模块说明:模块 1-2 解决“为什么”和“是什么”——MCP 要解决什么问题、它的整体架构如何设计;模块 3-4 是全文核心——消息格式和四大概念是理解 MCP 具体运作的基础;模块 5 是工程保障——能力协商和安全性是 MCP 生产可用性的保障;模块 6 揭示 MCP 与 Function Calling 的层次关系;模块 7-8 承上启下与面试巩固。
  • 关键结论MCP 是 AI 工具生态的“标准化层”——它不替代 Function Calling(那是 LLM 厂商的底层协议),而是在 Function Calling 之上定义了一套统一的工具描述和调用协议。它的设计哲学与微服务架构高度一致——最小能力单元(每个 MCP Server 专注单一领域)、可插拔 Transport(Stdio/SSE/WebSocket 按需选择)、能力协商(Client 和 Server 互相了解对方的能力边界)。掌握了 MCP,你就掌握了构建开放、可复用、跨框架 AI 工具生态的钥匙。后续系列将逐步展开 MCP 的通信流程、Java 实现与生态应用。

1. MCP 的起源:Function Calling 的碎片化与标准化需求

1.1 Function Calling 的巴别塔

当前 LLM 生态中,各厂商的 Function Calling(工具调用)格式呈现出严重的碎片化。核心问题在于:每个模型都定义了自己的工具描述 JSON 结构,且语义相近却互不兼容。例如:

  • OpenAI:工具定义放在 tools 数组,参数使用 function.parameters(JSON Schema),模型返回 tool_calls 数组,其中每个元素包含 idfunction.namefunction.arguments(JSON 字符串)。
  • Anthropic Claude:工具定义放在 tools 数组,参数使用 input_schema(同样 JSON Schema),但模型返回的是 content 块数组,类型为 tool_use,包含 idnameinput(已解析的 JSON 对象)。
  • Google Gemini:工具定义使用 functionDeclarations,参数为 parameters,返回 functionCall 对象,包含 nameargs(JSON 对象)。
  • Azure OpenAI:基本沿袭 OpenAI 格式,但额外支持 strict 参数控制 JSON 模式,认证方式也不同。

更严重的是,Agent 框架(LangChain、LangChain4j、Semantic Kernel)为了屏蔽这些差异,各自引入了自己的 Tool 抽象。例如,LangChain4j 使用 @Tool 注解和 ToolSpecification,LangChain 使用 @tool 装饰器,Semantic Kernel 使用 KernelFunction。于是,一个为 LangChain 编写的天气查询工具,无法直接用在 LangChain4j 上,更不用说在不同 LLM 厂商之间切换——你需要写适配代码,将工具定义转换为各厂商要求的 JSON 格式。

这种碎片化导致了 “M×N 问题”:M 个 Agent 框架 × N 个 LLM 厂商 = M×N 种适配组合。开发者被迫为每种组合编写和维护转换逻辑,严重阻碍了 AI 工具的复用和生态发展。

1.2 MCP 的价值主张:成为 AI 世界的“USB-C”

MCP 协议应运而生。它的核心思想是:定义一个统一的 Client-Server 协议,让 Server 端通过标准接口暴露 Resources、Tools、Prompts,Client 端(任何 LLM 或 Agent 框架)通过标准接口发现和调用这些能力。这就像 USB-C 接口——一个 USB-C 设备可以插入任何 USB-C 接口(无论是 MacBook、手机还是显示器),而无需关心底层协议细节。

在 AI 生态中,MCP Server 相当于“USB-C 设备”(提供具体工具),MCP Client 相当于“USB-C 接口”(统一接入层),LLM/Agent 相当于“主机”(消费工具能力)。只需要编写一次 MCP Server,它就可以被 Claude Desktop、VS Code 插件、你的 Spring Boot 应用(通过 LangChain4j)、或者任何实现了 MCP Client 的 Agent 框架直接使用。

1.3 对比现有标准:为什么不是 OpenAPI 或 gRPC?

你可能会有疑问:OpenAPI(REST 接口描述)和 gRPC 的 .proto 定义不也是用于接口标准化的吗?为什么 AI 工具需要 MCP?关键在于 “发现 + 动态调用” 能力:

  • OpenAPI 描述了 REST 接口,但 AI Agent 需要运行时动态发现有哪些工具可用、它们的参数 Schema 是什么,并根据用户意图动态构造调用。OpenAPI 不具备内置的发现机制(需要显式绑定端点)。
  • gRPC 提供了接口定义,但通常依赖强类型的代码生成,不适合 LLM 根据自然语言动态选择工具。
  • MCP 专为 AI 场景设计:tools/list 方法让 Client 动态获取工具列表和 JSON Schema,tools/call 方法让 LLM 生成的参数被直接转发给工具执行。这种“发现-调用”模式极其契合 Agent 工作流。

MCP 不是另一个 RPC 框架,它是建立在现有通信协议之上的“上下文协议”,专门解决 AI 上下文(工具、数据、提示)的标准化问题。


2. MCP 的架构设计:Host、Client、Server 与 Transport 层

2.1 三大角色详解

MCP 架构定义了三个清晰的角色:Host、Client、Server。我们用一个 Java 工程师熟悉的类比来理解:

  • Host(宿主):这是最终用户直接交互的应用,例如 Claude Desktop、一个基于 Spring Boot 的客服 Agent,或者 VS Code 插件。它是业务入口,负责发起 MCP 连接。类比微服务架构中的“主应用程序”。
  • Client(客户端):运行在 Host 进程内部,是一个协议栈。它维护与一个 MCP Server 的专用连接,负责发送请求(如 tools/listresources/read),接收响应和通知,并管理连接生命周期。一个 Host 可以拥有多个 MCP Client,每个连接到一个不同的 MCP Server。类比 RPC 框架的 Stub(如 gRPC Stub)——封装了通信细节,让上层只看到本地方法调用。
  • Server(服务端):提供具体的上下文能力。一个 MCP Server 是轻量级的、无状态的,专注于单一领域(如一个 Filesystem Server 只提供文件操作,一个 GitHub Server 只提供 Issues/PR 管理)。类比微服务——它通过标准接口暴露自己的一组能力。

它们的交互关系如下图所示:

flowchart LR
    User[用户] --> Host
    subgraph Host [Host 应用进程]
        App[业务逻辑] --> Client1[MCP Client A]
        App --> Client2[MCP Client B]
    end
    Client1 -->|Transport: Stdio| Server1[MCP Server A\n文件系统]
    Client2 -->|Transport: SSE| Server2[MCP Server B\n天气查询]
    Client2 -->|Transport: WebSocket| Server3[MCP Server C\n数据库查询]

图表主旨概括:该图展示了 MCP 架构中 Host、Client、Server 三大角色的物理部署关系,以及 Transport 层的多样性。一个 Host 可以内嵌多个 MCP Client,每个 Client 连接到不同的 MCP Server,使用的 Transport 协议可以不同。

逐层分解

  • 用户层:用户只与 Host 交互,无需关心底层 MCP 连接。
  • Host 层:包含业务逻辑,例如一个客服 Agent 的意图识别与对话管理。Host 内部分别实例化了两个 MCP Client,一个连接文件系统 Server,另一个同时连接天气和数据库 Server(多路复用)。
  • Client 层:MCP Client 封装了 JSON-RPC 消息的序列化、反序列化和 Transport 发送接收。
  • Transport 层:展示了三种典型协议。Client A 与本地文件系统 Server 通过 Stdio 通信;Client B 与远端天气 Server 通过 SSE 通信;Client B 还与数据库 Server 通过 WebSocket 通信(Client 可以管理多个 Transport 连接)。
  • Server 层:每个 Server 独立部署,专注单一领域。

设计原理映射:这种架构完美体现了关注点分离:Host 负责业务编排,Client 负责协议转换,Server 负责能力提供。Transport 的可插拔设计让同一个 Server 可以在开发阶段使用 Stdio 本地调试,在生产环境切换为 SSE 或 WebSocket 进行远程部署,而无需修改一行 Server 代码。

工程联系与关键结论Java 工程师可将其视为微服务架构中的 Service Mesh 数据平面:MCP Client 是 Sidecar 代理,负责服务发现、协议转换和路由;MCP Server 是具体的微服务实例。这种设计让 AI 工具天然具备了分布式、可扩展、多语言的特点。在实际开发中,你只需要为每种后端能力编写一个 MCP Server,然后通过配置的方式将它们“插入”到你的 Agent Host 中,即插即用。

2.2 Transport 层的可插拔设计

MCP 规范将 Transport 层抽象为**“可靠、有序的消息传输通道”**。无论是 Stdio、SSE 还是 WebSocket,只要实现了“发送消息”和“接收消息”的语义,上层协议(JSON-RPC)完全不感知。下表和图对比了三种 Transport 的特性:

flowchart TD
    classDef subA fill:#f0f4ff,stroke:#93a3d3,stroke-width:1.5px
    classDef subB fill:#f0fff4,stroke:#93c5a3,stroke-width:1.5px
    classDef subC fill:#fef9f0,stroke:#c4a77d,stroke-width:1.5px
    classDef nodeStyle fill:#ffffff,stroke:#cbd5e1,stroke-width:1.5px,color:#1e293b
    subgraph C["WebSocket"]
        direction TB
        App3["Host/Client"] <-->|"全双工"| Svr2["远程 MCP Server"]
        Note3["双向实时,运维稍复杂"]
    end

    subgraph B["SSE"]
        direction TB
        App2["Host/Client"] -->|"HTTP POST"| Svr1["远程 MCP Server"]
        Svr1 -->|"SSE 流"| App2
        Note2["单向推送,兼容性好"]
    end


    
    subgraph A["Stdio"]
        direction TB
        App1["Host"] -->|"stdin"| Proc["子进程 MCP Server"]
        Proc -->|"stdout"| App1
        Note1["低延迟,本地通信"]
    end


    class A subA
    class B subB
    class C subC
    class App1,Proc,Note1,App2,Svr1,Note2,App3,Svr2,Note3 nodeStyle

图表主旨概括:对比 MCP Transport 层的三种实现方式,展示其通信模式、延迟特性和适用场景。

逐层分解

  • Stdio:Host 通过子进程的 stdin/stdout 通信,没有网络开销,延迟极低,适合本地工具(如 Filesystem、Git 等),但仅限同一台机器。
  • SSE:Client 通过 HTTP POST 发送 JSON-RPC 请求,Server 通过 SSE(text/event-stream)推送响应和通知。基于 HTTP,防火墙友好,适合微服务间通信,但 Server 无法主动向 Client 发起请求(除非通过已有的 SSE 连接推送)。
  • WebSocket:全双工通道,双方可自由发送消息。适合需要双向实时交互的场景(如 Server 主动通知 Client 资源变化,或 Agent 需要持续接收工具执行进度)。延迟比 SSE 更低(无需反复建立连接),但需要维护长连接和心跳。

设计原理映射:Transport 层的抽象正是 MCP 设计优雅的地方。它遵循了依赖倒置原则:上层协议不依赖具体通信方式,而是依赖一个“消息通道”抽象。在 Java 中,你可以定义 Transport 接口,包含 send(message)onMessage(callback),然后分别为 Stdio、SSE、WebSocket 提供实现。这种设计让 MCP 能适应从命令行工具到云原生微服务的各种部署场景。

工程联系与关键结论在实际应用中,开发阶段推荐使用 Stdio——你可以像运行 JUnit 测试一样启动一个 MCP Server 进程进行调试。上生产环境时,为了支持多 Host 并发访问,应将 Server 部署为独立进程并暴露 SSE 端点,前面加一层 Nginx 反向代理和 TLS 终端。如果工具执行耗时较长且需要实时推送进度,则考虑 WebSocket。选择的关键是权衡部署复杂度和通信需求。


3. 消息格式:JSON-RPC 2.0 的四种消息类型

MCP 协议的消息层基于 JSON-RPC 2.0,这是一个轻量级的远程过程调用协议,使用 JSON 作为数据格式。它简洁、语言无关、易于实现,已被广泛应用于 Web3(以太坊)、编辑器 LSP 协议等领域。JSON-RPC 2.0 定义了四种消息类型:

3.1 Request(请求)

客户端发送的调用请求,必须包含 jsonrpcmethod,可选的 id(如果没有 id,则视为通知 Notification)。params 为结构化参数,可以是数组或对象。例如,查询工具列表的请求:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
  • jsonrpc:固定为 "2.0"
  • id:请求标识符,可以是字符串或数字,用于关联响应。
  • method:要调用的方法名,MCP 定义了大量以 resources/tools/prompts/ 开头的标准方法。
  • params:方法参数,对于 tools/list 通常为空对象(但可包含分页信息)。

3.2 Response(响应)

服务器对请求的成功响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "inputSchema": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "城市名称" }
          },
          "required": ["city"]
        }
      }
    ]
  }
}
  • id 必须与请求的 id 一致。
  • result 包含方法的返回值,其结构与具体方法相关。

3.3 Error(错误响应)

当请求失败时,服务器返回错误对象:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request",
    "data": "详细错误信息"
  }
}
  • error.code:整数错误码,MCP 使用 JSON-RPC 定义的标准错误码(如 -32600 无效请求、-32601 方法不存在)以及自定义范围。
  • error.message:简短描述。
  • error.data:可选的附加信息。

3.4 Notification(通知)

通知是一种没有 id 的请求,服务器不需要响应。MCP 用通知实现 Server 主动推送事件,例如资源变更:

{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "file:///path/to/changed/file.txt"
  }
}
  • 因为没有 id,服务器不发送响应。
  • 常用于 Server 到 Client 的事件流。

工程映射:JSON-RPC 2.0 的请求-响应模式与 HTTP 相似,但独立于传输协议。在 Java 实现中,你通常会有一个 Message 抽象类,子类 RequestMessageResponseMessageErrorMessageNotificationMessage。序列化与反序列化可以使用 Jackson 的 @JsonTypeInfo 根据 id 存在与否进行鉴别。


4. 四大核心概念:Resources、Tools、Prompts、Sampling

MCP 定义了四种基础能力原语,它们构成了 AI 应用可获取的“上下文”范畴。

4.1 Resources(资源)—— 只读数据源

Resources 代表服务器暴露的只读数据,通过 URI 标识。例如:

  • file:///path/to/document.pdf:本地文件
  • postgres://database/table/schema:数据库表结构
  • api://external/api/users:外部 API 数据

发现方法resources/list,返回 URI 列表及其 MIME 类型、描述。 读取方法resources/read,参数为 uri,返回内容(文本或 Base64 二进制)。 订阅通知resources/subscribe 后,当资源变更时,Server 会发送 notifications/resources/updated 通知。

Java 类比:Resources 就是 MCP 的“GET 接口”——像 REST 的 GET /resources/{id},但 URI 作为统一标识符,且内置了订阅机制,类似于 Spring 的 @EventListener 或响应式编程中的 Flux

4.2 Tools(工具)—— 可执行函数

Tools 代表 Server 端可被调用的执行动作,这正是 Function Calling 标准化的核心。每个 Tool 包含:

  • name:唯一标识。
  • description:自然语言描述,帮助 LLM 判断何时使用。
  • inputSchema:JSON Schema 格式的参数定义,与 Function Calling 的参数规范完全对齐。

发现方法tools/list 返回工具列表。 调用方法tools/call,传入 namearguments(JSON 对象),返回 content 数组(可包含文本、图片等)。

完整示例:一个天气查询和文件读取工具的定义(tools/list 响应片段):

{
  "tools": [
    {
      "name": "get_weather",
      "description": "获取指定城市当天的天气情况,包括温度、湿度、天气状况",
      "inputSchema": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "城市名称,例如 Beijing"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"],
            "description": "温度单位,默认为摄氏度"
          }
        },
        "required": ["city"]
      }
    },
    {
      "name": "read_file",
      "description": "读取指定路径的文件内容(文本文件)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file_path": {
            "type": "string",
            "description": "文件的绝对路径"
          },
          "encoding": {
            "type": "string",
            "description": "文件编码,默认 UTF-8"
          }
        },
        "required": ["file_path"]
      }
    }
  ]
}

Java 类比:Tools 就是 MCP 的“POST 接口”——像 POST /tools/{name},请求体为 JSON 参数,返回执行结果。与 Function Calling 的适配将在第 6 节详述。

4.3 Prompts(提示词)—— 参数化模板

Prompts 提供预定义的、可复用的提示词模板,支持参数化。通过中央化管理,让 Prompt Engineering 的成果能在不同 Agent 之间共享。

发现方法prompts/list 获取方法prompts/get,传入模板名称和参数,返回渲染后的完整 Prompt 文本。

例如,一个“代码审查”模板:

  • 模板名:code_review
  • 参数:language(编程语言)、style(审查风格,如 strict/relaxed)
  • 调用 prompts/get 后,Server 返回拼接好的 Prompt:“请以 style风格审查以下{style} 风格审查以下 {language} 代码:...”

Java 类比:这类似于 Thymeleaf 或 JSP 的视图模板,将可变部分抽象为参数。在工程上,你可以将 Prompt 模板存储在配置中心,由专门的 MCP Server 管理,实现 Prompt 的版本控制和 A/B 测试。

4.4 Sampling(采样/委托推理)—— Server 请求 LLM 能力

这是 MCP 的高级特性:Server 可以向 Client 请求 LLM 推理。例如,一个“代码审查 Server”在分析完代码后,可以通过 Sampling 请求 Host 的 LLM 生成审查报告摘要。

注意:Sampling 本质上是一个反向调用,因此安全性要求极高——防止恶意 Server 滥用 Host 的 LLM 配额。MCP 在 capabilities 协商中明确了 Sampling 支持,并且 Host 可以对请求进行授权控制(如弹出用户确认)。

Java 类比:这类似于回调函数或 Spring Cloud 的 @EnableFeignClients 反向调用。Server 定义了需要 LLM 完成的任务,Client(Host)负责调用 LLM 并将结果传回 Server。

四大核心概念关系图

flowchart TD
    subgraph MCP Server
        R[Resources<br>数据源<br>URI 标识] -->|resources/list<br>resources/read| Client
        T[Tools<br>可执行函数<br>JSON Schema] -->|tools/list<br>tools/call| Client
        P[Prompts<br>参数化模板] -->|prompts/list<br>prompts/get| Client
        S[Sampling<br>请求 LLM] -->|反向调用| Client
    end
    Client[MCP Client] --> Agent[Agent 框架]
    Agent --> LLM[LLM]

图表主旨概括:展示 MCP Server 向 Client 暴露的四种能力类型及其发现/调用方法,以及 Client 如何将能力传递给 Agent 框架和 LLM。

逐层分解

  • Resources 和 Tools 是最基础的两种能力,分别对应“读取”和“执行”。
  • Prompts 为对话模板提供了标准化封装。
  • Sampling 是一个反向箭头,表示 Server 可以请求 Client 的 LLM 能力,实现更复杂的 Agent 协作。
  • Client 作为中间层,汇聚这些能力并交给 Agent 框架,最终由 Agent 编排 LLM 使用。

设计原理映射:这四种原语覆盖了 AI 应用所需的上下文种类:数据(Resources)、动作(Tools)、知识(Prompts)和推理委托(Sampling)。设计上遵循了“最小化核心、最大化扩展”的原则——你可以在 Server 上自由组合这些能力。

工程联系与关键结论在 Spring Boot 中实现 MCP Server 时,你通常会用一个 @RestController 类似的方式暴露这些能力,但底层是通过 JSON-RPC 而不是 HTTP 语义。对于 Java 工程师,关键是理解:MCP Server 相当于一个提供了特定接口的微服务,接口签名由 MCP 规范定义。Agent 框架通过 MCP Client 与之交互,就像 Spring Cloud Feign 调用远程服务一样。


5. 能力协商、生命周期与安全模型

5.1 initialize 握手与能力交换

MCP 连接建立后,首先进行能力协商,确保双方了解彼此的支持范围。这一过程通过 initialize 请求和响应完成,时序如下:

sequenceDiagram
    participant Client as MCP Client
    participant Server as MCP Server

    Client->>Server: initialize (capabilities: {tools, resources}, clientInfo)
    Server-->>Client: initialize response (capabilities: {tools, prompts, sampling}, serverInfo)
    Client->>Server: initialized notification
    Note over Client,Server: 进入正常通信状态
    Client->>Server: tools/list
    Server-->>Client: tools/list response
    Client->>Server: tools/call
    Server-->>Client: tools/call response
    Client->>Server: shutdown request
    Server-->>Client: shutdown response

图表主旨概括:展示 MCP 从握手、能力交换、正常操作到关闭的完整生命周期。

逐层分解

  • initialize 请求:Client 发送自身的 capabilitiesclientInfo。例如 "capabilities": {"tools": {}, "resources": {"subscribe": true}} 表示 Client 支持工具调用、资源读取和资源订阅。
  • initialize 响应:Server 返回自己的 capabilitiesserverInfo。例如 "capabilities": {"tools": {"listChanged": true}, "prompts": {}} 表示 Server 提供工具列表变更通知和提示词模板。
  • initialized 通知:Client 确认握手完成。
  • 随后即可进行正常的方法调用。
  • shutdown:Client 请求优雅关闭,Server 停止接受新请求,处理完已接受的请求后断开连接。

设计原理映射:能力协商类似于 TCP 三次握手后的特性协商,或者 HTTP/2 的 SETTINGS 帧。它避免了调用不支持的方法导致的运行时错误,同时为协议的平滑升级提供可能。

工程联系与关键结论在 Java 客户端实现中,你可以将 capabilities 映射为一个 Capabilities 对象,并在发送 initialize 时根据当前配置动态生成。Server 端需要在注册时明确声明自己的能力集,并在运行中遵循该声明。这种模式类似于声明式接口(@EnabledCapability),增强了系统的健壮性。

5.2 安全模型基础

MCP 协议本身不定义认证和授权机制,但提供了清晰的集成点:

  • 传输安全:Stdio 依赖操作系统进程隔离;SSE/WebSocket 必须使用 TLS 加密(HTTPS/WSS)。
  • 身份认证:可以在 Transport 层添加自定义 HTTP Header(如 Authorization: Bearer <token>),或在 initialize 参数的 meta 字段传递认证信息。更规范的做法是结合 OAuth2 Proxy。
  • 权限校验:Server 端应实现细粒度的 RBAC。例如,数据库 Server 可以为不同 Client 提供不同权限的数据库账户,或限制某些 Tools 只能被特定 Client 调用。实现时可在 tools/call 处理逻辑中检查 Client 身份与操作的授权。

最佳实践:在生产环境中,通常会在 MCP Server 前放置 API 网关,统一负责 TLS 终结、认证和限流。MCP Client 与网关之间的通信与普通微服务无异。


6. MCP 与 Function Calling 的关系:标准化层

许多开发者初识 MCP 时会混淆它与 Function Calling 的界限。严格来说:

  • Function CallingLLM 厂商内部的机制:它定义了模型如何输出一个结构化的工具调用请求,以及如何将工具结果返回给模型。每种厂商有自己的格式。
  • MCP工具提供者与工具消费者之间的协议:它定义了工具如何被发现、描述和调用,与具体的 LLM 无关。

MCP 是 Function Calling 之上的标准化层。一个典型的集成流程如下:

sequenceDiagram
    participant LLM
    participant Agent as Agent 框架
    participant MCPClient as MCP Client
    participant MCPServer as MCP Server

    Agent->>MCPClient: tools/list
    MCPClient->>MCPServer: tools/list (JSON-RPC)
    MCPServer-->>MCPClient: 工具列表
    MCPClient-->>Agent: 转换为 ToolSpecification 列表

    Agent->>LLM: 发送 Prompt + tools (按厂商格式)
    LLM-->>Agent: Function Calling 请求 (tool_name, arguments)
    Agent->>MCPClient: tools/call (name, args)
    MCPClient->>MCPServer: tools/call (JSON-RPC)
    MCPServer-->>MCPClient: 执行结果
    MCPClient-->>Agent: 结果
    Agent->>LLM: 追加工具结果,继续推理

图表主旨概括:揭示 MCP 在 LLM Function Calling 和实际工具执行之间的角色——作为标准化的工具抽象层,将厂商无关的工具描述和调用与具体的模型调用解耦。

逐层分解

  • Agent 框架通过 MCP Client 获取工具列表,得到与厂商无关的工具定义(符合 MCP 的 JSON Schema)。
  • Agent 框架将 MCP 工具定义转换为 LLM 需要的格式(如 OpenAI 的 tools 参数),这个过程只需编写一次适配器。
  • 当 LLM 返回工具调用请求时,Agent 框架再通过 MCP Client 调用远程 Server,完全不依赖厂商。

设计原理映射:这是一个典型的适配器模式 + 外观模式。MCP 是外观,对 LLM 和 Agent 屏蔽了后端工具的复杂性;适配器负责将 MCP 的统一格式与各厂商格式互转。这种设计让新增 LLM 厂商只需实现一个适配器,即可复用所有 MCP Server。

工程联系与关键结论作为 Java 架构师,你可以将 MCP 视为工具领域的 JDBC。JDBC 定义了一组接口(ConnectionStatementResultSet),各数据库厂商提供驱动实现。MCP 定义了 tools/listtools/call 等接口,各工具开发者提供 MCP Server 实现。Agent 框架通过 MCP Client(类似 JDBC Driver)与 Server 通信。你完全可以用一个 ToolProvider 接口来抽象 MCP 连接,并在 Spring 容器中注入多个 ToolProvider Bean,由它们负责从不同的 MCP Server 拉取工具定义并执行调用。这样,你的 Agent 就天然具备了跨厂商、跨框架的工具复用能力。


7. 与前后系列的衔接

本文作为 MCP 系列的开篇,承接了前文的相关主题,并为后续篇章埋下伏笔:

  • 关联本系列第 4 篇(LLM 服务化协议):第 4 篇拆解的 REST、SSE、gRPC 协议,正是 MCP Transport 层的候选协议。MCP 本身不绑定任何特定 Transport,而是建立在它们之上。理解这些底层协议的性能与适用场景,有助于你为 MCP Server 选择合适的传输方式。
  • 关联本系列第 1 篇(LangChain 生态):第 1 篇中提到 MCP 是“工具标准化的未来”,本文是对这一论断的系统展开,详细拆解了其标准化原理与架构设计。
  • 关联系列一第 5 篇(Tools 深度):该篇建立了工具的抽象模型(name + description + parameters + execute),MCP 的 Tools 正是这一模型的标准化协议实现。
  • 关联后续(本系列第 6 篇 MCP 通信流程):本文建立了概念模型,下一篇将通过完整的 initialize → tools/list → tools/call → shutdown 时序图,逐一拆解每个消息的精确 JSON 结构和流转细节。
  • 关联后续(本系列第 7 篇 MCP Java 实现):本文是理论篇,第 7 篇将用 Spring Boot 3.4.x + LangChain4j 1.0.0-alpha1 实现一个完整的 MCP Server(暴露数据库查询 Tools 和文档 Resources)以及一个 MCP Client 集成示例。

建议阅读路径:读者应先理解本文的架构与概念,然后阅读下一篇的通信细节,最后动手实践第 7 篇的代码。这样才能形成从理论到实现的完整闭环。


8. 面试高频专题

(以下题目均假设读者为 Java 架构师,站在工程角度回答)

Q1. 什么是 MCP?它主要解决什么问题?为什么它被称为 AI 工具的“USB-C”?

一句话回答:MCP 是 Anthropic 发布的标准化 Client-Server 协议,旨在统一 AI 应用中工具(Tool)、数据源(Resource)和提示词(Prompt)的暴露与调用方式,解决 Function Calling 生态的碎片化问题。

详细解释:不同 LLM 厂商(OpenAI、Anthropic、Google)的 Function Calling 格式各不相同,Agent 框架也各自定义了 Tool 抽象。这导致一个工具需要为每种组合编写适配。MCP 定义了统一的消息格式(JSON-RPC 2.0)和能力发现机制,让 Server 以标准接口暴露能力,Client 通过标准协议调用,实现即插即用。

多角度追问

  • MCP 和 OpenAPI 有什么不同? OpenAPI 描述静态 REST 端点,缺少动态发现和函数调用语义;MCP 专为 LLM 设计,内置工具发现、参数 Schema、异步通知等。
  • MCP 是否只能用于 Claude? 不,任何 LLM 和 Agent 框架只要实现 MCP Client,就能接入所有 MCP Server。
  • MCP 是否依赖特定的传输协议? 不,MCP 支持 Stdio、SSE、WebSocket 等可插拔传输。

加分回答:MCP 的设计理念与 JDBC 类似——JDBC 统一了 Java 应用与数据库的交互,MCP 统一了 AI 应用与工具的交互。它们都通过抽象接口将具体的实现细节隔离,从而实现生态的互操作性。

Q2. MCP 的三大角色 Host/Client/Server 分别是什么?它们的分工是怎样的?

一句话回答:Host 是最终用户交互的应用,Client 是 Host 内负责与 Server 通信的协议栈,Server 是提供 Resources、Tools、Prompts 等能力的服务端。

详细解释:Host 发起连接并管理 Client 的生命周期,业务逻辑在此层;Client 封装 JSON-RPC 消息的发送/接收、序列化和传输管理;Server 专注于单一领域的能力提供,响应 Client 的请求。多个 Client 可连接多个 Server。

多角度追问

  • 为什么需要 Client 这个独立角色? 解耦——Host 无需关心底层通信细节,可以像调用本地方法一样使用远程工具。
  • Server 是否必须是无状态的? MCP 推荐 Server 无状态,但有状态的场景可以通过 Session 机制在 Server 端实现。
  • 能否在同一 Host 中连接多个同类型的 MCP Server? 可以,例如同时连接一个 GitHub Server 和一个 GitLab Server。

加分回答:在 Spring 应用中,Host 是你的 @SpringBootApplication,Client 可以被封装为一个 @Service 类,Server 则是一个独立部署的进程。通过依赖注入,你可以轻松替换 Client 的 Transport 实现(例如开发时使用 Stdio,生产时使用 SSE)。

Q3. MCP 的四大核心概念(Resources/Tools/Prompts/Sampling)各自是什么?它们有什么发现和调用方法?

一句话回答:Resources 是 URI 标识的只读数据源;Tools 是带 JSON Schema 的可执行函数;Prompts 是可参数化的提示词模板;Sampling 是 Server 反向请求 Host 的 LLM 推理能力。

详细解释:Resources 通过 resources/list 发现,resources/read 读取;Tools 通过 tools/list 发现,tools/call 调用;Prompts 通过 prompts/list 发现,prompts/get 获取;Sampling 通过 Server 向 Client 发送特定请求实现。

多角度追问

  • Resources 和 Tools 的本质区别是什么? Resources 是幂等的只读数据,Tools 可能产生副作用(如写文件、发请求)。
  • Prompts 为什么需要独立出来? 可复用、可版本化管理,避免硬编码。
  • Sampling 的安全性如何保证? Host 可以展示用户确认弹窗,或对 Server 的 Sampling 请求进行频次控制和额度限制。

加分回答:在 Java 建模时,可用 ResourceToolPrompt 三个领域类,加上 SamplingRequestSamplingResponse。每个领域类都有对应的 ListCall 服务方法。

Q4. MCP 的消息传输层有哪几种选择?它们的适用场景有什么不同?

一句话回答:主要可选 Stdio、SSE 和 WebSocket。Stdio 适合本地进程通信,延迟最低;SSE 适合基于 HTTP 的单向推送,防火墙友好;WebSocket 适合需要双向实时交互的场景。

详细解释:Stdio 通过子进程 stdin/stdout 通信,适合开发环境和本地工具;SSE 基于 HTTP,Client POST 请求,Server 通过长连接推送响应,适用于微服务部署;WebSocket 全双工,延迟低,适合需要 Server 主动推送进度或事件的场景。

多角度追问

  • 如何在 Spring Boot 中实现 Stdio Transport? 使用 ProcessBuilder 启动子进程,获取其输入输出流。
  • SSE 和 WebSocket 在运维上的主要区别是什么? SSE 可以与普通 HTTP 负载均衡无缝集成,WebSocket 需要特殊配置(如 Nginx 的 proxy_set_header Upgrade)。
  • 是否可以使用 gRPC 作为 Transport? MCP 规范未禁止,但官方未定义,理论上可以,只需要满足有序、可靠的消息传递。

加分回答:LangChain4j 的 MCP 模块目前支持 Stdio 和 SSE Transport。实际项目中,我推荐开发时使用 Stdio 快速迭代,CI/CD 部署时将 Server 打包为 Docker 镜像并暴露 SSE 端点,通过 API 网关对外提供能力。

Q5. MCP 的 initialize 握手是如何工作的?为什么要交换 capabilities

一句话回答initialize 握手是 Client 和 Server 在连接建立后的首次交互,双方交换自己的 capabilities,以声明各自支持的功能,避免后续调用不支持的方法。

详细解释:Client 发送 initialize 请求,携带自身能力(如 {"tools": {}, "resources": {"subscribe": true}})和客户端信息。Server 返回自己的能力和服务器信息。之后 Client 发送 initialized 通知,双方进入正常操作。能力协商类似于 HTTP/2 的 SETTINGS 帧,为协议扩展奠定基础。

多角度追问

  • 如果 Client 声明支持 Sampling,但 Server 不支持,会发生什么? Server 在响应中不声明 Sampling 能力,Client 就不会向该 Server 发送 Sampling 请求。
  • capabilities 是否可以动态更新? 当前规范在握手时固定,后续可能引入动态更新机制。
  • 如果握手失败怎么办? 连接关闭,Client 应提示错误。

加分回答:在 Java 实现中,可以用一个 Capabilities 对象封装所有能力布尔值或子对象,并在 initialize 处理时进行验证。Server 端可以在配置文件(如 YAML)中定义能力声明,避免硬编码。

Q6. MCP 是如何解决 Function Calling 碎片化问题的?请简述其与 Function Calling 的关系。

一句话回答:MCP 在 LLM 的 Function Calling 之上定义了统一的工具发现和调用协议,将厂商私有格式与 Agent 框架的 Tool 抽象解耦,通过标准化的 JSON Schema 描述工具参数,实现一次编写、多平台使用。

详细解释:传统 Function Calling 要求 Agent 框架为每个 LLM 厂商编写适配器。而 MCP 将工具定义和调用统一为 tools/listtools/call 接口,Agent 框架只需要实现一个 MCP Client 适配器,即可调用任何 MCP Server 的工具。LLM 的 Function Calling 格式转换在 Agent 框架内部完成,对于工具开发者透明。

多角度追问

  • MCP 是否完全不依赖 OpenAI 的格式? MCP 的工具定义使用 JSON Schema,可以映射到 OpenAI 的 function.parameters,但不必限于它。
  • LangChain4j 如何集成 MCP? langchain4j-mcp 模块提供 McpToolProvider,自动将 MCP Server 的工具注册为 LangChain4j 的 ToolSpecification,LLM 调用时通过 tools/call 执行。
  • 如果 LLM 不支持 Function Calling,MCP 还有用吗? 有用,Agent 可以通过硬编码或规则引擎决定调用哪个工具,仍可通过 MCP 统一工具调用。

加分回答:MCP 之于 Function Calling,如同 JPA 之于 Hibernate——JPA 是 ORM 标准,Hibernate 是实现;MCP 是工具协议标准,各 LLM 厂商的 Function Calling 是底层实现。Spring Data JPA 可以轻松切换底层实现,同理,Agent 框架通过 MCP 可以无缝切换 LLM 提供商。

Q7. MCP 中的 Sampling 是什么?它带来了什么可能性?

一句话回答:Sampling 允许 MCP Server 反向请求 Host(Client)调用 LLM 完成推理任务,实现 Agent 间的“委托推理”,从而构建更复杂的多 Agent 协作模式。

详细解释:例如,一个代码审查 Server 在执行静态分析后,希望由 LLM 生成自然语言摘要,它可以通过 Sampling 向 Client 发起请求,Client 调用 LLM 并将结果返回。这相当于 Server 拥有了“思考”的能力,而不需要自己集成 LLM。

多角度追问

  • Sampling 会增加安全风险吗? 会,Server 可能滥用 Host 的 LLM 额度或提示注入。因此 Host 应实现权限控制、额度管理和用户确认。
  • Sampling 是否支持流式? 协议允许,但实现较复杂。
  • 与普通 Function Calling 有何不同? Function Calling 是 Host 主动调用 Tool,Sampling 是 Server 主动调用 Host 的推理。

加分回答:这在 Java 中可以实现为回调接口 SamplingCallback。Spring Boot 应用可以通过 AOP 拦截 Sampling 请求,检查调用频率和来源,确保安全。

Q8. MCP 如何保障安全?在生产环境中应如何部署 MCP Server?

一句话回答:MCP 本身不定义安全机制,但推荐在 Transport 层使用 TLS 加密,并通过 API 网关进行身份认证和授权;Server 内部实现细粒度的权限控制和输入校验。

详细解释:Stdio 通信天然依赖操作系统安全边界;SSE/WebSocket 必须使用 TLS。身份认证通常通过在 HTTP Header 中传递 JWT 或 API Key 实现。Server 内部应为每个 Tool 和 Resource 定义访问控制列表(ACL)。此外,应对所有输入进行严格校验,防止注入。

多角度追问

  • 如何防止恶意 MCP Server 窃取 Host 数据? Host 应只连接可信任的 Server,并对 Resources 暴露的数据进行最小化原则。
  • MCP 协议本身是否支持加密? 不支持,加密依赖于 Transport 层(如 TLS)。
  • 如何实现多租户隔离? 为每个租户启动独立的 Server 实例,或通过命名空间隔离资源和工具。

加分回答:Kubernetes 部署时,可将每个 MCP Server 作为独立 Pod,通过 Service 暴露 SSE 端口。使用 Istio 做 mTLS 和 RBAC,配合 OPA 实现策略控制。这种模式与企业微服务安全架构完全一致。

Q9. 请对比 MCP 的 Resources、Tools 与 REST 的 GET、POST 的异同。

一句话回答:Resources 类似于 REST 的 GET(只读),Tools 类似于 REST 的 POST(执行动作),但 MCP 提供了内置的发现机制、订阅通知和统一的调用语义。

详细解释:Resources 通过 URI 标识数据,resources/read 相当于 GET;Tools 通过名称和参数执行操作,tools/call 相当于 POST。但 MCP 更强:resources/list 提供了动态资源目录;resources/subscribe 实现了变更推送,是 REST 通常不具备的。且 Tools 的参数使用 JSON Schema 强类型约束,比 REST 的松散参数更严格。

多角度追问

  • REST 也可以使用 OpenAPI 描述参数 Schema,MCP 的优势在哪? MCP 的发现和调用是运行时一体化的,无需额外文档;LLM 可以动态理解工具并构造调用,而 REST 通常需要人类阅读文档。
  • MCP 的 Tools 返回值是什么格式? 一个 content 数组,可以包含多种 MIME 类型的片段(文本、图片等),比 REST 的单一响应体更灵活。
  • 能否在 MCP Server 上同时提供 REST 接口? 可以,但会破坏统一性。

加分回答:你可以把 MCP 看作是一种专为 AI 优化的“动态 REST”,它的接口契约不是由人类手动编写,而是由 LLM 在运行时通过 tools/list 读取并遵循的。

Q10. (系统设计题)设计一个支持 MCP 的智能客服系统,要求能接入任意的 MCP Server 工具,例如订单查询 Server、物流查询 Server、退款处理 Server。请画出架构图与时序图,并说明如何集成 LangChain4j 和 Spring Boot。

架构图(Mermaid flowchart):

flowchart TD
    classDef nodeStyle fill:#f1f5f9,stroke:#334155,stroke-width:1.5px,color:#1e293b

    User["用户"] --> ChatUI["客服聊天界面"]
    ChatUI --> Gateway["API 网关<br/>认证/限流"]
    Gateway --> AgentService["客服 Agent 服务<br/>Spring Boot + LangChain4j"]
    AgentService --> MCPClient1["MCP Client<br/>订单查询"]
    AgentService --> MCPClient2["MCP Client<br/>物流查询"]
    AgentService --> MCPClient3["MCP Client<br/>退款处理"]
    MCPClient1 -->|"SSE"| OrderServer["订单查询 MCP Server"]
    MCPClient2 -->|"SSE"| LogisticsServer["物流查询 MCP Server"]
    MCPClient3 -->|"SSE"| RefundServer["退款处理 MCP Server"]
    AgentService --> LLM["LLM 服务<br/>(OpenAI/Azure)"]

    class User,ChatUI,Gateway,AgentService,MCPClient1,MCPClient2,MCPClient3,OrderServer,LogisticsServer,RefundServer,LLM nodeStyle

业务时序图(Mermaid sequenceDiagram):

sequenceDiagram
    participant User
    participant AgentService
    participant MCPClient as MCP Client (订单)
    participant MCPServer as 订单查询 Server
    participant LLM

    User->>AgentService: "帮我查订单 12345 的状态"
    AgentService->>LLM: 发送 Prompt + 所有 MCP 工具定义
    LLM-->>AgentService: function_call: get_order_status(orderId="12345")
    AgentService->>MCPClient: tools/call ("get_order_status", {"orderId":"12345"})
    MCPClient->>MCPServer: JSON-RPC tools/call
    MCPServer-->>MCPClient: {"status": "已发货"}
    MCPClient-->>AgentService: 工具结果
    AgentService->>LLM: 追加工具结果,要求生成回复
    LLM-->>AgentService: "您的订单 12345 已发货,预计明日到达。"
    AgentService-->>User: 展示回复

组件职责

  • API 网关:统一认证(JWT)、限流、TLS 终结。
  • Agent 服务:核心业务逻辑,使用 LangChain4j 进行对话管理,通过 McpToolProvider 将三个 MCP Client 注册为工具。
  • MCP Client:每个 Client 连接一个 MCP Server,负责 JSON-RPC 通信和工具定义拉取。启动时通过 initialize 握手,并周期性或按需拉取工具列表。
  • MCP Server:独立的微服务,分别处理订单、物流、退款业务,内部调用现有业务系统的 REST API 或数据库。

技术选型权衡

  • Transport 选择 SSE:因为 Server 需要独立部署,SSE 基于 HTTP,运维简单,且客服场景对实时性要求不是极致。如果未来需要 Server 推送异步事件(如物流状态自动更新),可以升级为 WebSocket。
  • 工具注册策略:Agent 服务启动时,调用所有 Client 的 tools/list,汇总为 List<ToolSpecification> 并缓存。当用户提问时,Agent 将这些规范传递给 LLM。LLM 返回工具调用后,Agent 通过 McpToolProvider 调用对应的 Client 的 tools/call
  • 安全:API 网关拦截所有请求,校验 JWT。MCP Client 与 Server 之间通过 mTLS 双向认证(在 Service Mesh 中)。Server 端检查 JWT 中的权限,确保用户只能查询自己的订单。

量化分析:假设三个 MCP Server 各有 3-5 个工具,总工具数 <20,LLM 一次推理时携带所有工具定义不会超出 token 限制。如果工具数增长到数百个,则需要引入工具检索(如 embedding 匹配)来动态筛选工具,这正是 MCP 的高级用法,但其协议不变。

加分回答:这种架构天然支持水平扩展:Agent 服务、MCP Server 都可以通过容器化部署,根据负载自动扩缩。MCP Client 与 Server 之间的连接采用长连接(SSE),避免了频繁握手开销。同时,由于 MCP 的标准化,将来如果需要新增一个“商品推荐 MCP Server”,只需在 Agent 服务的配置中添加一个新 Client,无需修改任何业务代码——这正是 MCP 作为“USB-C”接口的巨大价值。

(面试专题结束)


附录:MCP 核心概念速查表

概念定义发现方法调用方法Java 类比
Host用户交互的应用,管理 MCP Client 生命周期--Spring Boot 应用
Client协议栈,维护与 Server 的连接,消息编解码-发送 JSON-RPC 请求RPC Stub / Feign Client
Server能力提供者,暴露 Resources/Tools/Prompts-响应请求微服务实例
ResourcesURI 标识的只读数据源resources/listresources/readGET /resources/{uri}
Tools带 JSON Schema 的可执行函数tools/listtools/callPOST /tools/{name}
Prompts可参数化的提示词模板prompts/listprompts/get视图模板(Thymeleaf)
SamplingServer 向 Client 请求 LLM 推理-反向请求回调 / Feign 反向调用
JSON-RPC 2.0轻量级 RPC 消息格式-Request/ResponseHTTP/2 帧的 JSON 版
Transport底层通信通道 (Stdio/SSE/WebSocket)-可靠有序字节流Netty / Servlet

延伸阅读