概述
Model Context Protocol (MCP) 是基于灵活、可扩展架构构建的开放标准,它实现了 LLM 应用程序与集成服务之间的无缝通信。本章将详细介绍 MCP 的核心架构组件和设计理念。
1.1 客户端-服务器架构
MCP 遵循标准的客户端-服务器架构模式:
架构组件
- 主机 (Hosts) : LLM 应用程序(如 Claude Desktop 或 IDE),负责发起连接
- 客户端 (Clients) : 在主机应用程序内部,与服务器维持 1:1 连接关系
- 服务器 (Servers) : 向客户端提供上下文、工具和提示的服务提供者
架构图示
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ LLM 应用 │ │ MCP 客户端 │ │ MCP 服务器 │
│ (主机) │◄──►│ │◄──►│ │
│ │ │ - 协议管理 │ │ - 资源提供 │
│ - Claude │ │ - 连接维护 │ │ - 工具执行 │
│ - IDE │ │ - 消息路由 │ │ - 提示模板 │
│ - AI Agent │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
1.2 协议层 (Protocol Layer)
协议层负责处理消息帧、请求/响应链接和高级通信模式。
TypeScript SDK 核心类
import { Protocol, Client, Server } from '@modelcontextprotocol/sdk';
// 协议处理器
interface ProtocolOptions {
timeout?: number;
maxRetries?: number;
logging?: boolean;
}
class MCPProtocol {
private options: ProtocolOptions;
constructor(options: ProtocolOptions = {}) {
this.options = {
timeout: 30000,
maxRetries: 3,
logging: false,
...options
};
}
// 处理消息帧
handleFrame(frame: any): void {
// 消息验证和路由
}
// 链接请求和响应
linkRequestResponse(requestId: string, response: any): void {
// 请求响应匹配逻辑
}
}
// 客户端实现
class MCPClient extends Protocol {
private connectionId: string;
private capabilities: ClientCapabilities;
constructor(info: ClientInfo) {
super();
this.connectionId = crypto.randomUUID();
this.capabilities = {
experimental: {},
sampling: {}
};
}
// 连接到服务器
async connect(transport: Transport): Promise<void> {
await this.init(transport);
await this.initialize();
}
// 初始化协议
private async initialize(): Promise<InitializeResult> {
const request: InitializeRequest = {
protocolVersion: "2024-11-05",
capabilities: this.capabilities,
clientInfo: {
name: "my-mcp-client",
version: "1.0.0"
}
};
const result = await this.request(
{ method: "initialize", params: request },
InitializeResultSchema
);
// 发送初始化完成通知
await this.notification({
method: "notifications/initialized"
});
return result;
}
}
// 服务器实现
class MCPServer extends Protocol {
private tools = new Map<string, Tool>();
private resources = new Map<string, Resource>();
private prompts = new Map<string, Prompt>();
constructor(info: ServerInfo) {
super();
this.setRequestHandler(InitializeRequestSchema, this.handleInitialize.bind(this));
this.setRequestHandler(ListToolsRequestSchema, this.handleListTools.bind(this));
this.setRequestHandler(CallToolRequestSchema, this.handleCallTool.bind(this));
}
// 处理初始化请求
private async handleInitialize(
request: InitializeRequest
): Promise<InitializeResult> {
return {
protocolVersion: "2024-11-05",
capabilities: {
tools: { listChanged: true },
resources: { subscribe: true, listChanged: true },
prompts: { listChanged: true },
logging: {}
},
serverInfo: {
name: "my-mcp-server",
version: "1.0.0"
}
};
}
// 注册工具
registerTool(name: string, description: string, handler: ToolHandler): void {
const tool: Tool = {
name,
description,
inputSchema: {
type: "object",
properties: {},
required: []
}
};
this.tools.set(name, tool);
this.setRequestHandler(`tools/${name}`, handler);
}
}
1.3 传输层 (Transport Layer)
传输层处理客户端和服务器之间的实际通信,所有传输都使用 JSON-RPC 2.0 协议。
Stdio 传输
import { StdioTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { spawn } from 'child_process';
// Stdio 传输 - 适用于本地进程通信
class StdioTransportExample {
async createStdioConnection(): Promise<void> {
// 启动服务器进程
const serverProcess = spawn('node', ['./my-server.js'], {
stdio: ['pipe', 'pipe', 'inherit']
});
// 创建 Stdio 传输
const transport = new StdioTransport({
stdin: serverProcess.stdin!,
stdout: serverProcess.stdout!
});
// 创建客户端并连接
const client = new MCPClient({
name: "stdio-client",
version: "1.0.0"
});
await client.connect(transport);
// 使用连接
const tools = await client.listTools();
console.log('可用工具:', tools);
// 清理资源
process.on('exit', () => {
serverProcess.kill();
});
}
}
HTTP with SSE 传输
import { SSETransport } from '@modelcontextprotocol/sdk/client/sse.js';
// HTTP with SSE 传输 - 适用于远程通信
class SSETransportExample {
async createSSEConnection(): Promise<void> {
// 创建 SSE 传输
const transport = new SSETransport({
url: 'http://localhost:3000/mcp',
headers: {
'Authorization': 'Bearer your-token-here',
'Content-Type': 'application/json'
}
});
// 创建客户端并连接
const client = new MCPClient({
name: "sse-client",
version: "1.0.0"
});
await client.connect(transport);
// 处理连接事件
transport.onClose = () => {
console.log('SSE 连接已关闭');
};
transport.onError = (error) => {
console.error('SSE 连接错误:', error);
};
}
}
1.4 消息类型
MCP 定义了四种主要消息类型:
消息类型定义
// JSON-RPC 2.0 基础消息结构
interface JSONRPCMessage {
jsonrpc: "2.0";
id?: string | number | null;
}
// 1. 请求消息 - 期待响应
interface JSONRPCRequest extends JSONRPCMessage {
method: string;
params?: any;
id: string | number;
}
// 2. 结果消息 - 成功响应
interface JSONRPCResult extends JSONRPCMessage {
result: any;
id: string | number;
}
// 3. 错误消息 - 失败响应
interface JSONRPCError extends JSONRPCMessage {
error: {
code: number;
message: string;
data?: any;
};
id: string | number | null;
}
// 4. 通知消息 - 单向消息
interface JSONRPCNotification extends JSONRPCMessage {
method: string;
params?: any;
}
// 消息处理器示例
class MessageHandler {
// 处理请求
async handleRequest(request: JSONRPCRequest): Promise<JSONRPCResult | JSONRPCError> {
try {
const result = await this.processRequest(request.method, request.params);
return {
jsonrpc: "2.0",
result,
id: request.id
};
} catch (error) {
return {
jsonrpc: "2.0",
error: {
code: -32603,
message: "Internal error",
data: error instanceof Error ? error.message : String(error)
},
id: request.id
};
}
}
// 发送通知
sendNotification(method: string, params?: any): void {
const notification: JSONRPCNotification = {
jsonrpc: "2.0",
method,
params
};
this.transport.send(notification);
}
private async processRequest(method: string, params: any): Promise<any> {
switch (method) {
case "initialize":
return this.handleInitialize(params);
case "tools/list":
return this.handleListTools(params);
case "tools/call":
return this.handleCallTool(params);
default:
throw new Error(`未知方法: ${method}`);
}
}
}
1.5 连接生命周期
MCP 连接遵循标准的生命周期管理:
生命周期实现
class ConnectionManager {
private state: 'disconnected' | 'connecting' | 'initializing' | 'connected' | 'closing' = 'disconnected';
private client: MCPClient;
private transport: Transport;
constructor(client: MCPClient) {
this.client = client;
}
// 1. 初始化阶段
async initialize(transport: Transport): Promise<void> {
this.state = 'connecting';
this.transport = transport;
try {
// 建立传输连接
await this.transport.connect();
this.state = 'initializing';
// 发送初始化请求
const initRequest: InitializeRequest = {
protocolVersion: "2024-11-05",
capabilities: {
experimental: {},
sampling: {}
},
clientInfo: {
name: "typescript-client",
version: "1.0.0"
}
};
const initResult = await this.client.request(
{ method: "initialize", params: initRequest },
InitializeResultSchema
);
console.log('服务器信息:', initResult.serverInfo);
console.log('服务器能力:', initResult.capabilities);
// 发送初始化完成通知
await this.client.notification({
method: "notifications/initialized"
});
this.state = 'connected';
console.log('连接初始化完成');
} catch (error) {
this.state = 'disconnected';
throw new Error(`初始化失败: ${error}`);
}
}
// 2. 消息交换阶段
async messageExchange(): Promise<void> {
if (this.state !== 'connected') {
throw new Error('连接未初始化');
}
// 请求-响应模式示例
const tools = await this.client.listTools();
console.log('可用工具:', tools.tools);
// 调用工具
if (tools.tools.length > 0) {
const result = await this.client.callTool({
name: tools.tools[0].name,
arguments: {}
});
console.log('工具执行结果:', result);
}
// 通知模式示例
await this.client.notification({
method: "notifications/progress",
params: {
progress: 50,
total: 100
}
});
}
// 3. 终止阶段
async close(): Promise<void> {
if (this.state === 'disconnected' || this.state === 'closing') {
return;
}
this.state = 'closing';
try {
// 发送关闭通知
await this.client.notification({
method: "notifications/cancelled"
});
// 关闭传输
await this.transport.close();
this.state = 'disconnected';
console.log('连接已关闭');
} catch (error) {
console.error('关闭连接时出错:', error);
this.state = 'disconnected';
}
}
// 获取连接状态
getState(): string {
return this.state;
}
// 检查连接是否活跃
isConnected(): boolean {
return this.state === 'connected';
}
}
1.6 错误处理
MCP 定义了标准错误代码和处理机制:
错误处理实现
// MCP 标准错误代码
enum MCPErrorCode {
// JSON-RPC 标准錯誤
PARSE_ERROR = -32700,
INVALID_REQUEST = -32600,
METHOD_NOT_FOUND = -32601,
INVALID_PARAMS = -32602,
INTERNAL_ERROR = -32603,
// MCP 特定錯誤
RESOURCE_NOT_FOUND = -32001,
TOOL_NOT_FOUND = -32002,
INVALID_TOOL_INPUT = -32003,
UNAUTHORIZED = -32004,
RATE_LIMITED = -32005
}
class ErrorHandler {
// 创建标准错误响应
static createError(code: MCPErrorCode, message: string, data?: any): JSONRPCError {
return {
jsonrpc: "2.0",
error: {
code,
message,
data
},
id: null
};
}
// 错误处理中间件
static wrapHandler<T, R>(
handler: (params: T) => Promise<R>
): (params: T) => Promise<R | JSONRPCError> {
return async (params: T) => {
try {
return await handler(params);
} catch (error) {
if (error instanceof MCPError) {
throw error;
}
// 未知错误转换为内部错误
throw new MCPError(
MCPErrorCode.INTERNAL_ERROR,
"Internal server error",
error instanceof Error ? error.message : String(error)
);
}
};
}
// 传输层错误处理
static handleTransportError(error: any): void {
console.error('传输错误:', error);
// 根据错误类型进行不同处理
if (error.code === 'ECONNREFUSED') {
console.error('连接被拒绝,请检查服务器是否运行');
} else if (error.code === 'ETIMEDOUT') {
console.error('连接超时');
} else {
console.error('未知传输错误:', error.message);
}
}
}
// 自定义 MCP 错误类
class MCPError extends Error {
public code: MCPErrorCode;
public data?: any;
constructor(code: MCPErrorCode, message: string, data?: any) {
super(message);
this.name = 'MCPError';
this.code = code;
this.data = data;
}
toJSONRPCError(id: string | number | null = null): JSONRPCError {
return {
jsonrpc: "2.0",
error: {
code: this.code,
message: this.message,
data: this.data
},
id
};
}
}
1.7 完整示例
以下是一个完整的 MCP 客户端-服务器交互示例:
完整的客户端实现
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { spawn } from 'child_process';
class CompleteMCPClient {
private client: Client;
private transport: StdioClientTransport;
async start(): Promise<void> {
try {
// 1. 启动服务器进程
const serverProcess = spawn('node', ['./server.js'], {
stdio: ['pipe', 'pipe', 'inherit']
});
// 2. 创建传输
this.transport = new StdioClientTransport({
stdin: serverProcess.stdin!,
stdout: serverProcess.stdout!
});
// 3. 创建客户端
this.client = new Client({
name: "complete-client",
version: "1.0.0"
}, {
capabilities: {
experimental: {},
sampling: {}
}
});
// 4. 连接到服务器
await this.client.connect(this.transport);
console.log('✅ 客户端连接成功');
// 5. 进行交互
await this.interact();
} catch (error) {
console.error('❌ 客户端启动失败:', error);
}
}
private async interact(): Promise<void> {
try {
// 列出可用工具
const tools = await this.client.listTools();
console.log('📋 可用工具:', tools.tools.map(t => t.name));
// 列出可用资源
const resources = await this.client.listResources();
console.log('📁 可用资源:', resources.resources.map(r => r.name));
// 列出可用提示
const prompts = await this.client.listPrompts();
console.log('💡 可用提示:', prompts.prompts.map(p => p.name));
// 调用工具示例
if (tools.tools.length > 0) {
const result = await this.client.callTool({
name: tools.tools[0].name,
arguments: { message: "Hello from client!" }
});
console.log('🔧 工具执行结果:', result.content);
}
} catch (error) {
console.error('❌ 交互过程中出错:', error);
}
}
async close(): Promise<void> {
if (this.client) {
await this.client.close();
console.log('👋 客户端已关闭');
}
}
}
// 使用示例
const client = new CompleteMCPClient();
client.start().then(() => {
// 程序退出时清理资源
process.on('SIGINT', async () => {
await client.close();
process.exit(0);
});
});
小结
本章详细介绍了 MCP 的核心架构,包括:
- 客户端-服务器架构:清晰的角色分工和通信模式
- 协议层:消息处理和通信管理的核心组件
- 传输层:支持多种传输机制(Stdio、HTTP+SSE)
- 消息类型:四种标准 JSON-RPC 2.0 消息格式
- 连接生命周期:完整的连接建立、使用和关闭流程
- 错误处理:标准化的错误代码和处理机制
理解这些核心概念是有效使用 MCP 的基础。在接下来的章节中,我们将深入探讨 MCP 的具体功能模块:资源、提示、工具、采样、根和传输的详细实现。