MCPのエラーコードは-32000番台をどう割り当てるか
MCPはJSON-RPCの予約領域-32000〜-32099番台を、レガシー・MCP予約・自由領域の3つに区分しています。自作サーバーが新しいエラーコードを安全に割り当てる基準をまとめました。
MCPのエラー応答はJSON-RPC 2.0の仕様にそのまま乗っています。標準コード5つは、解析エラーや不正なパラメータなど、実装を問わない一般的な失敗を表す共通コードです。問題はその先です。JSON-RPC自体が実装固有のサーバーエラー用に確保した100個のコード空間を、MCPはどう使い分けているのか。2026-07-28版の仕様は、この領域を3つに区分する明文化されたポリシーを持っています。自作MCPサーバーが独自のエラーコードを割り当てるとき、この区分を知らないと標準コードと衝突する余地を残します。
MCPのエラーコードはなぜ標準の5コードだけでは足りないのか
JSON-RPC 2.0が定義する標準エラーコードは、固定された意味を持つ5つと、実装が自由に使える-32000〜-32099の領域です。たとえば未知のツール名やプロンプト名を渡したとき、カーソルが期限切れのときはいずれも-32602(Invalid params)が返ります。
しかしMCP固有の失敗はこの5つには収まりません。HTTPヘッダーとリクエストボディの値が矛盾している、クライアントが宣言していない機能をサーバーが要求している、リクエストのプロトコルバージョンをサーバーが認識できない。これらはJSON-RPCの一般エラーではなく、MCPというプロトコルの構造に固有の失敗です。MCPは実装定義領域の中に、自分専用のコードを持つ必要がありました。
標準5コードはMCPの中で何を表しているか
標準コードの意味は仕様書の記述だけでは実感しにくいので、MCPの文脈でどう使われるかを見ておきます。
| コード | 名前 | MCPでの主な発生場面 |
|---|---|---|
-32700 | 名前ParseError | MCPでの主な発生場面受信したJSONそのものが構文的に壊れている |
-32600 | 名前InvalidRequestError | MCPでの主な発生場面jsonrpcやmethodの欠落など、リクエストの形が仕様に沿っていない |
-32601 | 名前MethodNotFoundError | MCPでの主な発生場面サーバーが実装していないメソッド、または広告していないサーバー機能配下のメソッド |
-32602 | 名前InvalidParamsError | MCPでの主な発生場面不明なツール名・引数の型不一致・期限切れカーソル・不正なログレベルなど |
-32603 | 名前InternalError | MCPでの主な発生場面受信側の内部で予期しない状態が発生し、リクエストを処理できない |
見落としやすいのは-32601(MethodNotFoundError)と-32021(MissingRequiredClientCapabilityError)の使い分けです。仕様はこの2つを明確に区別しています。サーバーが広告していない機能(たとえばprompts機能を実装していないサーバーにprompts/listを呼んだ場合)は-32601です。一方でクライアントが宣言していない機能をサーバー側が要求する場合は-32021になります。前者はサーバー機能の有無、後者はクライアント機能の有無が原因という違いで、どちらも「機能が足りない」という結果だけを見ると混同しやすいところです。
-32602(InvalidParamsError)がカバーする範囲もMCPでは広く、単一のコードで複数のカテゴリの検証失敗を束ねています。ツール呼び出しでは不明なツール名や引数の型不一致、プロンプト取得では未知のプロンプト名や必須引数の欠落、ページネーションでは無効・期限切れのカーソル、ロギングでは不正なログレベルの指定がここに含まれます。elicitationでは、クライアントのcapabilitiesに宣言されていないモードをサーバーが要求した場合も同じ-32602です。samplingでは、必要なツール実行結果が欠けている、あるいはツール実行結果と他の種類のコンテンツが混在しているケースが該当します。これだけ多様な失敗を1つのコードにまとめている以上、原因の切り分けはmessageとdataの記述に委ねられている、という設計だと分かります。
-32000から-32099までの3区分
2026-07-28版の仕様は、この100個のコード空間を次のように分割しています。
| 範囲 | 区分 | 誰が使えるか |
|---|---|---|
-32000〜-32019 | 区分レガシー | 誰が使えるか新規実装での割り当て禁止。過去の実装が既に使っている分のみ有効 |
-32020〜-32099 | 区分MCP予約 | 誰が使えるかMCP仕様が定義するコードのみ有効。それ以外の値を返してはならない |
レガシー領域は、このポリシーが導入される前に各実装が独自に割り当てていたコードの受け皿です。仕様は新規実装がここに新しいコードを割り当てることを明確に禁止しています。受信側もこの範囲のコードに特定の意味を仮定してはいけません。唯一の例外が-32002で、これは2025-11-25以前の版で「リソースが見つからない」を意味していたコードです。現行版はこの意味を-32602(Invalid params)に統合したため新規実装は-32002を発行しませんが、クライアントは旧サーバーからの-32002を引き続き受け入れるべきだとされています。もう1つの旧コード-32042(URL elicitation required)は2025-11-25版限定の一時的なコードで、現行版には引き継がれていません。
MCP予約領域は逆に、仕様に定義されていないコードを実装が勝手に発行することを禁じています。この領域は仕様のスキーマファイルで一元管理され、定義済みのコードは3つです。
MCPが定義する3つのエラーコード
| コード | 名前 | 発生条件 |
|---|---|---|
-32020 | 名前HeaderMismatch | 発生条件HTTPヘッダーの値がリクエストボディの値と一致しない、または必須ヘッダーが欠落・不正 |
-32021 | 名前MissingRequiredClientCapability | 発生条件サーバーが要求する機能をクライアントがclientCapabilitiesで宣言していない |
-32022 | 名前UnsupportedProtocolVersion | 発生条件リクエストが指定するプロトコルバージョンをサーバーがサポートしていない |
いずれもHTTP経由では応答ステータスを400 Bad Requestにすることが仕様で定められています。HeaderMismatchErrorはHTTPのヘッダーとボディの不整合を検出したときに返り、たとえばMcp-Nameヘッダーの値がボディの値と食い違うと次のようになります。
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32020,
"message": "Header mismatch: Mcp-Name header value 'foo' does not match body value 'bar'"
}
}HeaderMismatchが存在する理由はセキュリティです。ロードバランサーがHTTPヘッダーの値でルーティングを決め、MCPサーバー自身はリクエストボディの値で処理する。経路上の異なるコンポーネントがこう異なる値を信頼していると、両者の食い違いを突いた攻撃が成立します。Streamable HTTPのサーバー検証規則は、次のいずれかを検出したら必ずリクエストを拒否することを求めています。
- 必須ヘッダー(
MCP-Protocol-Version・Mcp-Method・Mcp-Name)のいずれかが欠落している - ヘッダーの値がボディの値と一致しない
- ヘッダーに不正な文字が含まれる
整数値の比較は文字列としてではなく数値として行うべきだとも定められており、42.0と42は同じ値として扱われます。
MissingRequiredClientCapabilityErrorはdataフィールドにrequiredCapabilitiesを含めることが必須です。たとえばサーバーがelicitation機能を要求しているのにクライアントが宣言していない場合、応答は次のようになります。
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32021,
"message": "Server requires the elicitation capability for this request",
"data": {
"requiredCapabilities": { "elicitation": {} }
}
}
}UnsupportedProtocolVersionErrorも同様にdata.supported(サーバーが対応する版の配列)とdata.requested(拒否された版)を必ず含みます。クライアントはこの配列から相互にサポートされる版を選び直してリトライする設計です。バージョン交渉の全体像はMCPのバージョニングと後方互換性にまとめています。
自作サーバーが新しいエラーコードを割り当てるときの基準
MCP予約領域にコードを追加できるのは仕様そのものだけです。この領域はGitHub上のスキーマファイルで一元管理されており、実装のリポジトリごとに勝手に追記できる場所ではありません。では自作サーバーが独自のエラー(認証切れ、レート制限超過など)を区別したい場合はどうするか。仕様の答えは明快です。JSON-RPCの予約範囲そのものを避け、-32768から-32000の外側に置くこと。この範囲外は「アプリケーション定義のエラー」に開放された領域で、実装がここに好きな値を割り当てることを妨げる規則はありません。
見落としやすいのはローカルエラーの扱いです。SDK内部で発生するリクエストタイムアウトのような、通信相手に届く前に自分の実装内で完結する失敗には、現行仕様はコードを割り当てていません。JSON-RPC形式でこうしたローカルエラーを表現する場合、仕様は「相手から受信したエラーと混同されない形にすべき」とだけ求めています。具体的な標準コードは将来のMCP予約領域の拡張に委ねられており、今それらしいコードを自分で決め打ちすると、後から仕様が同じコードを別の意味で定義したときに衝突します。
自作したエラーコードをデバッグする際は、実際にサーバーが返すJSON-RPC応答をそのまま確認できるMCP Inspectorが手早い手段です。接続そのものが失敗している場合の切り分けはMCPサーバーに接続できないときの切り分け手順を参照してください。
この3分割は何を優先した設計か
エラーコードを3つに割った設計は、後方互換と将来拡張の両立を優先しています。レガシー領域を凍結して意味の再解釈を禁じたのは、旧サーバーが返す値をクライアントが誤読しないための保険です。一方でMCP予約領域を仕様の専有物にしたのは、実装がばらばらに数字を割り当てて衝突する事態を防ぐためです。
裏を返せば、この設計はMCP仕様の管理者だけがエラーコードの語彙を増やせる体制を選んだということです。実装者が独自の失敗理由を細かく区別したいなら、コード自体ではなくerror.dataに構造化情報を積む方が仕様の意図に沿います。標準のInvalidParamsErrorがdataなしで「不明なツール名」も「引数の型不一致」も同じ-32602で表しているのは、この方針の表れです。コードは粗く、詳細はdataで伝える。この非対称な設計は、MCPサーバーを自作する際のエラー設計にもそのまま応用できます。実装全体の設計はMCPサーバー自作ガイド、接続後の権限や信頼境界はMCPセキュリティガイドで扱っています。
まとめ
MCPのエラーコードは、JSON-RPC標準の5コードと、MCP予約の3コード(-32020〜-32022)、そして実装が自由に使える-32768〜-32000の外側という3層で構成されています。自作サーバーで新しいエラー種別を区別したい場合は、MCP予約領域(-32000〜-32099)を避け、JSON-RPC予約範囲の外に独自コードを置くのが仕様に沿った選択です。レガシー領域(-32000〜-32019)の値に新しい意味を仮定しないことも、旧サーバーと安全に通信するための前提になります。プロトコル全体の入り口はMCPとはで解説しています。