Skip to content

2.3 通信协议

🎯 学习目标:掌握MCP的通信协议规范、消息格式和交互模式
⏱️ 预计时间:45分钟
📊 难度等级:⭐⭐

📡 MCP通信协议概述

MCP协议是基于JSON-RPC 2.0的标准化通信协议,就像互联网的HTTP协议一样,它定义了Client和Server之间的"语言规则"。

🎪 协议的比喻理解

想象MCP协议就像是外交礼仪

🤝 外交会议
──────────────────────────────────
📋 议程表(协议规范) - 定义会议流程
🗣️ 发言格式(消息格式) - 统一表达方式  
🔄 对话规则(交互模式) - 谁先说,怎么回应
📝 会议记录(日志追踪) - 记录所有交流

🔧 协议基础架构

📊 协议栈层次

各层职责:

  • 🔝 应用层:MCP特定的业务逻辑(工具调用、资源访问等)
  • 📨 消息层:JSON-RPC 2.0标准消息格式
  • 🚀 传输层:底层传输机制(WebSocket、HTTP、标准输入输出)
  • 🌐 网络层:基础网络通信

🎯 JSON-RPC 2.0基础

MCP基于JSON-RPC 2.0协议,这是一个轻量级的远程过程调用协议:

javascript
// JSON-RPC 2.0 请求格式
{
    "jsonrpc": "2.0",      // 协议版本(必须)
    "method": "methodName", // 调用的方法名(必须)
    "params": {...},       // 参数对象(可选)
    "id": 123             // 请求ID(必须,用于匹配响应)
}

// JSON-RPC 2.0 响应格式
{
    "jsonrpc": "2.0",      // 协议版本(必须)
    "result": {...},       // 成功结果(成功时必须)
    "error": {...},        // 错误信息(失败时必须)
    "id": 123             // 对应的请求ID(必须)
}

// JSON-RPC 2.0 通知格式(无需响应)
{
    "jsonrpc": "2.0",      // 协议版本(必须)
    "method": "notify",    // 通知方法名(必须)
    "params": {...}        // 参数对象(可选)
    // 注意:通知没有id字段
}

🔄 MCP消息类型

📋 三种核心消息类型

1. 🔍 请求消息(Request)

用于Client向Server发起调用:

javascript
// 工具调用请求
{
    "jsonrpc": "2.0",
    "id": "req-001",
    "method": "tools/call",
    "params": {
        "name": "calculator",
        "arguments": {
            "operation": "add",
            "a": 123,
            "b": 456
        }
    }
}

2. ✅ 响应消息(Response)

Server对Request的回复:

javascript
// 成功响应
{
    "jsonrpc": "2.0",
    "id": "req-001",
    "result": {
        "content": [
            {
                "type": "text",
                "text": "579"
            }
        ]
    }
}

// 错误响应
{
    "jsonrpc": "2.0",
    "id": "req-001",
    "error": {
        "code": "INVALID_PARAMS",
        "message": "参数a必须是数字类型"
    }
}

3. 📢 通知消息(Notification)

单向消息,无需响应:

javascript
// 初始化完成通知
{
    "jsonrpc": "2.0",
    "method": "notifications/initialized"
}

// 资源变更通知
{
    "jsonrpc": "2.0",
    "method": "notifications/resources/list_changed"
}

🚀 MCP标准方法

📖 核心方法分类

MCP定义了一系列标准方法,按功能分为几大类:

🔧 初始化流程

连接建立的完整握手过程

初始化请求详解

javascript
// Client发送的initialize请求
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2025-01-07",
        "capabilities": {
            "roots": {
                "listChanged": true
            },
            "sampling": {}
        },
        "clientInfo": {
            "name": "My MCP Client",
            "version": "1.0.0"
        }
    }
}

// Server返回的响应
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "protocolVersion": "2025-01-07",
        "capabilities": {
            "logging": {},
            "tools": {
                "listChanged": true
            },
            "resources": {
                "subscribe": true,
                "listChanged": true
            },
            "prompts": {
                "listChanged": true
            }
        },
        "serverInfo": {
            "name": "Example MCP Server",
            "version": "1.0.0"
        }
    }
}

🛠️ 工具相关方法

tools/list - 获取工具列表

javascript
// 请求
{
    "jsonrpc": "2.0",
    "id": "tools-list-001",
    "method": "tools/list"
}

