Skip to main content
Glama
Tom-Chencao

Tavily MCP Key Pool

by Tom-Chencao

Tavily MCP Key Pool

简体中文版 README: README.zh.md

Зачем? Если у вас есть несколько ключей API Tavily (несколько учетных записей, командный бюджет, пакетно приобретенные кредиты и т. д.) и вы используете их через ИИ-агента для кодирования, вы быстро столкнетесь с тремя проблемами:

  1. Узкие места одного ключа — ограничение скорости одного ключа тормозит всё.

  2. Тихие сбои — ключ истекает, достигает квоты или отзывается, и ваши поиски просто... перестают работать.

  3. Отсутствие видимости — вы не знаете, какие ключи используются и сколько.

Этот проект решает все три проблемы: крошечный MCP-сервер, который циклически перебирает ваш пул ключей, автоматически деактивирует мертвые ключи и предоставляет статистику использования — так что вы можете подключить его к Claude Desktop, Cursor, DeepSeek Harness или любому MCP-клиенту, не меняя свой рабочий процесс.

MCP-сервер Tavily с пулом API-ключей на основе циклического перебора, поддерживаемым SQLite, встроенным отслеживанием использования, автоматическим переключением на основе состояния здоровья и отдельной панелью управления FastAPI. Стандартный протокол MCP — работает с любым MCP-совместимым клиентом (Claude Desktop, Cursor, DeepSeek Harness и т. д.).

Основные возможности

  • 🔄 Циклическая ротация ключей по N ключам API Tavily (SQLite, нулевая стоимость запуска).

  • 📊 Отслеживание использования: количество запросов на ключ, количество ошибок, потребленные кредиты.

  • 🩺 Автоматическая проверка состояния: проверка всех ключей легким поиском, автоматическая деактивация неработающих; вывод результатов через tavily_pool_status.

  • 🛠️ Шесть основных MCP-инструментов (паритет с Tavily: поиск, извлечение, обход, карта, исследование) плюс tavily_pool_status и tavily_research_status (асинхронная выборка).

  • 🌐 Отдельная панель управления FastAPI (с поддержкой CORS, только loopback) со статистикой, просмотром по ключам, добавлением/удалением/деактивацией/активацией и проверкой состояния одним щелчком.

  • 🔌 Подключение к любому MCP-клиенту через stdio; интеграция с DSH — это одностраничный патч + пример плагина клиента (см. examples/dsh-integration/).

Отличия от официального tavily-mcp

Особенность

Официальный tavily-mcp

Этот репозиторий

Переменная окружения для одного ключа API

Несколько ключей, циклический перебор

✅ Пул SQLite

Статистика использования по ключам

✅ количество запросов + кредиты + ошибки

Проверка состояния + автоматическая деактивация

Отдельная панель управления

✅ FastAPI на 127.0.0.1:8000

Паритет инструментов MCP (поиск/извлечение/обход/карта/исследование)

✅ (плюс дополнительные статусы пула/исследования)

Асинхронный опрос исследований

(вручную)

✅ встроенный tavily_research + tavily_research_status

Архитектура

+--------------------------------------------------+
|  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.txt

Ограничение mcp в requirements.txt<2.0: см. интеграцию с DSH / Подводный камень №1 — импорт FastMCP переместился в mcp 2.x.

2. Добавление ключей API

Создайте keys.txt с одним ключом на строку:

tvly-xxxxxxxxxxxxxxxx
tvly-yyyyyyyyyyyyyyyy

Затем импортируйте их:

python cli.py add --from-file keys.txt

Или запустите панель управления (следующий шаг) и вставьте их в форму Добавление ключей API. Ключи хранятся в открытом виде в tavily_keys.db (SQLite), чтобы пул мог циклически перебирать их с нулевой стоимостью запуска — см. Безопасность.

3. Запуск MCP-сервера

Для прямого MCP-сервера через stdio (любой MCP-клиент):

./run_mcp.sh                                # Linux/macOS
# or:  .venv\Scripts\python.exe mcp_server.py   (Windows)

Сервер объявляет семь инструментов; публичные имена в 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 для источников loopback, так что встроенная панель настроек в другом интерфейсе может вызывать её.

MCP-инструменты

Инструмент

Назначение

tavily_search

Веб-поиск (базовый/расширенный, тема, временной диапазон, включать/исключать домены, страна и т. д.)

