Claude Architect 試験対策
Phase 3 配点 18% | Domain 2
Domain 2 / 試験配点 18%

Tool Design &
MCP Integration

Claude が外部の世界とやり取りする仕組みを学びます。ツールスキーマの設計から MCP によるサーバー統合、本番運用までを体系的にカバーします。

対応コース

Introduction to MCP
MCP Advanced Topics
Tool Use (API & GitHub)

試験シナリオ

Scenario 1, 2, 4
ツール統合 / データ取得 / 外部連携

学習目標

Task 2.1 ~ 2.5
ツール設計・MCP構築・スケーリング

MCP の全体像と設計思想

Model Context Protocol: LLMと外部サービスの標準接続規格

MCP (Model Context Protocol) は、LLM アプリケーションが外部データやツールに接続するためのオープンな標準プロトコルです。USB-C が様々なデバイスを統一的に接続するように、MCP は LLM と外部サービスの間に共通のインターフェースを提供します。

MCP が解決する課題

MCP が登場する前、各 LLM アプリケーションは外部サービスごとに個別のインテグレーションを構築する必要がありました。N 個のアプリと M 個のサービスがあれば N x M の接続が必要になります。MCP はこれを N + M に削減します。

ホストアプリケーション (Claude Desktop, IDE など)
MCP クライアント (ホスト内蔵, 1:1 でサーバーと接続)
MCP サーバー (軽量プロセス, 外部サービスへの橋渡し)
外部サービス (DB, API, ファイルシステムなど)

用語解説

Host (ホスト)
ユーザーが操作するアプリケーション本体。Claude Desktop や VS Code 拡張などが該当します。複数の MCP クライアントを持てます。
MCP Client (クライアント)
ホストの内部に存在し、1つの MCP サーバーと 1:1 で接続を維持するコンポーネントです。プロトコルの交渉やメッセージのルーティングを担当します。
MCP Server (サーバー)
外部サービスへのアクセスを提供する軽量プロセス。ツール、リソース、プロンプトという3つのプリミティブを公開します。

リクエスト-レスポンスフロー

ユーザーの質問が外部データを必要とする場合、以下の流れでデータが取得されます。

  1. 1ユーザーがホストアプリでクエリを入力する
  2. 2ホストが MCP クライアント経由で利用可能なツール一覧を Claude に渡す
  3. 3Claude が必要なツールを選択し、呼び出しパラメータを生成する
  4. 4MCP クライアントが該当サーバーにリクエストを転送する
  5. 5MCP サーバーが外部サービスからデータを取得し、結果を返す
  6. 6Claude が結果を元にユーザーへの応答を生成する

試験で問われるポイント

MCP はトランスポート非依存 (transport-agnostic) な設計です。通信の仕組みとプロトコルのロジックが分離されているため、同じ MCP サーバーを Stdio でローカル実行しても、HTTP でリモート実行しても、ツールの定義やロジックは変わりません。

JSON メッセージアーキテクチャ

MCP の全ての通信は JSON-RPC 2.0 ベースのメッセージで行われます。メッセージには3種類あります。

種類 特徴
Request id を持つ。必ず Result が返る tools/call, resources/read
Result Request と同じ id で対応 ツール実行結果、リソースデータ
Notification id を持たない。応答不要の一方通行 progress, logging, initialized
// Request の例 (id があるので Response を期待する) { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_weather", "arguments": { "city": "Tokyo" } } } // Notification の例 (id がないので応答不要) { "jsonrpc": "2.0", "method": "notifications/progress", "params": { "progress": 50, "total": 100 } }

3つのプリミティブ: Tools / Resources / Prompts

MCP サーバーが公開する3種類の機能

MCP サーバーはツール、リソース、プロンプトという3つのプリミティブ (基本要素) を公開できます。それぞれ「誰が制御するか」が異なるのが最重要ポイントです。

Tools モデル制御 (Model-controlled)

