本文将深入探讨MCP传输层的核心概念、实现机制,并通过TypeScript SDK提供详细的代码示例,帮助开发者理解和实践MCP传输层的开发。
MCP传输层核心概念
什么是传输层
传输层在模型上下文协议(MCP)中为客户端和服务器之间的通信提供基础支撑,负责处理消息发送和接收的底层机制。传输层的主要职责包括:
- 消息格式转换:将MCP协议消息转换为JSON-RPC格式进行传输
- 连接管理:维护客户端和服务器之间的连接状态
- 错误处理:处理各种网络和协议错误
- 资源管理:合理分配和释放网络资源
JSON-RPC 2.0消息格式
MCP使用JSON-RPC 2.0作为其线路格式,传输层负责将MCP协议消息转换为JSON-RPC格式进行传输。JSON-RPC消息包含三种类型:
- 请求(Requests) :客户端向服务器发送的操作请求
- 响应(Responses) :服务器对请求的回复
- 通知(Notifications) :单向消息,不需要响应
内置传输类型详解
1. 标准输入输出传输 (Stdio Transport)
stdio传输通过标准输入和输出流进行通信,特别适用于本地集成和命令行工具。
适用场景
- 构建命令行工具
- 实现本地集成
- 简单的进程间通信
- Shell脚本集成
TypeScript实现示例
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
class StdioMCPServer {
private server: McpServer;
private transport: StdioServerTransport;
constructor() {
// 初始化MCP服务器
this.server = new McpServer(
{
name: "example-stdio-server",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
prompts: {}
}
}
);
// 创建stdio传输
this.transport = new StdioServerTransport();
}
async start() {
try {
// 连接服务器和传输层
await this.server.connect(this.transport);
console.error("Stdio MCP server started successfully");
} catch (error) {
console.error("Failed to start stdio server:", error);
process.exit(1);
}
}
// 添加工具处理
setupTools() {
this.server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "echo",
description: "Echo back the input",
inputSchema: {
type: "object",
properties: {
message: {
type: "string",
description: "Message to echo"
}
}
}
}
]
}));
this.server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "echo") {
return {
content: [
{
type: "text",
text: `Echo: ${args.message}`
}
]
};
}
throw new Error(`Unknown tool: ${name}`);
});
}
}
// 启动服务器
const server = new StdioMCPServer();
server.setupTools();
server.start();
2. 服务器发送事件传输 (SSE Transport)
SSE传输支持服务器到客户端的流式传输,并通过HTTP POST请求实现客户端到服务器的通信。
适用场景
- 仅需要服务器到客户端的流式传输
- 网络受限环境
- 简单的更新推送
TypeScript实现示例
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
import cors from "cors";
class SSEMCPServer {
private server: McpServer;
private app: express.Application;
private port: number;
constructor(port: number = 3000) {
this.port = port;
this.app = express();
// 初始化MCP服务器
this.server = new McpServer(
{
name: "example-sse-server",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
prompts: {}
}
}
);
this.setupMiddleware();
this.setupRoutes();
}
private setupMiddleware() {
// 配置CORS以防止DNS重绑定攻击
this.app.use(cors({
origin: (origin, callback) => {
// 验证Origin头,防止DNS重绑定攻击
const allowedOrigins = [
'http://localhost:3000',
'http://127.0.0.1:3000'
];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
}));
this.app.use(express.json());
}
private setupRoutes() {
// SSE端点
this.app.get('/sse', (req, res) => {
// 验证Origin头
const origin = req.get('Origin');
if (origin && !['http://localhost:3000', 'http://127.0.0.1:3000'].includes(origin)) {
res.status(403).send('Forbidden');
return;
}
// 设置SSE头
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': origin || 'http://localhost:3000'
});
// 创建SSE传输
const transport = new SSEServerTransport(res, req);
// 连接服务器
this.server.connect(transport).catch(error => {
console.error('SSE connection failed:', error);
res.end();
});
// 处理客户端断开连接
req.on('close', () => {
console.log('SSE client disconnected');
});
});
// POST端点用于客户端到服务器的消息
this.app.post('/message', async (req, res) => {
try {
// 验证Origin头
const origin = req.get('Origin');
if (origin && !['http://localhost:3000', 'http://127.0.0.1:3000'].includes(origin)) {
res.status(403).json({ error: 'Forbidden' });
return;
}
// 处理消息
const message = req.body;
console.log('Received message:', message);
res.json({ status: 'received' });
} catch (error) {
console.error('Message handling error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
}
async start() {
// 绑定到localhost以防止安全风险
this.app.listen(this.port, '127.0.0.1', () => {
console.log(`SSE MCP server running on http://127.0.0.1:${this.port}`);
});
}
}
// 启动服务器
const sseServer = new SSEMCPServer(3000);
sseServer.start();
自定义传输实现
MCP使自定义传输的实现变得简单,任何传输实现都只需要符合Transport接口。
自定义WebSocket传输示例
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
import WebSocket from "ws";
export class WebSocketTransport implements Transport {
private ws: WebSocket;
private messageHandlers: Set<(message: JSONRPCMessage) => void> = new Set();
private errorHandlers: Set<(error: Error) => void> = new Set();
private closeHandlers: Set<() => void> = new Set();
constructor(private url: string) {
this.ws = new WebSocket(url);
this.setupEventHandlers();
}
private setupEventHandlers() {
this.ws.on('message', (data: Buffer) => {
try {
const message: JSONRPCMessage = JSON.parse(data.toString());
this.messageHandlers.forEach(handler => handler(message));
} catch (error) {
this.errorHandlers.forEach(handler =>
handler(new Error(`Message parsing error: ${error}`))
);
}
});
this.ws.on('error', (error: Error) => {
this.errorHandlers.forEach(handler => handler(error));
});
this.ws.on('close', () => {
this.closeHandlers.forEach(handler => handler());
});
}
async send(message: JSONRPCMessage): Promise<void> {
return new Promise((resolve, reject) => {
if (this.ws.readyState !== WebSocket.OPEN) {
reject(new Error('WebSocket connection not ready'));
return;
}
try {
const data = JSON.stringify(message);
this.ws.send(data, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
} catch (error) {
reject(error);
}
});
}
onMessage(handler: (message: JSONRPCMessage) => void): void {
this.messageHandlers.add(handler);
}
onError(handler: (error: Error) => void): void {
this.errorHandlers.add(handler);
}
onClose(handler: () => void): void {
this.closeHandlers.add(handler);
}
async close(): Promise<void> {
return new Promise((resolve) => {
if (this.ws.readyState === WebSocket.CLOSED) {
resolve();
return;
}
this.ws.once('close', () => resolve());
this.ws.close();
});
}
}
// 使用示例
class WebSocketMCPClient {
private client: any; // MCP Client类型
private transport: WebSocketTransport;
constructor(url: string) {
this.transport = new WebSocketTransport(url);
}
async connect() {
try {
// 等待WebSocket连接建立
await this.waitForConnection();
// 创建MCP客户端并连接传输
// await this.client.connect(this.transport);
console.log('WebSocket MCP client connected successfully');
} catch (error) {
console.error('Connection failed:', error);
throw error;
}
}
private waitForConnection(): Promise<void> {
return new Promise((resolve, reject) => {
const ws = (this.transport as any).ws;
if (ws.readyState === WebSocket.OPEN) {
resolve();
return;
}
const timeout = setTimeout(() => {
reject(new Error('Connection timeout'));
}, 5000);
ws.once('open', () => {
clearTimeout(timeout);
resolve();
});
ws.once('error', (error: Error) => {
clearTimeout(timeout);
reject(error);
});
});
}
}
错误处理与最佳实践
错误处理策略
传输实现应该处理各种错误场景,包括连接错误、消息解析错误、协议错误、网络超时和资源清理。
class RobustTransport implements Transport {
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 5;
private reconnectDelay: number = 1000;
private heartbeatInterval?: NodeJS.Timeout;
private messageQueue: JSONRPCMessage[] = [];
async send(message: JSONRPCMessage): Promise<void> {
try {
// 实现重试机制
await this.sendWithRetry(message, 3);
} catch (error) {
// 如果发送失败,将消息加入队列
this.messageQueue.push(message);
throw error;
}
}
private async sendWithRetry(
message: JSONRPCMessage,
retries: number
): Promise<void> {
for (let i = 0; i < retries; i++) {
try {
await this.actualSend(message);
return;
} catch (error) {
if (i === retries - 1) throw error;
// 指数退避
await this.delay(Math.pow(2, i) * 1000);
}
}
}
private async actualSend(message: JSONRPCMessage): Promise<void> {
// 实际发送逻辑
// 验证消息格式
this.validateMessage(message);
// 检查消息大小
const messageSize = JSON.stringify(message).length;
if (messageSize > 1024 * 1024) { // 1MB限制
throw new Error(`Message too large: ${messageSize} bytes`);
}
// 发送消息...
}
private validateMessage(message: JSONRPCMessage): void {
if (!message.jsonrpc || message.jsonrpc !== "2.0") {
throw new Error("Invalid JSON-RPC version");
}
if (!message.id && !message.method) {
throw new Error("Invalid JSON-RPC message");
}
}
private async reconnect(): Promise<void> {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
throw new Error("Max reconnection attempts exceeded");
}
this.reconnectAttempts++;
try {
await this.delay(this.reconnectDelay * this.reconnectAttempts);
await this.connect();
// 重连成功后,发送队列中的消息
await this.flushMessageQueue();
this.reconnectAttempts = 0;
} catch (error) {
console.error(`Reconnection attempt ${this.reconnectAttempts} failed:`, error);
throw error;
}
}
private async flushMessageQueue(): Promise<void> {
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift()!;
try {
await this.actualSend(message);
} catch (error) {
// 如果仍然失败,重新加入队列
this.messageQueue.unshift(message);
break;
}
}
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
private startHeartbeat(): void {
this.heartbeatInterval = setInterval(async () => {
try {
await this.ping();
} catch (error) {
console.error('Heartbeat failed:', error);
await this.reconnect();
}
}, 30000); // 30秒心跳
}
private async ping(): Promise<void> {
// 发送ping消息检查连接状态
await this.send({
jsonrpc: "2.0",
method: "ping",
id: Date.now()
});
}
async close(): Promise<void> {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
}
// 清理资源...
}
}
安全考虑
SSE传输可能容易受到DNS重绑定攻击,需要验证Origin头、避免绑定到所有网络接口,并为所有SSE连接实施适当的身份验证。
class SecureSSETransport {
private validateOrigin(origin: string | undefined): boolean {
const allowedOrigins = [
'https://myapp.com',
'https://localhost:3000',
'https://127.0.0.1:3000'
];
return origin ? allowedOrigins.includes(origin) : false;
}
private authenticateClient(token: string): boolean {
// 实现JWT或其他认证机制
try {
// 验证token
return this.verifyJWT(token);
} catch (error) {
console.error('Authentication failed:', error);
return false;
}
}
private verifyJWT(token: string): boolean {
// JWT验证逻辑
return true; // 简化示例
}
setupSecureSSEEndpoint(app: express.Application) {
app.get('/secure-sse', (req, res) => {
// 1. 验证Origin头
const origin = req.get('Origin');
if (!this.validateOrigin(origin)) {
res.status(403).send('Invalid origin');
return;
}
// 2. 验证认证token
const token = req.get('Authorization')?.replace('Bearer ', '');
if (!token || !this.authenticateClient(token)) {
res.status(401).send('Unauthorized');
return;
}
// 3. 实施速率限制
if (!this.checkRateLimit(req.ip)) {
res.status(429).send('Rate limit exceeded');
return;
}
// 4. 设置安全头
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'Access-Control-Allow-Origin': origin
});
// 继续SSE处理...
});
}
private checkRateLimit(ip: string): boolean {
// 实现速率限制逻辑
return true; // 简化示例
}
}
性能优化与监控
连接池管理
class ConnectionPoolTransport {
private pools: Map<string, WebSocketTransport[]> = new Map();
private poolSize: number = 5;
private activeConnections: Map<string, number> = new Map();
async getConnection(endpoint: string): Promise<WebSocketTransport> {
let pool = this.pools.get(endpoint);
if (!pool) {
pool = [];
this.pools.set(endpoint, pool);
this.activeConnections.set(endpoint, 0);
}
// 检查空闲连接
for (const connection of pool) {
if (await this.isConnectionHealthy(connection)) {
return connection;
}
}
// 创建新连接
if ((this.activeConnections.get(endpoint) || 0) < this.poolSize) {
const connection = new WebSocketTransport(endpoint);
pool.push(connection);
this.activeConnections.set(endpoint, pool.length);
return connection;
}
throw new Error('Connection pool exhausted');
}
private async isConnectionHealthy(connection: WebSocketTransport): Promise<boolean> {
try {
// 发送ping检查连接健康状态
await connection.send({
jsonrpc: "2.0",
method: "ping",
id: Date.now()
});
return true;
} catch (error) {
return false;
}
}
async releaseConnection(endpoint: string, connection: WebSocketTransport): Promise<void> {
const pool = this.pools.get(endpoint);
if (pool) {
// 连接回到池中,可以被重用
console.log(`Connection returned to pool for ${endpoint}`);
}
}
}
监控和指标
class MonitoredTransport implements Transport {
private metrics = {
messagesSent: 0,
messagesReceived: 0,
errorsCount: 0,
connectionTime: 0,
avgResponseTime: 0,
totalRequests: 0
};
private responseTimestamps: Map<string, number> = new Map();
async send(message: JSONRPCMessage): Promise<void> {
const startTime = Date.now();
try {
// 记录请求时间戳
if (message.id) {
this.responseTimestamps.set(String(message.id), startTime);
}
await this.actualSend(message);
this.metrics.messagesSent++;
this.logMetrics();
} catch (error) {
this.metrics.errorsCount++;
console.error('Send error:', error);
throw error;
}
}
onMessage(handler: (message: JSONRPCMessage) => void): void {
this.baseTransport.onMessage((message) => {
this.metrics.messagesReceived++;
// 计算响应时间
if (message.id) {
const requestTime = this.responseTimestamps.get(String(message.id));
if (requestTime) {
const responseTime = Date.now() - requestTime;
this.updateAverageResponseTime(responseTime);
this.responseTimestamps.delete(String(message.id));
}
}
handler(message);
});
}
private updateAverageResponseTime(responseTime: number): void {
this.metrics.totalRequests++;
this.metrics.avgResponseTime =
(this.metrics.avgResponseTime * (this.metrics.totalRequests - 1) + responseTime)
/ this.metrics.totalRequests;
}
private logMetrics(): void {
if (this.metrics.messagesSent % 100 === 0) {
console.log('Transport Metrics:', {
sent: this.metrics.messagesSent,
received: this.metrics.messagesReceived,
errors: this.metrics.errorsCount,
avgResponseTime: this.metrics.avgResponseTime.toFixed(2) + 'ms',
errorRate: (this.metrics.errorsCount / this.metrics.messagesSent * 100).toFixed(2) + '%'
});
}
}
getMetrics() {
return { ...this.metrics };
}
}
总结
MCP传输层是构建高效、可靠的AI应用集成的关键组件。通过深入理解传输层的工作原理,掌握stdio和SSE两种内置传输类型的使用方法,以及学会实现自定义传输,开发者可以构建适应各种场景需求的MCP应用。
TypeScript SDK提供了全面的工具包,简化了MCP客户端和服务器的创建过程,使开发者能够专注于业务逻辑的实现,而不必过度关注底层通信细节。
在实际开发中,务必重视安全性考虑,实施适当的错误处理和性能优化策略,确保MCP应用在生产环境中的稳定性和可靠性。随着AI应用生态的不断发展,MCP传输层将继续演进,为更复杂的AI集成场景提供更强大的支持。