MCPサーバー

MCPサーバーのテスト・デバッグ手順|接続障害を層別に切り分ける

MCPの接続エラーは、最初に「どの層まで正常か」を確定すると短時間で絞り込めます。実行環境、トランスポート、プロトコル、公開スキーマ、認証・認可、外部サービス、業務結果の順に境界を置き、各境界で観測事実を一つずつ残すのが基本です。本稿はMCPサーバー開発者と社内接続を担当する情報システム部門を対象に、再現記録を完成させるところまで扱います。

MCPサーバーの接続障害を七つの層へ分解する

「つながらない」という申告だけでは、サーバープロセスが起動していないのか、接続後のツール実行が失敗したのかを区別できません。最初の聞き取りでは、利用したクライアント、サーバーの配布版、選択したトランスポート、MCPプロトコル版、失敗したメソッド、発生時刻、直前に成功した時刻を記録します。画面上の文言より、終了コード、HTTP状態、JSON-RPCのエラーコード、要求IDを優先してください。

MCP仕様2026-07-28はJSON-RPC 2.0を土台とし、要求ごとのメタデータでプロトコル版とクライアント能力を伝えるステートレスな設計です。旧版で使われた接続単位の初期化やセッションを前提に調査すると、新版の正常通信を異常と誤認します。反対に、旧クライアントへ新版だけの期待値を当てても原因は見えません。まず双方が宣言する版を証拠に残すことが、層別調査の入口です[1]

確認対象合格とみなす観測失敗時の担当
1. 実行環境実行ファイル、作業フォルダー、環境変数、依存版同一設定でプロセスが再起動できる開発者または端末管理者
2. トランスポートstdioまたはStreamable HTTPの入出力要求と応答が壊れず往復する開発者またはネットワーク担当
3. プロトコルJSON-RPC形式、MCP版、能力宣言版不一致や必須項目不足がないMCP実装担当
4. 公開スキーマtools、resources、promptsの名前と引数一覧と実装が同じ契約を示すサーバー開発者
5. 認証・認可主体、トークン、audience、scope、許可判定許可と拒否がテスト設計どおりになるIAMまたはセキュリティ担当
6. 外部依存接続先API、DB、キュー、DNS、証明書MCPを外した単独試験でも応答する接続先システム所有者
7. 業務結果取得件数、更新内容、重複実行、監査記録期待した結果と副作用が一致する業務責任者

調査の目的はもっともらしい原因名を付けることではなく、「層4までは合格し、層5の拒否で止まる」のように、最後に成功した境界を再現可能な証拠で示すことです。

この表を一行ずつ埋めれば、担当部署へ渡す情報も明確になります。たとえば一覧取得は成功するが特定ツールだけ403になる場合、起動確認を繰り返す必要はありません。認可ポリシー、要求scope、対象データの所有権へ調査を移します。逆に、stdioプロセスが直後に終了するなら、OAuth設定を先に読むより終了コードと標準エラーを確認する方が合理的です。

本番から隔離した再現環境を作る

再現環境は、障害を再び起こしても顧客データや本番資産を変えないことが条件です。ローカルstdioなら専用の作業フォルダー、読み取り専用のサンプルデータ、期限付きのテスト資格情報を用意します。リモートHTTPならテスト用エンドポイント、テストテナント、出口通信の許可先を限定した実行場所を使います。削除、送信、決済、権限変更を行うツールは、モックへ差し替えるか、対象IDをテスト資産へ強制するガードをコード側に置きます。

記録する実行条件は、OS、CPUアーキテクチャ、言語ランタイム、MCP SDK、サーバーのコミットまたはパッケージ版、Inspectorの解決版、クライアント版、プロトコル版です。Node.js製サーバーなら、少なくとも次の出力とロックファイルのハッシュを障害票へ添付します。秘密値そのものは採取せず、設定の有無、発行先、scope、失効時刻を別欄へ書きます。

