了解 MCP 如何连接客户端、服务器和 LLM
模型上下文协议(Model Context Protocol,MCP) 基于灵活且可扩展的架构,支持 LLM 应用程序与集成之间的无缝通信。本文件介绍 MCP 的核心架构组件和概念。
概述
MCP 遵循 客户端-服务器 架构,其中:
- 主机(Hosts):LLM 应用程序(如 Claude Desktop 或 IDE)用于发起连接。
- 客户端(Clients):在主机应用程序内,与服务器保持 1:1 连接。
- 服务器(Servers):为客户端提供上下文、工具和提示信息。
核心组件
协议层(Protocol Layer)
协议层负责处理 消息框架、请求/响应关联 以及 高级通信模式,支持以下语言实现:
- TypeScript
- Python
示例代码:
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>
}
关键类包括:
Protocol
Client
Server
传输层(Transport Layer)
传输层负责客户端和服务器之间的实际通信。MCP 支持多种传输机制:
标准输入/输出(Stdio)传输
- 通过标准输入/输出进行通信
- 适用于本地进程
HTTP + SSE 传输
- 采用 服务器推送事件(Server-Sent Events,SSE) 进行服务器到客户端的消息传递
- 使用 HTTP POST 进行客户端到服务器的消息传递
所有传输方式都使用 JSON-RPC 2.0 进行消息交换,详细的协议消息格式可参考 MCP 规范。
消息类型
MCP 主要有以下四种消息类型:
请求(Requests):需要对方返回响应。
interface Request {
method: string;
params?: { ... };
}
结果(Results):对请求的成功响应。 ```typescript interface Result {
[key: string]: unknown;
}
3. **错误(Errors)**:表示请求失败。
```typescript
interface Error {
code: number;
message: string;
data?: unknown;
}
- 通知(Notifications):单向消息,不需要响应。
interface Notification {
method: string;
params?: { ... };
}
连接生命周期
1. 初始化(Initialization)
- 客户端发送
initialize
请求,包含协议版本和功能信息。 - 服务器返回响应,确认协议版本和功能信息。
- 客户端发送
initialized
通知以确认连接。 - 连接建立后,正常的消息交换开始。
2. 消息交换(Message Exchange)
初始化完成后,MCP 支持两种通信模式:
- 请求-响应模式(Request-Response):客户端或服务器发送请求,对方返回响应。
- 通知模式(Notifications):单向消息,不需要响应。
3. 终止(Termination)
连接可由任意一方终止,方式包括:
- 调用
close()
进行正常关闭 - 传输连接断开
- 发生错误
错误处理(Error Handling)
MCP 定义了以下标准错误代码:
enum ErrorCode {
// JSON-RPC 标准错误代码
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603
}
此外,SDK 和应用程序可以定义自定义错误代码(范围在 -32000
及以上)。
错误会通过以下方式传播:
- 作为请求的错误响应返回
- 在传输层触发错误事件
- 在协议层执行错误处理程序
实现示例(Implementation Example)
以下是一个简单的 MCP 服务器示例:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {
resources: {}
}
});
// 处理请求
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "example://resource",
name: "Example Resource"
}
]
};
});
// 连接传输层
const transport = new StdioServerTransport();
await server.connect(transport);
最佳实践(Best Practices)
传输选择(Transport Selection)
本地通信
- 使用 stdio 传输,适用于本机进程间通信
- 高效、简单,便于进程管理
远程通信
- 使用 SSE 传输 以适配 HTTP 兼容场景
- 需考虑安全性,包括身份验证和授权
消息处理(Message Handling)
请求处理
- 严格验证输入
- 使用类型安全的模式(schema)
- 处理错误
- 实现超时机制
进度报告
- 使用进度标识符(progress token)跟踪长时间操作
- 逐步报告进度
- 提供总进度信息(如果已知)
错误管理
- 采用适当的错误代码
- 提供清晰的错误信息
- 发生错误时清理资源
安全性考虑(Security Considerations)
传输安全
- 远程连接使用 TLS
- 验证连接来源
- 必要时实施身份验证
消息验证
- 严格校验所有传入消息
- 过滤并清理输入数据
- 设置消息大小限制
- 确保符合 JSON-RPC 规范
资源保护
- 实施访问控制
- 验证资源路径
- 监控资源使用情况
- 对请求进行速率限制
错误处理
- 避免泄露敏感信息
- 记录安全相关的错误
- 适当清理错误状态
- 处理拒绝服务(DoS)攻击
调试与监控(Debugging & Monitoring)
日志记录
- 记录协议事件
- 跟踪消息流
- 监控性能
- 记录错误
诊断
- 实现健康检查(Health Checks)
- 监控连接状态
- 跟踪资源使用情况
- 进行性能分析
测试
- 测试不同传输方式
- 验证错误处理逻辑
- 检查边界情况
- 进行服务器负载测试