tavily_extract

Извлечение чистого контента из URL

tavily_crawl

Обход веб-сайта и извлечение контента с нескольких страниц

tavily_map

Обнаружение URL на сайте (быстрее, чем обход)

tavily_research

Глубокое исследование с ИИ (30–120+ с; использует фоновый опрос внутри — см. Подводный камень №2)

tavily_pool_status

Статистика пула: активные ключи, общее количество запросов/ошибок/кредитов, разбивка за последние 24 часа

tavily_research_status(request_id)

Получение результата асинхронной задачи исследования, которая вышла по тайм-ауту

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****yy

Использование с Claude 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/dsh 0.1.0-rc.6 (веб-профиль).

DeepSeek Harness (dsh) использует фреймворк плагинов Cordis и поставляется с официальным мостом MCP-клиента (@deepseek-ai/dsh-mcp-client). Поэтому интеграция очень тонкая: один слой пользовательских патчей + пример плагина на стороне браузера (этот репозиторий: examples/dsh-integration/client-tavily-panel/).

A. Регистрация MCP-сервера Tavily в DSH

Отредактируйте ~/.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/ в любое место на диске. В примере используется слот settings.section из @deepseek-ai/dsh-client-ui-slots — плагин регистрирует панель Tavily 号池, которая вызывает панель управления через fetch. Для установки:

  1. Поместите пакет (например, ~/.dsh/plugins/client-tavily-panel/).

  2. Создайте ссылку в 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"

    Использование junction (а не симлинка) позволяет избежать прав администратора. Если вы пропустите это и используете pnpm add для локального пакета — тоже нормально, но учтите: pnpm может зависнуть на других несвязанных зависимостях file: / GitHub-исходниках в вашем профиле.

  3. Добавьте запись в roster в cordis.patch.yml:

    - insert:
        - id: client-tavily-panel
          name: 'dsh-client-tavily-panel'
  4. Перезапустите dsh web. (См. Подводный камень №6 — HMR намеренно отключен для веб-профиля; изменения в патчах загружаются только при полном перезапуске.)

После перезапуска откройте ⚙️ Настройки — запись Tavily 号池 появится в левой навигации.

Подводные камни, обнаруженные при интеграции с DeepSeek

Это реальные ошибки, с которыми столкнулся я (оригинальный интегратор). Прочитайте их до начала, в порядке ниже — каждая из них отняла время.

Подводный камень №1: Версионирование SDK mcp

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.0

Проверено с mcp 1.29.0.

Подводный камень №2: tavily_research асинхронен и привязан к создавшему ключу

Три подошибки в одной:

  • SDK tavily-python переименовал первый позиционный аргумент research() с query на input. Вызов client.research(query=…) завершается ошибкой missing 1 required positional argument: 'input'.

  • SDK во время выполнения проверяет, что model ∈ {"mini", "pro", "auto"}, но сам REST API Tavily принимает 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, чтобы вызывающий мог получить результат позже. Второй инструмент, tavily_research_status(request_id), обходит список активных ключей, чтобы найти нужный ключ для ad-hoc выборки — это необходимо, потому что вызов инструмента мог выйти по тайм-ауту в другом процессе.

Подводный камень №3: Ошибка чтения UTF-8 в dashboard.py на Windows

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. Авторы скриптов также поставили unit systemd, использующий /home/user/code/Tavily — явно только для Linux.

Вам не нужны эти скрипты на Windows; просто вызывайте .venv\Scripts\python.exe напрямую (см. YAML выше). Они сохранены в репозитории для исходного случая использования Linux.

Подводный камень №5: Конфигурация патча DSH загружается только при запуске

cordis.patch.yml читается при загрузке профиля 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

из pwsh, который был порождён тем же dsh web, вы убьёте себя прямо посреди команды, прежде чем новый экземпляр вообще запустится. Когда я попробовал в первый раз, сеанс 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 секунд, чтобы вернуть окончательный ответ, прежде чем старый экземпляр умрёт. Скажите пользователю обновить http://127.0.0.1:3080 через 20–30 секунд.

Подводный камень №7: Перемещение каталога инструментов во время работы MCP-сервера

