WebSocket MCP协议实现

基于WebSocket和Cloudflare Workers的Model Context Protocol (MCP)参考实现,提供双向实时通信和持久状态会话。

  • by dinasaur404
  • JavaScript
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 dinasaur404/math-mcp

使用说明

WebSockets MCP数学演示

一个参考实现,展示了 模型上下文协议(MCP) 通过使用Cloudflare Workers和持久对象的WebSockets。

概述

此存储库提供了基于WebSockets的MCP的参考实现。它展示了:

  • 完整的MCP客户端-服务器架构
  • 通过持久对象持久化有状态会话
  • WebSockets上的双向实时通信
  • 工具发现和调用
  • 使用Cloudflare Workers进行部署

技术概述

建筑

此项目演示了在WebSockets上使用客户端和服务器组件的完整MCP实现:

┌─────────────────┐                 ┌─────────────────┐
│                 │                 │                 │
│  MCP Client     │◄───WebSocket───►│  MCP Server     │
│  (CF Worker)    │                 │  (CF Worker)    │
│                 │      HTTP       │                 │
└─────────────────┘───────────────►└─────────────────┘
                                        │
                                        │ State Persistence
                                        ▼
                                  ┌─────────────────┐
                                  │  Durable Object │
                                  │  (MathAgent)    │
                                  │                 │
                                  └─────────────────┘
  • 客户端:服务于HTML/JS客户端应用程序的Cloudflare Worker
  • 服务器:使用工具端点实现MCP协议的Cloudflare Worker
  • 耐用物品:维护每个代理会话的持久状态

WebSocket实现

该实现同时支持HTTP和WebSocket传输:

  1. 连接建立:

    • 客户端通过HTTP POST创建代理
    • 客户端建立WebSocket连接到 /agent/{agentId}/websocket
    • 服务器在持久对象中维护连接
  2. 消息格式:

    // Client to Server
    {
      "type": "mcp_request",
      "request": {
        "method": "add",
        "params": { "a": 5, "b": 3 }
      }
    }
    
    // Server to Client
    {
      "type": "mcp_response",
      "result": {
        "result": 8,
        "operation": "add",
        "a": 5,
        "b": 3
      },
      "timestamp": "2023-05-01T12:34:56.789Z"
    }
    
  3. 连接管理:

    • 乒乓球心跳机制
    • 自动重新连接
    • 会话跟踪

入门指南

先决条件

  • Node.js (v18或更高版本)
  • 牧马人 (Cloudflare Workers CLI)
  • Cloudflare帐户

安装

  1. 克隆此存储库:

    git clone https://github.com/your-username/mcp-websockets-demo.git
    cd mcp-websockets-demo/math-mcp
    
  2. 安装依赖项:

    npm install
    
  3. 部署服务器:

    cd server
    wrangler deploy
    
  4. 部署客户端:

    cd ../client
    wrangler deploy
    
  5. 请注意这两个worker的已部署URL,您需要它们才能使用应用程序。

用法

web界面

  1. 在浏览器中打开客户端URL。该界面允许您:
    • 连接到MCP服务器
    • 运行数学运算
    • 查看WebSocket消息日志

程序化API

您还可以通过编程方式使用MCP服务器:

HTTP示例:

// Create an agent
const agentResponse = await fetch('https://your-server.workers.dev/agent', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'MathAgent' })
});
const { agentId } = await agentResponse.json();

// Make an MCP request
const result = await fetch('https://your-server.workers.dev/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    agentId,
    request: {
      method: 'add',
      params: { a: 5, b: 3 }
    }
  })
});

WebSocket示例:

// Create an agent first via HTTP (see above)

// Establish WebSocket connection
const ws = new WebSocket(`wss://your-server.workers.dev/agent/${agentId}/websocket`);

// Listen for messages
ws.addEventListener('message', (event) => {
  const message = JSON.parse(event.data);
  console.log('Received:', message);
});

// Send an MCP request
ws.addEventListener('open', () => {
  ws.send(JSON.stringify({
    type: 'mcp_request',
    request: {
      method: 'add',
      params: { a: 5, b: 3 }
    }
  }));
});

## WebSocket MCP Protocol Specification

This implementation proposes the following extensions to the MCP protocol for WebSocket support:

### 1. Transport Layer

The WebSocket transport extends MCP with these characteristics:

- **Bidirectional Communication**: Both client and server can initiate messages
- **Persistent Connection**: Long-lived connection reduces overhead
- **Real-time Updates**: Enables server-initiated notifications and streaming results
- **Reduced Latency**: Eliminates HTTP request overhead for frequent interactions

### 2. Message Envelope

All WebSocket messages are wrapped in an envelope with a `type` field:

