webfetch について
webfetch は、LLM エージェント向けのセルフホスト可能な Web 検索 MCP サーバーです。検索、取得、ランキングのパイプラインとセマンティックキャッシュを備えています。モデルが他のツールと同様に呼び出せる web_search ツールとして提供され、入力トークンと費用の削減を目指します。
主な機能
- 01DDG を含む複数エンジンの RRF 統合(DDG はキー不要)
- 02JS レンダリングに対応したローカルでのページ取得と抽出
- 03ハイブリッドランキングと文単位の圧縮
- 04完全一致とセマンティックの二層キャッシュ、クエリ種別ごとの有効期間
- 05save_finding、status、savings_report などのツール
活用シーン
- 01Claude Code に検索ごとの料金なしで Web 検索を追加
- 02長いセッションで検索結果が占めるコンテキストトークンの削減
- 03言い換えられた同一の検索クエリに対するキャッシュの再利用
MCP 対応
本プロジェクトは MCP サーバーであり、web_search、fetch_url、save_finding、status、savings_report の 5 つのツールを MCP クライアントに公開します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx webfetch-llmBRAVE_API_KEYシークレットOptional - adds Brave to the multi-engine fusion. DDG works with no keys at all.SERPER_API_KEYシークレットOptional - adds Serper (Google results) to the multi-engine fusion.TAVILY_API_KEYシークレットOptional - adds Tavily to the multi-engine fusion.WEBFETCH_PROVIDEROptional - search strategy: multi (RRF fusion of available engines, default), fallback (priority failover), or a single engine name like ddg.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
webfetch
自分で実行する LLM エージェント向けのウェブ検索です。精度は同等のまま、ホスト型の web_search と比べて入力トークンを最大 8 分の 1、コストを 3 分の 1 に抑えます。
ホスト型のウェブ検索ツールでは、検索 1,000 回あたり 10 ドルが請求され、さらに取得したコンテンツをコンテキストウィンドウに渡すたびに、トークン料金が発生します。webfetch は、マルチエンジン検索、ページの取得と抽出、セマンティックな再ランキング、文単位の圧縮を行うローカルパイプラインに置き換え、それらをモデルがほかのツールと同じように呼び出せる web_search ツールとして提供します。また、調査したすべてのホスト型ツールや検索 API とは異なり、繰り返しのクエリや言い換えたクエリは、セマンティックキャッシュから無料で提供されます。
(pip install webfetch-llm でインストールします。インポート名は webfetch です。)
移動先: 主な結果 · 得られるもの · はじめに · セットアップを確認する · ベンチマーク結果の全容 · Claude Code · エージェントループ · コスト削減レポート · 仕組み · 注意点
精度は同等。コストは 3 分の 1。トークンは 8 分の 1。
1 つのエージェントループ、1 つのモデル、1 人の評価者、50 問の SimpleQA。各行で異なるのは検索ツールだけです。
| 検索ツール | 精度 | クエリあたりの入力トークン | クエリあたりのコスト |
|---|---|---|---|
| Anthropic のホスト型 web_search | 96% | 17,408 | $0.108 |
| webfetch(4 エンジンの融合) | 92% | 3,467 | $0.035 |
| webfetch(DDG のみ、手数料 $0) | 84% | 3,623 | $0.026 |
Opus を gpt-5.6-sol に替えると、同じ webfetch ツールで精度 96%(ホスト型と同等) を達成し、コストは クエリあたり $0.040、トークン数は 2,156 です。これは、ホスト型ツールがコンテキストに渡す量の 8 分の 1 です。結果の全容では、実施したすべての条件の結果を確認できます。
これらの数値は、空のキャッシュで測定した webfetch にとっての最悪のケースです。実際の使用では、差は自然に広がります。繰り返しや言い換えはキャッシュから無料で提供され、検索結果がコンテキストに残る後続のターンでも、トークンの優位性は毎回発揮されます。普通の Claude Code セッションで得られた、次のような請求額の差につながります。