ツールは Claude が「いつ使うか」を自律的に判断する機能です。API を叩く、データベースを検索する、計算をするなど、副作用を伴う操作が該当します。Claude はユーザーの質問を分析し、必要だと判断した場合にのみツールを呼び出します。

# MCP サーバーでのツール定義 (Python SDK) @server.tool() async def get_weather(city: str) -> str: """指定された都市の現在の天気を取得します。 Args: city: 天気を取得したい都市名 (例: Tokyo, Osaka) """ data = await weather_api.fetch(city) return f"{city}の天気: {data['condition']}, {data['temp']}°C"

Claude が「この質問に答えるには天気データが必要だ」と判断したときに自動で呼び出す

Resources アプリ制御 (Application-controlled)

リソースは読み取り専用のデータソースです。ファイルの内容やデータベースのスキーマなど、コンテキストとして Claude に渡したいデータを提供します。ツールと異なり、リソースを読み込むタイミングはホストアプリケーション側が制御します。

リソースには2種類の URI があります。

静的 URI (Direct Resource)

内容が固定されたリソース。一覧として公開される。

config://app/settings

テンプレート URI (Resource Template)

パラメータを含む動的リソース。URI 構造が公開される。

db://users/{user_id}/profile
# 静的リソース @server.resource("config://app/settings") async def get_settings() -> str: """アプリケーション設定を取得します""" return json.dumps(app_config) # テンプレートリソース @server.resource("db://users/{user_id}/profile") async def get_user_profile(user_id: str) -> str: """指定ユーザーのプロフィールを取得します""" profile = await db.get_user(user_id) return json.dumps(profile)
Prompts ユーザー制御 (User-controlled)

プロンプトは事前に用意されたテンプレートで、ユーザーが明示的に選択して使います。よく使うワークフローやタスクの定型パターンをサーバー側に定義しておき、ユーザーがスラッシュコマンドのように呼び出す使い方を想定しています。

@server.prompt() async def review_code(language: str, code: str) -> str: """コードレビューのプロンプトテンプレート""" return f"""以下の{language}コードをレビューしてください。 バグ、セキュリティ問題、パフォーマンスの改善点を指摘してください。 ```{language} {code} ```"""

試験で問われるポイント: 3つの使い分け

プリミティブ 制御者 主な用途 副作用
Tools モデル (Claude) API 呼出し、DB 操作、計算 あり
Resources アプリケーション 設定読込、ファイル参照 なし (読取専用)
Prompts ユーザー 定型ワークフロー起動 なし

アンチパターン

リソースで提供すべき読み取り専用データをツールとして実装してしまうケース。ツールは Claude が自律的に呼び出すため、不要な API コールが発生するリスクがあります。データが副作用なく読み取るだけのものなら Resources を使いましょう。

MCP サーバーの構築 (Python SDK)

デコレータベースの宣言的なサーバー構築

MCP の Python SDK では、JSON スキーマを手書きする代わりにデコレータと型ヒントでツールを定義します。SDK が自動的にスキーマを生成し、バリデーションも行います。

最小構成のサーバー

from mcp.server.fastmcp import FastMCP # サーバーインスタンスを作成 mcp = FastMCP("my-weather-server") # ツールを定義 (デコレータ + 型ヒント + docstring) @mcp.tool() async def get_forecast( city: str, days: int = 3 ) -> str: """指定都市の天気予報を取得します。 Args: city: 都市名 (例: Tokyo) days: 予報日数 (デフォルト3日) """ forecast = await weather_api.get_forecast(city, days) return json.dumps(forecast) # リソースを定義 @mcp.resource("weather://supported-cities") async def list_cities() -> str: """サポートしている都市の一覧""" return json.dumps(["Tokyo", "Osaka", "Kyoto"]) # プロンプトを定義 @mcp.prompt() async def travel_plan(destination: str) -> str: """旅行プランの作成テンプレート""" return f"{destination}への旅行プランを作成してください。天気予報も考慮に入れてください。" # サーバーを起動 if __name__ == "__main__": mcp.run()

ベストプラクティス