```json
{
  "type": "message_type",
  "payload": { ... },
  "timestamp": "ISO-8601 timestamp"
}

常见的消息类型包括:

  • mcp_request:客户端到服务器MCP方法调用
  • mcp_response:服务器到客户端的响应
  • ping/pong:连接健康检查
  • error:错误通知
  • notification:服务器发起的通知

3.连接生命周期

  1. 初始化:客户端在建立WebSocket之前通过HTTP创建代理
  2. 连接:客户端连接到特定于代理的WebSocket端点
  3. 心跳:客户端定期发送ping以保持连接
  4. 终止:任何一方都可以关闭连接

4.实施注意事项

在为MCP实现WebSocket支持时:

  • 状态管理:处理重新连接和状态恢复
  • 消息排序:实施排序以实现可靠的消息排序
  • 错误处理:优雅地处理连接错误和消息失败
  • 安全:应用与HTTP传输相同的身份验证机制

关键代码组件

以下是实现WebSocket MCP的关键组件:

服务器端WebSocket处理

// Handle WebSocket connections
async function handleWebSocketConnection(request, agentId, env) {
  // Get Durable Object stub for the agent
  const id = env.MATH_AGENT.idFromName(agentId);
  const stub = env.MATH_AGENT.get(id);
  
  // Forward the request to the Durable Object
  return await stub.fetch(request);
}

// Durable Object implementation
export class MathAgent {
  // Handle WebSocket connections
  async handleWebSocketConnection(request) {
    // Create a WebSocket pair
    const pair = new WebSocketPair();
    const [client, server] = Object.values(pair);
    
    // Accept the WebSocket connection
    server.accept();
    
    // Set up event handlers for the WebSocket
    server.addEventListener("message", async (event) => {
      const message = JSON.parse(event.data);
      
      // Handle different message types
      if (message.type === "mcp_request") {
        const result = await this.handleMcpRequest(message.request);
        server.send(JSON.stringify({
          type: "mcp_response",
          result,
          timestamp: new Date().toISOString()
        }));
      }
    });
    
    return new Response(null, {
      status: 101,
      webSocket: client
    });
  }
}

客户端WebSocket使用情况

// Connect WebSocket
function connectWebSocket(agentId, serverUrl) {
  const ws = new WebSocket(`${serverUrl}/agent/${agentId}/websocket`);
  
  ws.onopen = () => {
    console.log('WebSocket connection established');
  };
  
  ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    
    // Handle different message types
    if (message.type === 'mcp_response') {
      handleMcpResponse(message);
    }
  };
  
  return ws;
}

// Send MCP request
function sendMcpRequest(ws, method, params) {
  ws.send(JSON.stringify({
    type: 'mcp_request',
    request: {
      method,
      params
    },
    timestamp: new Date().toISOString()
  }));
}

与TypeScript SDK集成

此参考实现可用于扩展 MCP TypeScript SDK 支持WebSocket:

import { MCPClient } from '@modelcontextprotocol/typescript-sdk';

// Create WebSocket transport
class WebSocketTransport implements MCPTransport {
  private ws: WebSocket;
  private pendingRequests: Map<string, {resolve, reject}>;
  
  constructor(serverUrl: string, agentId: string) {
    this.ws = new WebSocket(`${serverUrl}/agent/${agentId}/websocket`);
    this.pendingRequests = new Map();
    
    this.ws.addEventListener('message', this.handleMessage.bind(this));
  }
  
  async send(method: string, params: any): Promise<any> {
    return new Promise((resolve, reject) => {
      const requestId = crypto.randomUUID();
      
      this.pendingRequests.set(requestId, { resolve, reject });
      
      this.ws.send(JSON.stringify({
        type: 'mcp_request',
        request: { method, params },
        requestId
      }));
    });
  }
  
  private handleMessage(event: MessageEvent) {
    const message = JSON.parse(event.data);
    
    if (message.type === 'mcp_response' && message.requestId) {
      const pending = this.pendingRequests.get(message.requestId);
      if (pending) {
        pending.resolve(message.result);
        this.pendingRequests.delete(message.requestId);
      }
    }
  }
}

// Use transport with MCP client
const transport = new WebSocketTransport('wss://example.com', 'agent-123');
const client = new MCPClient({ transport });

// Use MCP methods as usual
const result = await client.invoke('add', { a: 5, b: 3 });

WebSocket MCP的优点

向MCP添加WebSocket支持提供了几个优点:

  1. 减少延迟:非常适合需要快速交互的环境

    • 高频交易
    • 实时协作环境
    • 需要快速响应的交互式代理
  2. 双向通信:启用新的交互模式

    • 服务器可以在没有客户端轮询的情况下推送更新
    • 将大量响应分块流式传输
    • 推送外部事件通知
  3. 减少网络开销:更有效地进行频繁通信

    • 每个请求都没有HTTP标头开销
    • 连接设置成本在多个请求中摊销
    • 在移动网络上特别有用
  4. 有意义的会议:简化对话上下文的维护

    • 服务器可以将状态与WebSocket连接相关联
    • 客户端不需要为每个请求发送完整的上下文
    • 更容易实现流式响应和部分更新

挑战和解决方案

WebSockets还引入了此实现所解决的挑战:

  1. 连接管理:

    • 挑战:WebSockets可能会意外断开连接
    • 解决方案:心跳机制和自动重新连接
  2. 无国籍工人:

    • 挑战:Cloudflare Workers默认为无状态
    • 解决方案:持久对象保持连接状态
  3. 请求/响应配对:

    • 挑战:在共享通道上匹配对请求的响应
    • 解决方案:邮件ID跟踪和关联
  4. 错误处理:

    • 挑战:优雅地管理连接失败
    • 解决方案:结构化错误响应和重新连接逻辑

贡献

欢迎投稿!请随时提交拉取请求。

许可证

此项目根据MIT许可证获得许可-有关详细信息,请参阅许可证文件。