node --version
npm --version
npm ls --depth=0
git rev-parse HEAD
git status --short
# UIでローカルstdioサーバーを確認する例
npx @modelcontextprotocol/inspector node dist/server.js
# CLIで公開ツールだけを列挙する例
npx @modelcontextprotocol/inspector --cli node dist/server.js --method tools/list

MCPの公式デバッグガイドは、作業フォルダーの不定、環境変数の不足、実行ファイルのパス、設定JSONの型不一致を代表的な起動原因として挙げています。また、stdioではプロトコルの通信に標準出力を使うため、アプリのログをstdoutへ書くとフレームが壊れます。診断ログはstderrへ送り、HTTP接続ではサーバー側のログ基盤やOpenTelemetryへ出す、という分離が必要です[2]

InspectorはMCPサーバーを対話的に検査でき、ツール、リソース、プロンプト、通知を個別に確認できます。公式ガイドの2026-07-28版には、stdioとStreamable HTTPの双方を対象とすること、無効入力や引数不足、並行処理も試すことが示されています[3]

ただしInspectorのプロキシにはローカルプロセスを起動する権限があるため、インターネットへ公開してはいけません。localhost以外へバインドする必要が出た時点で通常の開発確認を停止し、ネットワーク管理者の承認対象へ切り替えます。

起動とトランスポートを確かめる

stdioは「起動した」と「会話できた」を分ける

stdioサーバーでは、同じコマンドを端末から実行して待機するか、すぐ終了するかを見ます。すぐ終了した場合は終了コード、stderrの先頭エラー、実際の作業フォルダー、実行ユーザー、PATHを保存します。

端末では動くのにMCPクライアントから起動できない場合、相対パス、ログインシェルだけに設定された環境変数、GUIアプリへ継承されない資格情報が主な差分です。設定ファイルのcommandとargsは配列境界を保ち、Windowsでは実行ファイルとスクリプトの絶対パスを一度試します。

プロセスが残っていても、stdoutへ通常ログを一行出しただけでJSON-RPCの読み取りが破綻することがあります。診断時は標準出力をプロトコル専用、標準エラーを観測専用として扱います。最小の一覧要求を送り、要求IDと同じIDを持つresultまたはerrorが返るまでを一単位とします。応答がないときは、サーバーが入力待ちなのか、別の文字コードや改行処理で詰まったのかをプロセス監視とstderrで区別します。

Streamable HTTPはHTTPとMCPの証拠を別々に残す

HTTPではDNS、TLS、プロキシ、ロードバランサー、認証ミドルウェア、MCPハンドラーの順に通過します。404ならURLやルーティング、401なら認証開始、403なら認可、415ならContent-Type、400とJSON-RPC errorなら要求形式を疑います。タイムアウトは「何秒で、どの層が打ち切ったか」を必ず書き、クライアント側30秒とサーバー側5分を同じ障害名にしないでください。

観測時刻: 2026-07-30T14:05:21+09:00
transport: streamable-http
endpoint: テスト環境のMCP URL
HTTP status: 400
JSON-RPC id: 184
error.code: -32022
error.message: Unsupported protocol version
client protocol: 2025-11-25
server accepted: 2026-07-28
trace id: 取得できた値を記録

2026-07-28仕様では、要求が前の接続状態へ依存しないことが原則です。特定のサーバーインスタンスへ固定したときだけ成功するなら、MCPの接続問題ではなく、アプリケーション状態を暗黙のメモリーやプロセス内セッションへ置いている可能性があります。必要な状態は明示的なハンドルとしてツール引数へ渡し、別インスタンスでも同じ結果になるかを確認します。

プロトコルとツール定義を検査する

トランスポートが往復したら、いきなり本番相当のツールを呼ばず、一覧、正常な読み取り、無効引数の順で契約を確認します。Model Context Protocol公式仕様「Base Protocol: Overview」2026-07-28版は、JSON-RPCの一般エラーに加え、ヘッダーと本文の不一致を示す-32020、必要なクライアント能力がない場合の-32021、対応外のプロトコル版に対する-32022を定義しています。必須の要求メタデータが欠けた場合は-32602となるため、旧SDKが生成した要求と新版の期待値を並べると差を見つけやすくなります[1]

