核心架构
了解 MCP 如何连接客户端、服务器和 LLM
模型上下文协议 (MCP) 建立在灵活、可扩展的架构之上,可实现 LLM 应用程序和集成之间的无缝通信。本文档介绍了核心架构组件和概念。
一、概述
MCP 遵循客户端-服务器架构,其中:
- 主机是启动连接LLM的代理应用程序(如 Claude Desktop 、代码编辑器、你准备开发的AI客户端)
- 客户端在主机应用程序内与服务器保持 1:1 连接 (附注:你需要导入具体开发语言的SDK)
- 服务器向客户端提供上下文、工具和提示 (定义业务规范)
二、核心组件
css
[ 主机 ]
│
[ 传输层 ]
│
[MCP 客户端] <—(协议和传输)—> [MCP 服务器]<——> [业务服务层]
1、协议层
涉及的关键类:
Protocol
协议层负责处理消息帧、请求/响应链接和高级通信模式。Client
Server
《模型上下文协议中文网》附注:
这是典型的网络通信模型中的三层结构,常出现在自定义协议或框架设计中。每一层职责分明,三者关系可以简单理解为:
cssClient <--> Protocol <--> Server
TypeScript范例
需要实现协议
typescript
class Protocol<Request, Notification, Result> {
// 处理请求
setRequestHandler<T>(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise<Result>): void
// 处理通知
setNotificationHandler<T>(schema: T, handler: (notification: T) => Promise<void>): void
// 发送请求,等待响应
request<T>(request: Request, schema: T, options?: RequestOptions): Promise<T>
// 发送单向通知
notification(notification: Notification): Promise<void>
}
《模型上下文协议中文网》附注:
官方文档没有注明是谁发送给谁、谁通知谁。
我的理解,MCP 是一种全双工协议,客户端和服务器之间是 对等通信,不同于传统 HTTP 那样只有客户端请求、服务器响应。
2、传输层
传输层负责处理客户端和服务器之间的实际通信。
MCP 支持多种传输机制:
- 标准通讯
- 使用标准输入/输出进行通信
- 本地流程的理想选择
- 使用 SSE (Server-Sent Events)传输的 HTTP
- 对服务器到客户端消息使用服务器发送的事件
- 客户端到服务器消息的 HTTP POST
所有传输都使用 JSON-RPC 2.0 来交换消息。有关模型上下文协议消息格式的详细信息,请参阅规范。
3、消息类型
MCP 包含以下主要类型的消息:
请求需要来自另一端的响应:
typescriptinterface Request { method: string; params?: { ... }; }
结果是对请求的成功响应:
typescriptinterface Result { [key: string]: unknown; }
错误指示请求失败:
typescriptinterface Error { code: number; message: string; data?: unknown; }
通知是不需要响应的单向消息:
typescriptinterface Notification { method: string; params?: { ... }; }
三、连接生命周期
mermaid
sequenceDiagram
participant Client
participant Server
Client->>Server: 初始化请求
Server->>Client: 初始化响应
Client->>Server: 初始化通知
Note over Client,Server: 完成连接,正常使用
1. 初始化
服务器客户服务器客户连接随时可用初始化请求初始化响应已初始化通知
- 客户端发送包含协议版本和功能的请求
initialize
- Server 使用其协议版本和功能进行响应
- 客户端发送通知作为确认
initialized
- 正常消息交换开始
2. 消息交换
初始化后,支持以下模式:
- 请求-响应:客户端或服务器发送请求,另一个响应
- 通知:任一方发送单向消息
3. 终止
任何一方都可以终止连接:
- 干净关机方式
close()
- 传输断开
- 错误条件
四、错误处理
MCP 定义了以下标准错误代码:
typescript
enum ErrorCode {
// 标准 JSON-RPC 错误码
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603
}
SDK 和应用程序可以在 -32000 以上定义自己的错误代码。
《模型上下文协议中文网》附注:
-31999 ❌ 不行
-32001 ✅ 可以
错误通过以下方式传播:
- 对请求的错误响应
- 传输上的错误事件
- 协议级错误处理程序
五、实现示例
以下是实现 MCP 服务器的基本示例:
TypeScript 范例
typescript
// 导入MCP SDK中的Server和StdioServerTransport模块
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// 创建一个MCP服务器实例
const server = new Server(
{
// 配置服务器的名称和版本
name: "example-server", // 服务器的名称
version: "1.0.0" // 服务器的版本
},
{
capabilities: {
// 服务器的功能声明,此处为空,表示没有声明具体的功能
resources: {} // 目前没有资源的具体功能
}
}
);
// 设置处理请求的函数
// 该请求处理函数将会响应 ListResourcesRequestSchema 类型的请求
server.setRequestHandler(ListResourcesRequestSchema, async () => {
// 返回一个包含资源的响应
return {
resources: [
{
// 定义资源的URI和名称
uri: "example://resource", // 资源的URI,表示资源的唯一标识
name: "Example Resource" // 资源的名称
}
]
};
});
// 创建一个标准输入输出(Stdio)传输实例
const transport = new StdioServerTransport();
// 连接服务器与传输
// 使用异步方式连接服务器与传输,这样可以确保服务器可以接收请求和发送响应
await server.connect(transport);
其他
《模型上下文协议中文网》附注:下面部分新手可先不关注
1、最佳实践
传输选择
- 本地通信
- 将 stdio 传输用于本地进程
- 高效实现同机通信
- 简单的流程管理
- 远程通信
- 将 SSE 用于需要 HTTP 兼容性的场景
- 考虑安全隐患,包括身份验证和授权
消息处理
- 请求处理
- 全面验证输入
- 使用类型安全架构
- 优雅地处理错误
- 实施超时
- 进度报告
- 使用进度令牌进行长时间作
- 逐步报告进度
- 在已知时包括总进度
- 错误管理
- 使用适当的错误代码
- 包含有用的错误消息
- 清理错误资源
2、安全注意事项
- 运输安全
- 使用 TLS 进行远程连接
- 验证连接源
- 在需要时实施身份验证
- 消息验证
- 验证所有传入消息
- 清理输入
- 检查邮件大小限制
- 验证 JSON-RPC 格式
- 资源保护
- 实施访问控制
- 验证资源路径
- 监控资源使用情况
- 速率限制请求
- 错误处理
- 不要泄露敏感信息
- 记录与安全相关的错误
- 实施适当的清理
- 处理 DoS 场景
3、调试和监控
- 伐木
- 记录协议事件
- 跟踪消息流
- 监控性能
- 记录错误
- 诊断
- 实施运行状况检查
- 监视连接状态
- 跟踪资源使用情况
- 配置文件性能
- 测试
- 测试不同的传输
- 验证错误处理
- 检查边缘情况
- 负载测试服务器