メインコンテンツへスキップ
ブログ一覧

Claude Code Tool Search実践ガイド — Deferred Toolsで実現するコンテキスト95%削減の仕組みと、MCP Server設計の最適解

Claude CodeMCPTool Searchコンテキスト最適化AI開発

MCP Serverを5つ接続したら、Claude Codeの応答が目に見えて遅くなった——そんな経験はないだろうか。

50以上のツールスキーマがすべてシステムプロンプトに展開されると、コンテキストウィンドウの大半がツール定義で埋まってしまう。Claude Codeはこの問題を「Deferred Tools + Tool Search」という仕組みで解決している。ツール名だけを軽量にリストし、必要になった瞬間にスキーマを取得する——いわば「遅延読み込み」だ。

本記事では、この最適化メカニズムの内部動作から、自作MCP Serverのdescription設計がTool Search精度に直結する理由、そして実際の運用で踏むハマりポイントまでを解説する。

なぜTool Searchが必要なのか — ツール爆発問題の実態

全ツールスキーマ展開のコスト計算

Claude Codeに接続されたツールは、通常であれば会話開始時にJSON Schemaとしてシステムプロンプトに展開される。1ツールあたりの定義は、パラメータの数や説明文の長さにもよるが、平均200〜500トークンを消費する。

仮に50ツールを接続した場合、それだけで1万〜2.5万トークンがシステムプロンプトを占有する計算になる。Sonnetの200Kコンテキストウィンドウであっても、ユーザーのコードや会話履歴に使える領域が大きく圧迫されるのは明らかだ。

コンテキスト汚染がもたらす3つの弊害

ツール定義がコンテキストを圧迫すると、以下の3つの問題が同時に発生する。

  1. 推論精度の低下: コンテキストの大部分が無関係なツール定義で埋まると、LLMが本来集中すべきユーザーの指示やコードに対する注意が分散する
  2. 応答速度の低下: 入力トークン数が増えれば、処理時間もそれに比例して増加する
  3. 料金の増加: API利用の場合、入力トークンに対して課金されるため、使いもしないツール定義のために余分なコストが発生する

この3重苦を解決するのがDeferred Toolsだ。Deferred Toolsでは、ツール名だけがsystem-reminderに軽量リストとして表示される。1ツールあたり約10〜20トークンで済むため、50ツールでも500〜1000トークン程度に収まる。正直、初めてこの仕組みを知ったときは「なぜ最初からこうしなかったのか」と思った。

Claude Code起動時に以下のようなメッセージを見たことがあるはずだ。

code
<system-reminder>
The following deferred tools are now available via ToolSearch.
Their schemas are NOT loaded — calling them directly will fail
with InputValidationError. Use ToolSearch with query
"select:<name>[,<name>...]" to load tool schemas before calling them:
AskUserQuestion
WebFetch
WebSearch
mcp__my-server__create_item
mcp__my-server__delete_item
mcp__my-server__list_items
...
</system-reminder>

名前だけが並び、パラメータ定義は一切含まれていない。これがDeferred Toolsの「軽量リスト」だ。

Deferred Toolsの仕組み — 2段階ロードアーキテクチャ

通常ツール vs Deferred Toolの違い

Claude Codeのツールは2種類に分かれる。

通常ツール Deferred Tool
会話開始時 完全なJSON Schemaがfunctionsブロックで提供 名前のみsystem-reminderにリスト
即座に呼び出し 可能 不可(InputValidationError)
スキーマ取得 不要 ToolSearchで事前取得が必要

全ツール定義の合計トークン数が閾値(推定10Kトークン前後)を超えると、自動的にdefer_loadingが有効化される。この判定はClaude Codeが内部的に行うもので、ユーザーが明示的にON/OFFする設定は存在しない。

ToolSearchによるオンデマンドスキーマ取得

Deferred Toolを使うには、まずToolSearchでスキーマを取得する必要がある。ToolSearchには3つのクエリ形式がある。

typescript
// 1. select指定 — 正確なツール名で直接取得(最も確実)
ToolSearch({ query: "select:WebFetch,WebSearch", max_results: 5 })

// 2. キーワード検索 — 曖昧マッチでツールを探す
ToolSearch({ query: "slack send message", max_results: 5 })

// 3. プレフィクス+ランキング — 名前にプレフィクスを含むものを優先
ToolSearch({ query: "+mcp__analytics report", max_results: 5 })

取得されたスキーマは通常ツールと同一のfunctionsブロック形式で返される。以降はパラメータを指定して普通に呼び出せる。

code
// ToolSearchの返却例
<functions>
<function>{"description": "Fetch content from a URL...",
  "name": "WebFetch",
  "parameters": {"type": "object", "properties": {...}, ...}}
</function>
</functions>

defer_loading判定の閾値

閾値は公式に明示されていないが、接続ツール数が少ない(10個以下程度)場合はすべて通常ツールとして展開される。MCP Serverを複数接続してツール総数が増えたときに初めてdefer_loadingが発動する。

少数ツールのMCP Serverを1つだけ使っている場合は、この仕組みを意識する必要はない。

自作MCP Serverのツール設計 — Tool Search精度を左右するdescription最適化

descriptionが検索精度に直結する理由

Tool Searchのキーワード検索は、ツール名とdescriptionを対象にマッチングを行う。つまり、descriptionの書き方が検索精度を直接左右する。

以下は良い例と悪い例の比較だ。

