agent-web-search-setup について
agent-web-search-setupは、エージェントのウェブ検索ツールを診断・設定するスキルです。実際のモデルエンドポイントを検査し、利用できない組み込みツールを削除して代替ツールを使えるよう案内します。
主な機能
- 01AnthropicとOpenAIの検索エンドポイントを検査
- 02利用不可と判定不能を区別
- 03バックエンドとAPIルートの制約を特定
- 04Claude CodeとCodexでツール削除を設定
- 05既存の設定と認証情報を保持
活用シーン
- 01エージェントが検索結果を返さない問題の調査
- 02中継経由でホスト型検索が動くか確認
- 03クライアント設定で動作しない検索ツールを無効化
- 04エージェントのセッションでツール利用可否を検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ daymade/ claude-code-skills --skill agent-web-search-setupインストール後、Claude Code で/agent-web-search-setupを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/backends.mdscripts/diagnose.pytests/test_diagnose.py詳細
エージェントの Web 検索セットアップ
検索できないモデルバックエンドと、検索した結果何も見つからなかったモデルは同じではありません。しかし、会話の中から見ると、この2つは区別がつきません。このスキルは、どのエージェントを使っていても、前者を後者に変えます。エージェントのツールを設定するものであり、検索エンジンそのものではないため、ここにある内容でクエリに直接答えることはありません。セットアップが完了した証拠は、エージェント自身のセッションで実際のツールが呼び出されることです。
実際に起きている問題
Anthropic の web_search と web_fetch はサーバーツールです。API がリクエスト中にそれらを実行し、結果を同じレスポンスに組み込みます。OpenAI の Responses API の web_search も同じ仕組みです。クライアントはツールを宣言するだけです。
別のクラウドにプロキシする再販業者では、これらを実行できません。Anthropic の公式ドキュメントには、Amazon Bedrock と Google Cloud では web fetch が利用できないと記載されています。search についても、両方で同様に失敗することが確認されています。返ってくるのはエラーではありません。中身のない応答であるため、モデルはその話題は存在しないと結論づけ、確信を持ってそう答えます。これが問題の全容であり、ユーザーがツールの故障ではなく、エージェントが「バカになった」と報告する理由です。
実際に確認するのに時間がかかった点が、3つあります。
- モデルを切り替えても解決しません。 ある再販業者では、4つのモデル名が3つの異なるバックエンドにルーティングされていることが確認されましたが、どのモデルでも検索は動作しませんでした。
web_fetchも一緒に壊れます。 search だけを直すと、「何も見つかりませんでした」という失敗が、「リンクは見つけましたが開けません」という失敗に変わるだけです。- 代替ツールをインストールするだけでは不十分です。 使えないツールがメニューに残っていると、組み込みツールは壊れていると説明されていたにもかかわらず、モデルは Web 検索を21回呼び出し、インストール済みの代替ツールは一度も呼び出しませんでした。組み込みツールは直接比較では優先されます。使えないツールを削除しなければ、ほかに何をしても意味がありません。
1. このマシンで検証する
どのツールが壊れているか、ユーザーの言うことを鵜呑みにせず、自分の判断も鵜呑みにしないでください。
以下の <skill> は、この SKILL.md が入っているディレクトリです。実際のパスに置き換えてください。どうしても場所が分からない場合は、find ~ -type d -name agent-web-search-setup で見つけられます。
python3 <skill>/scripts/diagnose.py
ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN / ANTHROPIC_MODEL を読み取ります。--api openai を指定した場合は、同等の OPENAI_ 環境変数を読み取ります。または --url --key --model を指定します。終了コードは、0 は修正不要、1 は少なくとも1つのツールが使えない、2 は判定不能です。解析には --json を指定してください。
これらの値は通常、シェルにはありません。クライアントから読み取ってください。 リレーを使うユーザーは、環境変数をエクスポートするのではなく、プロバイダー切り替えツールや設定画面でセットアップしています。そのため通常のシェルでは何も見つからず、プローブは開始前に止まります。Claude Code の場合は ~/.claude/settings.json の env ブロックにあります。Codex の場合は、ベース URL が ~/.codex/config.toml の [model_providers.*] に、キーが ~/.codex/auth.json にあります。そこから読み取り、--url と --key を指定してください。キーを表示してはいけません。
この手順には動作する python3 が必要です。新しい Mac では、最初にダイアログが1つ表示されます。 /usr/bin/python3 は、初回の呼び出し時に Command Line Tools インストーラーを開くスタブとして提供されています。表示されることを想定し、表示された後ではなく、その前に説明してください。スクリプトは標準ライブラリのみを使用し、macOS に付属する 3.9 で動作するため、それ以外のインストールは不要です。Node と SDK を必要とする MCP サーバーとの違いは、まさにこのダイアログ1つだけです。
ツールごとの判定が報告され、ツール呼び出し ID のプレフィックスから実際のバックエンドが示されます(toolu_vrtx_ は Vertex AI、toolu_bdrk_ は Bedrock、ws_ は OpenAI のホスト型ツールです)。単にツールの呼び出しを拒否したモデルは、壊れているのではなく判定不能と報告されます。無反応を証拠とみなさず、再実行するか別のモデルを試してください。
遅いことは死んでいることではなく、その違いは間違えやすいものです。 あるゲートウェイは、2 つのモデル ID では約 15 秒、3 つ目では約 146 秒で応答すると計測されました。この 2 つの数値の間に設定されたタイムアウトは、完全に正常なエンドポイントを壊れていると報告します。これは、このスキルが存在する理由である誤診と同じものです。デフォルトでは遅いケースを許容します。これを短くしても、タイムアウトは判定ではなく依然として不明と報告します。
Codex は別の API を通じてバックエンドに到達するため、そちらを調べます。 そのホスト型検索は OpenAI Responses API にあり、そこでは動作するエンドポイントが web_search_call 項目を返します。--api openai はそこで問い合わせます。Anthropic の形式だけで問い合わせると、Codex ユーザーはまったく判定を得られません。
このプローブが失敗する最も一般的な方法は拒否ではなく、ルートの欠落であり、それは見た目よりも決定的です。 ここで計測されたあるリレーは、古い /v1/chat/completions には HTTP 200 で応答し、/v1/responses には HTTP 404 を返します。両方の事実が一緒に重要です。つまり、そのエンドポイントは本当に OpenAI 互換であり、ホスト型ツールが提供されるサーフェスを単に実装していないのです。したがって、そこではホスト型検索をまったく実行できず、Codex にとってはこれで問題全体が決着します。なぜなら、そのルートがホスト型ツールの使用するルートだからです。プローブはこの 2 番目のリクエストを自身で行い、unavailable を報告します。動作する Chat Completions ルートがない 404 は不明のままです。なぜなら、その場合はキーまたはベース URL のほうがより可能性の高い原因だからです。
2 つの API はモデルの名前空間を共有していないため、--api both には --openai-model (または OPENAI_MODEL) も必要です。これがないと、OpenAI プローブはスキップされ、その旨を伝えます。Claude のモデル ID を /v1/responses に送って、ツールについての判定とまったく同じように読めるモデルに関する 400 を受け取ることはありません。
Codex 側では、設定は web_search です。確認された値は disabled、cached、indexed、live でしたが、このリストはスナップショットとして扱ってください。無効な値を指定すると、Codex 自身が完全なセットを出力します。これは現在の構文を確認する最速の方法であり、古くならない唯一の方法でもあります。
すべてのプローブが動作していると返ってきたら、何かを設定する前に立ち止まって別の場所を調べてください。 そのエンドポイントではツールは正常なので、代替をインストールすると、最初の問題を修正しないまま検索する 2 つ目の方法を追加することになります。実際のマシンで 2 つの原因が確認されています。別のインストール済みコンポーネントが、どのツールも考慮される前に検索形式のリクエストに応答すること、そしてクライアント自身の設定が検索をオフにしていることです。どちらも、会話の中から見ると死んだバックエンドとまったく同じに見えます。
2. 死んだツールを削除する
diagnose.py が実際に死んでいると報告したツールのみを対象にします。動作しているツールを削除することは、安全マージンではなくリグレッションです。
| エージェント | 場所 | 内容 |
|---|---|---|
| Claude Code、ターミナルまたはデスクトップアプリの Code サーフェス | ~/.claude/settings.json | 死んだツール名を permissions.deny に追加する |
| Codex | ~/.codex/config.toml | web_search = "disabled" |
| Claude Desktop、チャットサーフェス | サポート対象外 | 以下を参照 |
クライアントはこれらを API とは異なる綴りで表し、間違った綴りは静かに失敗します。 diagnose.py は web_search と web_fetch を報告します。それは API がそう呼んでいるからです。deny リストは WebSearch と WebFetch を受け取ります。API の綴りを permissions.deny に書いても、どのツールにも一致しません。そのためファイルは変更され、実行は成功を報告し、ツールはモデルのメニューに残ったままです。何も編集しないのと同じ行き止まりです。このため、診断はその結論の隣にクライアントの綴りを出力します。それを使ってください。
permissions.deny にツール名をそのまま書くと、モデルのコンテキストからツールが完全に削除されます。これが望む動作です。セッションの init イベントを読んで検証済みです。ツールは、使用を控えるよう助言付きで提示されるのではなく、モデルが受け取るリストから存在しなくなります。
このイベントは以下で何度か言及するため、実際に取得する方法を説明します。
最初の行を取得しないでください — SessionStart フックが設定されたマシンでは、フック自体の出力の後ろにある24行目(全24行中)に到着したことが測定されています。
このように、種類でフィルターしてください。
claude -p "reply ok" --output-format stream-json --verbose < /dev/null > /tmp/init.jsonl
python3 -c "
import json
for line in open('/tmp/init.jsonl'):
d = json.loads(line)
if d.get('type') == 'system' and d.get('subtype') == 'init':
print('WebSearch:', 'WebSearch' in d['tools'], ' WebFetch:', 'WebFetch' in d['tools'])
break"
2つの False は、モデルが受け取る内容からツールがなくなったことを意味します。同じイベントには permissionMode も含まれているため、ステップ4で説明する理由から、同時に読み取る価値があります。
拒否は許可よりも広い範囲に適用されます。この非対称性はステップ4で重要です。
permissions.deny は、誰も信頼したことのないディレクトリであっても、プロジェクト独自の .claude/settings.json から適用されます。そこで init イベントを読み取って測定したところ、WebSearch と WebFetch を除いた24個のツールが列挙され、警告は表示されませんでした。ステップ4の許可は、このようには機能しません。信頼されていないファイルから届いた制限に従うのは安全ですが、権限の付与はそうではありません。クライアントがこの2つを異なるものとして扱うのは正しいことです。
もう1つの非対称性は同期に関するもので、複数プロファイルのマシンで拒否をどこに設定するかを左右します。 ステップ4では、他のプロファイルが同期元とするプロファイルに許可を設定します。settings.json を統合する同期ツールは、それ以外の場所にある設定を削除するためです。拒否はその場所には設定できません。ソースプロファイルは他のすべてのプロファイルがコピー元とするプロファイルなので、そこに拒否を設定すると、組み込み検索が機能しているプロファイルにまで適用されます。機能しているツールを取り除くことは、このステップの冒頭で警告した回帰です。プロファイルごとに設定でき、かつ同期ツールの範囲外にあるレイヤーは、プロファイルランチャーが --settings で渡す設定ファイルです。同じマーケットプレイスにある claude-switch-models-setup には、そのファイルと、そこから拒否が適用されることを示す測定結果が記載されています。設定を誤ると、すぐに見分けられる症状が現れます。修正は実行したセッションでは機能するものの、ユーザーに依頼した再起動後には機能しなくなります。これは、ファイルが書き換えられたというより、再起動が反映されなかったように見えます。
どちらの編集も、そのまま示せるほど簡潔です。読み手が形を説明から組み立てるよりも確実です。
{ "permissions": { "deny": ["WebSearch", "WebFetch"] } }
web_search = "disabled"
この TOML の行は、ファイル内の最初の [table] ヘッダーより前に置く必要があります。末尾に追加すると誤った設定になります。 これは単独のキーであるため、TOML では直前のテーブルに属します。ステップ1で読み取りのために同じファイルを開いたときに見つける [model_providers.…] ブロックの後に置くと、model_providers.<name>.web_search となり、どこからも読み取られない設定になります。ファイルは変更され、コマンドも成功しますが、ホスト型検索は有効なままです。ファイルの先頭に独立した行として追加し、ファイルを読み戻して確認してください。
置き換えず、統合してください。 これらのファイルにはユーザー自身の設定が含まれています。キーを1つ追加し、残りはバイト単位で変更しないでください。変更前と変更後を見せてください。
キーをコピーするより、キーを参照する設定を優先してください。 クライアントが環境変数から認証情報を読み取れる場合は、シークレットを設定ファイルに書き込むのではなく、その参照を登録してください。これらのファイルは、ヘルプリクエストに添付するためにスクリーンショットを撮られたり、丸ごと共有されたりします。ファイルに貼り付けたキーは、そのファイルと一緒に共有されます。
デスクトップアプリには、1 つではなく 2 つのクライアントがあります。 Code サーフェスは、アプリがダウンロードして同梱する本物の
claude バイナリを実行し、Claude Code の設定エンジンを備えているため、
上の行が当てはまります。アプリ自体のバンドルから、このエンジンが設定を探す場所が決まります。設定ルートは、設定されていればアプリの設定ストアに保存されている値、そうでなければ
process.env.CLAUDE_CONFIG_DIR、それもなければ ~/.claude です。アプリ独自のエラーメッセージにも明記されています。設定ルートの移動は、デスクトップの設定から CLAUDE_CONFIG_DIR を指定すればサポートされます。つまり、~/.claude/settings.json
を編集すれば両方のクライアントに反映されます。この前提が崩れるのは、その画面で設定ルートを移動したユーザーの場合だけです。修正済みだと伝える前に、本人に確認するか、セッションの init イベントを読み、ツールが実際に消えていることを確かめてください。その際、アプリの coworkWebSearchEnabled
設定に手を出してはいけません。アプリはこれを設定として読み取るのではなく、アカウントで機能を利用できるかどうかに基づいて書き込むため、手動で編集しても次回の起動時に上書きされます。
スコープは見た目以上に重要です。 claude mcp add は local、user、project を指定する --scope を受け取り、既定値は local です。一見、影響範囲が限定されているような名前ですが、実際にはユーザーの本物の ~/.claude.json に書き込みます。必ず --scope を明示し、変更する前に、どのファイルを変更するのか伝えてください。
チャットサーフェスは対象外です。そのことを伝えるほうが、即興で対処するより適切です。 組み込みの検索をオフにする方法は見つかっておらず、コネクターの設定手順は専用の設定画面で一連のクリックを行うもので、スクリプトでは操作できません。また、そのクリック手順もメニュー名もここには記載されていないため、試すエージェントは UI を推測することになります。そうしてはいけません。この手順はそのサーフェスを対象としていないことをユーザーにはっきり伝え、対象となる場所で作業を進めてください。同じマシン上の Claude Code、つまりターミナルかデスクトップアプリの Code サーフェスなら、以下のすべての手順をファイル編集で行えます。
ゲートウェイがツール定義に対して HTTP 400 を返し、無言で空の結果を返すのではない場合、削除は単なる設定上の選択ではなく前提条件になります。モデルが何かを読む前に、リクエストが検証エラーで失敗するためです。
3. モデルが実際に呼び出せる代替手段をインストールする
代替手段はクライアント実行型のツールでなければなりません。壊れているツールに欠けているのが、その性質だからです。MCP サーバーはこれに該当します。エージェントがローカルで実行し、バックエンドには通常の関数呼び出しとしてしか見えません。
スキルバンドルもこの基準に照らして確認してください。基準を満たせないものもあるためです。「エージェントにインターネットアクセスを与える」パッケージの多くは、サーバーではありません。モデルがすでに宣言している機能を調整するための指示にすぎません。それが致命的かどうかは、どの機能を使うかによって決まります。指示に従って組み込みの WebSearch や web_fetch を呼び出すパッケージは、修正対象である問題をそのまま引き継ぎ、もっともらしい見かけだけを上乗せします。一方、ローカルプロセス、つまり CLI、curl、シェル経由のスクリプトを動かすものには影響しません。
そのため、インストールする前に、バンドルが実際にどのようにネットワークへアクセスするのかを確認してください。これは、バンドル全般を信用すべきでないという意味ではありません。ここで調べたもののうち、ローカルにインストールして内容を確認した 2 つは、どちらもシェル経由で動作していました。1 つは CLI、もう 1 つは Python スクリプトを使っていました。動作しないのは、より限定された種類です。メニューにも記載されています。検索 URL の一覧をモデルに渡し、モデル自身のフェッチツールで結果を読むよう求めるパッケージです。このエンドポイントでは、そのツールが使えない可能性があります。
このことは、組み込み検索が機能していないゲートウェイを経由し、モデルが知り得ない乱数を使って、エンドツーエンドで検証しました。結果は直接 API を使った対照実行とバイト単位で一致しました。同じゲートウェイが異なる 2 つのクラウドに振り分ける 2 つのモデル ID で確認できたため、この往復処理が特定ベンダーのパススルーの挙動に依存しているわけではありません。 references/backends.md を読んで、現在の選択肢を確認してください。各選択肢でユーザーに必要な登録とローカルインストールの内容、どこから利用できるか、デフォルトとしてマークされているものを確認します。次の基準を、この順番で適用してください。
- 登録不要の選択肢を、アカウントが必要なものより優先します。
- ローカルへのインストール不要の選択肢を、ランタイムが必要なものより優先します。標準状態の macOS には Node も、使える
python3もありません。システム付属のものはスタブで、初回の使用時に Xcode インストーラーのダイアログを開きます。また、ここで検討した MCP サーバーはすべて、標準ライブラリに含まれていない SDK を必要とします。 - ユーザーが実際にいる場所から利用できること。
- ユーザーが質問した言語で回答すること。 これは品質の好みの問題ではありません。中国語で仕事をしている人が英語の情報源を返されれば、そのツールはまだ壊れたままだと受け取ります。それこそ、この手順全体で防ごうとしている結果です。
- 最後に、結果の品質です。実行できない優れた検索より、動作する検索のほうが優れています。
技術に詳しくないユーザーに選択肢をすべて提示してはいけません。選んだものとその理由を一文で伝え、残りは尋ねられたときの選択肢として残してください。
Codex では、ホスト型サーバーを codex mcp add で登録してはいけません。2 行を自分で書いてください。 codex mcp add <name> --url <url> は設定項目を書き込んだ後、エンドポイントが OAuth を通知していることに気付き、ブラウザーのフローを開始して、認証 URL を表示したままタイムアウトなしで停止します。そのため、これを同期的に実行するエージェントは、どれだけ待つことになるか分からないまま自分のセッションを停止させます。待つ必要はありません。フローが始まる前に項目はすでにディスクに書き込まれており、フローを完了しなくても、デフォルトのバックエンドはその後匿名で応答しました。コマンドは使わず、これを追記してください。書き込まれる内容とバイト単位で一致します。
[mcp_servers.exa]
url = "https://mcp.exa.ai/mcp"
ステップ 2 の web_search 行とは異なり、こちらにはテーブルヘッダーが含まれているため、ファイルの末尾に記述しても問題ありません。
次に、git リポジトリの外で codex exec を実行すると、Not inside a trusted directory and --skip-git-repo-check was not specified というエラーが発生して拒否されます。フラグを渡すか、追跡対象の場所で実行してください。また、標準状態の Mac では timeout を使ってどちらの問題も回避できません。これは基本システムには含まれておらず、Homebrew の coreutils にしかありません。
この手順の後半は、推測ではなく、実際のバックエンドに対して最初から最後まで実行しました。web_search = "disabled" の状態で codex mcp add を 1 回実行すると、モデルは時事問題に関する質問に対して mcp__exa__web_search_exa と mcp__exa__web_fetch_exa を呼び出して回答しました。開いたページには実行日の前日の日付が記載されており、学習データから得られるはずのない、十分に新しい情報でした。利用可能な検索ツールはほかにありませんでした。自身のツールを列挙した結果にも、該当するものは含まれていませんでした。
4. 動作を確認する
設定を書き込んだだけでは成果物とは言えません。モデルがすでに知っているはずのない、今週の出来事などを尋ね、実際の URL とともに本当の検索結果をユーザーに示してください。技術に詳しくない人が「設定済み」と「動作中」の違いを見分けられないなら、まだ完了していません。
今インストールしたものだけが使える状態で確認してください。 複数のバックエンドが登録されていると、動作するものが壊れているものの代わりに応答し、実際には機能していない設定でもチェックが成功してしまいます。結果が表示されたことを確認するだけでなく、どのツールが結果を生成したのか、名前を確認してください。同じ落とし穴で製品のリリースに支障が出たことがありました。そのため現在では、接続テスト中はまさにこの理由から、自身のフォールバックを無効にしています。
そのチェックはやる価値があります。この手順全体は、まさにこの診断が死んでいると報告したばかりの組み込み検索を備えたライブリレーに対して、厳密な default 権限を報告するセッションで、代わりに応答できたはずの接続済み MCP サーバーを他に 4 台抱えるマシン上で実行されました。トランスクリプトには置き換えツールが呼ばれたことだけが示され、実行のカウンターには組み込み検索の呼び出しがゼロであることが示され、その回答にはその週に公開された実際の URL が含まれていました。回答へ飛ばずにツール名を読んでください。同じ手順の以前の実行は間違った理由でグリーンに見え、それを示したのはツール名だけでした。
トランスクリプトファイルを探しに行くのではなく、実行自身の出力から読み取ってください。 検証コマンドに --verbose --output-format stream-json を追加すると、その実行は上で読んだ init イベントに加えて、tool_use ブロックごとに 1 つの assistant イベントを出力します。それらのブロック内の名前を数えればこのステップに答えが出ますし、それらはこの実行からしか来られません。これらのフラグは stdout を JSONL に変えるので、ユーザーが見る回答は画面からではなく最後の result イベントから出てきます。そして上記の stderr リダイレクトは別のストリームなので影響を受けません。代わりにトランスクリプトを探しに行くと、それぞれが自信満々の誤った答えを返す 3 つの形で失敗します。-p サブプロセスはトランスクリプトを呼び出し元のものではなく自身の作業ディレクトリから導かれたディレクトリに保存するため、明白なディレクトリ内の最新ファイルは呼び出し元自身のセッションになります。そのセッションのトランスクリプトには呼び出し元自身の以前の組み込み検索呼び出しが記録されており、うまくいった修正に対する反証として読めてしまいます。そして非 ASCII のプロンプトはエスケープされて保存されるため、入力どおりのプロンプトでファイルを grep しても何も一致しません。あるセッションはこれで 3 回の試行を失い、その後、修正前の実行を修正がうまくいった証拠として報告しました。
先に付与を行ってください。 その証拠が属する場所がそこだからという理由で、このセクションのさらに下に書かれていますが、それはこのコマンドの前に行われます。付与されていないサーバーでチェックを実行すると拒否が返り、それはステップがまだ実行されていないというよりも、修正が失敗したように読めます。
Claude Code では、分離は検証実行における 2 つのフラグで、どちらも CLI 上に存在することが確認されています。チェックを 1 つのコマンドとして実行してください:
claude -p "search the web for news published this week about <topic>, open one of them and quote a line from the page" \
--disallowedTools WebSearch,WebFetch \
--disable-slash-commands < /dev/null 2> /tmp/verify-stderr.log
このクエリが検索およびフェッチを求めているのは意図的です。検索のみのチェックは、フェッチツールが一度も付与されなかった構成でも合格してしまい、それが元の失敗の「見つけたが開けない」という半分だからです。
2> /tmp/verify-stderr.log はフラグと同じくらい重要です。黙って落とされた付与を説明する唯一の警告はそこにだけ現れ、他のどこにも現れません。ですので後でそのファイルを読んでください。空のファイルは情報の欠如ではなく、合格の一部です。
< /dev/null は飾りではありません。これがないとコマンドは決して来ない入力を待ち、stdin についての警告を出力します。それはユーザーの肩越しに見ている人にとって、あなたが直すよう頼まれた失敗とまったく同じに見えます。
その分離を得るために CLAUDE_CONFIG_DIR に手を伸ばさないでください。 認証情報は config ディレクトリに存在するので、それを空のディレクトリに向けると Not logged in と返り、それは検索とは何の関係もなく、セッションを誤った道へ送ります。2 つのフラグはログインが存在する場所に触れることなく実行を分離します。
そのメッセージにはマルチプロファイルのマシンで第 2 の原因があり、同じように読めます。設定ファイル内で認証情報が、プロファイルランチャーが --settings で渡す場所に存在する場合、CLAUDE_CONFIG_DIR を設定してもそのフラグを外したままの実行は同じく Not logged in と返ります。他にトークンを読み込むものがないからです。同等に見えるものを組み立てるのではなく、ユーザー自身の起動コマンドを、それが持つすべてのフラグとともに再現してください。
--disallowedTools は組み込みを比較から除外し、クライアントの綴り、つまり拒否リストが取るのと同じものを取ります。--disable-slash-commands はインストールされたすべてのスキルをオフにするので、新しいツールが検討される前にそれらのどれもクエリを横取りできません。
モデルが新しいツールを名前で呼び出したことを確認します。結果だけでは証明になりません。
別のインストール済みスキルが、ツールが検討される前に検索らしいリクエストを横取りできることが、実機で確認されています。その場合、誤った経路でトークンを1ドル分消費しました。
Codexでは、同等の確認に必要なのは2つのコマンドです。また、すぐ思いつくgrepは間違いです。 クエリを実行してから、その処理が書き出したロールアウトを読み取ります。
codex exec --skip-git-repo-check \
"search the web for news published this week about <topic>, open one and quote a line" \
2> /tmp/codex-verify.log
SID=$(grep -o 'session id: [0-9a-f-]*' /tmp/codex-verify.log | tail -1 | awk '{print $3}')
[ -z "$SID" ] && echo "no session id in the log -- stop and read it" && exit 1
ROLLOUT=$(find "${CODEX_HOME:-$HOME/.codex}/sessions" -name "rollout-*$SID.jsonl" | head -1)
[ -z "$ROLLOUT" ] && echo "no rollout file for $SID -- is CODEX_HOME the one codex just wrote to?" && exit 1
python3 -c "
import json, re, sys
names = set()
for line in open(sys.argv[1]):
try: d = json.loads(line)
except Exception: continue
p = d.get('payload') or d
if p.get('type') in ('custom_tool_call', 'function_call'):
names.update(re.findall(r'mcp__[a-z0-9_]+', json.dumps(p)))
print('\n'.join(sorted(names)) if names else 'NO MCP TOOL CALLS IN THIS SESSION')
" "$ROLLOUT"
ここで重要なのは3点です。どれも、すぐ思いつく近道ではうまくいきません。
Codexが標準エラー出力に表示するセッションIDでファイルを見つけるのは、最新のロールアウトをglobで探すよりも確実です。これは細かいことにこだわっているわけではありません。一般的なインストール環境で、累積セッション数が9,021件あると、ls -t .../sessions/*/*/*/rollout-*.jsonl は argument list too long で失敗することが実測されています。さらに、これを head にパイプすると、行全体が出力なしで終了コード0を返します。これは「モデルはMCPを一度も呼び出さなかった」ようにしか見えません。実行できなかったために成功を報告する確認ステップこそ、このスキルが別の形で正そうとしている問題です。find は引数リストを展開せずにたどるため、セッション数がどれだけ増えても、この上限には達しません。
exit 1 の行が2つあるのは、それぞれ無出力になる原因が異なるためです。 最初の行がなければ、codex exec が起動しなかった場合にログが空のままになり、コマンドは何も解析しません。2つ目の行がなければ、誤ったセッションツリーを指す CODEX_HOME ではファイルが見つからず、パーサーは自身の NO MCP TOOL CALLS IN THIS SESSION というフォールバックも含め、まったく実行されません。そのため、確認処理は何も出力せずに0を返します。ここでは、どの分岐でもツール名を出力するか、ツールがなかったことを出力するか、完了できなかった手順を示します。
同じ理由から、ツール呼び出しレコードだけを読むことも重要です。ファイルに対して単純に grep mcp__ を実行すると、モデルに渡されたツールの一覧にも一致します。そのため、サーバーが宣言されただけで一度も呼び出されていない場合でも、チェックは成功してしまいます。実際のセッション1件で両方向の動作を確認済みです。上記のパーサーは、実際に呼び出された2つのExaツールを返し、同じファイル内に宣言だけで記録されている38個の mcp__codex_apps__* ツールは返しません。
また、function_call をgrepしてはいけません。ここで測定したビルドでは、MCPツールはexecのインターフェースを通じてモデルに渡されます。そのためモデルは tools.mcp__exa__web_search_exa(...) を呼び出すJavaScriptを書き、レコードでは exec という名前の custom_tool_call として記録されます。function_call をgrepすると、正常に動作した実行でも0件になります。パーサーはどちらの形式も処理できます。
サーバーの登録は最後の手順ではありません。権限の付与こそが最後の手順です。 新しく追加したMCPサーバーは未承認の状態で起動します。通常の権限で実行中のセッションでは、そのツールは Claude requested permissions to use mcp__<server>__<tool>, but you haven't granted it yet というメッセージとともに拒否されます。するとモデルはユーザーに認可が必要だと伝えて停止します。ユーザーから見れば、これは修正を依頼した検索が壊れた状態と区別がつきません。permissions.allow に、診断とクライアントの両方で使われる、プレフィックス付きのツール名を追加して許可します。claude を対話形式で一度実行し、承認することでも同じ設定が行われます。
検索ツールだけでなく、利用するすべてのツールに権限を付与してください。 web_fetch も動作しなくなっていて、検索と取得の両方を置き換えるバックエンドをインストールした場合、取得ツールにも独自のエントリが必要です。検索だけを許可すると、ページは見つけても開けない実行になります。また、検索だけを行う確認クエリではこの問題に気づけません。デフォルトのバックエンドでは、次の2つの名前を指定します。
{ "permissions": { "allow": ["mcp__exa__web_search_exa", "mcp__exa__web_fetch_exa"] } }
このマシンで複数の Claude Code 設定プロファイルを使っている場合は、プロファイルの同期元になっているものに許可を追加してください。 複数のプロファイル間で settings.json の内容を統一するプロファイル同期ツールは、permissions.allow などのネストされたコレクションを、同期元プロファイルの値全体で上書きします。そのため、ほかのプロファイルに追加した許可は、次回の同期時に消えてしまいます。同じマーケットプレイスにある claude-switch-models-setup はそのような同期ツールの一つで、同期元の決定方法を確認する際の参考になります。この説明をここに記載しているのは、ステップ 4 で追加する許可が、まさにこのツールによって統一されるファイルに記述されるからです。
claude mcp list ではサーバーが公開するツールはわかりませんし、claude mcp get でもわかりません。references/backends.md には、一部のエントリーについてはツール名が記載されていますが、ほかのエントリーにはありません。デフォルトの 2 つは記載されていますが、記載のないものも複数あり、候補の一つはアカウントなしではツール名を特定できないことがわかりました。
そのため、必ずツール名が示される拒否メッセージを使ってください。 何も許可せずにクエリを一度実行し、Claude requested permissions to use mcp__<server>__<tool> の中から直接ツール名を読むか、--output-format json の permission_denials[].tool_name から読み取ってください。これは、誰も情報を記録していないバックエンドでも使える唯一の方法で、実行は一度で済みます。
許可は ~/.claude/settings.json に追加してください。プロジェクト固有の
.claude/settings.json に追加しても無視されます。以前のバージョンのこの
スキルでは、誤ってそのファイルを案内していました。 Claude Code がプロジェクト共通設定ファイルの permissions.allow を受け入れるのは、ユーザーが信頼ダイアログを承認したワークスペースだけです。それ以外の場所ではエントリーを破棄し、そのことを stderr に報告します。--output-format json には決して出力されないため、構造化出力を読むエージェントには拒否だけが見え、その理由はわかりません。
Ignoring 2 permissions.allow entries from .claude/settings.json: this workspace has
not been trusted. Run Claude Code interactively here once and accept the trust
dialog, or set projects["<dir>"].hasTrustDialogAccepted: true in <config>/.claude.json.
この数値は破棄されたエントリーの数であり、許可したツールの数と一致します。文全体ではなく、has not been trusted を検索してください。
あるマシンでリレー経由の実行を 5 回行いました。サーバーは 5 回すべてで同じ設定で登録し、許可の追加先だけを変えました。さらに、失敗したケースをストリームとして 6 回目に記録しました。モードの確認元はこのストリームです。そのセッションの init イベントには、制限の厳しい permissionMode: default と記録されており、同じイベントで WebSearch はすでに除外された状態で、ツールが 24 個あることも確認できます。5 回の結果は次のとおりです。~/.claude/settings.json では機能します。.claude/settings.local.json でも機能します。プロジェクト共通の .claude/settings.json では拒否され、その警告が stderr に出力されます。hasTrustDialogAccepted を持つワークスペースでは、同じファイルでも機能します。何も許可しない場合は、信頼されていない共通設定ファイルと同じように失敗します。これが要点であり、会話の中からは気づきにくい理由です。どちらの拒否でも、モデルがユーザーに許可を求めます。
仕組みは以上です。これは信頼に関するもので、「project」という単語に関するものではありません。解決できるスコープフラグを探す必要はありません。
同じ理由で、サーバーも同じ階層に登録してください。ユーザーファイルに許可を追加し、サーバーを特定のプロジェクトに登録した場合、機能はします。しかし、ユーザーがエージェントを別のフォルダーで開くと、機能しなくなります。「インターネットへのアクセス」を求める人が望んでいるのは、そういうことではありません。
あなたのマシンでは通る権限チェックが、相手のマシンでは失敗することがあります。実際にこのケースがありました。 同一の設定で実行しても結果が異なりました。セッションが permissionMode: auto と報告した一方では、ツールを自由に呼び出せましたが、permissionMode: default と報告したもう一方では、同じ呼び出しが拒否されました。違いは認証情報でした。クライアントをリレートークンに接続すると、ログイン済みアカウントで利用できていた緩和モードからセッションが外れます。そのため、リレートークンも含め、ユーザーが実際に使っている設定で検証してください。そうしないと、緑色のチェックが得られても、それはあなたのマシンだけのもので、相手のマシンでは通用しません。
claude mcp list も準備状況の確認にはなりません。 能力ではなくステータスを報告するもので、ツールが応答した場合も拒否された場合も、どちらの実行でも Pending approval と表示され続けました。一覧表示を検証として扱うエージェントは、すでにインストール済みのものを再インストールしてしまい、それでも動作するかどうかは分かりません。
curl が到達できるサーバーでも読み込みに失敗することがあり、その間もヘルスチェックは Connected と表示します。 一連の兆候は次のとおりです。登録済みで、ステータス行には Connected と表示され、詳細には tools fetch failed — MCP error -32001: Request timed out とあり、ツールはモデルのコンテキストに表示されず、同じ URL に対する単純な curl は終始 200 を返します。あるマシンでは、原因は到達可能性ではなくラウンドトリップごとの遅延でした。initialize に 7.1s、tools/list に 8.1s、コールドハンドシェイクには 23.2s かかり、クライアントの許容範囲を超えていました。ユーザーがプロキシを再起動すると、同じハンドシェイクは 7.3s で完了し、ツールが読み込まれました。そのため、ラウンドトリップの所要時間を計測し、比較対象として同じマシンから 2 つ目のホストも計測してください。一方のホストは一瞬で応答し、MCP ホストには数秒かかるなら、問題は設定ではなく経路にあります。その場で安易に筋の通った説明に飛びつかないでください。 そのセッションでは、MCP ホストがプロキシのフェイク IP 範囲に解決されたことが原因だとされましたが、後の確認で反証されました。両方のホストがその範囲内にありながら、レイテンシには 20 倍の差がありました。その範囲内にあることは、動作するホストと失敗するホストを分ける要因ではありません。ラウンドトリップ時間こそが要因です。
claude mcp get <name> でサーバーのヘルスチェックを行い、Status: ✔ Connected または実際のトランスポートエラーを確認できますが、フィルタリングされていない出力をエージェントとの会話に表示しないでください。stdio の Environment やリモートヘッダーに認証情報が含まれている可能性があります。登録の範囲だけを確認すればよい場合は、フィールドを限定した確認の手順を使用してください。トランスポートの詳細をすべて確認する必要がある場合は、人間がエージェントとの会話の外で確認し、秘密情報を含まないエラーの種類だけを報告してください。どちらの方法でも、許可が反映されたかどうかや、サーバーが公開しているツールは分かりません。準備状況の確認に答えられるのは、実行時の init イベントと tool_use イベントからツール名を読み取って行うライブクエリだけです。
確認すべきなのは名前ではなく、トリガーの一覧です。 インストール済みスキルのフロントマターを読み、トリガーに単独の検索語(「search」「find」「搜」「查」)が含まれるものを探してください。グローバルにインストールされたルーターが、まさにその一覧を持っていることが確認されました。そのため、そのマシンでは MCP ツールが検討される前に、すべての検証クエリがそのルーターに先取りされていました。確認時は --disable-slash-commands を使えば解決します。日常的に使う場合は、別のスキルがあることをユーザーが把握しておく必要があります。
URL を抜き取りで確認し、偽物だと判断する前に基準を確かめてください。 バックエンドは、解決できない URL に対してももっともらしいタイトルを返すことがあるため、ユーザーに提示するリンクは curl -sIL で確認する価値があります。200 以外の応答だけで、リンクが捏造されたとは限りません。ニュースサイトは自動リクエストを拒否することがあり、curl に 401 や 404 を返すページでも、ブラウザーでは問題なく読み込める場合があります。結論を出す前に、同じコマンドでそのサイトのルートを取得してください。ルートも同じように失敗するなら、リンクが捏造されたのではなく、サイトがクライアントを拒否しています。この手順を試した 2 回の実行では、どちらも最初に「バックエンドがでっち上げた」と判断しましたが、どちらも誤りでした。1 回はサイト全体が 404 を返し、もう 1 回はドメインがすべてに 401 を返していました。
回答が使う言語で検索してください。中国語の質問なら、中国語で尋ねたほうが中国製品についてよりよい情報源が得られます。
元に戻す
試用して役に立たなかった場合、バックエンドが応答を拒否し始めた場合、マシンをほかの人に引き渡す場合など、誰かが元の状態に戻すよう求めることがあります。どちらのコマンドも、変更したファイルを正確に表示します。
claude mcp remove <name> --scope user
codex mcp remove <name>
どちらも実行しました。どちらも、それ以外の部分はバイト単位で同一のままです。Codex のコマンドでは、config.toml のほかのキーはすべて変更されません。
落とし穴は、手順の半分しか戻らず、しかも間違った半分を戻すことです。 動作しない組み込み機能は引き続き拒否されるため、ここで作業をやめたユーザーは、もともとの壊れた検索機能よりも悪い状態、つまり検索機能がまったく使えない状態になります。これは、アンインストール手順に従った結果です。置き換えた機能を取り除くなら、手順 2 で無効にしたものも元に戻す必要があります。permissions.deny からツール名を削除し、Codex では codex mcp remove が変更しない web_search も復元してください。あとから config.toml を読み返すと、web_search = "disabled" がそのまま残っていることを確認できます。
以前の値を覚えていることに頼らないでください。 手順 2 では、設定を変更する前に値を確認し、その結果をユーザーへのメッセージに記録してください。セッション後も残るのは、このメッセージだけです。キーがファイルに存在しなかった場合は、そのことを記録しておくほうが役に立ちます。その場合、元に戻すときはデフォルト値を推測するのではなく、行を削除します。記録されていない値を復元するには、値を選ぶしかありません。ここで妥当そうな誤った値を選ぶと、正常に動作するバックエンドでもホスト型検索が無効なままになる可能性があります。
完了状態
diagnose.pyが動作しないツールを特定し、そのツールだけを削除しました。- 置き換え機能が登録され、許可も付与されています。モデルはその機能を呼び出し、権限によって拒否されることはありません。
- ライブクエリから実際の最新情報を示す引用可能な URL が返され、ユーザーに表示されました。
- 実行時の出力に、回答したツール名が記載されており、それは新しいツールです。
- クエリは、このマシンにたまたま設定されていた緩い設定ではなく、中継の認証情報も含め、ユーザーが実際に使用している設定で実行されました。
- 権限付与の設定は、クライアントが実際に読み込む場所にあります。検証の実行時に、無視されたエントリーについて標準エラー出力に何も表示されませんでした。
- 手順 2 で変更したすべての設定について、変更前の値を記録しました。そのため、開始時よりも悪い状態にすることなく手順を元に戻せます。
- 変更したファイルはすべて上書きせず、既存の内容に統合し、ユーザーには差分を表示しました。
リファレンス
- references/backends.md — 選択肢の一覧、それぞれのコスト、現在のデフォルト値。