tools/listでは、ツール名、説明、inputSchema、outputSchema、注記、公開数を保存します。サーバーの実装コードだけを正としてはいけません。クライアントが実際に受け取った定義が外部契約です。必須引数を一つ欠かす、型を文字列から配列へ変える、許容外の列挙値を渡す、未知のプロパティを加えるという四種類の負例を作り、どれがクライアントで拒否され、どれがサーバーで拒否されるかを記録します。

ケース入力期待結果不合格の意味
一覧tools/list承認済みツールだけが重複なく返る公開設定またはキャッシュのずれ
正常最小必須項目だけを持つ引数resultTypeと所定の結果形式が返る実装とスキーマの不一致
必須欠落識別子を省略副作用なしでInvalid params入力検証の欠落
境界値空文字、上限値、上限超過仕様どおり受理または拒否上限定義と実装のずれ
未知ツール存在しないツール名外部処理を始めず明示的に失敗ルーティングの誤り
並行要求異なるIDで同時に二件IDと結果が正しく対応する共有状態または相関処理の欠陥

結果が文章で返るツールでも、業務側で必要な識別子、件数、状態、警告を機械判定できる形にします。HTTP 200でも結果本文が空、検索0件でも成功扱い、更新対象が二件なのに一件だけ処理という問題はプロトコルテストだけでは見落とします。層4の合格条件には構文だけでなく、業務上の最小成果を含めてください。

権限エラーと外部障害を分離する

認証は「誰か」を確かめ、認可は「その主体がこの操作をしてよいか」を決めます。テスト資格情報は、閲覧だけ、限定更新、無権限、期限切れの少なくとも四種類を準備します。管理者トークンだけで正常系を通すと、一般利用者の403、テナント境界、対象行単位の制約を検証できません。成功する強い権限と失敗する弱い権限を対にして、拒否時に外部APIへ一件も到達していないことまで確認します。

HTTPベースのMCP認可仕様2026-07-28は、保護対象メタデータによる認可サーバー発見、対象リソースを示すresource、操作に必要なscope、トークンの検証を定めています。一方、stdioは同じOAuthフローをそのまま使う前提ではなく、資格情報を環境から取得する扱いです[5]。接続方式をまたいで同じ設定項目を機械的にコピーせず、主体、保管場所、失効方法をトランスポート別に設計します。

公式のセキュリティ解説は、MCPサーバー向けに発行されていないトークンの受け入れと、下流APIへの未検証トークン転送を明確な危険として説明しています[4]。テストではaudienceが別サービスのトークンを投入し、MCPサーバーが拒否することを確かめます。拒否せず下流へ届いた場合は重大不具合として試験を中断し、採取済みトークンを失効させます。

試験入力期待する停止位置確認するログ続行可否
署名不正トークンMCP入口で401検証失敗、要求ID、発行者資格情報を更新後に再試験
別audience下流転送前に拒否対象不一致と外部呼出し0件転送されたら即時停止
scope不足ツール実行前に403または仕様所定のchallenge必要scopeと付与scope最小権限の設計を見直す
下流APIの429認可通過後の依存層再試行回数、Retry-After、相関ID上限回数内だけ再試行
下流APIの500依存層で失敗下流状態、MCP変換結果、重複防止ID書き込み結果不明なら止める

外部サービスをモックへ切り替えてMCP処理だけを通し、次に同じ要求を外部APIへ直接送って依存側だけを測ると責任境界が見えます。更新ツールではタイムアウト後の再試行が二重更新を生むため、冪等キー、処理済み照会、ロールバックのいずれもない状態で自動再試行してはいけません。結果不明のまま同じ更新を再送する必要が生じたら、業務所有者へ確認を戻します。

エラー表示から次の確認先を決める

エラー文は原因そのものではなく、どの層が観測したかを示す手掛かりです。たとえば「connection closed」は、サーバーの異常終了、クライアントのタイムアウト、HTTP中継の切断で同じように見えます。メッセージだけを検索せず、その直前にサーバープロセスが残っていたか、HTTP応答が存在したか、JSON-RPCのerrorオブジェクトが返ったかを並べます。ローカルSDKが作ったタイムアウトを、相手が返したJSON-RPCエラーとして記録しないことも重要です。