typescript
// 悪い例: 曖昧で検索にヒットしにくい
server.tool("process", "Process the data", { ... }, async (params) => {
  // ...
});

// 良い例: 動詞+目的語で明確、検索キーワードが含まれている
server.tool("create_user_account",
  "Create a new user account with email and role assignment. " +
  "Validates email format and checks for duplicates before creation.",
  { ... },
  async (params) => {
    // ...
  }
);

ツール粒度の設計指針

1ツール1責務が基本原則だ。「何でもできる万能ツール」は、Tool Searchでどのクエリにも中途半端にマッチしてしまい、結果として適切なツールが検索上位に来ない。

python
# 悪い例: 1つのツールに複数の責務
@server.tool()
def manage_database(action: str, table: str, data: dict):
    """Manage database operations (create, read, update, delete)"""
    ...

# 良い例: 責務ごとに分離
@server.tool()
def insert_record(table: str, data: dict):
    """Insert a new record into the specified database table."""
    ...

@server.tool()
def query_records(table: str, filter: dict):
    """Query records from a database table with optional filters."""
    ...

命名規則のベストプラクティス

MCP Serverのツールはmcp__サーバー名__ツール名の形式で命名される。この構造を活かすポイントは以下の通り。

  • descriptionの1行目に動詞+目的語で要約を書く(例: "Create a new user account")
  • 詳細は2行目以降に追記する
  • 同一サーバー内の類似ツールはツール名で明確に区別する(list_users vs list_roles
  • max_resultsのデフォルトは5なので、同じサーバーに似た名前のツールが6つ以上あると検索漏れのリスクがある

Claude Codeには、Deferred Toolsとは別にSkillsという仕組みがある。両者はsystem-reminderにリスト表示される点で似ているが、根本的に異なるメカニズムだ。

Tool Search (Deferred Tools) Skills
取得対象 JSON Schema(ツール定義) プロンプト全体
呼び出し方 ToolSearchツール Skillツール
呼び出し後 パラメータを渡してツール実行 プロンプトが会話に注入される
用途 ツールの遅延読み込み 専門知識・ワークフローの遅延読み込み

Anthropic APIにはtool_search_toolというサーバーサイドの機能も存在する。Claude CodeのToolSearchは、これを内部的にラップした実装と考えてよい。

注意すべきは、ツール数が少なくてもSkillsが大量にあればsystem-reminderは肥大化するという点だ。Deferred ToolsとSkillsの両方が遅延読み込みで動いている前提で、全体のコンテキスト予算を設計する必要がある。

実践Tips — よくあるハマりポイントと対処法

「InputValidationError」が出たら

最もよくあるエラーがこれだ。Deferred Toolを直接呼び出すと発生する。

code
// エラーになるパターン
mcp__my-server__create_item({ name: "test" })
// → InputValidationError: tool schema not loaded

// 正しいパターン: 先にToolSearchでスキーマを取得
ToolSearch({ query: "select:mcp__my-server__create_item", max_results: 1 })
// → functionsブロックでスキーマが返却される
// → 以降は通常通り呼び出し可能
mcp__my-server__create_item({ name: "test" })
// → 成功

Claude Codeを普通に使っていれば、AIが自動的にToolSearchを呼んでからツールを実行してくれるため、ユーザーが意識する場面は少ない。しかし、プロンプトで明示的にツールを指定した場合や、カスタムスキルの中でツールを参照する場合には注意が必要だ。

以下のチェックリストを確認してほしい。

  1. select:で正確な名前を指定する: キーワード検索は曖昧マッチなので、意図しないツールが返ることがある。確実に取得するならselect:ツール名を使う
  2. descriptionを見直す: MCP Serverのツール定義で、検索キーワードとなりうる単語がdescriptionに含まれているか確認する
  3. ツール名変更時のキャッシュ: MCP Serverのツール名を変更した場合、Claude Codeの再起動が必要になることがある
  4. 不要なツールを無効化する: Claude Codeのsettings.jsonでMCP Serverごとにツールの有効/無効を制御できる。使わないツールをオフにすれば、閾値以下に抑えてそもそもdefer_loadingを回避する戦略も取れる
jsonc
// ~/.claude/settings.json での制御例
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["server.js"],
      "disabledTools": [
        "mcp__my-server__rarely_used_tool",
        "mcp__my-server__debug_only_tool"
      ]
    }
  }
}

個人的には、このdisabledToolsによる間引き戦略がもっと知られてもいいと思う。全ツールを有効にしたまま「なぜか遅い」と悩むケースは意外と多い。

まとめ

MCP Serverのエコシステムが拡大するほど、Tool Search / Deferred Toolsの理解は必須になる。押さえるべきポイントは3つだ。

  1. ツール数が増えたら自動的にdefer_loadingが効く。パフォーマンス劣化を感じたら、まずツール総数を確認する
  2. 自作MCP Serverではツール名とdescriptionの設計がTool Searchの検索精度を決める。1行目に動詞+目的語の要約、1ツール1責務を徹底する
  3. 不要なツールはsettings.jsonで無効化し、コンテキスト予算を本当に必要なツールに集中させる

これらを意識するだけで、50+ツール環境でもClaude Codeの推論精度と応答速度を維持できる。ツールが増えてきたなと感じたら、まずはsystem-reminderの冒頭を確認してみてほしい。"The following deferred tools are now available via ToolSearch"というメッセージが出ていれば、この最適化はすでに動いている。

もっと読む他の技術記事も読む