DSH mcp-client переподключается при потере соединения с экспоненциальной задержкой (initialDelayMs 500, maxAttempts 10). Убийство дочернего процесса Python вызывает переподключение — который порождает новый дочерний процесс немедленно. Если затем попытаться выполнить Move-Item для каталога, новый .venv\Scripts\python.exe удерживает файл заблокированным, и robocopy завершается ошибкой [Result: 32] / «используется другим процессом».

Две жизнеспособные стратегии:

  • Сначала копировать, затем удалить исходник. Copy-Item читает заблокированные файлы через общий доступ к файлам Windows; ему не нужен монопольный доступ. После успешного копирования убейте старый MCP-сервер + удалите исходник. .venv полностью перемещаем, пока строка home = из pyvenv.cfg по-прежнему указывает на тот же базовый установленный Python.

  • Цикл убийства + 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 разрешает всю рабочую область профиля — включая любые пакеты из GitHub или HTTP-пакеты, перечисленные в вашем package.json. Если ваш профиль уже включает что-то вроде 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. Затем слой исправлений ссылается на пакет по его полю name, точно так же, как если бы pnpm установил его.

Подводный камень №9: Формат клиентского плагина панели настроек

Если вы пишете свой собственный клиентский плагин DSH (сторона браузера), формат времени выполнения — не ESM, не Cordis из исходников. Плагин 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 — это точка входа хоста — она выполняется на стороне сервера; она может быть пустой (function apply() {}; export { apply };).


Безопасность

  • Ключи открытым текстом при хранении. tavily_keys.db хранит ваши ключи API Tavily в открытом виде, так как пул на основе SQLite запрашивается при каждом запросе. Защитите файл с помощью прав доступа к файловой системе (Linux: chmod 600). Никогда не фиксируйте tavily_keys.db (см. .gitignore).

  • Панель управления только на локальной петле по умолчанию. dashboard.py привязывается к 127.0.0.1:8000. Если вы предоставляете доступ по локальной сети, немедленно добавьте аутентификацию.

  • CORS намеренно открыт — панель управления предназначена для вызова встроенными UI на том же хосте. Это безопасно из-за привязки к локальной петле, но если вы измените адрес привязки, сузьте CORSMiddleware.allow_origins до соответствующего.

  • Ротация скомпрометированного ключа: python cli.py remove tvly-xxxxxxxx****yyyy, отзовите его в панели управления Tavily, повторите для каждой строки в пуле.

Устранение неполадок

Симптом

Причина / исправление

ModuleNotFoundError: No module named 'mcp.server.fastmcp'

mcp ≥ 2.0; зафиксировать версию <2.0 (Подводный камень №1)

TavilyClient.research() missing 1 required positional argument: 'input'

Устаревший вызов — mcp_server.py уже использует input= (Подводный камень №2)

model must be one of: mini, pro or auto

Ограничение уровня SDK, сопоставлено с auto в этом репозитории (Подводный камень №2)

Research всегда возвращает pending

Вы вызывали get_research после research? В этом репозитории это делается за вас

UnicodeDecodeError: 'gbk' codec can't decode…

Ошибка чтения HTML панели управления (Подводный камень №3); исправлено в этом репозитории

Файлы node.exe и python.exe заблокированы при перемещении

Убейте MCP-сервер, сначала скопируйте, удалите после (Подводный камень №7)

Инструменты зарегистрированы, но сессия DSH их не видит

Вы перезапустили dsh web? Исправления загружаются только при запуске (Подводный камень №5)

__DSH_BOOT__ не содержит ваш плагин

Проблема с соединением/require-resolve (Подводный камень №8); проверьте с помощью dsh --profile web --dump-config

Благодарности

Код управления пулом (key_pool.py, dashboard.py, скелет FastMCP mcp_server.py, cli.py) был изначально написан неуказанным автором и опубликован открыто. Этот репозиторий добавляет:

  • Совместимость с mcp 1.x (queryinput, сопоставление model, опрос research).

  • Новый инструмент tavily_research_status для асинхронной загрузки.

  • Исправления для кроссплатформенной работы Windows (чтение UTF-8 в dashboard.py).

  • Готовый клиентский плагин панели настроек для DSH и приведенный выше журнал подводных камней интеграции.

Если вы знаете оригинального автора, пожалуйста, откройте issue, чтобы я мог добавить благодарность.

Лицензия

MIT. См. LICENSE.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all MCP Connectors

Latest Blog Posts

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