このレッスンのロックを解除するには、まず「初めてのMCPサーバーを構築する」を完了してください。前のレッスンに戻る

はじめに

MCPプリミティブは、AIアプリケーションを外部の機能やコンテキストに接続する主要な設計単位です。MCPサーバーを構築する際の中心的な設計課題は、いくつのエンドポイントを公開するかではありません。各機能をツール、リソース、プロンプトのいずれとして表現すべきかを判断することです。誤ったプリミティブを選択すると、エージェントの安全性が損なわれたり、コンテキストの発見が難しくなったり、ユーザーが指示を手動で繰り返さなければならなくなったりします。

3つのプリミティブには、それぞれ異なる制御モデルとインタラクションモデルがあります。ツールは一般にモデル制御です。エージェントは、アクションや計算が必要なときにツールを呼び出すかどうかを判断できます。リソースは一般にアプリケーション制御です。ホストアプリケーションが、いつ取得してその内容を提示するかを決定します。プロンプトは一般にユーザー制御です。ユーザーが再利用可能なインタラクションテンプレートを選択または呼び出します。これらは一般的なMCP設計上の規約であり、単に同じ操作に異なる名前を付けたものではありません。

このレッスンでは、実践的な選択方法、コントラクト設計のルール、小規模な判断ヘルパーを紹介します。目的は、実装を開始する前にプリミティブの選択を予測可能なものにすることです。

MCPのツール、リソース、プロンプトを比較する3列の図。モデルからツール、アプリケーションからリソース、ユーザーからプロンプトへ向かう制御フローの矢印を示す

3つのプリミティブ

ツールは、モデルまたはエージェントがリクエストできる操作を表します。その操作は、データの読み取り、データの変換、サービスの呼び出し、または副作用の発生を伴う場合があります。例として、チケットシステムの検索、配送料の計算、請求書の下書きの作成、予約のキャンセルなどがあります。ツールには、具体的な名前、明確な説明、定義済みの入力スキーマ、およびモデルが解釈できる出力を設定する必要があります。

リソースは、URIによって識別されるアドレス指定可能な情報を表します。ドキュメント、設定、レコード、スキーマ、レポート、その他のコンテキストなど、アプリケーションが読み込み、モデルに提供できる情報に適しています。リソースには、ポリシードキュメントのように静的なものもあれば、URIが現在のエンティティを識別する顧客レコードのように動的なものもあります。リソースの読み取りは、アクションを実行する指示ではなく、コンテキストの取得として扱う必要があります。

プロンプトは、目的が明確な再利用可能なインタラクションテンプレートです。推奨メッセージ、引数、タスクの想定される構造を定義できます。たとえば、サポートアプリケーションでは顧客の苦情を要約するためのプロンプトを、コードレビューアプリケーションではプルリクエストをレビューするためのプロンプトを公開できます。プロンプトはツールの代替ではなく、外部状態を変更する操作を隠すために使用すべきではありません。

適切なプリミティブの選択

まず、ユーザーまたはエージェントが何を取得する必要があるのかを特定します。要件がアクション、計算、パラメータ付きの検索、または外部への副作用である場合は、toolから始めます。ある操作がデータを読み取るだけであることは、それだけでresourceになることを意味しません。現在の注文をパラメータ付きで検索する処理は、モデルが計算を要求し、指定された引数に基づく結果を受け取るため、多くの場合toolに該当します。

主な価値が、安定した識別子を持つ取得可能なコンテキストにある場合は、resourceを選択します。返品ポリシーなどのドキュメント、データベースレコードのURI、生成されたレポートは、アプリケーションがいつ読み込むべきかを判断できる場合、resourceとして表現できます。resourceは、ユーザーがエージェントの判断とは独立して、コンテキストを参照、添付、キャッシュ、更新、または検査する必要がある場合に特に役立ちます。