docstring を丁寧に書くことが重要です。Claude はツールの description を頼りに「どのツールを使うべきか」を判断します。引数の意味、具体例、制約事項を明記すると、Claude の判断精度が上がります。

MCP Server Inspector

MCP Server Inspector は、開発中のサーバーをテスト・デバッグするための公式ツールです。ブラウザベースの UI でサーバーに接続し、ツールの一覧確認、手動実行、レスポンスの検証ができます。

# Inspector を起動してサーバーに接続 $ npx @modelcontextprotocol/inspector python my_server.py

Inspector が起動するとブラウザで操作画面が開き、ツールの定義を確認したり、任意の引数でツールを手動実行して結果を確認できます。本番環境にデプロイする前のデバッグ工程で必ず使いましょう。

用語解説: デコレータ vs JSON スキーマ

従来の Claude API でツールを定義するには JSON Schema を手書きする必要がありました。MCP Python SDK では @mcp.tool() デコレータを関数に付けるだけで、Python の型ヒントと docstring から自動的に JSON Schema が生成されます。開発効率とスキーマの正確性が同時に向上します。

MCP クライアントの実装

サーバーへの接続とツール呼び出しの橋渡し

クライアントの役割

MCP クライアントはホストアプリケーション内に存在し、以下の処理を行います。

  1. 1MCP サーバーとの接続を確立し、初期化ハンドシェイクを行う
  2. 2サーバーが公開するツール、リソース、プロンプトの一覧を取得する
  3. 3取得したツール定義を Claude API の tools パラメータに変換して渡す
  4. 4Claude がツール呼び出しを返したら、該当する MCP サーバーにリクエストを転送する
  5. 5サーバーからの結果を Claude に tool_result として返す
from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client # サーバーへの接続パラメータ server_params = StdioServerParameters( command="python", args=["my_weather_server.py"] ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 初期化ハンドシェイク await session.initialize() # 利用可能なツール一覧を取得 tools = await session.list_tools() # ツールを実行 result = await session.call_tool( "get_forecast", arguments={"city": "Tokyo", "days": 5} )

試験で問われるポイント

MCP クライアントとサーバーは 1:1 の関係です。1つのホストアプリケーションが複数のサーバーに接続する場合、サーバーごとに個別のクライアントインスタンスを作成します。クライアント間でセッションやツール定義は共有されません。

ツールスキーマの設計原則

Claude API でのツール定義と高度な制御

MCP を使わずに Claude API に直接ツールを渡す場合、JSON Schema で定義します。MCP Python SDK はこのスキーマを自動生成しますが、設計原則そのものを理解しておくことは試験でもシステム設計でも重要です。

ツール定義の構造

Claude API にツールを渡す際は、name, description, input_schema の3つのフィールドで定義します。

tools = [{ "name": "search_orders", "description": "顧客の注文履歴を検索します。注文番号、顧客名、 日付範囲で絞り込みが可能です。結果は最大50件まで返します。", "input_schema": { "type": "object", "properties": { "customer_id": { "type": "string", "description": "顧客ID (例: CUST-12345)" }, "status": { "type": "string", "enum": ["pending", "shipped", "delivered", "cancelled"], "description": "注文ステータスで絞り込み" }, "date_from": { "type": "string", "description": "検索開始日 (YYYY-MM-DD形式)" } }, "required": ["customer_id"] } }]

ベストプラクティス: description の書き方

  • ツールが「何をするか」だけでなく「いつ使うべきか」も書く
  • 引数の description には具体的なフォーマットや例を含める
  • enum を積極的に使い、Claude が選択肢から選べるようにする
  • 制約事項 (最大件数、レート制限など) があれば明記する

アンチパターン

description を空にする、または "Search orders" のような最低限の記述にすること。Claude はこの description を手がかりにツール選択を行うため、曖昧な記述では正しいツールが選ばれなかったり、不要なツールが呼ばれたりします。

レスポンスの処理: TextBlock と ToolUseBlock

ツールが定義された状態で Claude にリクエストを送ると、レスポンスの content 配列には2種類のブロックが混在する可能性があります。

