通讯机制
了解 MCP 的通信机制
模型上下文协议 (MCP) 中的传输为客户端和服务器之间的通信提供了基础。传输处理消息发送和接收方式的基本机制。
一、消息格式
MCP 使用 JSON-RPC 2.0 作为其通讯格式。传输层负责将 MCP 协议消息转换为 JSON-RPC 格式进行传输,并将收到的 JSON-RPC 消息转换回 MCP 协议消息。
《模型上下文协议中文网》附注:json-rpc理论上是存在性能瓶颈的,不如gRPC。但也能理解Anthropic为什么一开始优先支持json-rpc,因为MCP协议正常是面向AI客户端场景的。一般而言用户客户端确实不会存在太大并发,除非超大尺寸的数据交互,而json对开发者的普适性远超一切。
使用三种类型的 JSON-RPC 消息:
1、请求
json
{
jsonrpc: "2.0", // 声明使用 JSON-RPC 2.0 协议
id: number | string, // 请求的唯一标识符,可以是数字或字符串,用于匹配响应
method: string, // 需要调用的方法名称
params?: object // 可选的参数对象,传递给方法的参数
}
2、响应
json
{
jsonrpc: "2.0", // 声明使用 JSON-RPC 2.0 协议
id: number | string, // 请求的唯一标识符,与请求中的 id 对应,用于匹配请求和响应
result?: object, // 可选,表示调用成功时的返回结果
error?: { // 可选,表示调用失败时的错误信息
code: number, // 错误代码,表示错误类型
message: string, // 错误描述信息
data?: unknown // 可选,包含额外的错误信息,类型不固定
}
}
3、通知
json
{
jsonrpc: "2.0", // 声明使用 JSON-RPC 2.0 协议
method: string, // 需要调用的通知方法名称
params?: object // 可选,传递给方法的参数
}
二、内置通讯类型
MCP 包括两个标准传输实现:
1、标准输入/输出 (stdio)
stdio 传输支持通过标准输入和输出流进行通信。这对于本地集成和命令行工具特别有用。
在以下情况下使用 stdio:
- 构建命令行工具
- 实施本地集成
- 需要简单的过程通信
- 使用 shell 脚本
TypeScript范例 (服务器)
typescript
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new StdioServerTransport();
await server.connect(transport);
TypeScript范例 (客户端)
typescript
const client = new Client({
name: "example-client",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new StdioClientTransport({
command: "./server",
args: ["--option", "value"]
});
await client.connect(transport);
2、服务器发送的事件 (SSE)
SSE 传输支持使用 HTTP POST 请求进行服务器到客户端流式处理,以实现客户端到服务器的通信。
在以下情况下使用 SSE:
- 只需要服务器到客户端流式传输
- 使用受限网络
- 实施简单更新
TypeScript范例 (服务器)
typescript
import express from "express";
const app = express();
const server = new Server({
name: "example-server",
version: "1.0.0"
}, {
capabilities: {}
});
let transport: SSEServerTransport | null = null;
app.get("/sse", (req, res) => {
transport = new SSEServerTransport("/messages", res);
server.connect(transport);
});
app.post("/messages", (req, res) => {
if (transport) {
transport.handlePostMessage(req, res);
}
});
app.listen(3000);
TypeScript范例 (客户端)
typescript
const client = new Client({
name: "example-client",
version: "1.0.0"
}, {
capabilities: {}
});
const transport = new SSEClientTransport(
new URL("http://localhost:3000/sse")
);
await client.connect(transport);
三、自定义通讯
MCP 可以轻松实现针对特定需求的自定义通讯机制,比如以下场景:
- 自定义网络协议
- 专门的沟通渠道
- 与现有系统集成
- 性能优化
只需要实现 Transport 接口:
TypeScript范例
typescript
interface Transport {
// 开始处理消息
start(): Promise<void>;
// 发送一条JSON-RPC消息
send(message: JSONRPCMessage): Promise<void>;
// 关闭连接
close(): Promise<void>;
// 定义回调
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
}
四、错误处理
Transport 实现应处理各种错误场景:
- 连接错误
- 消息解析错误
- 协议错误
- 网络超时
- 资源清理
错误处理示例:
TypeScript范例
typescript
class ExampleTransport implements Transport {
async start() {
try {
// 连接逻辑
} catch (error) {
this.onerror?.(new Error(`Failed to connect: ${error}`));
throw error;
}
}
async send(message: JSONRPCMessage) {
try {
// 发送逻辑
} catch (error) {
this.onerror?.(new Error(`Failed to send message: ${error}`));
throw error;
}
}
}
其他
1、最佳实践
实施或使用 MCP 传输时:
- 正确处理连接生命周期
- 实施适当的错误处理
- 在连接关闭时清理资源
- 使用适当的超时
- 发送前验证消息
- 用于调试的日志传输事件
- 在适当的时候实施重新连接逻辑
- 处理消息队列中的背压
- 监控连接运行状况
- 实施适当的安全措施
2、安全注意事项
实施 transport 时:
身份验证和授权
- 实施适当的身份验证机制
- 验证客户端凭据
- 使用安全令牌处理
- 实施授权检查
数据安全
- 使用 TLS 进行网络传输
- 加密敏感数据
- 验证消息完整性
- 实施消息大小限制
- 清理输入数据
网络安全
- 实施速率限制
- 使用适当的超时
- 处理拒绝服务场景
- 监控异常模式
- 实施适当的防火墙规则
3、调试传输
调试传输问题的提示:
- 启用调试日志记录
- 监视消息流
- 检查连接状态
- 验证消息格式
- 测试错误场景
- 使用网络分析工具
- 实施运行状况检查
- 监控资源使用情况
- 测试边缘案例
- 使用适当的错误跟踪