表示・コード例第一候補最初の確認次の一手
ENOENT / command not found実行環境絶対パスと実行ユーザークライアントから同じ実行ファイルを起動
Unexpected token in JSONstdio汚染stdoutの先頭バイト通常ログをstderrへ移す
-32700JSON解析送受信した生データ文字コードとフレーミングを点検
-32601メソッド不一致要求methodと対応版クライアント・サーバーの機能表を照合
-32602引数または必須メタデータinputSchemaと要求payload欠落、型、版宣言を一項目ずつ修正
-32020HTTPヘッダー不一致ヘッダーと本文のmethod/nameゲートウェイ変換を含めて比較
-32022プロトコル版不一致双方が宣言した版互換表に沿ってSDKをそろえる
401 / 403認証または認可WWW-Authenticate、audience、scope資格情報の強化ではなく必要権限を確認
timeout複数候補打切主体と設定秒数クライアント、プロキシ、サーバーを個別計測

具体例として、tools/listが成功しtools/callだけ-32602になるなら、接続再設定より引数と要求メタデータを調べます。全ツールが一律403なら対象データより認可共通部を疑い、一つのテナントだけ403なら行またはテナント単位のポリシーへ進みます。毎回異なる時間で切れるなら依存先の遅延分布、常に30秒ならクライアントの固定タイムアウトというように、再現パターンから調査対象を狭めます。

エラーを握りつぶして空の成功結果へ変換する実装は、復旧ではなく誤判定を増やします。利用者向けには安全な要約を返しても、サーバーログには分類可能なエラー種別、相関ID、再試行可否、外部処理の成立状況を残します。ただしアクセストークン、Authorizationヘッダー、入力本文の個人情報はマスクし、調査権限を持つ担当者だけが詳細へ到達できるようにします。

修正を回帰テストへ固定する

修正後に一度成功しただけでは、同じ障害を防げません。障害を起こした最小入力を匿名化し、正常系、境界値、拒否系、依存障害、並行実行のケースへ追加します。テスト名には期待する層を含め、失敗したときに担当を割り当てられるようにします。サーバー版、SDK版、プロトコル版、ツール定義のハッシュを実行結果と結び付けると、後から「どの契約で通ったか」を説明できます。

case_id: AUTH-AUD-004
protocol: 2026-07-28
transport: streamable-http
tool: documents.update
fixture: tenant-b/document-17
credential: token-for-another-resource
expected:
protocol_result: rejection
downstream_calls: 0
changed_records: 0
secret_in_log: false
stop_if:
- downstream_calls > 0
- changed_records > 0
owner: IAM担当
evidence: trace_id とマスク済みログ

想定例として、全48件を「必須24件、通常16件、観察8件」に分けます。必須ケース合格率は合格必須件数÷24、全体合格率は合格総数÷48で計算します。必須24件がすべて通り、全体46件合格なら、必須合格率は100%、全体合格率は46÷48=95.8%です。ただし別audienceのトークン転送や本番データ更新が一件でも発生した場合は、平均点にかかわらず不合格とします。数値は説明用の想定であり、実運用ではツールの影響度に応じて母数と必須条件を決めます。

判定項目合格条件証拠不合格時
版互換対応対象の全プロトコル列が合格SDK別テスト結果対応版を限定して再設計
スキーマ一覧と実装契約の差分0件定義ハッシュと差分破壊的変更を別版へ分離
最小権限許可・拒否の組合せが期待どおり主体別実行記録認可ポリシーを修正
副作用拒否・失敗時の更新0件監査ログとDB差分公開を中止して復旧
観測性全要求を相関IDで追跡可能マスク済みトレースログ設計を先に直す
復旧固定した旧版へ規定時間内に戻せるロールバック演習本番移行を延期