// 响应
{
    "jsonrpc": "2.0",
    "id": "tools-list-001",
    "result": {
        "tools": [
            {
                "name": "calculator",
                "description": "基础数学计算器",
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "operation": {
                            "type": "string",
                            "enum": ["add", "subtract", "multiply", "divide"]
                        },
                        "a": { "type": "number" },
                        "b": { "type": "number" }
                    },
                    "required": ["operation", "a", "b"]
                }
            },
            {
                "name": "weather",
                "description": "获取天气信息",
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "city": { "type": "string" },
                        "country": { "type": "string", "default": "CN" }
                    },
                    "required": ["city"]
                }
            }
        ]
    }
}

tools/call - 调用工具

javascript
// 调用计算器工具
{
    "jsonrpc": "2.0",
    "id": "calc-001",
    "method": "tools/call",
    "params": {
        "name": "calculator",
        "arguments": {
            "operation": "add",
            "a": 123,
            "b": 456
        }
    }
}

// 成功响应
{
    "jsonrpc": "2.0",
    "id": "calc-001",
    "result": {
        "content": [
            {
                "type": "text",
                "text": "计算结果:123 + 456 = 579"
            }
        ],
        "isError": false
    }
}

// 错误响应
{
    "jsonrpc": "2.0",
    "id": "calc-001",
    "error": {
        "code": "INVALID_PARAMS",
        "message": "不支持的运算操作: modulo",
        "data": {
            "operation": "modulo"
        }
    }
}

📚 资源相关方法

资源是Server提供的可读取内容,如文件、数据库记录等:

resources/list - 获取资源列表

javascript
// 请求
{
    "jsonrpc": "2.0",
    "id": "res-list-001",
    "method": "resources/list"
}

// 响应
{
    "jsonrpc": "2.0",
    "id": "res-list-001",
    "result": {
        "resources": [
            {
                "uri": "file:///home/user/documents/report.txt",
                "name": "报告文件",
                "description": "项目进度报告",
                "mimeType": "text/plain"
            },
            {
                "uri": "db://localhost/users/123",
                "name": "用户数据",
                "description": "用户ID 123的详细信息",
                "mimeType": "application/json"
            }
        ]
    }
}

resources/read - 读取资源内容

javascript
// 请求读取文件
{
    "jsonrpc": "2.0",
    "id": "read-001",
    "method": "resources/read",
    "params": {
        "uri": "file:///home/user/documents/report.txt"
    }
}

// 响应
{
    "jsonrpc": "2.0",
    "id": "read-001",
    "result": {
        "contents": [
            {
                "uri": "file:///home/user/documents/report.txt",
                "mimeType": "text/plain",
                "text": "项目进度报告\n\n本月完成情况:\n1. 需求分析 - 100%\n2. 设计阶段 - 80%\n3. 开发阶段 - 60%"
            }
        ]
    }
}

🔒 错误处理机制

📋 标准错误代码

MCP定义了一系列标准错误代码:

错误代码含义示例场景
PARSE_ERRORJSON解析错误无效的JSON格式
INVALID_REQUEST无效请求缺少必需字段
METHOD_NOT_FOUND方法不存在调用不支持的方法
INVALID_PARAMS参数无效参数类型或值错误
INTERNAL_ERROR内部错误服务器内部异常
TOOL_NOT_FOUND工具不存在调用不存在的工具
RESOURCE_NOT_FOUND资源不存在访问不存在的资源

🛠️ 错误处理示例

javascript
// 复杂的错误响应
{
    "jsonrpc": "2.0",
    "id": "req-001",
    "error": {
        "code": "INVALID_PARAMS",
        "message": "工具参数验证失败",
        "data": {
            "tool": "calculator",
            "errors": [
                {
                    "field": "operation",
                    "message": "必须是 add, subtract, multiply, divide 之一",
                    "received": "modulo"
                },
                {
                    "field": "a",
                    "message": "必须是数字类型",
                    "received": "abc"
                }
            ]
        }
    }
}

🔄 传输层实现

🌐 多种传输方式

MCP支持多种底层传输机制:

1. 标准输入输出(Stdio)

适用于本地进程通信:

javascript
// Node.js Stdio传输实现
class StdioTransport {
    constructor() {
        this.messageBuffer = '';
    }
    
    send(message) {
        const messageStr = JSON.stringify(message) + '\n';
        process.stdout.write(messageStr);
    }
    
    onMessage(callback) {
        process.stdin.on('data', (chunk) => {
            this.messageBuffer += chunk.toString();
            
            // 处理完整的消息行
            const lines = this.messageBuffer.split('\n');
            this.messageBuffer = lines.pop(); // 保留不完整的行
            
            lines.forEach(line => {
                if (line.trim()) {
                    try {
                        const message = JSON.parse(line);
                        callback(message);
                    } catch (error) {
                        console.error('JSON解析错误:', error);
                    }
                }
            });
        });
    }
}

2. WebSocket传输

