Resources・Prompts・共通ユーティリティ
Tools 以外のサーバー機能 (Resources / Prompts) と、共通ユーティリティ (Completion / Pagination / Caching) を解説します。Tools は Tools - ツールの定義と実行、全体像は MCP入門 を参照してください。
1. このドキュメントで扱うこと
- Resources
- リソース未検出のエラー
- Prompts
- Prompts の活用
- Completion
- Pagination
- Caching
- 制御主体による使い分け
Resources
Resources は、サーバーがクライアントに公開するコンテキストのデータです。ファイル、データベースのスキーマ、アプリケーション固有の情報などを、URI (RFC 3986) で一意に識別します。Resources はアプリケーション主導の機能です。ホストアプリケーションが、どのリソースをどうコンテキストに取り込むかを決めます。たとえば、ツリーや一覧からの明示的な選択、検索と絞り込み、ヒューリスティクスやモデルの選択による自動的な取り込みなどが考えられます。
サーバーは resources capability を宣言します。
{
"capabilities": {
"resources": {
"listChanged": true,
"subscribe": true
}
}
}
listChanged: 利用可能なリソースの一覧が変わったときに通知を送るかsubscribe: 個別のリソースの更新通知に対応するか
2 つは独立しており、どちらも持たないサーバーは "resources": {} と宣言できます。
リソースに関するメソッドは次のとおりです。
| メソッド | 用途 |
|---|---|
resources/list | 利用可能なリソースの一覧 (ページネーションとキャッシュに対応) |
resources/read | URI を指定して内容を取得 (キャッシュに対応) |
resources/templates/list | URI テンプレートによるパラメーター付きリソースの一覧 |
リソースの定義は、uri、name、title、description、icons、mimeType、size で構成されます。内容 (contents) は、テキストなら text、バイナリーなら base64 の blob を持ちます。1 回の resources/read で、複数の内容を返してもかまいません (ディレクトリーを読んだときに、複数のファイルを返す、など)。
リソースやコンテンツブロックには、利用側へのヒントとして annotations を付けられます。
audience: 想定する読み手。"user"と"assistant"の配列priority: 0.0 から 1.0 の重要度。1 は「最重要 (実質的に必須)」、0 は「完全に任意」lastModified: ISO 8601 形式の最終更新日時
resources/templates/list は、RFC 6570 の URI テンプレート でパラメーター付きのリソースを公開します。たとえば file:///{path} です。テンプレートの引数は、後述の Completion で補完できます。
購読は、2026-07-28 版で変わりました。個別のリソースの更新は、subscriptions/listen の notifications.resourceSubscriptions に URI を並べて購読し、サーバーは変更のたびに notifications/resources/updated をそのストリームで届けます。通知の _meta には、どの購読の通知かを示す io.modelcontextprotocol/subscriptionId が付きます。以前の resources/subscribe は、この仕組みに置き換わりました。一覧の変更は resourcesListChanged: true で購読します。購読の詳細は MCPプロトコル基礎 と トランスポート - stdioとStreamable HTTP を参照してください。
URI スキームは自由に選べますが、仕様は次の一般的なものを挙げています。
https://: クライアントが MCP サーバーを介さず、自力でウェブから取得できる場合だけ使う。そうでなければ、別のスキームかカスタムスキームを使うfile://: ファイルシステムのように振る舞うリソース。実際の物理ファイルである必要はない。ディレクトリーのような通常でないファイルには、inode/directoryのような MIME タイプを使えるgit://: Git のバージョン管理との統合- カスタムスキーム: RFC 3986 に従う
resources/read も、処理の途中でユーザー入力が必要なときは、resultType: "input_required" を返せます。詳細は ElicitationとMulti Round-Trip Requests を参照してください。
セキュリティ面では、サーバーはすべてのリソース URI を検証し、機微なリソースにアクセス制御をかけ、file:// のリソースを扱うときはディレクトリートラバーサルを防ぐためにパスをサニタイズしなければなりません。
リソース未検出のエラー
存在しないリソースには、JSON-RPC エラーのコード -32602 (Invalid Params) を返さなければなりません。内部エラーには -32603 を推奨します。以前のプロトコルバージョンは -32002 を使っていたため、後方互換のため、クライアントは -32002 も「リソースが見つからない」として受け入れることが推奨されています。
存在しないリソースに対して、空の contents 配列を返してはいけません。空の配列は、「リソースは存在するが内容が空」とも「存在しない」とも読めてしまうためです。
{
"jsonrpc": "2.0",
"id": 5,
"error": {
"code": -32602,
"message": "Resource not found",
"data": { "uri": "file:///nonexistent.txt" }
}
}
Prompts
Prompts は、サーバーが公開するプロンプトのテンプレートです。ユーザー主導の機能で、ユーザーが明示的に選んで呼び出すことを想定しています。「誰が使うかを決めるか」の話であって、内容を誰が書くかの話ではありません。内容はサーバーが定義します。典型的には、UI のスラッシュコマンドとして実装されます。
prompts capability を宣言したサーバーは、prompts/list (ページネーションとキャッシュに対応) と prompts/get に応答します。
プロンプトの定義は、name、title、description、icons、arguments (名前、説明、必須かどうか) で構成されます。prompts/get は、引数を受け取り、role (user または assistant) と content を持つメッセージの配列を返します。content は、text、image、audio、resource_link、埋め込みの resource のいずれかです。引数は Completion で補完できます。
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"description": "Code review prompt",
"messages": [
{
"role": "user",
"content": { "type": "text", "text": "Please review this Python code:\ndef hello():\n print('world')" }
}
]
}
}
エラーは、不明なプロンプト名と必須引数の欠落が -32602、内部エラーが -32603 です。サーバーは、プロンプトの入力と出力を注意深く検証し、インジェクションを防ぎます。prompts/get も、input_required を返せます。一覧の変更は、subscriptions/listen に promptsListChanged: true を指定したクライアントへ、notifications/prompts/list_changed で通知されます。
Prompts の活用
プロンプトは、ユーザーが呼び出す定型のワークフローの入口になります。「コードレビューを始める」「障害の初動を確認する」といった、サーバーを提供する側が知っている手順を、引数付きのテンプレートとして配れます。
近年は、Prompts をスキルの配布手段として使えないか、という関心もあります。ただし、クライアントごとに対応状況に差があります。スラッシュコマンドとして出すクライアントもあれば、Prompts を扱わないクライアントもあります。Prompts だけに依存した設計は、対応していないクライアントで機能が失われます。エージェント向けの構造化された手順書の配布は、専用の拡張である Skills over MCP が定められています (詳細は MCP拡張機能 - Tasks・MCP Apps・Skills)。重要な手順は、Prompts だけでなく、Tools の description や、他の経路でも到達できるようにしておくのが安全です。
Completion
Completion は、プロンプトの引数やリソーステンプレートの引数に、IDE のコード補完のような候補を返す機能です。サーバーは completions capability を宣言します。
{
"jsonrpc": "2.0",
"id": 1,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "code_review" },
"argument": { "name": "framework", "value": "fla" },
"context": { "arguments": { "language": "python" } }
}
}
ref: 補完の対象。ref/prompt(プロンプト名) またはref/resource(リソース URI かテンプレート)argument: 補完中の引数のnameと、現在のvaluecontext.arguments: すでに決まっている他の引数。複数の引数があるとき、前の引数の値を踏まえて候補を絞れる
結果は、関連度の順に並べた values (最大 100 件)、任意の total (全体の件数)、まだ候補があるかを示す hasMore です。サーバーは関連度順に返し、あいまい一致を使い、補完のリクエストにレート制限をかけます。クライアントは、素早い入力に対してデバウンスし、結果を適切にキャッシュします。補完は情報の漏えい経路にもなり得るため、サーバーは機微な候補へのアクセスを制御します。
Pagination
resources/list、resources/templates/list、prompts/list、tools/list は、不透明なカーソルによるページネーションに対応します。番号付きのページではありません。
- サーバーは、結果の 1 ページと、続きがあれば
nextCursorを返す - クライアントは、
nextCursorをparams.cursorに入れて、続きを要求する - ページサイズはサーバーが決める。クライアントは固定のサイズを仮定してはならない
nextCursorがなければ、結果の終わり- カーソルは不透明なトークン。形式を仮定したり、解析や変更をしたりしてはならない。空文字列も有効なカーソルで、終わりとは見なさない (値が入っているかどうかだけで判断する)
- 無効なカーソルには、
-32602(Invalid params) を返す
Caching
2026-07-28 版は、一部の結果にキャッシュのヒントを付けます。CacheableResult と呼ばれ、resultType: "complete" の結果に、サーバーが次の 2 つのフィールドを必ず含めなければなりません。対象は server/discover、tools/list、prompts/list、resources/list、resources/templates/list、resources/read です。input_required の中間結果にはヒントを付けず、キャッシュもしません。
| フィールド | 意味 |
|---|---|
ttlMs | クライアントが結果を「新鮮」と見なしてよい時間 (ミリ秒)。HTTP の Cache-Control: max-age に近い。サーバーは 0 以上の値を返す |
cacheScope | public または private。HTTP の Cache-Control: public / private に近い |
ttlMs が 0 なら、すぐに古いものとして扱います。省略されたときは 0 とみなします。TTL は新鮮さのヒントであり、保証ではありません。期限の前に内容が変わることもあります。クライアントは、TTL をポーリング間隔として自動で再取得してはならず (そうするなら、ジッターとバックオフが必須)、必要になった時点で新鮮さを確認し、古ければ取得し直します。
cacheScope の意味は次のとおりです。
public: ユーザー固有のデータを含まない。どのクライアントや共有ゲートウェイでも、どのユーザーにもキャッシュを再利用してよいprivate: 呼び出し元ごとのデータを含む。同じ認可コンテキストの中でだけ再利用でき、別のアクセストークンのキャッシュと共有してはならない
ユーザーに依存しない tools/list やリソーステンプレートは public、認証されたユーザーによって内容が変わる resources/read や、ユーザーごとに絞り込んだ一覧は private が適切です。認証付きのエンドポイントから返した結果でも、public なら認可の枠を超えて共有され得ます。サーバーは、cacheScope だけに頼らず、プリミティブごとのアクセス制御を必ずかけます。
キャッシュのキーは、メソッドと、結果に影響するパラメーター (resources/read なら uri、ページネーションなら cursor) の組です。inputResponses や requestState を伴う再試行の結果は、キャッシュしてはいけません。ページネーションされた一覧では、各ページが独立してキャッシュされ、ページごとに ttlMs を変えてもかまいませんが、1 つの一覧の全ページで cacheScope は同じにします。
list_changed 通知と TTL は、補完関係にあります。TTL だけでも、通知だけでも使え、両方を使えば、TTL で不要な再取得を避けつつ、通知で即座に無効化できます。新鮮な間に関連する通知が届いたら、キャッシュはすぐに古いものとして扱います。
制御主体による使い分け
Tools はモデル主導、Resources はアプリケーション主導、Prompts はユーザー主導です。次の表にまとめます。
2. Tools / Resources / Prompts の使い分け
| 機能 | 制御する主体 | 用途の例 |
|---|---|---|
| Tools | モデル | 課題の検索、チケット作成、デプロイの実行 |
| Resources | アプリケーション (ホスト) | ファイル、スキーマ、設定などをコンテキストとして添付 |
| Prompts | ユーザー | 「コードレビューを始める」などの定型ワークフローの呼び出し |
「誰が使うかを決めるか」が基準です。副作用のある操作や、モデルに選ばせたいものは Tools にします。参照するだけのデータで、ユーザーやアプリケーションが添付するものを選ぶなら Resources です。ユーザーが明示的に始める定型の手順は Prompts です。ただし、実際のクライアントは、Resources や Prompts への対応が Tools ほど広くありません。モデルが自律的に使う必要がある機能を、Resources だけで公開すると、モデルから使われないことがあります。Tools のほうが、現状は広く対応しています。
3. 開発者がつまずきやすいポイント
3.1 「Resources があれば、モデルが自動で読む」と考える
Resources は、アプリケーション主導です。モデルが自律的に読むかは、ホストの実装次第です。モデルに読ませたいデータは、resource_link を Tools の結果に含めるか、読み取り用のツールも用意します。
3.2 リソース未検出に空の配列を返す
存在しない URI に空の contents を返すと、「空のリソース」と区別できません。-32602 のエラーを返します。クライアントは、以前のバージョンのサーバー向けに -32002 も許容します。
3.3 ttlMs と cacheScope を付け忘れる、またはユーザーごとに変わる結果を public にする
list 系と resources/read の結果には、これらを必ず付けます。ユーザーごとに内容が変わる結果を public にすると、別のユーザーのトークンのキャッシュに、他人の内容が混ざります。迷ったら private にします。
3.4 ページサイズやカーソルの形式を仮定する
クライアントがカーソルを解析したり、空文字列を終わりとして扱ったりしてはいけません。サーバー側は、無効なカーソルに -32602 を返し、クライアントはその場合、キャッシュ済みのページをすべて捨てて、先頭から取得し直します。
3.5 リソース購読に resources/subscribe を使う
2026-07-28 版には、resources/subscribe がありません。subscriptions/listen に、resourceSubscriptions で URI を渡します。サーバーが認めた範囲は、最初の notifications/subscriptions/acknowledged で確認します。
3.6 file:// のパスをそのまま使う
resources/read の URI を、そのままファイルシステムのパスとして開くと、.. によるディレクトリートラバーサルが成立します。正規化したうえで、許可されたルートの内側であることを検証します。
3.7 Prompts の対応を前提にする
Prompts に対応していないクライアントでは、機能が見えません。Prompts を使うときは、同等の内容へ別の経路でも届くようにします。
4. コード例
リソースの一覧と読み取り
{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": { "uri": "file:///project/src/main.rs" }
}
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"contents": [
{
"uri": "file:///project/src/main.rs",
"mimeType": "text/x-rust",
"text": "fn main() {\n println!(\"Hello world!\");\n}"
}
],
"ttlMs": 60000,
"cacheScope": "private"
}
}
リソースの購読
{
"jsonrpc": "2.0",
"id": 4,
"method": "subscriptions/listen",
"params": {
"notifications": {
"resourcesListChanged": true,
"resourceSubscriptions": ["file:///project/config.json"]
}
}
}
(_meta は省略しています。2026-07-28 版では、すべてのリクエストに必須です。)
プロンプトの引数の補完
{
"jsonrpc": "2.0",
"id": 1,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "code_review" },
"argument": { "name": "language", "value": "py" }
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"completion": { "values": ["python", "pytorch", "pyside"], "total": 10, "hasMore": true }
}
}
ページネーションの読み取りループ
async function listAllTools(client: Client): Promise<Tool[]> {
const all: Tool[] = [];
let cursor: string | undefined = undefined;
do {
const page = await client.listTools(cursor ? { cursor } : {});
all.push(...page.tools);
cursor = page.nextCursor; // 空文字列も有効なカーソル。undefined かどうかだけで判断する
} while (cursor !== undefined);
return all;
}
5. まとめ
- Tools はモデル主導、Resources はアプリケーション主導、Prompts はユーザー主導。制御する主体で使い分ける
- Resources は URI で識別し、
resources/list、resources/read、resources/templates/listを持つ。未検出は-32602。空のcontentsは返さない - 購読は
subscriptions/listenに集約された。resources/subscribeは使わない - Prompts はユーザーが明示的に呼び出すテンプレート。クライアントの対応には差があるため、Prompts だけに頼らない
- Completion は引数の補完 (最大 100 件)、Pagination は不透明なカーソルで行う
- Caching は
ttlMsとcacheScope。ユーザーごとに変わる結果はprivate。cacheScopeはアクセス制御の代わりにならない