# Claude のレスポンス (content 配列) response.content = [ TextBlock(text="注文を検索しますね。"), # テキスト応答 ToolUseBlock( # ツール呼び出し id="toolu_01abc", name="search_orders", input={"customer_id": "CUST-12345", "status": "pending"} ) ]

ツール実行後は、結果を tool_result として Claude に返します。

# ツール結果を messages に追加して再度 Claude に送る messages.append({"role": "assistant", "content": response.content}) messages.append({ "role": "user", "content": [{ "type": "tool_result", "tool_use_id": "toolu_01abc", # ToolUseBlock の id と一致させる "content": "[{\"order_id\": \"ORD-001\", \"status\": \"pending\"}]" }] })

試験で問われるポイント

tool_result の tool_use_id は、対応する ToolUseBlock の id と完全に一致させる必要があります。また、tool_result は常に role: "user" のメッセージ内に含めます。これは直感に反するかもしれませんが、API の仕様です。

tool_choice: ツール呼び出しの制御

Claude がどのようにツールを選ぶかを tool_choice パラメータで制御できます。

動作 使いどころ
{"type": "auto"} Claude が自由に判断 (デフォルト) 通常のエージェント操作
{"type": "any"} 必ず何かのツールを使う ツール使用を強制したい場面
{"type": "tool", "name": "..."} 指定したツールを必ず使う 構造化データ抽出
{"type": "none"} ツールを使わない テキスト応答のみを強制

活用例: 構造化データ抽出

tool_choice: {"type": "tool", "name": "extract_info"} を使うと、Claude はテキストから情報を抽出して指定のツールスキーマに沿った JSON を出力します。これは JSON 出力の強制に非常に有効で、ツールを実際に外部サービスに接続しなくても「構造化された出力フォーマット」として機能します。

特殊ツール: バッチツール、テキスト編集、Web検索

Batch Tool (バッチツール)

複数のツール呼び出しを1回のリクエストで並列実行できるツールです。Claude が「これらのツールは同時に呼べる」と判断した場合に自動で使われます。レスポンスの content 配列に複数の ToolUseBlock が含まれる形で返ります。

Text Edit Tool (テキスト編集ツール)

Anthropic が提供するビルトインツールで、Claude がファイルの内容を部分的に編集する操作を表現できます。type: "text_editor_20250124" で指定します。全文を書き直すのではなく、差分ベースの編集指示を Claude に出させたい場面で有効です。

Web Search Tool (Web検索ツール)

Claude に Web 検索機能を付与するビルトインツールです。type: "web_search_20250305" で有効化します。Claude が最新情報を必要とする質問に対し、自動的に Web を検索して回答に組み込みます。

トランスポート (Stdio / StreamableHTTP)

MCP サーバーとクライアントの通信方式

MCP はトランスポート非依存ですが、実装では2つの標準トランスポートが定義されています。どちらを選ぶかは、デプロイ環境やスケーリング要件で決まります。

Stdio ローカル実行向け

クライアントが MCP サーバープロセスを子プロセスとして起動し、標準入力 (stdin) と標準出力 (stdout) で JSON メッセージをやり取りします。最もシンプルな方式で、ローカル開発やデスクトップアプリに適しています。

メリット

  • セットアップが簡単 (プロセスを起動するだけ)
  • ネットワーク設定不要
  • セキュリティリスクが低い (外部に公開されない)

制限

  • 同一マシンでの実行に限定される
  • 複数クライアントからの共有ができない
  • スケーリングが難しい

初期化ハンドシェイクの流れは次の通りです。

# 1. クライアント → サーバー: initialize リクエスト {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"capabilities": {}, "protocolVersion": "2025-03-26"}} # 2. サーバー → クライアント: initialize 結果 (capabilities を返す) {"jsonrpc": "2.0", "id": 1, "result": { "capabilities": {"tools": {}, "resources": {}}, "protocolVersion": "2025-03-26"}} # 3. クライアント → サーバー: initialized 通知 (ハンドシェイク完了) {"jsonrpc": "2.0", "method": "notifications/initialized"}
Streamable HTTP リモート / 本番環境向け

