Claude Media
MCPの「server/discover」はサーバーの何を返すRPCか

MCPの「server/discover」はサーバーの何を返すRPCか

MCPの2026-07-28版仕様で追加されたserver/discoverは、対応プロトコルバージョン・機能・サーバー識別を1回のリクエストで返す必須RPCです。initializeハンドシェイクとの違いと使いどころをまとめます。

server/discoverはサーバーの対応バージョン・機能・身元を1回で返すRPC

server/discoverは、MCPの2026-07-28版仕様で新設されたRPCです。クライアントは他のどのリクエストよりも先にこれを呼び出すことで、サーバーが対応しているプロトコルバージョン・機能(capabilities)・サーバー自身の識別情報をまとめて受け取れます。仕様はサーバー側の実装をMUST(必須)としています。

リクエストは標準の_meta以外にボディパラメータを持たない、最小限の形です。

{
  "jsonrpc": "2.0",
  "id": "discover-1",
  "method": "server/discover",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

サーバーは対応バージョンの一覧・機能・自己申告の識別情報を返します。

{
  "jsonrpc": "2.0",
  "id": "discover-1",
  "result": {
    "resultType": "complete",
    "supportedVersions": ["2026-07-28"],
    "capabilities": { "tools": {}, "resources": {} },
    "_meta": {
      "io.modelcontextprotocol/serverInfo": { "name": "ExampleServer", "version": "1.0.0" }
    },
    "instructions": "This server provides weather and resource utilities.",
    "ttlMs": 3600000,
    "cacheScope": "public"
  }
}

呼び出しは任意 — それでも用意されている2つの理由

仕様が明記している重要な点は、クライアントがserver/discoverを呼び出すこと自体は任意だということです。クライアントは対応バージョンを確認せずにいきなりtools/listなどのRPCを送ってよく、サーバーが対応していなければUnsupportedProtocolVersionErrorを返してくるので、それを見てから判断する運用も許容されています。

それでも仕様が2つの使いどころを挙げています。

  • サーバー情報の一括取得tools/listprompts/listresources/listを個別に呼んで機能を推測する代わりに、server/discover1回でサーバーの身元と対応機能をまとめて表示できます。
  • stdioでの後方互換プローブ。stdioトランスポートにはHTTPのようなステータスコードによるフォールバック手段がありません。新旧両方のサーバーに対応したいクライアントは、まずserver/discoverを送り、応答の有無や中身で相手が2026-07-28版(per-requestの_meta方式)か、旧来のinitializeハンドシェイク方式かを判定します。

discoverの往復が担う3つの役割

architectureドキュメントは、server/discoverのリクエストとレスポンスに含まれる_metaフィールドが果たす役割を3つに整理しています。

  • プロトコルバージョンの選択。クライアントはio.modelcontextprotocol/protocolVersionでそのリクエストが話しているバージョンを宣言し、サーバーはsupportedVersionsで自分が受け付けるバージョン一覧を返します。要求されたバージョンにサーバーが対応していなければUnsupportedProtocolVersionErrorとともに対応バージョン一覧を返し、クライアントは双方が対応する版で再試行します。
  • 機能(capability)の発見。クライアントはio.modelcontextprotocol/clientCapabilitiesをリクエストのたびに宣言し、サーバーはserver/discoverの応答で自分のcapabilitiesオブジェクトを返します。たとえばサーバーが{"tools": {"listChanged": true}}を返せば、tools機能に対応しかつツール一覧の変更通知にも対応していることが分かり、クライアント側は対応していない操作を試みずに済みます。なお拡張機能の対応表明はcapabilities.extensionsフィールドで行われ、MCPの拡張機能ネゴシエーションはどう合意形成されるかで仕組みを扱っています。
  • 身元交換。リクエスト側のclientInfoとレスポンス側のserverInfoは、デバッグや互換性確認のための識別・バージョン情報を提供します(ただし前述のとおりセキュリティ判断には使えません)。

initializeハンドシェイクとの違いは「毎回性」

2026-07-28版の仕様変更で最も大きいのは、接続の最初に一度だけ行うinitialize/notifications/initializedハンドシェイクが仕様から削除されたことです。代わりに、プロトコルバージョンとクライアントのケーパビリティはすべてのリクエストの_metaに毎回乗せる方式に変わっています。

server/discoverはこの新方式のもとでも、接続の最初に一度使う目的のRPCとして位置づけられています。ただし旧来のinitializeとは性格が違います。initializeは接続の状態を確立する手続きの一部でしたが、server/discoverは状態を伴わない問い合わせです。呼んでも呼ばなくても後続のリクエストの扱いは変わらず、単にクライアントが情報を先出しで得られるかどうかの違いにとどまります。この「セッションという状態を前提にしない」設計は、同じ改訂でセッションIDそのものが削除された流れとも一致します(詳細はMCPのセッションID(Mcp-Session-Id)はなぜ廃止されたのか)。

discoverを呼ばずに直接リクエストしたときの実際のエラー

server/discoverを呼ばずにいきなりtools/callなどを送り、サーバーが対応していないバージョンだった場合、返ってくるのは次のようなエラーです。

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32022,
    "message": "Unsupported protocol version",
    "data": {
      "supported": ["2026-07-28", "2025-11-25"],
      "requested": "1900-01-01"
    }
  }
}

data.supportedに対応バージョンの一覧が入っているため、クライアントはこの一覧から自分も対応している版を選んで同じリクエストを再送できます。仕様は、事前にserver/discoverを呼ぶ経路と、いきなりリクエストしてUnsupportedProtocolVersionErrorを受けてから対応する経路の両方を正式にサポートしています。新旧の実装が混在する相互運用の組み合わせ(モダン同士・新旧混在・レガシー同士)はすべてこの2つの経路のどちらかで解決するように仕様上整理されており、server/discoverはその中の「先に確認する」側の選択肢という位置づけです。

