了解 MCP 如何连接客户端、服务器和 LLM

模型上下文协议(Model Context Protocol,MCP) 基于灵活且可扩展的架构,支持 LLM 应用程序与集成之间的无缝通信。本文件介绍 MCP 的核心架构组件和概念。

概述

MCP 遵循 客户端-服务器 架构,其中:

  • 主机(Hosts):LLM 应用程序(如 Claude Desktop 或 IDE)用于发起连接。
  • 客户端(Clients):在主机应用程序内,与服务器保持 1:1 连接。
  • 服务器(Servers):为客户端提供上下文、工具和提示信息。

核心组件

协议层(Protocol Layer)

协议层负责处理 消息框架请求/响应关联 以及 高级通信模式,支持以下语言实现:

  • TypeScript
  • Python

示例代码:

  1. class Protocol<Request, Notification, Result> {
  2. // 处理传入的请求
  3. setRequestHandler<T>(schema: T, handler: (request: T, extra: RequestHandlerExtra) => Promise<Result>): void
  4. // 处理传入的通知
  5. setNotificationHandler<T>(schema: T, handler: (notification: T) => Promise<void>): void
  6. // 发送请求并等待响应
  7. request<T>(request: Request, schema: T, options?: RequestOptions): Promise<T>
  8. // 发送单向通知
  9. notification(notification: Notification): Promise<void>
  10. }

关键类包括

  • Protocol
  • Client
  • Server

传输层(Transport Layer)

传输层负责客户端和服务器之间的实际通信。MCP 支持多种传输机制:

  1. 标准输入/输出(Stdio)传输

    • 通过标准输入/输出进行通信
    • 适用于本地进程
  2. HTTP + SSE 传输

    • 采用 服务器推送事件(Server-Sent Events,SSE) 进行服务器到客户端的消息传递
    • 使用 HTTP POST 进行客户端到服务器的消息传递

所有传输方式都使用 JSON-RPC 2.0 进行消息交换,详细的协议消息格式可参考 MCP 规范


消息类型

MCP 主要有以下四种消息类型:

  1. 请求(Requests):需要对方返回响应。

    1. interface Request {
    2. method: string;
    3. params?: { ... };
    4. }
  2. 结果(Results):对请求的成功响应。 ```typescript interface Result {

  1. [key: string]: unknown;

}

  1. 3. **错误(Errors)**:表示请求失败。
  2. ```typescript
  3. interface Error {
  4. code: number;
  5. message: string;
  6. data?: unknown;
  7. }
  1. 通知(Notifications):单向消息,不需要响应。
    1. interface Notification {
    2. method: string;
    3. params?: { ... };
    4. }

连接生命周期

1. 初始化(Initialization)

  1. 客户端发送 initialize 请求,包含协议版本和功能信息。
  2. 服务器返回响应,确认协议版本和功能信息。
  3. 客户端发送 initialized 通知以确认连接。
  4. 连接建立后,正常的消息交换开始。

2. 消息交换(Message Exchange)

初始化完成后,MCP 支持两种通信模式:

  • 请求-响应模式(Request-Response):客户端或服务器发送请求,对方返回响应。
  • 通知模式(Notifications):单向消息,不需要响应。

3. 终止(Termination)

连接可由任意一方终止,方式包括:

  • 调用 close() 进行正常关闭
  • 传输连接断开
  • 发生错误

错误处理(Error Handling)

MCP 定义了以下标准错误代码:

  1. enum ErrorCode {
  2. // JSON-RPC 标准错误代码
  3. ParseError = -32700,
  4. InvalidRequest = -32600,
  5. MethodNotFound = -32601,
  6. InvalidParams = -32602,
  7. InternalError = -32603
  8. }

此外,SDK 和应用程序可以定义自定义错误代码(范围在 -32000 及以上)。

错误会通过以下方式传播:

  • 作为请求的错误响应返回
  • 在传输层触发错误事件
  • 在协议层执行错误处理程序

实现示例(Implementation Example)

以下是一个简单的 MCP 服务器示例:

  1. import { Server } from "@modelcontextprotocol/sdk/server/index.js";
  2. import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  3. const server = new Server({
  4. name: "example-server",
  5. version: "1.0.0"
  6. }, {
  7. capabilities: {
  8. resources: {}
  9. }
  10. });
  11. // 处理请求
  12. server.setRequestHandler(ListResourcesRequestSchema, async () => {
  13. return {
  14. resources: [
  15. {
  16. uri: "example://resource",
  17. name: "Example Resource"
  18. }
  19. ]
  20. };
  21. });
  22. // 连接传输层
  23. const transport = new StdioServerTransport();
  24. await server.connect(transport);

最佳实践(Best Practices)

传输选择(Transport Selection)

  1. 本地通信

    • 使用 stdio 传输,适用于本机进程间通信
    • 高效、简单,便于进程管理
  2. 远程通信

    • 使用 SSE 传输 以适配 HTTP 兼容场景
    • 需考虑安全性,包括身份验证和授权

消息处理(Message Handling)

  1. 请求处理

    • 严格验证输入
    • 使用类型安全的模式(schema)
    • 处理错误
    • 实现超时机制
  2. 进度报告

    • 使用进度标识符(progress token)跟踪长时间操作
    • 逐步报告进度
    • 提供总进度信息(如果已知)
  3. 错误管理

    • 采用适当的错误代码
    • 提供清晰的错误信息
    • 发生错误时清理资源

安全性考虑(Security Considerations)

  1. 传输安全

    • 远程连接使用 TLS
    • 验证连接来源
    • 必要时实施身份验证
  2. 消息验证

    • 严格校验所有传入消息
    • 过滤并清理输入数据
    • 设置消息大小限制
    • 确保符合 JSON-RPC 规范
  3. 资源保护

    • 实施访问控制
    • 验证资源路径
    • 监控资源使用情况
    • 对请求进行速率限制
  4. 错误处理

    • 避免泄露敏感信息
    • 记录安全相关的错误
    • 适当清理错误状态
    • 处理拒绝服务(DoS)攻击

调试与监控(Debugging & Monitoring)

  1. 日志记录

    • 记录协议事件
    • 跟踪消息流
    • 监控性能
    • 记录错误
  2. 诊断

    • 实现健康检查(Health Checks)
    • 监控连接状态
    • 跟踪资源使用情况
    • 进行性能分析
  3. 测试

    • 测试不同传输方式
    • 验证错误处理逻辑
    • 检查边界情况
    • 进行服务器负载测试