MCP の仕様 (4) - 基本プロトコル - ライフサイクル
以下の記事が面白かったので、簡単にまとめました。
前回
1. ライフサイクル
「MCP」は、クライアントサーバ接続の厳格なライフサイクルを定義し、適切な機能ネゴシエーションと状態管理を保証します。
・Initialization
機能ネゴシエーションとプロトコルバージョンの合意
・Operation
通常のプロトコル通信
・Shutdown
接続の正常な終了

2. ライフサイクルフェーズ
2-1. Initialization
Initializationフェーズは、クライアントとサーバ間の最初のやり取りでなければなりません。このフェーズでは、クライアントとサーバは以下の処理を行います。
・プロトコルバージョンの互換性を確立する
・機能の交換とネゴシエーションを行う
・実装の詳細を共有する
クライアントは、以下の情報を含む初期化リクエストを送信することにより、このフェーズを開始しなければなりません。
・サポートされているプロトコルバージョン
・クライアントの機能
・クライアントの実装情報
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {},
"elicitation": {}
},
"clientInfo": {
"name": "ExampleClient",
"title": "Example Client Display Name",
"version": "1.0.0"
}
}
}サーバは自身の機能と情報で応答しなければなりません。
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"tools": {
"listChanged": true
}
},
"serverInfo": {
"name": "ExampleServer",
"title": "Example Server Display Name",
"version": "1.0.0"
},
"instructions": "Optional instructions for the client"
}
}初期化が成功した後、クライアントは通常の操作を開始する準備ができていることを示す初期化通知を送信する必要があります。
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}・クライアントは、サーバが初期化要求に応答する前に、ping 以外の要求を送信すべきではありません。
・サーバは、初期化通知を受信する前に、ping とログ記録以外の要求を送信すべきではありません。
・バージョンネゴシエーション
クライアントは、初期化リクエストにおいて、サポートするプロトコルバージョンを送信しなければなりません(MUST)。これは、クライアントがサポートする最新バージョンである必要があります。
サーバが要求されたプロトコルバージョンをサポートしている場合、同じバージョンで応答しなければなりません(MUST)。そうでない場合、サーバはサポートする別のプロトコルバージョンで応答しなければなりません(MUST)。これは、サーバがサポートする最新バージョンである必要があります。
クライアントがサーバの応答でサポートしていないバージョンをサポートしている場合、接続を切断する必要があります(SHOULD)。
HTTPを使用する場合、クライアントはMCPサーバへの後続のすべてのリクエストにMCP-Protocol-Version: <protocol-version> HTTPヘッダーを含める必要があります。詳細については、「トランスポート」の「プロトコルバージョンヘッダー」セクションを参照してください。
・機能ネゴシエーション
クライアントとサーバの機能により、セッション中に利用可能なオプションのプロトコル機能が決定されます。
主な機能は次のとおりです。
◎ クライアント
・roots
ファイルシステムルートの提供が可能
・sampling
LLMサンプリングリクエストのサポート
・elicitation
サーバの抽出リクエストのサポート
・experimental
非標準の試験的機能のサポートについて説明
◎ サーバ
・prompts
プロンプトテンプレートを提供
・resources
読み取り可能なリソースを提供
・tools
呼び出し可能なツールを公開
・logging
構造化されたログメッセージを出力
・completions
引数の自動補完をサポート
・experimental
非標準の試験的機能のサポートについて説明
機能オブジェクトは、次のようなサブ機能を記述できます。
・listChanged
リストの変更通知のサポート (プロンプト、リソース、ツール用)
・subscribe
個々のアイテムの変更の購読のサポート (リソースのみ)
2-2. Operation
Operationフェーズでは、クライアントとサーバはネゴシエートされた機能に従ってメッセージを交換します。
双方は以下の要件を満たす必要があります。
・ネゴシエートされたプロトコルバージョンを尊重する
・ネゴシエートに成功した機能のみを使用する
2-3. Shutdown
Shutdownフェーズでは、一方 (通常はクライアント) がプロトコル接続をクリーンに終了します。特定のシャットダウンメッセージは定義されていません。代わりに、基盤となるトランスポートメカニズムを使用して接続終了を通知する必要があります。
・stdio
stdio トランスポートの場合、クライアントは以下の方法でシャットダウンを開始する必要があります。
(1) まず、子プロセス (サーバ) への入力ストリームを閉じます。
(2) サーバが終了するのを待ちます。サーバが適切な時間内に終了しない場合は SIGTERM を送信します。
(3) SIGTERM 送信後、適切な時間内にサーバが終了しない場合は SIGKILL を送信します。
サーバは、クライアントへの出力ストリームを閉じて終了することでシャットダウンを開始できます。
・HTTP
HTTP トランスポートの場合、シャットダウンは関連する HTTP 接続を閉じることで示されます。
3. タイムアウト
実装は、接続のハングやリソース枯渇を防ぐため、送信されたすべてのリクエストにタイムアウトを設定する必要があります(SHOULD)。リクエストがタイムアウト期間内に成功またはエラーのレスポンスを受信しなかった場合、送信者はそのリクエストのキャンセル通知を発行し、レスポンスの待機を停止する必要があります(SHOULD)。
SDKやその他のミドルウェアは、これらのタイムアウトをリクエストごとに設定できるようにする必要があります(SHOULD)。
実装は、リクエストに対応する進捗通知を受信したときにタイムアウトクロックをリセットすることを選択できます(MAY)。これは、作業が実際に行われていることを意味するためです。ただし、クライアントまたはサーバの不正な動作による影響を制限するため、実装は進捗通知の有無にかかわらず、常に最大タイムアウトを強制する必要があります(SHOULD)。
4. エラー処理
実装は、以下のエラーケースを処理できるように準備しておく必要があります。
・プロトコルバージョンの不一致
・必要な機能のネゴシエーション失敗
・リクエストのタイムアウト
・初期化エラーの例
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Unsupported protocol version",
"data": {
"supported": ["2024-11-05"],
"requested": "1.0.0"
}
}
}