新旧クライアント・サーバーの組み合わせでdiscoverが効く場面

versioning仕様は、クライアントとサーバーの世代(モダン / 新旧両対応 / レガシー)の組み合わせごとに期待される結果を相互運用マトリクスとして定義しています。server/discoverが実際に効いてくるのは、次のような組み合わせです。

クライアントサーバー結果
モダンサーバーモダン結果動作する。server/discoverは任意で、バージョン不一致はUnsupportedProtocolVersionErrorで表面化し再試行する
モダンサーバーレガシー結果失敗する。stdioではserver/discoverを先に送ることで決定論的に失敗させ、意味のあるエラーをユーザーに提示できる
新旧両対応サーバーモダン結果動作する。stdioのプローブがDiscoverResult(またはエラー)を返し、クライアントはモダンのまま処理を続ける
新旧両対応サーバーレガシー結果動作する。stdioのプローブが非モダンなエラーやタイムアウトを返し、クライアントはinitializeにフォールバックする

新旧両対応のクライアントにとってserver/discoverは、通信を始める前に「この接続はモダンかレガシーか」を1回のやり取りで確定させる決定的な手段です。stdioにはHTTPのステータスコードのような手がかりが無いため、この事前確認が無いと、レガシーサーバーに対してモダン専用のリクエストを送り続けてタイムアウトを待つような不確実な状態に陥りかねません。

レスポンスはキャッシュ対象になる

server/discoverの応答は仕様上、キャッシュ機構の対象です。レスポンス例に含まれるttlMs(ミリ秒単位の鮮度ヒント)とcacheScope(publicまたはprivate)は、tools/listなど他のリスト系RPCと共通のキャッシュ用フィールドです。サーバーの対応バージョンや機能は接続のたびに変わるものではないため、クライアントやその手前にいるプロキシは、ttlMsが示す期間だけ応答を再利用してリクエスト数を減らせます。

cacheScopeprivateの場合、共有プロキシなど複数クライアントの間でキャッシュを共有してはいけません。逆にpublicなら、同じサーバーに接続する複数クライアントの間でキャッシュを共有してよいという意味になります。この2値の使い分けを取り違えると、本来は個別化すべき応答を他クライアントへ漏らす、あるいは逆に共有できる情報を無駄に再取得する、どちらかの実装ミスにつながります。

serverInfoは自己申告 — セキュリティ判断に使わない

server/discoverの応答に含まれる_meta['io.modelcontextprotocol/serverInfo']は、サーバー自身が名乗るソフトウェア名とバージョンです。仕様は明確に、この値がプロトコルによって検証されたものではないと注記しています。用途は表示・ログ・デバッグに限定され、クライアントはこの値を根拠にセキュリティ判断や挙動の切り替えを行うべきではありません。

複数のMCPサーバーを1つのクライアントで束ねる場合、serverInfo.nameが別サーバー間で一意である保証もありません。ツール名の衝突を防ぐディスアンビギュエーション(名前の一意化)戦略についても、serverInfoを信頼した設計は避けるべきです。

新旧両対応サーバーはリクエストの形で挙動を切り替える

旧仕様と2026-07-28版の両方をまだサポートし続けたいサーバー(仕様は「新旧両対応(dual-era)サーバー」と呼びます)は、クライアントからの最初のリクエストの形を見て挙動を切り替えます。モダンなper-requestの_metaを伴うリクエストが来れば、この2026-07-28版の仕様にもとづきステートレスに処理します。逆にinitializeリクエストが来れば、レガシーな意味論を選び、そのクライアントとのやり取り全体をレガシーの版で進めます。どちらの経路を選ぶかは接続のたびに1回だけ決まり、以後その接続の中で混在することはありません。

実装時に見落としやすい4点

  • server/discover未実装のまま2026-07-28版を名乗る。仕様はこのRPCの実装をMUSTとしているため、対応バージョンに2026-07-28を含めながらserver/discoverを実装していないサーバーは、仕様準拠を謳えません。
  • ttlMsを無視して毎回server/discoverを呼び直す。キャッシュヒントを無視すると、本来1回で済む問い合わせをクライアントが接続のたびに繰り返し、サーバー側の負荷が無駄に増えます。
  • serverInfoをアクセス制御の判定材料にする。自己申告の値を信頼した認可ロジックを組むと、サーバー側がなりすましのserverInfoを返した場合にそのまま突破されます。
  • 新旧両対応サーバーで、1つの接続の途中にinitializeとper-request _metaを混在させてしまう。仕様はこの世代選択を接続単位の一度きりの判定としているため、途中で切り替える実装は相互運用マトリクスの想定から外れ、クライアント側の状態管理を混乱させます。

まとめ

server/discoverは、MCPの2026-07-28版で追加された「対応バージョン・機能・身元をまとめて返す」ための必須RPCです。呼び出し自体はクライアントの任意ですが、サーバー情報の一括取得とstdioでの新旧判定という2つの用途で有効に使えます。initializeハンドシェイクのような接続確立の手続きではなく、状態を伴わない問い合わせである点、応答がキャッシュ対象である点、serverInfoが自己申告でしかない点の3つを押さえておくと、実装時の判断を誤りにくくなります。新旧混在の実運用に対応する自作サーバー・クライアントを書くなら、相互運用マトリクスの該当行を一度手元で確認してから設計に着手すると近道になります。

この記事を共有:XはてブLinkedIn
MCP をもっと見る →