MCPツールの遅延ロードにフックを差し込むJITコンテキスト注入
CloudCodeのToolSearch経由でのスキーマ取得タイミングにPreToolUseフックを噛ませ、必要な時にだけ必要な規約をモデルへ差し込むJITコンテキスト注入の設計と実例。
はじめに
CloudCodeはMCPツールを起動時に一括で読み込まず、モデルが必要としたタイミングでToolSearch経由でスキーマを取り出す「遅延ロード」を行う。この読み込みの瞬間にフックを噛ませると、そのツール固有のガイドだけをモデルへ差し込める。常時system promptを太らせずに、必要な時にだけ必要なコンテキストを渡すJIT (Just-In-Time)コンテキスト注入の構造ができる。
仕組み
CloudCodeはsettings.jsonで各種フックを登録できる。今回使うのはPreToolUseでmatcher: "ToolSearch"を指定したもの。これによりモデルがToolSearchを呼び、スキーマをロードしようとした直前にスクリプトが発火する。
スクリプトにはJSONでstdinが渡る。tool_input.queryを見れば、どのツールのスキーマを引こうとしているかが分かる。対象のツールであれば、以下の形式でstdoutにJSONを返すとモデルのコンテキストにadditionalContextが注入される。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "..."
}
}additionalContextはそのターンのモデルのコンテキストに一度だけ差し込まれる。同じツールを連続で引くケースでは、注入済みフラグを持たせて重複を避けると無駄が減る。
matcherの指定を誤ると意図しないタイミングでフックが発火する。設定変更後は必ずPreToolUseのログを確認し、対象ツール以外で発火していないか検証すること。
additionalContextにシークレット情報を含めると、モデルのコンテキストを通じて外部に漏洩するリスクがある。資格情報やAPIキーは絶対に注入しないこと。
具体例: R2ストレージのキー命名
たとえばR2を操作するツールのスキーマが引かれた瞬間にだけ、キー命名規約を差し込む。tool_input.queryにr2が含まれていれば、プレフィックス設計やライフサイクルの規約をadditionalContextとして返す。これにより、R2を触らないターンでは規約がコンテキストに乗らず、トークンを節約できる。
規約本体はリポジトリ内のMarkdownに置き、フックはそのファイルを読んで返すだけにしておくと、ドキュメントと注入内容の二重管理を避けられる。
設計上のポイント
注入する文章は短く・具体的に保つ。長い規約をまるごと流し込むと、せっかくの遅延ロードの利点が薄れる。判断に必要な最小限のルールと、参照先のパスだけを渡すのが要点になる。
また、フックは対象外のツールに対しては何も返さず即座に終了させる。全てのToolSearchで処理が走るため、対象判定は文字列マッチ程度の軽さに抑える。
フローの全体像
応用
同じ仕組みは規約の注入に限らない。テスト用ツールが引かれたらテストの実行手順を、デプロイ系ツールが引かれたら確認事項のチェックリストを差し込む、といった具合に、ツール種別ごとの作業ガイドをJITで供給する基盤として使える。
| 対象ツール | 注入する内容 | 想定タイミング |
|---|---|---|
| R2系 | キー命名規約 | ストレージ操作前 |
| テスト系 | 実行手順 | テスト追加時 |
| デプロイ系 | 確認チェック | デプロイ直前 |
| DB系 | スキーマ要約 | クエリ発行前 |
| 認証系 | トークン取り扱い | 資格情報参照前 |
| ログ系 | フォーマット規約 | ログ出力前 |
| CI系 | ワークフロー注意 | ジョブ追加時 |
| ドキュメント系 | 章構成テンプレ | ドキュメント追記時 |