mcp-failure-lab について
MCP Failure Labは、プロトコルやトランスポートの障害時におけるMCPクライアントの動作を調べる、決定論的な障害注入サーバー兼テストランナーです。クライアントや統合の開発者向けに、再現可能なシナリオ、障害後の接続確認、CIレポートを提供します。
主な機能
- 01再現可能なプロトコル障害シナリオ
- 02タイムアウトとキャンセルのテスト
- 03切断と不正応答のテスト
- 04障害後の接続確認
- 05JSONとJUnitのレポート
活用シーン
- 01タイムアウト後のクライアント動作をテスト
- 02障害後に接続が使えるか確認
- 03トランスポート別にSDKの挙動を比較
- 04CIで障害シナリオを実行
MCP 対応
組み込みMCPサーバーは、遅延、ハング、切断、不正または重複した応答、セッション喪失、過大な応答、不正な進捗通知を再現するツールを公開します。クライアントテスト用にstdioまたはローカルのStreamable HTTPで実行できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
MCP Failure Lab
MCP のタイムアウト、キャンセル競合、トランスポートの切断、不正なレスポンスを、再現可能なテストと CI レポートで再現します。
出力例(所要時間は変動します):
$ npx mcp-failure-lab demo
MCP Failure Lab — Demo
Running a real 500ms delay scenario...
Scenario: Deterministic delay demo
Outcome: success
Duration: ~500 ms
Assertions: passed
これを作った理由
実際の MCP クライアントは、障害発生時の挙動がそれぞれ異なります。タイムアウト後も接続を使える場合もあれば、応答が中断されると接続が閉じる場合もあります。不正な応答を拒否するクライアントもあれば、受け入れるクライアントもあります。
Failure Lab を使えば、こうした状況を再現可能な形でテストできるため、失敗した呼び出しと、その後の挙動の両方を確認できます。
実際の事例
- Python SDK #3522:Python
mcp2.2.0 は、HTTP 応答が中断された後も接続を閉じたままにし、次のリクエストを拒否し、クリーンアップ時にExceptionGroupを発生させました。 - Rust SDK #1283:
rmcp3.4.0 は、stdio と HTTP の両方で、resultとerrorの両方を含む不正な応答を受け入れました。 - Ruby SDK #589:
mcp1.6.1 は、3 回の繰り返しすべてで、stdio と HTTP の両方においてjsonrpcが欠落した応答、またはjsonrpc: "1.0"を宣言した応答を受け入れました。Ruby レポートには、60 回すべての実行結果が記録されています。結果と上流での調査結果は Observatory のエクスポートにも含まれています。 - Java SDK 2.0.1 は、両方のトランスポートで
jsonrpc: "1.0"を受け入れました(#1156)。stdio では、jsonrpcが欠落した応答、またはresultとerrorの両方を含む応答を受け取ると、次のpingがタイムアウトしました(#1157)。Java レポートをご覧ください。 - 重複応答の比較:テスト対象となった 5 つすべての SDK で、次の
pingが完了しました。TypeScript はエラーコールバックを通じて重複を報告しましたが、他のハーネスでは呼び出しレベルの重複エラーは報告されませんでした。
SDK の比較結果は、テストした特定のバージョンに関するものであり、すべてのリリースに当てはまるわけではありません。 再現手順と制限事項については、バージョン別レポートをご覧ください。

クイックスタート
Node.js 22.23.4 以降と npm が必要です。
npx mcp-failure-lab demo
デモに API キー、外部サーバー、グローバルインストールは必要ありません。独自の MCP クライアントをテストするには、stdio またはローカルの Streamable HTTP 経由で Failure Lab に接続してください。
npx mcp-failure-lab serve
# Or:
npx mcp-failure-lab serve --transport http
stdio プロセスはクライアントからの接続を待機します。対話型のターミナルコマンドではありません。クライアントに起動するよう設定するか、スタートガイドに従ってください。
手動で起動したサーバーを停止するには、Ctrl+C を押してください。
HTTP のデフォルトは http://127.0.0.1:3000/mcp です。認証も TLS も提供しません。
信頼できないネットワークに公開しないでください。
独自の MCP サーバーをテストする
外部ターゲットは HTTP と stdio に対応しています。リポジトリのセットアップの後、
実行ファイルが PATH 上にある状態で公式の GitHub MCP サーバーをインストールし、環境内に
GITHUB_PERSONAL_ACCESS_TOKEN を設定してください。その後、次を実行します。
npm run dev -- run examples/scenarios/github-get-me.json \
--target examples/targets/github-stdio.json
この例では、GitHub の読み取り専用の get_me ツールを呼び出します。ターゲット設定では envFrom
を使って、トークンを JSON に保存するのではなく、環境から渡します。
独自のシナリオと
ターゲット設定では、次を使用してください。
npx mcp-failure-lab run scenario.json --target target.json
外部サーバーの実行では、ツールの結果、期限、アダプターのセットアップとクリーンアップを確認します。 別のサーバーに障害を注入することはありません。Failure Lab はプロキシではありません。
前提条件、認証情報の取り扱い、設定については、外部ターゲットガイドをご覧ください。
Failure Lab で発生させられる障害
組み込みサーバーは、クライアントの動作をテストするために、次のツールを公開しています。
| ツール | 動作 |
|---|---|
ping | 決定論的なヘルスレスポンスを返します |
protocol_ping_liveness | 実行中の呼び出し中に、上限付きのプロトコル ping を送信します |
delay | 返す前に、上限付きの時間だけ待機します |
hang | クライアントがキャンセルするまで保留状態になります |
disconnect | リクエストの実行中にアクティブなトランスポートを中断します |
malformed_message | 選択した JSON-RPC レスポンス規則に一度だけ違反します |
duplicate_response | 1 つのリクエストに対して、同じ JSON-RPC レスポンスを 2 回送信します |
response_after_cancellation | キャンセルされた stdio リクエストに対して、遅れて 1 件のレスポンスを送信します |
session_loss | 呼び出し元のレガシー HTTP セッションを無効にします |
oversized_response | 最大 256 KiB の決定論的なテキストペイロードを返します |
invalid_progress | 未知の、後退する、または遅れて届く進捗通知を送信します |
プロトコルの ping は ping ツールとは異なります。組み込みシナリオのデフォルトは MCP 2026-07-28 です。
プロトコルの liveness には、シナリオで protocolVersion: "2025-11-25" を指定する必要があります。
どちらの公開トランスポートもレガシークライアントに対応しています。
タイミングの上限、アクティベーション、キャンセル、クリーンアップ、トランスポートの制限については、障害ツールのリファレンスを参照してください。
oversized_response は、0 から 262,144 までの sizeBytes を受け付けます。ASCII の x
文字だけを生成するため、テキストのサイズは UTF-8 バイト単位で正確で、外部データは含まれません。上限は stdio と HTTP の両方に適用されます。成功を確認するには、クライアントに設定されたレスポンス制限より小さいサイズを選び、クライアントによる拒否を確認するには、その制限より大きいサイズ(ただし 262,144 以下)を選んでください。付属の64 KiB シナリオでは、返されるテキストの正確なサイズと後続のリクエストを確認します。JSON-RPC とトランスポートのフレーミングによってテキストの前後にバイトが追加されるため、sizeBytes がしきい値に達する前に、クライアントのメッセージ全体に対する制限が作動する場合があります。統合テストでは、メッセージ制限が 4 KiB の stdio クライアントが、1 KiB のペイロードを受け入れ、8 KiB のペイロードを拒否することを確認します。
invalid_progress にはクライアントの進捗トークンが必要で、unknown-token、regressing-progress、または after-completion を受け付けます。これらは 1 回のツール呼び出しに関連付けられたプロトコル通知であり、ツールの結果コンテンツではありません。unknown-token バリアントは、異なるトークンで通知を 1 件送信します。regressing バリアントは、進捗 2 の後に 1 を送信します。late バリアントは、stdio、または HTTP レスポンスストリームで、対応するレスポンスの後に通知を 1 件送信します。これらはそれぞれ、リクエストトークンとの相関、単調な進捗、完了したリクエストのライフサイクルに違反します。
各バリアントの実行回数は 1 回に制限されています。後退、未知のトークン、および
完了後のシナリオを参照してください。
組み込みランナーでは、expect.progressValues を使ってコールバック値をアサートできます。外部ターゲットアダプターは進捗通知を報告しないため、このアサーションは使用できません。
リカバリーテストの仕組み
障害を発生させ、その結果を記録した後、同じ接続で2回目のリクエストを行います。 障害が検出されても、リカバリーが成功した証拠にはなりません。後続のリクエストも成功する必要があります。
シナリオの observe 呼び出しは、エラーやタイムアウトを含め、プライマリ呼び出しの後に実行されます。
たとえば、duplicate-response.json は
duplicate_response を呼び出した後、ping を使って接続が引き続き使用可能か確認します。
# From a repository checkout
npm run dev -- run examples/scenarios/duplicate-response.json
これは障害発生後の動作を確認するものであり、自動的なリカバリーポリシーを確認するものではありません。 stdio の切断によってサーバープロセスが終了するため、新しいプロセスと接続が必要です。
結果、所要時間、レスポンス、オブザーバーのアサーションについては、シナリオを参照してください。
SDK/トランスポートのエビデンス
MCP Failure Observatory は、SDK とトランスポートのエビデンスを収集します。 リポジトリのレポートでは、テスト済みのバージョン、メソッド、制限事項を確認できます。
結果は SDK、バージョン、トランスポート、プロトコルによって異なります。 テストに合格した場合、それはその組み合わせについてのエビデンスであり、 すべてのクライアントでの動作を保証するものではありません。
CI での使用方法
明示的な期待値とタイムアウトを設定したシナリオファイルを保存し、 JUnit レポートを生成します。
npx mcp-failure-lab run scenario.json --report junit > junit.xml
アップグレードによってテスト環境が予期せず変わらないよう、CI では Failure Lab パッケージのバージョンを固定してください。
終了コード:0 は期待値を満たしたこと、1 はシナリオを読み込めなかった、または実行できなかったこと、
2 はアサーションに失敗したことを示します。予期されたタイムアウトは合格する場合がありますが、予期しない成功は失敗と判定される場合があります。
JSON、JUnit、ライフサイクル診断については、レポートを参照してください。
ドキュメント
詳細なガイドは mcplab.dev にあります: はじめに · CLI · アーキテクチャ · トラブルシューティング。
コントリビューション
セットアップ、テスト、コントリビューションのワークフローについては、CONTRIBUTING.mdを参照してください。 予定されている作業は GitHub Issues で管理されています。
Failure Lab が MCP 統合のテストに役立った場合は、リポジトリにスターを付けてください。
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。