HTTP ベースのトランスポートで、リモートサーバーへの接続やマルチクライアント環境に対応します。クライアントからサーバーへのリクエストは通常の HTTP POST で送り、サーバーからクライアントへの通知は Server-Sent Events (SSE) で配信します。

メリット

  • リモートサーバーに接続可能
  • 複数クライアントからの接続に対応
  • ステートレス運用が可能 (スケーリング向き)
  • 既存のHTTPインフラ (ロードバランサ等) を活用可能

考慮点

  • セッション管理 (Mcp-Session-Id ヘッダー) が必要
  • 認証・認可の仕組みを別途実装する必要がある
  • ネットワーク経由のためレイテンシが増える

用語解説: SSE (Server-Sent Events)

サーバーからクライアントへ一方通行のストリームでデータを送り続ける仕組みです。WebSocket と違い、HTTP の上で動作するため、プロキシやファイアウォールとの相性がよいのが特徴です。MCP ではプログレス通知やログの配信に使われます。

試験で問われるポイント: トランスポート選択基準

要件 推奨トランスポート 理由
ローカルの CLI / デスクトップアプリ Stdio シンプルで安全
クラウド上のマルチユーザーサービス Streamable HTTP スケーリングと認証が必要
社内ツールで少数ユーザー どちらも可 要件次第で選択
ステートレスなサーバーレス環境 Streamable HTTP セッション不要のステートレスモード

Sampling とサーバー間連携

MCP サーバーから LLM を呼び出す仕組み

通常、LLM がツール (MCP サーバー) を呼び出します。Sampling はこの方向を逆転させ、MCP サーバーがクライアント経由で LLM を呼び出せる仕組みです。

Sampling の仕組み

Sampling では、MCP サーバーが処理の途中で「このテキストを LLM に分析してほしい」というリクエストをクライアントに送ります。クライアントはそのリクエストを LLM に中継し、結果をサーバーに返します。

MCP サーバー: 「このデータを要約して」
MCP クライアント: リクエストを LLM に中継
LLM: 分析結果を生成
MCP サーバー: 結果を使って処理を続行

試験で問われるポイント

Sampling で重要なのは、サーバーが直接 LLM API を呼ぶのではなく、必ずクライアントを経由する点です。これにより、ホストアプリケーションが全ての LLM 呼び出しを監視・制御でき、ユーザーの承認フローを挟むこともできます。セキュリティとコスト管理の観点で不可欠な設計です。

# サーバー側: Sampling を使って LLM を呼び出す @mcp.tool() async def analyze_logs(log_data: str, ctx: Context) -> str: """ログデータを分析して異常を検出します""" # ctx.sample() でクライアント経由で LLM を呼び出す result = await ctx.sample( messages=[{ "role": "user", "content": f"以下のログから異常パターンを検出してください:\n{log_data}" }], max_tokens=500 ) return result.text

アンチパターン

MCP サーバーが直接 LLM API を呼び出す実装。クライアントを経由しないと、ホストアプリケーションによる監視やコスト管理ができず、ユーザーの意図しない LLM 呼び出しが発生する可能性があります。

通知とプログレス

Context オブジェクトを使った非同期通知

Context オブジェクトの活用

ツール関数の引数に ctx: Context を追加すると、プログレス通知やログ出力をクライアントに送信できます。長時間かかる処理の進捗をリアルタイムでユーザーに伝えたい場面で使います。

@mcp.tool() async def process_large_dataset( file_path: str, ctx: Context ) -> str: """大規模データセットを処理します""" records = await load_records(file_path) total = len(records) for i, record in enumerate(records): await process_record(record) # プログレス通知 (Notification なので応答不要) await ctx.report_progress( progress=i + 1, total=total ) # ログ通知 if i % 100 == 0: await ctx.log( level="info", message=f"{i}/{total} 件処理完了" ) return f"全 {total} 件の処理が完了しました"

用語解説: Notification vs Request

