WebSockets MCP Math Demo について
Cloudflare Workers と Durable Objects を使った、WebSocket 経由の MCP 参照実装です。双方向で状態を保持する MCP セッションを検証する開発者向けに、クライアント、サーバー、数学演算のデモを提供します。
主な機能
- 01MCP クライアントとサーバーの実装例
- 02HTTP と WebSocket のトランスポート
- 03Durable Objects によるセッションの永続化
- 04双方向リアルタイムメッセージ通信
- 05ツールの発見と呼び出し
- 06ハートビートと自動再接続
活用シーン
- 01状態を保持する MCP WebSocket トランスポートの試作
- 02クライアント・サーバー間の通信とツール呼び出しの検証
- 03Cloudflare Workers 上での永続的なエージェントセッションのテスト
- 04ブラウザー画面での WebSocket メッセージ確認
MCP 対応
WebSocket と HTTP による MCP クライアント・サーバー通信を実演し、ツールの発見と呼び出しに対応します。サーバーは数学演算のデモを公開し、Durable Objects がセッション状態を保持します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
WebSockets MCP 数学デモ
Cloudflare Workers と Durable Objects を使用して、WebSockets 経由で Model Context Protocol (MCP) を実演するリファレンス実装です。
概要
このリポジトリは、WebSockets 経由の MCP のリファレンス実装を提供します。以下の機能を紹介します。
- 完全な MCP クライアント・サーバーアーキテクチャ
- Durable Objects による永続的なステートフルセッション
- 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
- Durable Objects:各エージェントセッションの永続状態を維持します
WebSocket の実装
この実装は、HTTP と WebSocket の両方のトランスポートに対応しています。
-
接続の確立:
- クライアントが HTTP POST でエージェントを作成します
- クライアントが
/agent/{agentId}/websocketへの WebSocket 接続を確立します - サーバーが Durable Object 内で接続を維持します
-
メッセージ形式:
// 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" } -
接続管理:
- Ping/pong ハートビート機構
- 自動再接続
- セッションの追跡
はじめに
前提条件
インストール
-
このリポジトリをクローンします。
git clone https://github.com/your-username/mcp-websockets-demo.git cd mcp-websockets-demo/math-mcp -
依存関係をインストールします。
npm install -
サーバーをデプロイします。
cd server wrangler deploy -
クライアントをデプロイします。
cd ../client wrangler deploy -
両方の Worker のデプロイ先 URL を控えておいてください。アプリケーションを使用する際に必要になります。
使い方
Web インターフェース
- ブラウザーでクライアントの 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. 接続のライフサイクル
- 初期化:クライアントは WebSocket を確立する前に、HTTP 経由でエージェントを作成します
- 接続:クライアントはエージェント固有の WebSocket エンドポイントに接続します
- ハートビート:クライアントは接続を維持するため、定期的に ping を送信します
- 終了:どちら側からでも接続を閉じることができます
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 のサポートを追加すると、次のような利点があります。
-
低レイテンシ:迅速なやり取りが必要な状況に最適です
- 高頻度取引
- リアルタイムの共同作業環境
- 迅速な応答を必要とする対話型エージェント
-
双方向通信:新しいインタラクションパターンを実現します
- クライアントによるポーリングなしで、サーバーが更新をプッシュできます
- 大きなレスポンスを分割してストリーミングできます
- 外部イベントのプッシュ通知を送信できます
-
ネットワークオーバーヘッドの削減:頻繁な通信をより効率的に行えます
- リクエストごとの HTTP ヘッダーのオーバーヘッドがありません
- 接続の確立にかかるコストを複数のリクエストで分散できます
- モバイルネットワークで特に役立ちます
-
ステートフルなセッション:会話のコンテキストを維持しやすくなります
- サーバーは WebSocket 接続に状態を関連付けられます
- クライアントはリクエストごとにコンテキスト全体を送信する必要がありません
- ストリーミングレスポンスや部分的な更新を実装しやすくなります
課題と解決策
WebSocket には課題もありますが、この実装では次のように対処しています。
-
接続管理:
- 課題:WebSocket 接続が予期せず切断されることがあります
- 解決策:ハートビート機構と自動再接続
-
ステートレスなワーカー:
- 課題:Cloudflare Workers はデフォルトでステートレスです
- 解決策:Durable Objects で接続状態を維持します
-
リクエストとレスポンスの対応付け:
- 課題:共有チャネル上でレスポンスをリクエストに対応付ける必要があります
- 解決策:メッセージ ID の追跡と相関付け
-
エラー処理:
- 課題:接続障害を適切に処理する必要があります
- 解決策:構造化されたエラーレスポンスと再接続ロジック
コントリビューション
コントリビューションを歓迎します!お気軽にプルリクエストを送信してください。
ライセンス
このプロジェクトは MIT ライセンスの下でライセンスされています。詳細については LICENSE ファイルをご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。