要件が、ユーザー向けに繰り返し利用できる会話パターンをパッケージ化することである場合は、promptを選択します。promptは、利用可能なコンテキストをモデルがどのように使うかを指示できますが、実行可能なビジネス処理であるかのように扱うべきではありません。リクエストが「返金申請の準備を手伝って」であれば、promptで会話を構造化できます。「返金を実行して」であれば、toolが承認済みの操作を実行する必要があります。

「このインタラクションを開始するのは誰か」という文を完成させると、判断しやすくなります。モデルがいつ操作を呼び出すかを決定すべき場合は、toolを使用します。ホストアプリケーションが情報を取得または添付すべき場合は、resourceを使用します。ユーザーが用意されたワークフローを選択すべき場合は、promptを使用します。ワークフローによっては、3つすべてのプリミティブを順番に使用するのが適切です。

強固なコントラクトの設計

優れたtoolコントラクトは曖昧さを最小限に抑えます。名前は実装ではなく操作を表すものにします。説明には、いつ使用するか、いつ使用しないか、必要な権限、適用される重要な制約を記載します。入力フィールドには、明示的な型、意味のある説明、バリデーションルール、可能な場合は範囲を限定した値を設定します。あらゆるリクエストで自由形式のオブジェクトを受け付けるtoolは、モデルとサーバーの双方が誤りを検出しにくくします。

toolの出力では、成功したデータと失敗情報を区別する必要があります。クライアントがフィールドをプログラムで検査する必要がある場合は構造化された結果を返し、結果をモデルやユーザーに表示する場合は簡潔で人間が読みやすい内容も含めます。リクエストがサーバーに到達しただけで成功と報告してはいけません。副作用を伴うtoolでは、操作が完了したのか、拒否されたのか、一部のみ完了したのか、それともドラフトとして準備されただけなのかを、結果から明確に判断できるようにします。

resourceの設計は、安定した識別子と予測可能なコンテンツに依存します。偶然の実装詳細を埋め込まずに、ドメインオブジェクトまたはドキュメントを識別するURIを使用します。resourceが不変、更新可能、またはバージョン管理対象のいずれであるかを決め、古いコンテンツをどのように扱うかを文書化します。機密データを含むresourceには、認可ポリシーも必要です。URIは識別子であって、基盤となるデータを読み取る権限そのものではありません。

promptの設計では、ユーザーまたはアプリケーションが合理的に提供できる引数だけを公開します。promptの説明には、想定される成果と必要なコンテキストを記載します。操作上の指示はユーザーデータから分離し、アプリケーションが維持できない限り、モデルが権威ある情報として扱うべき主張を埋め込まないようにします。promptはtool呼び出しを推奨できますが、認可とバリデーションはtoolおよびサーバーのレイヤーに残す必要があります。

実例

顧客サポートアプリケーションに3つの要件があるとします。顧客の未処理の注文を検索し、最新の返品ポリシーを提供し、返品に関する会話をエージェントが進められるよう案内する必要があります。1つ目は稼働中のシステムに対するパラメータ付きの検索であるため、toolに適しています。2つ目はアプリケーションが必要に応じて読み込めるアドレス指定可能なドキュメントであるため、resourceに適しています。3つ目はユーザーが選択して繰り返し利用できる会話パターンであるため、promptに適しています。

次のローカルJavaScriptヘルパーは、その判断ルールを表現したものです。これはMCPサーバーではなく、プロトコル登録の代替にもなりません。目的は、実装前の設計レビューを明確にすることです。結果には、選択したプリミティブと、その選択を裏付ける理由が含まれます。

