mcp-protocol-server-implementation
公式の@modelcontextprotocol/sdkクライアントと連携するMCP(Model Context Protocol)サーバー実装の要件です。以下の場合に使用してください:(1)MCPサーバーをゼロから実装する、(2)「Expected initialize response」エラーが発生する、(3)MCPクライアントが接続できない、またはタイムアウトする、(4)tools/listは成功するがクライアントがサーバーを認識しない、(5)MCP Streamable HTTPトランスポートを実装する。initializeメソッド、通知処理、SSEレスポンス形式、セッション管理について解説します。
description の原文を見る
Requirements for implementing an MCP (Model Context Protocol) server that works with the official @modelcontextprotocol/sdk client. Use when: (1) implementing an MCP server from scratch, (2) getting "Expected initialize response" errors, (3) MCP client fails to connect or times out, (4) tools/list returns successfully but client doesn't recognize server, (5) implementing MCP Streamable HTTP transport. Covers initialize method, notification handling, SSE response format, and session management.
SKILL.md 本文
MCPプロトコルサーバー実装
問題
カスタムMCPサーバーを実装する場合、公式のMCP SDKクライアント(@modelcontextprotocol/sdk)のStreamableHTTPClientTransportが接続に失敗したり、タイムアウトしたりすることがあります。これはtools/listが正しいJSON-RPC応答を返している場合でも発生します。
コンテキスト / トリガー条件
- カスタムMCPサーバー(Lambda、Express等)を一から構築している
@modelcontextprotocol/sdkからStreamableHTTPClientTransportを使用している- クライアントが「Expected initialize response」エラーをスローする
- 接続中にクライアントがタイムアウトする
- サーバーが
tools/listの有効なJSON-RPCを返すが、クライアントが機能しない tools/listへの直接curlは機能するが、SDKクライアントは失敗する
ソリューション
1. initializeメソッドを処理する(必須)
SDKクライアントは最初のリクエストとしてinitializeを送信します。サーバーは以下のように応答する必要があります。
if (method === "initialize") {
return {
jsonrpc: "2.0",
id,
result: {
protocolVersion: "2024-11-05", // Current MCP protocol version
serverInfo: {
name: "your-server-name",
version: "1.0.0",
},
capabilities: {
tools: {}, // Indicates server supports tools
},
},
};
}
2. 通知を処理する(必須)
クライアントはinitialize後にnotifications/initializedを送信します。JSON-RPC 2.0仕様に従い、通知にはidフィールドがなく、サーバーは応答ボディを送信してはいけません。
// Check if message is a notification
function isNotification(message: McpRequest): boolean {
return message.id === undefined;
}
// In handler:
if (isNotification(mcpRequest)) {
// Return 202 Accepted with empty body
return { statusCode: 202, headers, body: "" };
}
3. SSE応答フォーマット(推奨)
クライアントがAccept: text/event-streamを送信する場合、SSE形式で応答します。
function formatAsSSE(response: McpResponse): string {
return `event: message\ndata: ${JSON.stringify(response)}\n\n`;
}
function clientAcceptsSSE(acceptHeader: string | undefined): boolean {
return acceptHeader?.includes("text/event-stream") ?? false;
}
// Set Content-Type accordingly
const contentType = useSSE ? "text/event-stream" : "application/json";
4. セッション管理(推奨)
mcp-session-idヘッダーを介してセッションを追跡します。
const incomingSessionId = headers["mcp-session-id"];
const sessionId = incomingSessionId ?? randomUUID();
// Include in response headers
responseHeaders["mcp-session-id"] = sessionId;
responseHeaders["Access-Control-Expose-Headers"] = "mcp-session-id";
5. CORSヘッダー(ブラウザクライアント必須)
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers":
"Content-Type,Authorization,mcp-session-id,mcp-protocol-version",
"Access-Control-Allow-Methods": "GET,POST,OPTIONS",
"Access-Control-Expose-Headers": "mcp-session-id",
"Cache-Control": "no-cache",
};
検証
- まずcurlでテストします:
# Test initialize
curl -X POST https://your-server/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'
# Should return protocolVersion, serverInfo, capabilities
# Test tools/list
curl -X POST https://your-server/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
- 次にMCP SDKクライアントでテストします:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "test", version: "1.0.0" });
const transport = new StreamableHTTPClientTransport(
new URL("https://your-server/mcp"),
);
await client.connect(transport);
const tools = await client.listTools();
例
最小限のMCPサーバーハンドラー完全版:
export function handler(event: APIGatewayProxyEvent): APIGatewayProxyResult {
const headers = { "Content-Type": "application/json" /* CORS headers */ };
if (event.httpMethod === "OPTIONS") {
return { statusCode: 200, headers, body: "" };
}
const request = JSON.parse(event.body ?? "{}");
// Handle notifications (no id = notification)
if (request.id === undefined) {
return { statusCode: 202, headers, body: "" };
}
// Handle methods
switch (request.method) {
case "initialize":
return {
statusCode: 200,
headers,
body: JSON.stringify({
jsonrpc: "2.0",
id: request.id,
result: {
protocolVersion: "2024-11-05",
serverInfo: { name: "my-server", version: "1.0.0" },
capabilities: { tools: {} },
},
}),
};
case "tools/list":
return {
statusCode: 200,
headers,
body: JSON.stringify({
jsonrpc: "2.0",
id: request.id,
result: { tools: MY_TOOLS },
}),
};
case "tools/call":
// Handle tool execution
break;
default:
return {
statusCode: 200,
headers,
body: JSON.stringify({
jsonrpc: "2.0",
id: request.id,
error: {
code: -32601,
message: `Method not found: ${request.method}`,
},
}),
};
}
}
注記
- プロトコルバージョン: 2026年初頭の時点では
2024-11-05を使用します。MCPスペックで更新を確認してください。 - JSON-RPCエラーコード:
-32700: パースエラー-32600: 無効なリクエスト-32601: メソッドが見つかりません-32603: 内部エラー
- メソッド呼び出し順序: クライアントは常に最初に
initializeを送信し、次にnotifications/initializedを送信してから、tools/listなどの他のメソッドを送信します。 - タイムアウトの問題: クライアントがタイムアウトする場合は、
initializeの応答が正しいことを確認してください。これが最も一般的な原因です。
参考資料
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- cajias
- リポジトリ
- cajias/claude-skills
- ライセンス
- MIT
- 最終更新
- 2026/5/9
Source: https://github.com/cajias/claude-skills / ライセンス: MIT
関連スキル
agent-browser
AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。
anyskill
AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。
engram
AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。
skyvern
AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。
pinchbench
PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。
openui
OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。