プログレスやログは Notification (通知) として送信されます。Notification には id がなく、応答を必要としません。一方通行のメッセージであるため、送信側は結果を待たずに処理を続行できます。Request は id を持ち、必ず Result が返ることを期待する双方向のやり取りです。

Roots とファイルアクセス制御

MCP サーバーがアクセスできるファイルパスの境界定義

Roots の概念

Roots は、クライアントが MCP サーバーに「あなたがアクセスしてよいファイルパスの範囲」を宣言する仕組みです。サーバーは Roots で指定されたディレクトリの外にあるファイルにはアクセスすべきではありません。

# クライアント側: Roots の宣言 roots = [ {"uri": "file:///home/user/project", "name": "メインプロジェクト"}, {"uri": "file:///home/user/data", "name": "データディレクトリ"} ]

Roots はプロトコルレベルの強制ではなく、サーバーへの「ガイダンス」です。悪意あるサーバーがこれを無視する可能性もあるため、ホストアプリケーション側でも追加のアクセス制御を実装するのが望ましいです。

試験で問われるポイント

Roots は「サンドボックス」ではありません。強制力を持つアクセス制御ではなく、信頼関係に基づくガイダンスです。試験では「Roots だけでセキュリティを確保できるか」という問いに対し、「追加のアクセス制御が必要」と答える選択肢が正解になるパターンがあります。

Roots の動的更新

ユーザーが別のプロジェクトを開いたり、ファイルブラウザで新しいディレクトリを選択した場合、クライアントは Roots を動的に更新できます。更新時には notifications/roots/list_changed 通知をサーバーに送ります。サーバーはこの通知を受けて、利用可能なリソースやツールの振る舞いを調整します。

本番環境でのスケーリング

ステートレス HTTP とロードバランサの設計

ステートフル vs ステートレス

Streamable HTTP トランスポートでは、セッション管理の方法によって2つのモードがあります。

ステートフル (セッションあり)

Mcp-Session-Id ヘッダーでセッションを維持する方式。サーバーは接続ごとの状態を保持します。

  • Sampling や通知など双方向通信が可能
  • SSE による長時間のストリーミングに対応
  • ロードバランサにスティッキーセッションが必要

ステートレス (セッションなし)

セッション ID を発行せず、各リクエストを独立して処理する方式。

  • 水平スケーリングが容易
  • サーバーレス環境にデプロイ可能
  • Sampling やリアルタイム通知は使えない

ベストプラクティス: スケーリング設計

  • ステートフルサーバーでロードバランサを使う場合は、スティッキーセッション (同一クライアントを同一サーバーに振り分け) を設定する
  • ステートレスモードで十分なユースケースなら、ステートレスを選ぶ方がインフラの複雑さが減る
  • セッション状態を外部ストア (Redis 等) に保存すれば、ステートフルでもスケーリング可能

アンチパターン

ステートフルなサーバーを、スティッキーセッションなしのラウンドロビン型ロードバランサの背後に配置すること。セッション途中でリクエストが別のサーバーインスタンスに振り分けられると、状態が見つからずエラーになります。

本番デプロイ時のチェックリスト

認証と認可: MCP サーバーへのアクセスに OAuth やAPI キーなどの認証を実装する
レート制限: クライアントあたりのリクエスト数を制限し、サーバーの過負荷を防ぐ
タイムアウト: ツール実行の最大時間を設定し、ハングアップを防ぐ
エラーハンドリング: 外部サービスの障害時にグレースフルに失敗する
ログとモニタリング: 全てのツール呼び出しと結果を記録する
入力バリデーション: サーバー側でツール引数を検証し、不正入力を拒否する

確認テスト

クリックで解答と解説を表示

Q1. MCP の3つのプリミティブのうち、Claude が自律的に「いつ使うか」を判断するのはどれか?

A) Resources (リソース)

B) Prompts (プロンプト)

C) Tools (ツール)

D) Sampling (サンプリング)

正解: C

