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/).

Related MCP server: tavily-mcp-proxy

Отличия от официального 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 (query→input, сопоставление model, опрос research).

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

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

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

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

Лицензия

MIT. См. LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    A multi-API key load balancing MCP server for Tavily that automatically rotates between multiple API keys to provide high availability and increased request limits.
    6
    72
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    A proxy MCP server for Tavily search and extract APIs with support for multiple API keys, random rotation, and bearer token authentication.
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A proxy MCP server that connects to Tavily's official Streamable HTTP MCP, managing multiple API keys and automatically switching to the next one when the current key's quota is exhausted.
    5
    13 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes pooled Tavily API keys through an MCP streamable HTTP endpoint, providing search, extract, crawl, map, research, and pool status tools with automatic key rotation and quota management.
    MIT