この README に記載された主張はすべて、このリポジトリに含まれる評価ハーネスで生成されています。質問セット、質問ごとの記録、評価プロトコル、否定的な結果もすべて evals/ にあり、各表は 1 つのコマンドで再生成できます。評価結果をそのまま信じる必要はありません。evals/results/README.md では、各表の行を、その根拠となった生の結果ファイルに対応付けており、質問ごとの評価者の判定まで確認できます。
得られるもの
自分で管理できる検索パイプライン(4 エンジンの RRF 融合、ローカル抽出、文単位の圧縮)。 検索結果は、DuckDuckGo、Brave、Serper、Tavily のうち、キーを持っているエンジンを対象にした逆順位融合によって得られます。DDG はキー不要なので、このツールは初期状態で文字どおりコストゼロで動作します。キーを追加するたびに、自動的に融合対象に加わります。ページの取得と抽出はローカルで行われ(trafilatura、readability、newspaper4k、JS ページや 403 の壁に対する Playwright レンダリング)、チャンクに分割され、ハイブリッドな BM25 + bi-encoder のカスケードと、その上位に配置した cross-encoder によって順位付けされます。その後、クエリに答える文だけに圧縮されます。測定では、再現率を損なわずにトークン数を 50% 削減しました。
他にはないキャッシュ(完全一致とセマンティックマッチング、変動性に応じた TTL)。 1 つの sqlite ファイルに 2 つのレイヤーを備えています。URL ごとのページテキストと、クエリごとの順位付き検索結果です。同一のクエリは完全一致キャッシュにヒットします。言い換えたクエリはセマンティックキャッシュにヒットします。埋め込みによる候補の絞り込みを、NLI cross-encoder で検証します。精度を重視し、評価を先行して調整しており、これまでに実施したすべての実運用テストで、誤った対象へのマッチはゼロでした。キャッシュの有効期間はクエリに応じて変わります。価格やスコアは 15 分、最新性の高いトピックは 7 日、リリースノートや仕様は 90 日です。分類には、呼び出し元モデルのヒントかローカル分類器を使います。モデルには、キャッシュされた各結果の出所情報が表示され([cache: semantic match to "...", 2h old, recent])、内容に異議がある場合は force_fresh を送信できます。調査したホステッドツールや検索 API には、クライアントから見えるキャッシュを提供するものはありませんでした。
モデルが独自のキャッシュを維持できます(save_finding、UNVERIFIED ラベル付き、キルスイッチ付き)。 検索結果が見つからず、モデルが別の情報源(たとえばホステッド検索のフォールバック)に基づいて回答した場合、save_finding を呼び出して学習した内容を保存できます。その内容にはモデル提供のラベルが付き、明示的な UNVERIFIED 警告と force_fresh による回避手段とともに返され、通常の TTL ルールに従って期限切れになります。未検証の内容をキャッシュしたくないデプロイメント向けに、キルスイッチ(SAVE_FINDING_ENABLED = False)も用意されています。
モデルが本当に必要とする制御手段(full_results、fetch_url、freshness、force_fresh)。 full_results は、一覧表示や順位付けのクエリに対して、圧縮されていない抜粋を返します(圧縮によって並列リストの項目が削られることを測定で確認しました)。fetch_url は、引用されたページを 1 つ全文取得します。パイプラインが以前に取得したことがあれば、即座に取得できます。freshness ヒントはキャッシュの有効期間を制御し、force_fresh はキャッシュを迂回します。
利用実績(セッション単位と累計、正確なカウンター)。 使用量カウンターはキャッシュファイルに保存されます。
webfetch-savings(または savings_report ツール)を使うと、ホステッド検索の料金をどれだけ節約できたかを、セッション単位と累計に分けて確認できます。
以下にサンプルを示します。
はじめに
ワンライナー(uv は初回起動時にパッケージをインストールし、@latest は新しいリリースを自動的に取得します):
claude mcp add webfetch -- uvx --from webfetch-llm@latest webfetch-mcp
または、2 つのコマンドでインストールを自分で管理できます:
pip install "webfetch-llm[all]"
claude mcp add webfetch -- webfetch-mcp
スリムインストール(追加機能なしの webfetch-llm)は数秒で起動し、機能を制限した状態で動作します。BM25 による順位付け、完全一致のみのキャッシュ、語彙ベースの圧縮を利用します。[all] を指定すると、Playwright、PDF、テーブル抽出に加えて、セマンティックスタック(torch。初回のみ数分かかります)がインストールされます。この README のベンチマーク数値はすべて、この構成で測定したものです。新しい venv では pip >= 24 が必要です(python -m pip install -U pip を実行してください。古い pip は、依存関係ツリー内で重複している extra によってクラッシュします)。venv にインストールする場合は、webfetch-mcp の絶対パスを登録するか、venv を有効にしたままにしてください。
キーは任意です(DDG はキーなしで動作します)が、再現率を高めます。どのエンジンにも無料枠があります:
cp .env.example .env # fill in what you have
コンソールスクリプトと MCP サーバーは、実行ディレクトリにある .env を読み込みます。エクスポートされた環境変数と claude mcp add の --env フラグは、常に優先されます。ライブラリとして import webfetch しても .env は読み込まれません。プロセス環境はそのまま維持されます。
セットアップを確認する
webfetch-status(またはモデルに status ツールを呼び出すよう依頼する)により、
「キーは認識されていますか? 実際に何を実行していますか?」という質問に答えられます。
webfetch 0.1.3
search engines:
ddg ready (no key needed)
brave ready (BRAVE_API_KEY is set)
serper off (SERPER_API_KEY not set)
tavily ready (TAVILY_API_KEY is set)
active provider: multi(ddg+brave+tavily) (RRF fusion)
optional features:
semantic ranking/cache/compression: on
JS-page rendering (playwright): on
PDF extraction (pdfplumber): OFF (pip install 'webfetch-llm[pdf]')
HTML tables (pandas+tabulate): on
result compression: on (crossencoder)
cache: /Users/you/.webfetch/cache.db
5.4 MB, 70 lifetime searches (webfetch-savings for the receipt)
キー名のみを表示し、値は決して出力しません。設定は環境変数で行い、 サーバー起動時に読み込まれます。
| 変数 | 効果 |
|---|---|
BRAVE_API_KEY、SERPER_API_KEY、TAVILY_API_KEY | 各キーにより、融合にエンジンが追加されます |
WEBFETCH_PROVIDER | multi(デフォルト:キーが設定されたすべてのエンジンを融合)、fallback(DDG が検索を担当し、キーが設定されたエンジンが DDG のブロックを補完)、または単一のエンジン名 |
WEBFETCH_CACHE_DB | キャッシュファイルの場所を変更します(デフォルトは ~/.webfetch/cache.db) |
キーが1つも設定されていない場合、デフォルトは通常の DDG となります。ステータス出力では、
融合と称するのではなく、そのことを正直に示します。ライブラリの利用者は環境変数を
完全に省略できます:Pipeline(search=get_search_adapter("fallback"), cache=...)。
ベンチマーク結果の全容
各方式で同じ50問の SimpleQA 問題を使用し、同じ判定者で同じ日に1回実行しました (2026-07-14)。エージェントループを使う方式はすべて同じループを共有し、異なるのは 検索ツールのみです。コストにはモデルのトークンと各プロバイダーが公表する検索ごとの 料金が含まれます。webfetch のコストにはエンジン料金の推定値が含まれます。
| 検索ツール | モデル | 正答率 | 質問あたりの入力トークン数 | 質問あたりのコスト |
|---|---|---|---|---|
| OpenAI hosted web_search | gpt-5.6-sol | 100% | 10,027 | $0.066 |
| webfetch(4エンジン融合) | gpt-5.6-sol | 96% | 2,156 | $0.040 |
| Anthropic hosted web_search | Opus 4.7 | 96% | 17,408 | $0.108 |
| webfetch(4エンジン融合) | Opus 4.7 | 92% | 3,467 | $0.035 |
| Exa(検索+コンテンツ) | Opus 4.7 | 90% | 5,496 | $0.053 |
| Tavily | Opus 4.7 | 88% | 6,387 | $0.047 |
| webfetch(DDG のみ) | Opus 4.7 | 84% | 3,623 | $0.026 |
| webfetch(4エンジン融合) | Haiku 4.5 | 76%* | 3,021 | $0.031 |
* Haiku の失敗の大半は、ターン上限を超えて再検索したことが原因です。また、ベンチマークの途中で 無料枠を使い切ったため、最後の数問は性能が低下したエンジン構成で実行されました。下限値として 捉えてください。
トークン数の列に注目してください。webfetch の結果は、スニペット API の半分、 ホスト型ツールの5分の1から8分の1の入力トークン数で得られています。そのため、 検索ごとの料金が同程度の場合でも、webfetch のコストは最も低くなっています。
実行前の2週間に起きた出来事に関する27問の別データセット(手作業で作成し、 公開していないため、どのベンダーもそれを使った調整はできません)では、webfetch は 融合でも DDG のみでも正答率100%でした。ホスト型ツールも正答率100%でした。 新しい出来事への対応は難所ではありません。難所は 日付注入の落とし穴です。
再現方法:python evals/run_e2e_eval.py --arms ours-multi,hosted - ハーネス、
データセット、質問ごとの記録は evals/ にあります。上の表は
e2e_eval_20260714_005531.json
(および Haiku の実行と最新イベントのデータセット)に基づいています。主張とファイルの
完全な対応表は evals/results/README.md にあります。問題は
OpenAI の公開 SimpleQA セットからシード付き(seed 42)で抽出しているため、
build_datasets.py を実行すると、お使いのマシンでも同じ50問を再生成できます。正直に
述べるべき注意点が1つあります。ライブウェブの内容は実行ごとに変化し、n=50の場合、
正答率96%対92%の差は正解数にして48対46であり、誤差の範囲内で同等です。トークン数と
コストの列は、機械的に測定でき、安定した結果です。
Claude Code / Claude Desktop での使用
Claude Code で最速の方法は、プラグインとしてインストールすることです。スラッシュコマンドを 2 つ実行します(内部では同じ uv のワンライナーを実行します)。
/plugin marketplace add firish/webfetch
/plugin install webfetch@webfetch
または、MCP サーバーを自分で登録してください。どちらの方法でも、新しいセッションでは /mcp の下に webfetch が 5 つのツールとともに表示されます:web_search、fetch_url、save_finding、status、savings_report。最近の出来事について何か質問し、ツール呼び出しを確認してください。同じ質問を言い換えて尋ねると、新たに検索する代わりに [cache: semantic match ...] ヘッダー付きで結果が返ります。セッションでの最初の呼び出しは低速です(エンコーダーのウォームアップと実際のページ取得に 10~40 秒かかります)。キャッシュされた呼び出しは即座に完了します。
/mcp でセッションごとにサーバーをオフにできます。インストール方法に応じて、/plugin uninstall webfetch または claude mcp remove webfetch で削除できます。キャッシュとその記録履歴は ~/.webfetch/ に保存され、再インストール後も残ります。マシンごとにサーバーを 1 つ実行してください。セマンティックキャッシュは、単一のプロセスがファイルを所有することを前提としています。
更新通知:サーバーはプロセスごとに 1 回 pypi.org にリクエストを送信し、新しいリリースがないか確認します。結果は savings_report の出力に 1 行で表示されます。webfetch/config.py の UPDATE_CHECK_ENABLED = False で無効にできます。それ以外の情報が送信されることはありません。
独自のエージェントループで使う
import time
import anthropic
from webfetch import WEB_SEARCH_TOOL, handle_web_search
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "What did the FOMC decide this week?"}]
system = (f"Today's date is {time.strftime('%Y-%m-%d')}. "
"Use web_search for recent facts.")
while True:
response = client.messages.create(
model="claude-opus-4-7", max_tokens=2000, system=system,
tools=[WEB_SEARCH_TOOL], messages=messages,
)
if response.stop_reason != "tool_use":
break
messages.append({"role": "assistant", "content": response.content})
results = [{"type": "tool_result", "tool_use_id": b.id,
"content": handle_web_search(b.input)}
for b in response.content if b.type == "tool_use"]
messages.append({"role": "user", "content": results})
プロンプトキャッシュと適応型思考を備えた完全版は、examples/agent_loop.py にあります。ツールスキーマは、考え方としてはプロバイダーに依存しません。OpenAI の関数呼び出しでは、辞書を機械的に整形し直すだけで使えます。
今日の日付をシステムプロンプトに含めてください。 これは必須です。モデルは、まだ起きていないと思っている出来事の検索を拒否します。最新イベントのデータセットでは、日付を含めなかったループは、27 件の質問のうち最大 10 件でツールの呼び出しさえ拒否しました(「Wimbledon 2026 hasn't taken place yet」)。1 行追加するだけで解決します。ホスト型検索ツールはサーバー側でこれを行うため、独自のツールを実行するまで気づかれない理由の 1 つになっています。
handle_web_search は例外を送出しません。エンジンの障害、空の結果、不正な入力は、モデルが対応できる読みやすい文字列として返されます。会話中に例外が発生すると、エージェントループ全体が終了してしまうためです。
節約レポート
検索するたびに、カウンターがキャッシュファイルに蓄積されます。モデルにレポートの実行を依頼するか、自分で webfetch-savings を実行してください。MCP ツールはこのセッション分と累計分を分けて表示するため、1 回の会話で節約できた量を確認できます:

このワンライナーの結果の内訳は、今回のマシンでの 30 回の検索セッションの場合、次のとおりです:
| このセッション | 累計 | |
|---|---|---|
| 提供した検索 | 30 | 76 |
| キャッシュから提供 | 17(57%)- 10 件が完全一致、7 件がセマンティック一致 | - |
| 回避した検索料金 | 約 $0.30 | |
| 回避したコンテンツトークン費用 | 約 $2.56 | |
| 回避した費用の推定合計 | 約 $2.86 | 約 $7.21 |
カウンターは正確です。金額は推定値であり、その前提(検索ごとのホスト型料金、呼び出しごとのホスト型トークン数(どちらも実測値)、お使いのモデルのトークン料金)は、webfetch.savings_report() の引数として指定できます。
仕組み
query -> multi-engine search (RRF fusion, circuit breakers)
-> semantic query cache? serve with provenance header
-> fetch pages concurrently (page cache by URL)
-> extract (trafilatura -> readability -> newspaper4k -> playwright)
-> chunk (400 chars) -> BM25 + bi-encoder fusion -> cross-encoder top 5
-> compress to query-relevant sentences -> source-labeled result
重い機能はすべてオプションです。[rerank] がなければ、BM25 ランキング、完全一致キャッシュ、字句圧縮を利用でき、ImportError の代わりに警告がログに記録されます。DDG については特記が必要です。自動化されたクライアントをフィンガープリントで識別し、何も通知せず空の応答を返します。webfetch はこれを検出し(融合時には同時に検索した他のエンジンが結果を返しているのに空の場合、フォールバックチェーンでは空の場合すべて)、サーキットブレーカーでエンジンを一時停止して迂回します。TLS 側は ddgs 依存関係が処理します。
設計上の決定とその測定結果は、判明した時点で docs/architecture.md と docs/ROADMAP.md に記録されています。否定的な結果も含まれます。
正直な注意点
- レイテンシー。新規検索には10~40秒かかります。実際のページを取得し、ローカルで順位付けするためです。ホスト型検索は約10秒、スニペット API は約6秒で返します。キャッシュがヒットすれば瞬時です。1秒未満の検索が必要で、コストを気にしない場合、このツールは適していません。
- キャッシュは単一プロセスです。一度に使えるのは、エージェントのループ、MCP サーバー、またはノートブックのいずれか1つです。チームで共有するキャッシュバックエンドはロードマップにあります。
- エンジンの無料枠には実際の上限があります。ベンチマーク中に Brave の月間枠を使い切りました。耐障害レイヤーは適切に機能低下しますが、それに伴い再現率も低下します。表のエンジン料金は、公表価格に基づく推定値です。
- 回答の品質は、ツールを操作するモデルによって異なります。性能の低いモデルは質の低いクエリを作成し、回答を読まずに再検索する傾向があります(Haiku の行を参照)。
- 表現を変えた言い換え(「X が追加したものは何か」と「X の新機能」など)に対するセマンティックキャッシュの再現率は限定的です。調整後、実際のペアでの測定値は6/10でした。利用可能な検証器では対応できない言い換えがあるためです。見逃した場合は再検索が行われるだけで、誤った回答にはなりません。
ベンチマークとデータ
評価レイヤーは3つあり、すべて evals/ にあります。セマンティックキャッシュのしきい値を決めるオフラインのマッチャー評価、ライブ検索評価(再現率、トークン、キャッシュ診断)、そして上記のエンドツーエンド回答評価(SimpleQA プロトコル:正規化した完全一致の後に LLM の判定を行います)です。データセットは SimpleQA(MIT)、QQP/GLUE、FreshQA(CC-BY-SA)から決定論的に構築され、各ファイルの隣には出典情報を記したサイドカーファイルがあります。最新ニュースのセットは、ベンチマーク実施の数日前に、検証済みのニュースソースを基に手作業で作成しました。どのモデルやベンダーのパイプラインにも事前に見られていないことを意図したものです。
ライセンス
MIT.
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。