javascript
function chooseMcpPrimitive(requirement) {
const text = requirement.toLowerCase();
if (text.includes("perform") || text.includes("create") || text.includes("update") ||
text.includes("delete") || text.includes("search") || text.includes("calculate") ||
text.includes("send") || text.includes("live")) {
return {
primitive: "tool",
reason: "The requirement describes an operation, computation, parameterized lookup, or side effect."
};
}
if (text.includes("document") || text.includes("policy") || text.includes("record") ||
text.includes("report") || text.includes("read") || text.includes("context")) {
return {
primitive: "resource",
reason: "The requirement describes addressable information that an application can retrieve and attach as context."
};
}
if (text.includes("guide") || text.includes("workflow") || text.includes("template") ||
text.includes("conversation") || text.includes("summarize")) {
return {
primitive: "prompt",
reason: "The requirement describes a reusable interaction pattern selected by a user or application."
};
}
return {
primitive: "review",
reason: "The requirement does not provide enough information to distinguish action, context, and interaction template."
};
}
console.log(chooseMcpPrimitive("search live open orders for a customer"));
console.log(chooseMcpPrimitive("read the current return policy document"));
console.log(chooseMcpPrimitive("guide an agent through a return conversation"));

最初の呼び出しではツールの判断、2番目ではリソースの判断、3番目ではプロンプトの判断が生成されるはずです。このヘルパーは、曖昧さに対して意図的に保守的な設計になっています。実際の設計レビューでは、何かを登録する前に、認可、鮮度、ユーザーによる制御、そしてその操作に副作用があるかどうかを確認する必要があります。

よくある失敗パターン

ツールはエージェントから呼び出しやすいため、あらゆる機能をツールとして公開してしまうのは、よくある間違いです。これによりツールカタログが過度に肥大化し、本来は閲覧可能にするかアプリケーション側で制御すべきドキュメントを、モデルが操作経由で取得するようになります。特にコンテキストが安定していてキャッシュ可能な場合は、取得するコンテキストとアクションを分離してください。

もう1つの間違いは、ツールの説明を曖昧にすることです。process_requestのような名前では、それが何かを検索するのか、承認するのか、送信するのか、削除するのかをモデルに伝えられません。曖昧な説明は誤った呼び出しを増やし、認可レビューも難しくします。操作内容、必要な入力、重要な除外事項、副作用の挙動を直接明記してください。

リソースも、URIに秘密情報を含めたり、不安定なデータベース内部情報に依存したり、認可なしでアクセスできることを示唆したりすると、誤った設計になる可能性があります。必要に応じて不透明な識別子を使用し、読み取りのたびに認可を検証し、コンテンツが存在しない場合、古い場合、または利用できない場合の報告方法を定義してください。プロンプトについては、プロンプトをセキュリティ境界として扱わないでください。プロンプト内の指示で、サーバー側の検証を置き換えることはできません。

最後に、プリミティブを組み合わせれば自動的に優れたワークフローが生まれると考えてはいけません。ホストが適切なタイミングでリソースを公開するか、ユーザーがプロンプト引数を理解できるか、ツールが不正なリクエストや認可されていないリクエストを拒否するかをテストしてください。オブザーバビリティでは、機密値を不必要にログに記録することなく、プリミティブ名、検証結果、認可結果、失敗カテゴリを記録する必要があります。

まとめ

ツールは、操作、計算、パラメーター化された検索、副作用を伴う処理に使用します。リソースは、アプリケーションが取得してコンテキストとして提供できる、アドレス指定可能な情報に使用します。プロンプトは、ユーザーが選択または呼び出せる再利用可能な対話パターンに使用します。これらの違いは、データの形だけでなく、制御の主体にも関係します。

信頼性の高い設計プロセスは、要件から始まり、誰が対話を開始するのかを特定し、結果がアクションなのかコンテキストなのかを確認したうえで、限定的なコントラクトを定義します。各プリミティブについて、説明、スキーマ、権限、エラー、鮮度に関する挙動を明確にする必要があります。

ワークフローが複数の関心事にまたがる場合は、プリミティブを意図的に組み合わせてください。ユーザーがプロンプトを選択し、アプリケーションがリソースを追加し、モデルがツールを呼び出すことがあります。これらの責務を分離することで、挙動が明確になり、認可がより安全になり、テストや保守が容易なMCP統合を実現できます。

レッスンの練習

レッスンのチェックポイント

学んだ内容を復習し、回答へのフィードバックを受けましょう。

0/1
回答済み · 0/1