适用于Web应用和实时通信:

javascript
// WebSocket传输实现
class WebSocketTransport {
    constructor(url) {
        this.ws = new WebSocket(url);
        this.setupEventHandlers();
    }
    
    send(message) {
        if (this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(message));
        } else {
            throw new Error('WebSocket连接未开启');
        }
    }
    
    onMessage(callback) {
        this.messageCallback = callback;
    }
    
    setupEventHandlers() {
        this.ws.onmessage = (event) => {
            try {
                const message = JSON.parse(event.data);
                if (this.messageCallback) {
                    this.messageCallback(message);
                }
            } catch (error) {
                console.error('消息解析错误:', error);
            }
        };
        
        this.ws.onopen = () => {
            console.log('WebSocket连接已建立');
        };
        
        this.ws.onclose = () => {
            console.log('WebSocket连接已关闭');
        };
        
        this.ws.onerror = (error) => {
            console.error('WebSocket错误:', error);
        };
    }
}

3. HTTP传输

适用于无状态的请求-响应模式:

javascript
// HTTP传输实现
class HttpTransport {
    constructor(baseUrl) {
        this.baseUrl = baseUrl;
        this.requestId = 1;
    }
    
    async send(message) {
        const response = await fetch(`${this.baseUrl}/mcp`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(message)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP错误: ${response.status}`);
        }
        
        return await response.json();
    }
    
    // HTTP传输通常是同步的请求-响应模式
    async request(method, params) {
        const message = {
            jsonrpc: '2.0',
            id: this.requestId++,
            method,
            params
        };
        
        return await this.send(message);
    }
}

🎯 协议最佳实践

✅ 实现建议

1. 连接管理

javascript
class MCPConnection {
    constructor(transport) {
        this.transport = transport;
        this.pendingRequests = new Map();
        this.requestTimeout = 30000; // 30秒超时
        this.setupMessageHandler();
    }
    
    async request(method, params) {
        const id = this.generateRequestId();
        const message = {
            jsonrpc: '2.0',
            id,
            method,
            params
        };
        
        return new Promise((resolve, reject) => {
            // 设置超时
            const timeoutId = setTimeout(() => {
                this.pendingRequests.delete(id);
                reject(new Error(`请求超时: ${method}`));
            }, this.requestTimeout);
            
            // 存储待响应请求
            this.pendingRequests.set(id, {
                resolve,
                reject,
                timeoutId
            });
            
            // 发送请求
            this.transport.send(message);
        });
    }
    
    handleResponse(message) {
        const { id, result, error } = message;
        const pending = this.pendingRequests.get(id);
        
        if (pending) {
            clearTimeout(pending.timeoutId);
            this.pendingRequests.delete(id);
            
            if (error) {
                pending.reject(new MCPError(error.message, error.code));
            } else {
                pending.resolve(result);
            }
        }
    }
}

2. 消息验证

javascript
class MessageValidator {
    static validateRequest(message) {
        const errors = [];
        
        if (message.jsonrpc !== '2.0') {
            errors.push('jsonrpc字段必须是"2.0"');
        }
        
        if (!message.method || typeof message.method !== 'string') {
            errors.push('method字段必须是非空字符串');
        }
        
        if (message.id !== undefined && 
            typeof message.id !== 'string' && 
            typeof message.id !== 'number') {
            errors.push('id字段必须是字符串或数字');
        }
        
        return errors;
    }
    
    static validateResponse(message) {
        const errors = [];
        
        if (message.jsonrpc !== '2.0') {
            errors.push('jsonrpc字段必须是"2.0"');
        }
        
        if (message.id === undefined) {
            errors.push('响应必须包含id字段');
        }
        
        if (!message.result && !message.error) {
            errors.push('响应必须包含result或error字段');
        }
        
        if (message.result && message.error) {
            errors.push('响应不能同时包含result和error字段');
        }
        
        return errors;
    }
}

🎯 本节小结

通过这一小节,你应该已经掌握了:

协议基础:JSON-RPC 2.0协议和MCP的消息格式
消息类型:请求、响应、通知三种消息类型的使用
标准方法:初始化、工具调用、资源访问等核心方法
错误处理:标准错误代码和错误处理机制
传输层:Stdio、WebSocket、HTTP等传输方式的实现
最佳实践:连接管理、消息验证等实现建议

🤔 协议思考

  1. 💭 在你的使用场景中,哪种传输方式最合适?
  2. 🔍 如何设计自定义的错误处理机制?
  3. 🛠️ 你会如何优化协议的性能和可靠性?

理解了通信协议的细节,想知道数据在整个MCP系统中是如何流转的吗?

👉 下一小节:2.4 数据流转