Tavily MCP Key Pool
Tavily MCP キープール
简体中文版 README: README.zh.md
なぜ? 複数のTavily APIキー(複数のアカウント、チーム予算、一括購入したクレジットなど)を持っていて、AIコーディングエージェントを通じて使用する場合、すぐに3つの問題に直面します。
単一キーのボトルネック — 1つのキーのレート制限がすべてを制限します。
サイレント障害 — キーが期限切れになったり、クォータに達したり、失効したりすると、検索が... 単に動作しなくなります。
可視性の欠如 — どのキーが使用されているか、どれだけ使用されているかがわかりません。
このプロジェクトはこれら3つすべてを解決します。キープールをラウンドロビンで使用し、死んだキーを自動的に無効化し、使用統計を公開する小さなMCPサーバーです。Claude Desktop、Cursor、DeepSeek Harness、または任意のMCPクライアントにドロップインして、ワークフローを変更することなく使用できます。
SQLiteベースのラウンドロビンAPIキープール、組み込みの使用状況追跡、自動ヘルスベースのフェイルオーバー、スタンドアロンのFastAPIダッシュボードを備えたTavily MCPサーバー。標準のMCPプロトコル — 任意のMCP互換クライアント(Claude Desktop、Cursor、DeepSeek Harnessなど)で動作します。
ハイライト
🔄 ラウンドロビンキーローテーション:N個のTavily APIキーを横断(SQLite、起動コストゼロ)。
📊 使用状況追跡:キーごとのリクエスト数、エラー数、消費クレジット。
🩺 自動ヘルスチェック:軽量検索ですべてのキーをプローブし、死んだキーを自動的に無効化。結果は
tavily_pool_statusで公開。🛠️ 6つのコアMCPツール(Tavilyと同等:search、extract、crawl、map、research)に加えて
tavily_pool_statusとtavily_research_status(非同期フェッチ)。🌐 スタンドアロンFastAPIダッシュボード(CORS有効、ループバックのみ)統計、キーごとの表示、追加/削除/無効化/有効化、ワンクリックヘルスプローブ。
🔌 任意のMCPクライアントへのドロップイン(stdio経由)。DSH統合は1ページのパッチ+サンプルクライアントプラグイン(
examples/dsh-integration/参照)。
公式の tavily-mcp との違い
機能 | 公式 | このリポジトリ |
単一APIキー環境変数 | ✅ | — |
複数キー、ラウンドロビン | — | ✅ SQLiteプール |
キーごとの使用統計 | — | ✅ リクエスト数+クレジット+エラー |
ヘルスプローブ+自動無効化 | — | ✅ |
スタンドアロンダッシュボード | — | ✅ 127.0.0.1:8000 上の FastAPI |
MCPツールパリティ(search/extract/crawl/map/research) | ✅ | ✅(さらにプールステータス/リサーチステータスの追加) |
非同期リサーチポーリング | (手動) | ✅ 組み込み |
アーキテクチャ
+--------------------------------------------------+
| MCP clients (Claude Desktop / Cursor / DSH …) |
+--------+---------------------+-------------------+
| stdio (JSON-RPC) | HTTPS / CORS
+--------▼--------------+ +▼-----------------------+
| mcp_server.py (FastMCP)| | dashboard.py (FastAPI) |
| + key_pool.py (SQLite) | | uvicorn 127.0.0.1:8000 |
+----------------------+--+ +-----+----------------+
| |
v v
tavily_keys.db <— SQLite-backed pool
|
v
Tavily REST API (round-robin over N keys)クイックスタート
1. 依存関係のインストール
python -m venv .venv
. .venv/bin/activate # Linux/macOS
# or: .venv\Scripts\Activate.ps1 (Windows PowerShell)
pip install -r requirements.txtrequirements.txt の固定された mcp 制約は <2.0 です。DSH統合 / 落とし穴 #1 を参照 — FastMCPのインポートパスが mcp 2.x で移動しました。
2. APIキーの追加
keys.txt を作成し、1行に1つのキーを記述します:
tvly-xxxxxxxxxxxxxxxx
tvly-yyyyyyyyyyyyyyyy次にインポートします:
python cli.py add --from-file keys.txtまたは、ダッシュボード(次のステップ)を起動し、Add API Keys フォームに貼り付けます。キーは tavily_keys.db(SQLite)に平文で保存され、プールは起動コストゼロでラウンドロビンできます — セキュリティ を参照。
3. MCPサーバーの起動
直接stdio MCPサーバー(任意のMCPクライアント):
./run_mcp.sh # Linux/macOS
# or: .venv\Scripts\python.exe mcp_server.py (Windows)サーバーは7つのツールをアナウンスします。MCP対応クライアントでの公開名は tavily_search、tavily_extract などになります。
4. ダッシュボードの起動(オプション、独立プロセス)
./run_dashboard.sh # default port 8000
# or: .venv\Scripts\python.exe -m uvicorn dashboard:app --host 127.0.0.1 --port 8000ブラウザで http://127.0.0.1:8000 を開きます。ダッシュボードはループバックオリジンに対してCORS有効なので、別のUIに埋め込まれた設定パネルから呼び出すことができます。
MCPツール
ツール | 目的 |
| Web検索(基本/詳細、トピック、時間範囲、ドメインの包含/除外、国など) |
| URLからクリーンなコンテンツを抽出 |
| Webサイトをクロールし、複数のページからコンテンツを抽出 |
| サイト上のURLを発見(クロールより高速) |
| AI深層リサーチ(30~120秒以上;内部でバックグラウンドポーリングを使用 — 落とし穴 #2 参照) |
| プール統計:アクティブキー、総リクエスト/エラー/クレジット、最近24時間の内訳 |
| タイムアウトした非同期リサーチタスクの結果をフェッチ |
CLI
python cli.py list # all keys
python cli.py list --active # only active
python cli.py stats # JSON dump of pool state
python cli.py health # probe every active key; deactivate dead ones
python cli.py recent -n 20 # recent request log
python cli.py add tvly-... [...] # add one or more keys
python cli.py add --from-file keys.txt
python cli.py activate tvly-xx****yy # masked id, see `list`
python cli.py deactivate tvly-xx****yy --reason "manually disabled"
python cli.py remove tvly-xx****yyClaude Desktop / Cursor / その他の汎用MCPクライアントでの使用
MCP stdioコマンドを受け入れる任意のクライアントの場合:
{
"mcpServers": {
"tavily": {
"command": "/absolute/path/to/.venv/bin/python3",
"args": ["mcp_server.py"],
"cwd": "/absolute/path/to/this/repo"
}
}
}または、クライアントがサポートし、サーバーを自分でHTTPトランスポートでラップしている場合はストリーミングHTTP — このリポジトリの範囲外です。
DeepSeek Harness (DSH) 統合
@deepseek-ai/dsh0.1.0-rc.6(Webプロファイル)でテスト済み。
DeepSeek Harness (dsh) はCordisプラグインフレームワークを使用し、公式のMCPクライアントブリッジ(@deepseek-ai/dsh-mcp-client)が付属しています。したがって、統合は非常に薄いです:1つのユーザーパッチレイヤー+サンプルのブラウザサイドプラグイン(このリポジトリの examples/dsh-integration/client-tavily-panel/)。
A. DSHにTavily MCPサーバーを登録
~/.dsh/profiles/web/cordis.patch.yml(すべてのバンドルの後に適用されるユーザーパッチレイヤー)を編集します。新しい insert ブロックを追加します — 以下の値は、リポジトリが C:\Users\ASUS\.dsh\tavily-pool\ にあることを前提としています:
- insert:
- id: mcp-tavily
name: '@deepseek-ai/dsh-mcp-client'
config:
transport: stdio
serverName: tavily
command: 'C:\Users\ASUS\.dsh\tavily-pool\.venv\Scripts\python.exe'
args: ['mcp_server.py']
cwd: 'C:\Users\ASUS\.dsh\tavily-pool'
# research can take >2 minutes on big topics; the default 30s is too tight
toolCallTimeoutMs: 600000
failOnStartupError: false再起動する前に dsh --profile web --dump-config でマージを確認します。その後、MCPサーバーはエージェントのツールリストに mcp__tavily__tavily_search などとして表示されます。
B. (オプション)ダッシュボードをDSH設定に埋め込む
examples/dsh-integration/client-tavily-panel/ をディスク上の任意の場所にコピーします。この例では @deepseek-ai/dsh-client-ui-slots の settings.section スロットを使用しています — プラグインは、fetch経由でダッシュボードを呼び出す Tavily 号池 パネルを登録します。インストール手順:
パッケージを配置(例:
~/.dsh/plugins/client-tavily-panel/)。プロファイルの
node_modulesにリンクして、require.resolveが見つけられるようにします(DSHはパッケージ名解決チェーンを通じてクライアントプラグインをロードします):New-Item -ItemType Junction ` -Path "$env:DSH_HOME\profiles\node_modules\dsh-client-tavily-panel" ` -Target "C:\Users\ASUS\.dsh\plugins\client-tavily-panel"ジャンクション(シンボリックリンクではない)は管理者権限を必要としません。これをスキップしてパッケージをローカルで
pnpm addしても問題ありません — ただし注意:pnpmはプロファイル内の他の無関係なfile:/ GitHubソースの依存関係で停止する可能性があります。cordis.patch.ymlにロスターエントリを追加:- insert: - id: client-tavily-panel name: 'dsh-client-tavily-panel'dsh webを再起動。(落とし穴 #6 を参照 — HMRはWebプロファイルでは意図的に無効化されています。パッチの変更は完全な再起動でのみ読み込まれます。)
再起動後、⚙️ 設定を開くと、左側のナビゲーションに Tavily 号池 エントリが表示されます。
DeepSeek統合中に遭遇した落とし穴
これらは私(元の統合者)が実際に遭遇したエラーです。始める前に、以下の順序で読んでください — それぞれ時間を無駄にしました。
落とし穴 #1: mcp SDKのバージョニング
mcp_server.py は from mcp.server.fastmcp import FastMCP を行います。このモジュールは mcp 2.0 で削除されました(FastMCPの実装は別の fastmcp パッケージに移動し、APIが異なります)。pip install mcp で最新版を取得すると、MCPサーバーが起動しません:
ModuleNotFoundError: No module named 'mcp.server.fastmcp'固定します:
# requirements.txt
mcp>=1.0.0,<2.0.0mcp 1.29.0 でテスト済み。
落とし穴 #2: tavily_research は非同期であり、作成したキーにバインドされる
1つに3つのサブバグ:
tavily-pythonSDKはresearch()の最初の位置引数をqueryからinputに変更しました。client.research(query=…)を呼び出すとmissing 1 required positional argument: 'input'で失敗します。SDKは実行時に
model ∈ {"mini", "pro", "auto"}を強制しますが、Tavily REST API自体はmodel=standard|proを受け入れます。standardを渡すとmodel must be one of: mini, pro or autoが発生します。research()は即座にstatus: pendingのエンベロープを返します — 実際の結果は30~120秒以上後に到着します。get_research(request_id)をstatus == "completed"になるまでポーリングする必要があります。そうしないと、ツールは常に「pending」を返し、モデルは呼び出しが失敗したと判断します。リサーチタスクはそれを作成したAPIキーにバインドされます。 プール内の他のキーは結果をフェッチできません(404を返します)。常に同じ
TavilyClientインスタンスでポーリングしてください — ポーリングの反復ごとにpool.next_key()を再呼び出ししないでください。そうしないと、間違ったキーにヒットし続けます。
このリポジトリの tavily_research はすでに完全なライフサイクルをラップしています:最大約570秒間ポーリングし、その後 status: timeout のエンベロープと request_id を返して、呼び出し元が後でフェッチできるようにします。2番目のツール tavily_research_status(request_id) は、アクティブキーリストを走査してアドホックフェッチのための正しいキーを見つけます — ツール呼び出しが別のプロセスでタイムアウトした可能性があるため必要です。
落とし穴 #3: Windowsでの dashboard.py UTF-8読み取りバグ
dashboard.py は以下を行います:
DASHBOARD_HTML = TPL.read_text()Path.read_text() はデフォルトで locale.getpreferredencoding() を使用します。これはWindows(zh-CN)ではGBKです。バンドルされている templates/dashboard.html はUTF-8でCJK文字を含むため、ダッシュボードは以下を発生させます:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xb6 in position 4308修正:
DASHBOARD_HTML = TPL.read_text(encoding="utf-8")落とし穴 #4: run_*.sh のクロスプラットフォームパス
run_mcp.sh と run_dashboard.sh は .venv/bin/python3(Linuxの慣習)をハードコードしており、Windowsではテストされていません。スクリプト作成者はまた、/home/user/code/Tavily を使用する systemd ユニットを同梱しています — 明らかにLinux専用です。
Windowsではこれらのスクリプトはまったく必要ありません。.venv\Scripts\python.exe を直接呼び出してください(上記のYAMLを参照)。これらは元のLinuxユースケースのためにリポジトリに保持されています。
落とし穴 #5: DSHパッチ設定は起動時にのみ読み込まれる
cordis.patch.yml は web プロファイルが起動するときに読み込まれます。変更はホットリロードされません — Webアプリバンドルパッチの hmr 行は意図的に無効化されています:
- id: hmr
disabled: true
# TODO: Re-enable shared HMR for Web after its reload lifecycle is tested.したがって、cordis.patch.yml を編集するたびに、dsh web を再起動してください(安全に行う方法については落とし穴 #6 を参照)。
dsh --profile web --dump-config を使用すると、GUIを実際に起動せずにパッチが正しくマージされることを確認できます。起動、GUIの確認、強制終了、修正、繰り返しよりもはるかに高速です。
落とし穴 #6: 自分を殺さずに dsh web を再起動する方法
dsh web はこの会話を含むホストプロセスであり、ツールプロセスも含みます。もし単純に
Stop-Process -Id <dsh-web-pid> -Force
Start-Process dsh.cmd webを、同じ dsh web が生成したpwshから実行すると、新しいインスタンスが起動する前にコマンドの途中で自分自身を殺してしまいます。最初に試したとき、PowerShellセッションは exit code 4294967295 で中断され、何も起こりませんでした。
修正方法:再起動をWindowsタスクスケジューラに任せます。タスクスケジューラは svchost の下でスクリプトを実行します(dsh web の下ではありません):
$script = "$env:TEMP\dsh_restart.ps1"
@"
Start-Sleep -Seconds 8
Stop-Process -Id <dsh-web-pid> -Force
Get-CimInstance Win32_Process |
Where-Object { `$_.CommandLine -match 'dsh web' } |
ForEach-Object { Stop-Process -Id `$_.ProcessId -Force }
Start-Sleep -Seconds 3
Start-Process 'C:\…\dsh.cmd' web -WorkingDirectory 'H:\…' -WindowStyle Hidden
"@ | Out-File $script -Encoding utf8
schtasks /create /tn dsh-restart /tr "powershell -NoProfile -File $script" /sc once /st 23:59 /f
schtasks /run /tn dsh-restart
schtasks /delete /tn dsh-restart /fこれで、古いインスタンスが死ぬまでに約8秒の猶予があります。ユーザーには20~30秒後に http://127.0.0.1:3080 を更新するように伝えてください。
落とし穴 #7: MCPサーバー実行中にツールディレクトリを移行する
DSHのmcp-clientは、接続が切れた場合に指数バックオフ(initialDelayMs 500、maxAttempts 10)で再接続します。Pythonの子プロセスを強制終了すると、即座に新しい子プロセスが生成されて再接続がトリガーされます。その後、Move-Itemでディレクトリを移動しようとすると、新しい.venv\Scripts\python.exeがファイルをロックしているため、robocopyは[Result: 32] / 「別のプロセスで使用中」というエラーで失敗します。
2つの実用的な戦略があります:
まずコピーし、その後ソースを削除する。
Copy-ItemはWindowsのファイル共有を介してロックされたファイルを読み取ります。排他アクセスは必要ありません。コピーが成功したら、古いMCPサーバーを強制終了し、ソースを削除します。.venvは、pyvenv.cfgのhome =行が同じベースのPythonインストールを指している限り、完全に再配置可能です。バックオフウィンドウ内で成功するまで、kill + robocopy /MOVEをループする。 醜いですが、機能します。
元の移行では以下を使用していました:
Copy-Item -Path D:\Downloads\Tavily -Destination C:\Users\ASUS\.dsh\tavily-pool -Recurse -Force
# verify copy
Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'python.exe' -and $_.CommandLine -match 'mcp_server' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
# loop until deletion succeeds
for ($i=0; $i -lt 8; $i++) {
Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'mcp_server' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
Start-Sleep -Milliseconds 200
Remove-Item D:\Downloads\Tavily -Recurse -Force -ErrorAction SilentlyContinue
if (-not (Test-Path D:\Downloads\Tavily)) { break }
Start-Sleep -Seconds 2
}落とし穴 #8: pnpm add が無関係な依存関係で停止する可能性があります
dsh plugin --profile web add <dir> でローカルプラグインをインストールする場合、pnpmはプロファイル全体のワークスペースを解決します。これには、package.jsonにリストされているGitHubソースやHTTPソースのバンドルも含まれます。プロファイルにすでにdsh-files: https://codeload.github.com/...tar.gz/...のようなものが含まれており、そのダウンロードが(ファイアウォール、DNS、キャッシュのコールド状態、レジストリのクォータなどで)停止すると、ローカルプラグインはインストールされず、pnpmはタイムアウトまでハングします。
回避策:pnpmをスキップし、自分で解決策を作成します:
New-Item -ItemType Junction `
-Path "$env:DSH_HOME\profiles\node_modules\dsh-client-tavily-panel" `
-Target "<absolute path to your plugin package>"ジャンクション(シンボリックリンクではない)は管理者権限なしで機能し、require.resolveに対して同一に動作します。パッチレイヤーは、あたかもpnpmがインストールしたかのように、パッケージをnameフィールドで参照します。
落とし穴 #9: 設定パネルのクライアントプラグイン形式
独自のDSHクライアントプラグイン(ブラウザ側)を作成する場合、ランタイム形式はESMでもCordis-from-sourceでもありません。dsh-client-modulesプラグインは、小さなインメモリモジュールローダーをホストし、各クライアントバンドルを/plugins/<id>/client.jsから取得します。バンドルは次の呼び出しを行う必要があります:
window.__ModuleLoader__.load({
id: "your-package-name", // matches package.json "name"
factory: (require) => {
var module = { exports: {} };
var exports = module.exports;
var react = require("react"); // available
var jsx = require("react/jsx-runtime"); // available
// ... define components ...
function apply(ctx) {
ctx.slots.inject("settings.section", () => ctx.slots.register({
name: "settings.section",
id: "your-id",
order: 100,
label: "Your Label"
}, YourComponent));
}
exports.apply = apply;
exports.inject = ["slots"]; // services you depend on
return module.exports;
}
});そして、package.jsonには以下を含める必要があります:
{
"main": "lib/index.js",
"exports": { "./client": { "default": "./lib/client.js" } },
"dsh": { "client": { "inject": ["@deepseek-ai/dsh-client-ui-slots"], "platform": "web" } }
}lib/index.jsはホストエントリです。サーバー側で動作します。no-op(function apply() {}; export { apply };)にすることができます。
セキュリティ
保存時の平文キー。
tavily_keys.dbは、Tavily APIキーを平文で保存します。これは、SQLiteベースのプールがすべてのリクエストでクエリされるためです。ファイルシステムの権限でファイルを保護してください(Linux:chmod 600)。tavily_keys.dbをコミットしないでください(.gitignoreを参照)。デフォルトではループバックのみのダッシュボード。
dashboard.pyは127.0.0.1:8000にバインドします。LAN上で公開する場合は、すぐに認証を追加してください。CORSは意図的に全開です — ダッシュボードは同じホスト上の埋め込みUIから呼び出されることを想定しています。ループバックバインディングのためこれは安全ですが、バインドアドレスを変更する場合は、
CORSMiddleware.allow_originsを絞ってください。漏洩したキーのローテーション:
python cli.py remove tvly-xxxxxxxx****yyyyを実行し、Tavilyダッシュボードでキーを取り消し、プール内の各行に対して繰り返します。
トラブルシューティング
症状 | 原因 / 修正 |
|
|
| 古いスタイルの呼び出し — |
| SDKレベルの制限。このリポジトリでは |
リサーチが常に |
|
| ダッシュボードHTMLの読み取りバグ(落とし穴 #3);このリポジトリで修正済み |
| MCPサーバーを強制終了し、最初にコピーしてから削除する(落とし穴 #7) |
ツールが登録されているがDSHセッションで表示されない |
|
| ジャンクション/require-resolveの問題(落とし穴 #8); |
クレジット
プール管理コード(key_pool.py、dashboard.py、FastMCPのmcp_server.pyのスケルトン、cli.py)は、元々匿名の作者によって書かれ、公開されました。このリポジトリでは以下を追加しています:
mcp1.x互換性(query→input、modelマッピング、リサーチポーリング)。非同期フェッチ用の新しい
tavily_research_statusツール。Windowsクロスプラットフォーム修正(
dashboard.pyでのUTF-8読み取り)。DSH用のドロップイン設定パネルクライアントプラグイン、および上記の統合落とし穴ログ。
元の作者をご存知の方は、クレジットを追加できるようにIssueを開いてください。
ライセンス
MIT。LICENSEを参照してください。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
One API key for 6 AI models. Pay-per-use. MCP protocol support with web search.
Web search for AI agents — one tool across 6 engines, routed to the cheapest + cached.
Zenrows MCP server — Fetch, Extract, Batch, and Browser Sessions for AI coding assistants
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tom-Chencao/a-beginner-s-warehouse'
If you have feedback or need assistance with the MCP directory API, please join our Discord server