Tools はモデル制御 (model-controlled) です。Claude がユーザーの質問を分析し、必要と判断した場合にのみ呼び出します。Resources はアプリケーション制御、Prompts はユーザー制御です。Sampling はプリミティブではなく、サーバーが LLM を呼び出す仕組みです。

Q2. MCP サーバーが処理中に LLM の分析能力を借りたい場合、正しいアプローチは?

A) サーバー内部で直接 Anthropic API を呼び出す

B) Sampling を使い、MCP クライアント経由で LLM を呼び出す

C) 一度処理を中断し、クライアントに結果を返してから再度リクエストする

D) サーバー間通信で別の LLM サーバーにリクエストする

正解: B

Sampling は MCP サーバーがクライアント経由で LLM を呼び出す公式の仕組みです。直接 API を呼ぶ (A) と、ホストアプリケーションによる監視やコスト管理ができません。クライアントを経由することで、全ての LLM 呼び出しがホストの管理下に置かれます。

Q3. ステートフルな MCP サーバーを本番環境でスケールアウトする際に必要な設定は?

A) ラウンドロビン型のロードバランサを配置する

B) スティッキーセッション (セッションアフィニティ) を設定したロードバランサを配置する

C) サーバーをステートレスモードに切り替える

D) 各サーバーにセッションデータを全てレプリケーションする

正解: B

ステートフルサーバーはセッション状態をメモリに保持するため、同一クライアントからのリクエストが常に同じサーバーインスタンスに到達する必要があります。スティッキーセッションがないラウンドロビン (A) ではセッションが見つからずエラーになります。外部ストアに状態を保存する方法もありますが、選択肢 B が最も直接的な解決策です。

Q4. Claude API の tool_choice で {"type": "tool", "name": "extract_info"} を指定する最適なユースケースは?

A) Claude に複数のツールから最適なものを選ばせたい場合

B) テキストから構造化データを抽出し、決まったスキーマの JSON を得たい場合

C) ツールを一切使わせずテキスト応答だけを得たい場合

D) ツール実行の並列化を有効にしたい場合

正解: B

特定のツールを指定する tool_choice は、Claude に「必ずこのツールを呼べ」と強制します。ツールの input_schema が出力フォーマットとして機能するため、構造化データ抽出に最適です。A は auto、C は none に該当し、D は tool_choice とは無関係です。

Q5. MCP の JSON メッセージで、id フィールドを持たないメッセージタイプはどれか?

A) Request

B) Result

C) Notification

D) Error

正解: C

Notification は id を持たない一方通行のメッセージです。応答を期待せず、送りっぱなしで完了します。progress 通知やログ出力がこれに該当します。Request は id を持ち、同じ id の Result が返ることを期待します。

Q6. MCP の Roots について正しい記述はどれか?

A) Roots はサーバーがクライアントに対して宣言するアクセス可能パスの範囲である

B) Roots はプロトコルレベルで強制されるサンドボックスで、外部からの違反は不可能である

C) Roots はクライアントがサーバーに宣言するガイダンスで、追加のアクセス制御も推奨される

D) Roots は Streamable HTTP トランスポートでのみ利用可能である

正解: C

Roots はクライアント側からサーバーに対して「アクセスしてよいパスの範囲」を宣言するガイダンスです。プロトコルレベルの強制力はないため (B は誤り)、ホストアプリケーション側でも追加のアクセス制御を実装する必要があります。宣言の方向が A とは逆です。

Q7. Claude のレスポンスでツール結果を返す際の正しい方法は?

A) role: "assistant" のメッセージ内に tool_result を含める

B) role: "user" のメッセージ内に tool_result を含め、tool_use_id で対応する ToolUseBlock を指定する

C) role: "tool" のメッセージとして独立して送る

D) role: "system" のメッセージ内にツール結果を埋め込む

正解: B

Claude API では tool_result は role: "user" のメッセージ内に含めます。直感に反するかもしれませんが、これが仕様です。tool_use_id で対応する ToolUseBlock の id を必ず一致させる必要があります。role: "tool" (C) は Claude API には存在しません。