Model Context Protocol (MCP) 构建在一个灵活且可扩展的架构上,使 LLM 应用和集成之间的无缝通信成为可能。本文档涵盖了核心架构组件和概念。

概述

MCP 遵循一个 client-server 架构,其中:

  • Hosts 是 LLM 应用(如 Claude Desktop 或 IDEs),它们发起连接
  • Clients 在 host 应用中与 servers 保持 1:1 的连接
  • Servers 为 clients 提供上下文、tools 和 prompts

核心组件

协议层

协议层处理消息框架、请求/响应链接和高级通信模式。

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>
}

关键的 classes 包括:

  • Protocol
  • Client
  • Server

传输层

传输层处理 clients 和 servers 之间的实际通信。MCP 支持多种传输机制:

  1. Stdio

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

    • 使用服务器发送事件进行服务器到客户端的消息传递
    • 使用 HTTP POST 进行客户端到服务器的消息传递

所有传输都使用 JSON-RPC 2.0 进行消息交换。有关 Model Context Protocol 消息格式的详细信息,请参阅规范

消息类型

MCP 具有以下主要类型的消息:

  1. Requests 期望来自另一端的响应:

    interface Request {
      method: string;
      params?: { ... };
    }
    
  2. Notifications 是不期望响应的单向消息:

    interface Notification {
      method: string;
      params?: { ... };
    }
    
  3. Results 是对请求的成功响应:

    interface Result {
      [key: string]: unknown;
    }
    
  4. Errors 表示请求失败:

    interface Error {
      code: number;
      message: string;
      data?: unknown;
    }
    

连接生命周期

1. 初始化

  1. Client 发送包含协议版本和能力的 initialize 请求
  2. Server 以其协议版本和能力响应
  3. Client 发送 initialized 通知作为确认
  4. 开始正常消息交换

2. 消息交换

初始化后,支持以下模式:

  • 请求-响应:客户端或服务器发送请求,另一方响应
  • 通知:任一方发送单向消息

3. 终止

任一方可以终止连接:

  • 通过 close() 进行干净关闭
  • 传输断开
  • 错误条件

错误处理

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

enum ErrorCode {
  // 标准 JSON-RPC 错误代码
  ParseError = -32700,
  InvalidRequest = -32600,
  MethodNotFound = -32601,
  InvalidParams = -32602,
  InternalError = -32603
}

SDK 和应用可以定义其自己的错误代码,范围在 -32000 以上。

错误通过以下方式传播:

  • 对请求的错误响应
  • 传输上的错误事件
  • 协议级别的错误处理程序

实现示例

以下是实现 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);

最佳实践

传输选择

  1. 本地通信

    • 对于本地进程使用 stdio 传输
    • 对于同一机器的通信效率高
    • 简单的进程管理
  2. 远程通信

    • 在需要 HTTP 兼容性的场景中使用 SSE
    • 考虑安全隐患,包括身份验证和授权

消息处理

  1. 请求处理

    • 彻底验证输入
    • 使用类型安全的模式
    • 优雅地处理错误
    • 实现超时
  2. 进度报告

    • 对于长时间操作使用进度令牌
    • 增量报告进度
    • 在已知时包括总进度
  3. 错误管理

    • 使用适当的错误代码
    • 包含有帮助的错误信息
    • 在错误时清理资源

安全考虑

  1. 传输安全

    • 对于远程连接使用 TLS
    • 验证连接来源
    • 在需要时实现身份验证
  2. 消息验证

    • 验证所有传入消息
    • 清理输入
    • 检查消息大小限制
    • 验证 JSON-RPC 格式
  3. 资源保护

    • 实现访问控制
    • 验证资源路径
    • 监控资源使用
    • 限制请求速率
  4. 错误处理

    • 不泄露敏感信息
    • 记录安全相关错误
    • 实现适当的清理
    • 处理 DoS 场景

调试和监控

  1. 日志记录

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

    • 实现健康检查
    • 监控连接状态
    • 跟踪资源使用
    • 性能分析
  3. 测试

    • 测试不同的传输
    • 验证错误处理
    • 检查边缘案例
    • 负载测试服务器