CIでInspectorのCLIを使う場合も、パッケージを毎回無条件に最新版へ解決せず、承認した版をロックファイルで固定します。MCP仕様やSDKの更新は通常のアプリ変更と別の差分として評価し、プロトコル版、サーバー実装、テストツールを同時に上げない方が原因を追いやすくなります。一つの変更単位につき比較対象を一つに抑えるのが、デバッグ可能性を保つ実務上の要点です。

運用移行・停止・引き継ぎを判断する

開発者だけで解決を続けてよいのは、テスト環境で再現でき、影響範囲が限定され、資格情報の漏えいや本番副作用がなく、修正後の回帰ケースを作れる場合です。認証基盤、ネットワーク境界、個人情報、契約先API、顧客データが関係したら、それぞれの所有者へ調査を引き継ぎます。引き継ぎ票には推測を書き連ねず、最後に成功した層、最初に失敗した層、再現手順、時刻、版、要求ID、マスク済みログ、すでに除外した原因を入れます。

次のいずれかを観測したら、テストの自動続行を止めます。第一群は、テスト用でないレコードの変更、別テナントのデータ取得、秘密値のログ出力、想定外の外部送信です。第二群は、未承認ツールの出現、トークンのaudience検証失敗、更新結果が不明な状態での再試行です。同じ要求の連続失敗が設定上限へ到達した場合も停止します。停止後は資格情報の失効、ネットワーク遮断、影響レコードの保全を先に行い、原因追究のために危険な状態を再現し続けません。

MCP Inspectorによる直接確認が向かないケース

本番専用資格情報しかなく、呼び出すだけで送信・削除・決済が確定し、隔離先も取消手段もないツールには向きません。この状況ではInspectorで本番操作を試さず、録画済み要求、モック、読み取り専用の診断エンドポイント、コードレビューを組み合わせます。安全な試験面を用意できないこと自体を、リリースを見送る理由として扱います。

運用へ移す際は、成功率だけでなく、p95応答時間、認可拒否率、外部依存別エラー率、タイムアウト後の結果不明件数、未承認スキーマ差分を監視します。アラートから要求ID、サーバー版、ツール名、主体、外部相関IDへたどれることを当番担当者が演習します。障害対応手順が特定の開発者の端末履歴にしかないなら、技術的に直っていても運用準備は未完了です。

最後に、旧版対応を残す期間と終了条件を決めます。MCP 2026-07-28では旧版から変わったエラーや通信前提があるため、互換分岐を無期限に維持するとテスト行列が増えます。利用中クライアントの数、移行期限、旧版専用障害の件数を見て、廃止日を事前通知します。終了日を越えた旧要求は曖昧に処理せず、対応外の版として識別可能に拒否します。

MCP接続障害の最初の30分で行うこと

次の行動:当番担当者は、対象サーバーとクライアントの版を固定し、Inspectorまたは最小クライアントでtools/listまでを再現します。七層表へ最後の成功点と最初の失敗点を書き、別audience、外部送信、本番更新の兆候があれば直ちに止めます。再現入力と期待結果を一件の回帰ケースへ変換し、要求IDとマスク済みログを引き継ぎ票へ添付します。

参考文献・出典

  1. Model Context Protocol「Base Protocol: Overview」(仕様版2026-07-28、公開日2026年7月28日、参照日2026年7月30日)
  2. Model Context Protocol「Debugging」(文書版2026-07-28、参照日2026年7月30日)
  3. Model Context Protocol「MCP Inspector」(文書版2026-07-28、参照日2026年7月30日)
  4. Model Context Protocol「Security Best Practices」(文書版2026-07-28、参照日2026年7月30日)
  5. Model Context Protocol「Authorization」(仕様版2026-07-28、公開日2026年7月28日、参照日2026年7月30日)

関連記事

新着記事
  1. RAGシステムの作り方|文書取り込みから回答評価まで

  2. RAGとは|検索拡張生成の仕組み・用途・生成AI単体との違い

  3. プロンプトインジェクション対策|外部文書・ツール利用時の守り方

TOP

EmMatch AIPをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む