MCPのPrompts仕様を読み解く — Claude Codeがスラッシュコマンド化する仕組み
MCPのPrompts仕様はテンプレート化した指示をサーバーからクライアントへ渡す機能。Claude Codeがこれをスラッシュコマンドとして扱う実装の詳細と、引数設計の落とし穴を整理する。
MCPのPromptsとは何か
Model Context Protocol(MCP)のPromptsは、サーバーが用意した指示テンプレートをクライアントに公開する仕組みです。サーバー側で「このコードをレビューして」「この形式でissueを作って」といった定型の依頼文をname付きで登録しておき、クライアントはそれを一覧取得して呼び出します。Claude Codeでは、これがスラッシュコマンドとして並びます。
サーバーが公開する概念は3つあり、実行の引き金を誰が引くかで役割が分かれます。
MCPサーバーが公開する3つの概念
Tools
モデルが判断して呼びます。ファイルの読み書きやAPI呼び出しが典型です。
Resources
アプリがコンテキストとして取り込みます。ファイルの内容やDBスキーマが典型です。
Prompts
ユーザーが明示的に選んで実行します。コードレビュー依頼や定型のissue作成が典型です。
Promptsだけが「ユーザー制御」に設計されています。仕様が区別しているのはコンテンツの作者ではなく、使うタイミングを誰が決めるかです。中身はサーバーの著者が決めますが、実行の引き金を引くのはユーザーとされています。
仕様を読む前に押さえる、通信モデルの変更
現行のプロトコル改訂は2026-07-28で、前の改訂(2025-11-25)から通信モデルが変わりました。initializeハンドシェイクとプロトコルレベルのセッションIDが廃止され、MCPはステートレスになっています。
代わりに、すべてのリクエストが_metaでプロトコルバージョン(io.modelcontextprotocol/protocolVersion)とクライアントの能力(io.modelcontextprotocol/clientCapabilities)を運びます。この2つは必須で、欠けたリクエストは不正として-32602で拒否されます。HTTPなら400 Bad Requestです。clientInfoは任意です。
Promptsの解説ページに載っているリクエスト例は、簡潔さのために_metaを省いています。ページの例をそのままコピーして送ると、必須の_metaが欠けて弾かれます。
prompts/listとprompts/getのやり取り
呼び出しは2段階です。まずprompts/listで一覧を取り、次にprompts/getで個別の中身を取ります。
prompts/listの応答には、promptsの配列のほかにttlMs(何ミリ秒キャッシュしてよいか)とcacheScope(publicかprivate)が付きます。キャッシュヒントは完了応答にサーバーが必ず付ける決まりです。ttlMsは0以上でなければならず、値が0か欠けていれば、クライアントは取得直後から古いものとして扱います。
{
"jsonrpc": "2.0",
"id": 1,
"method": "prompts/get",
"params": {
"name": "code_review",
"arguments": {
"code": "def hello():\n print('world')"
}
}
}prompts/getのargumentsはキーと値のペアで、キーはサーバーが一覧で宣言した引数名です。補完候補はCompletion APIで出せますが、サーバー側の対応が前提です。
一覧が大きいときは、カーソルで分割して返します。1ページの件数はサーバーが決めるので、クライアントは固定の件数を前提にできません。nextCursorが無くなったところが末尾です。
一覧の中身は接続ごとには変わらない
仕様は、prompts/listが返す集合について次の線を引いています。時間とともに変わってよく、空でもかまいません。ただし接続ごとに違ったり、他のリクエストの副作用で変わったりしてはいけません。
例外は認可です。呼び出し側に付与されたスコープに応じて、見えるPromptを絞ることは認められています。認証情報はリクエストごとの入力であって、接続の状態ではないからです。「このユーザーにだけ出すPrompt」は認可で、「この接続にだけ出すPrompt」は仕様違反になります。
追加入力を求めるInputRequiredResult
サーバーはprompts/getに対し、完了応答の代わりにInputRequiredResultを返して追加の入力を求められます。これはMulti Round-Trip Requests(MRTR)という共通の型で、クライアントはinputResponsesを添えて同じリクエストを送り直します。
requestStateが付いてきたら、扱いは厳格です。
- クライアントは中身の解析も書き換えもできず、受け取った値をそのまま返送する
requestStateが無かった応答に対しては、再送リクエストにも付けない- 再送のJSON-RPC
idは、最初のリクエストと別の値にする - サーバーは返ってきた値を攻撃者が書き換えうる入力として扱い、認可やビジネスロジックに影響するならHMACやAEADで改ざんを検出する
サーバーに状態を持たせずに複数往復を成立させる仕掛けなので、requestStateの中にどこまで進んだかを符号化するのが想定された使い方です。
メッセージに含められる5種類のコンテンツ
prompts/getが返すmessagesは、role(userかassistant)とcontentを持ちます。contentの種類は次の5つです。
- テキスト(
text) — もっとも一般的 - 画像(
image) — base64エンコードと有効なMIMEタイプが必須 - 音声(
audio) — 画像と同じ条件 - リソースリンク(
resource_link) — URIだけを渡し、中身は必要になったら取得 - 埋め込みリソース(
resource) — サーバー管理の内容を直接メッセージに含める
使い分けに迷うのが、最後の2つです。
resource_link と resource の使い分け
resource_link
ファイルが大きいときや、呼ぶたびに内容が変わるときに向きます。クライアントがresources/readで必要なときに取りに行きます。
resource
短い定型のコードサンプルやドキュメント片に向きます。内容がprompts/getの応答に入るので、往復が1回減ります。
埋め込みリソースには、有効なURIとMIMEタイプに加えて、テキストかbase64のバイナリのどちらかが必須です。
定義の項目とエラーの返し方
Promptの定義はname(一意な識別子)を軸に、title(表示用の名前)、description、icons、argumentsを任意で持ちます。titleは表示用のラベルで、識別子はnameです。
標準のエラーは3種類で、messageに理由を書き添えておけばクライアント側で原因を見分けられます。
| 失敗の種類 | コード |
|---|---|
| 存在しないPrompt名 | コード-32602(Invalid params) |
| 必須引数の欠落 | コード-32602(Invalid params) |
| サーバー内部の失敗 | コード-32603(Internal error) |
実装の推奨は3点です。サーバーは引数を処理する前に検証し、クライアントは大きな一覧のページネーションを正しくたどります。両者とも能力交渉に従います。
セキュリティについて、仕様は「すべてのPrompt入出力を、インジェクション攻撃やリソースへの不正アクセスを防ぐよう慎重に検証しなければならない」とMUSTで定めています。argumentsの値は外から渡る文字列なので、そのままシェルコマンドや別のツール呼び出しに埋め込むと、Prompts経由の間接的なインジェクション経路になりえます。サーバー全体のアクセス範囲の設計はMCPセキュリティガイドにまとまっています。
一覧の変更はどう伝わり、Claude Codeはどう反映するか
Promptsは接続後に固定とは限らず、権限やプロジェクトの状態で増減しえます。変化を伝える手順は次のとおりです。
listChangedによる一覧の更新
- 1
一覧を取得する
クライアントが
prompts/listでその時点の一覧を取ります。 - 2
通知用のストリームを開く
サーバーが
listChanged: trueを宣言していれば、クライアントはsubscriptions/listenにpromptsListChanged: trueを指定して、通知専用のストリームを開きます。 - 3
変更の合図を受ける
Promptsの構成が変わると、ストリームに
notifications/prompts/list_changedが流れます。通知に変更後の中身は含まれません。 - 4
一覧を取り直す
クライアントは
prompts/listを再送して最新の一覧に差し替えます。Promptsが多いサーバーほど、この再取得が負担になります。
Claude Codeの動きは、実行形態で分かれます。対話ターミナルのセッションでは、通知を受けると更新後の一覧を取得するので、再接続は要りません。-p付きの非対話モードとAgent SDKでは、この通知で更新されるのはツールの一覧だけです。
更新の取得に失敗したときは、前回までに見つけたPrompts・ツール・リソースがそのまま残ります。v2.1.214より前は、一時的なエラーで空の一覧に置き換わっていました。
新しいプロトコル改訂のサーバーでは、通知用のストリームが閉じたとき、Claude Codeが開き直します。10秒以内にまた閉じる場合は最大3回まで、10秒より長く開いてから閉じる場合は1時間に5回の再オープンを超えると約6時間待ちます。ストリームが戻るまでは最後に取得した一覧のままなので、早く反映したければ/mcpから再接続します。
Claude Codeでの呼び出しと引数の制約
接続済みのサーバーが公開するPromptsは、スラッシュコマンドとして並びます。/を入力すると/servername:promptname (MCP)の形で候補に出て、/mcp__servername__promptnameと直接入力しても実行できます。
/mcp__github__list_prs引数を取るPromptsも同じ形です。
/mcp__jira__create_issue login-bug high/mcp__形式のコマンド名は、サーバー名のうちA-Z・a-z・0-9・_・-以外の文字が_に置き換わります。Prompt名は、サーバーが宣言したとおりに使われます。titleにどれだけ分かりやすい名前を付けても、打ち込む文字列はnameです。name自体を短く覚えやすくしておく設計が実用面で効きます。
anthropic-skillsという名前のサーバーは例外です。この名前はclaude.aiから同期されるスキルのために予約されており、そのサーバーのPromptsはコマンドに出てきません。ツールは動くので、Promptsを使いたければMCP設定でサーバー名を変えます。
Promptsにできないこと、Toolsに任せること
ToolsやResourcesがモデルやアプリの判断で動くのに対し、Promptsは人間の操作を経由します。クライアントはユーザーが明示的に選ぶ前提でUIを作れます(仕様はUIの形式までは定めていません)。Claude Codeがスラッシュコマンドという直接的な選択UIに落としたのは、この仕様の意図に沿った実装です。
逆に、モデルに自律的に使わせたい定型指示は、仕様上モデル制御とされるToolsで設計するのが素直です。
まとめ
Promptsは、サーバーが決めた指示をユーザーが明示的に選んで走らせる仕組みで、Claude Codeではスラッシュコマンドとして現れます。サーバーを作る側は、一覧を接続ごとに変えない・引数を1トークンで設計する・サーバー名をanthropic-skillsにしない、の3点を先に決めておくと手戻りが減ります。サーバーを自作する場合はMCPサーバー自作ガイドにツール定義からClaude Code接続までの手順があり、動作の検証にはMCP Inspectorが使えます。