Skip to main content
Glama

AI Search MCP

MCP-сервер для веб-поиска, созданный для агентов: готовая бесплатная поисковая система из коробки, подключаемые высококачественные движки, встроенный кэш, фильтрация по времени и комбинированный инструмент research, выполняющий целое исследование одним вызовом.

Agent-friendly web search MCP server — бесплатные движки без настройки, отказоустойчивость с учётом региона, фильтрация по свежести и инструмент research в один вызов.

npm version License: MIT Node


Почему это нужно (Why)

Поиск — самый частый инструмент агентов, но у существующих решений есть серьёзные недостатки:

Существующее решение

Проблема

Официальный MCP fetch

Может получить только известные URL, не умеет искать

Официальные MCP Tavily / Brave / Exa

Качественно, но всем нужен платный API-ключ

Community DuckDuckGo MCP

Бесплатный, но хрупкий, вывод неструктурированный, нет кэша/повторов

ai-search-mcp заполняет этот пробел: без настройки работает сразу (DuckDuckGo / Bing / 百度 / 搜狗), автоматически выбирает лучший движок по региону с отказоустойчивостью, поддерживает фильтр по свежести и ужимает весь цикл «поиск → выбор → извлечение → резюме» в один вызов research.

Related MCP server: WebVector MCP Server

Возможности (Features)

  • 🆓 Без настройки и сразу готово: npx ai-search-mcp запускается напрямую, никаких API-ключей не требуется.

  • 🔌 Много движков, подключаемые: бесплатные duckduckgo · bing · baidu · sogou + платные brave · tavily

  • 🌄 Автоматический выбор движка по региону: SEARCH_ENGINE=auto (по умолчанию) → для Китая bing→baidu→sogou, для остальных duckduckgo→bing; автоматический фейловер при 429/таймауте, поддержка цепочки движков через запятую

  • 🕒 Фильтр по времени: freshness=day|week|month|year или timeRange="YYYY-MM-DD..YYYY-MM-DD", автоматическое сопоставление с движком

  • 🧠 Удобный вывод для агента: структурированный JSON ({ id, title, url, snippet, domain }), а не сырой HTML; каждый результат имеет стабильный id, который можно использовать

  • 🧭 Комбинированный инструмент research: один вызов = поиск + извлечение Top-страниц → сводка фактов (устраняет 5~10 обращений к инструментам)

  • ⚡ Встроенный кэш (TTL, по умолчанию 10 минут): сокращает повторные запросы, быстрее и популярнее

  • 🛡️ Инженерная отказоустойчивость: таймауты, экспоненциальные повторные попытки, единые коды ошибок; ошибка RATE_LIMITED сопровождается рекомендациями suggestedEngine / retryAfter

  • 🐢 Встроен вежливый паук: ограничение частоты по движку (по умолчанию 8 раз/мин) + случайная пауза между запросами, чтобы не провоцировать антibot-системы; никакого обхода защиты от скрапинга (приоритет соответствия)

  • 📄 Инструмент fetch_page: любой URL (или id из результатов поиска) превращается в читаемый Markdown

  • 🌏 Поддержка прокси: SEARCH_HTTP_PROXY / HTTP(S)_PROXY

  • 🧪 Ноль сборки — чистый JS (CommonJS), 130 unit-тестов + сквозные смоук-тесты

Быстрый старт (Quick Start)

Требуется Node.js >= 18.

# 直接用 npx 运行(无需安装)
npx -y ai-search-mcp

# 或全局/本地安装
npm i -g ai-search-mcp
ai-search-mcp

Claude Desktop

В /claude_desktop_config.json добавьте:

{
  "mcpServers": {
    "ai-search-mcp": {
      "command": "npx",
      "args": ["-y", "ai-search-mcp"]
    }
  }
}

Cursor / Cline / другие клиенты, поддерживающие MCP

{
  "mcpServers": {
    "ai-search-mcp": {
      "command": "npx",
      "args": ["-y", "ai-search-mcp"],
      "env": {
        "SEARCH_REGION": "cn-zh"
      }
    }
  }
}

Китайским пользователям рекомендуется добавить SEARCH_REGION=cn-zh — автоматически будет использоваться цепочка движков с прямым доступом в Китае (bing → baidu → sogou), без прокси.

Запуск из исходников

git clone https://github.com/zhulingyu666/ai-search-mcp.git
cd ai-search-mcp
npm install
npm start

Описание инструментов (Tools)

{
  "query": "2026年 大模型 最新进展",
  "maxResults": 10,
  "site": "github.com",
  "region": "us-en",
  "freshness": "week"
}

Возвращает (структурированный JSON):

{
  "query": "2026年 大模型 最新进展",
  "queryRewritten": "大模型 最新进展",
  "queryYear": 2026,
  "engine": "bing",
  "engineSwitched": false,
  "cached": false,
  "total": 10,
  "deduped": 2,
  "freshnessApplied": true,
  "freshnessAutoInferred": true,
  "timeRange": "2025-08-25..2026-08-25",
  "results": [
    {
      "id": "a1b2c3d4",
      "title": "...",
      "url": "https://...",
      "snippet": "...",
      "domain": "example.com"
    }
  ]
}

Автоматическая перезапись китайских запросов: когда запрос содержит китайские знаки и слово «20xx年» (например, «2026年 大模型 最新进展»), инструмент убирает исходный год и автоматически добавляет freshness=year, чтобы компенсировать временное намерение. Потому что такие движки, как Bing, слабо обрабатывают китайскую сегментацию, и годовой префикс приводит к нерелевантным результатам (например, «энциклопедия/календарь 2026»). Перезапись прозрачно возвращается через queryRewritten / queryYear / freshnessAutoInferred, и агент может сам решить, принимать её.

Параметр

Тип

По умолчанию

Описание

query

string .

—

Поисковый запрос (обязательно)

maxResults

число

10

Количество результатов (1–20)

site

string

—

Ограничение одним доменом, напр. github.com (совместимый алиamed алиac includeDomains)

includeDomains

string[]

—

Возвращать только результаты с этих доменов, напр. ["github.com","arxiv.org"] (в engine, когда site: не работает, используется проверка на стороне результатов)

excludeДomains

string[]

—

Исключить результаты с этих доменов, напр. ["baidu.com"]

variant

string

—

Подсказка региона: código kl DDG (например, cn-zh, us-en) / Bing setlang / Brave country; также участвует в автовыборе движка

freshness

string

—

day | week | month | year (мапится на фильтр времени каждого движка)

timeRange

string

—

Точный интервал "YYYY-MM-DD..YYYY-MM-DD" (приоритетнее freshness)

Каждый результат имеет стабильный id (префикс sha1). Передайте этот id в fetch_page, чтобы прочитать страницу подробнее, не собирая URL вручную.

research — полное исследование за один вызов

Заменяет цикл агента «поиск → выбор страниц → извлечение → резюме» — один вызов:

{
  "query": "2026 LLM open source models comparison",
  "maxResults": 5,
  "fetchTopN": 2,
  "freshness": "month"
}

Возвращает краткую сводку (evidence brief):

{
  "query": "...",
  "engine": "bing",
  "overview": { "total": 5, "results": [ { "id": "...", "title": "...", "url": "...", "snippet": "...", "domain": "..." } ] },
  "pages": [ { "id": "...", "url": "...", "title": "...", "headings": [ { "level": 1, "text": "..." } ], "content": "...", "length": 4000, "truncated": false } ],
  "note": "证据简报已就绪,请基于页面内容总结并标注来源 URL。"
}
  • Многостраничное параллельное извлечение; сбой одной страницы фиксируется как { url, error }, не влияя на общий результат

  • Умный выбор страниц: pages подбираются по разнообразию доменов (сначала один результат с самым высоким рангом на каждый домен, затем добивается по рейтингу), чтобы один сайт не монополизировал результат — если один сайт блокирует парсинг, страницы других доменов не страдают; поле rank помечает исходный ранг результата в поисковой выдаче

  • extractMode (по умолчанию summary): summary возвращает очищенные ключевые точки текста (экономит токены), full возвращает полный Markdown страницы

  • Анализирует окончание модели хоста — MCP не зависит от каких-либо LLM, сохраняя нулевую внешнюю зависимость и нейтральность по вендору.

fetch_page — извлечение web-страницы в структурированный контент

{
  "url": "https://example.com/article",
  "extractMode": "summary",
  "maxLength": 8000
}
  • extractMode: summary (по умолчанию, экономный по токенам, возвращает очищенный текст mainText) / full (возвращает полный markdown страницы)

  • Возвращает { url, title, description, headings, mainText, markdown, length, truncated, cached } — headings — это outline заголовков страницы, чтобы агент мог сначала посмотреть структуру и решить, стоит ли углубляться.

Можно также использовать id результата: { "id": "a1b2c3d4", "maxLength": 8000 }.

Конфигурация (Переменные окружения)

Переменная

По умолчанию

Описание

SEARCH_ENGINE

auto

Один движок или цепочка устройств через запятую (например, brave,tavily); auto = выбор по региону

SEARCH_REGION

—

Регион по умолчанию для автовыбора движка, напр. cn-y3; он также является region по умолчанию для search

SEARCH_MAX_RESULTS

10

Количество результатов по умолчанию (1–20)

SEARCH_CACHE_TTL

600

Время жизни кэша (сек., 0 отключает)

SEARCH_CACHE_FILE

—

Путь к файлу персистентного кэша, напр. ./.cache/search.json; при установке кэш не теряется после перезапуска (только для одного процесса)

SEARCH_TIMEOUT_MS

10000

Таймаут одного запроса (мс)

SEARCH_RATE_PER_MINUTE

8

Максимум запросов в минуту на один движок (0 отключает лимит)

SEARCH_MIN_DELAY_MS / SEARCH_MAX_DELAY_MS

500 / 2000

Диапазон случайных задержек между запросами (мс, 0 отключает)

SEARCH_LANG_ROUTING

0

1 = при китайских запросах предпочитать Baidu/搜狗 (должен быть сетевой доступ к этим движкам, см. ниже)

SEARCH_LOG_LEVEL

info

debug | info | warn | error | off (структурированный журнал – stderr, не загрязняет протокол MCP)

SEARCH_LOG_QUERY

1

0 = маскировать текст запроса в журнале (приватность)

FETCH_MAX_LENGTH

9000

Максимальная длина Markdown отдельной страницы для fetch_page / research (в символах)

BRAVE_API_KEY

—

Обязательно для движка brave

TAVILY_API_KEY

—

Обязательно для движка tavily

SEARCH_HTTP_PROXY

—

Адрес прокси, напр. http://127.0.0.1:7890 (фолбэк на HTTPS_PROXY / HTTP_PROXY)

SEARCH_USER_AGENT

встроенный

КастиOM User-Agent

Сравнение движков

Движок

Бесплатный

API-ключ

Фильтр по времени

Описание

google

✅

❌

❌

Только за рубежом (недоступен из-за стены); глобально лучшее качество индекса, сильный противобот, нужен зарубежный IP + сессия (cookie)

bing

✅

❌

✅(qft)

Глобально; по умолчанию для китайского региона, хорошее покрытие китайского/английского, в Китае прямой доступ без прокси

duckduckgo

✅

️❌

✅(df)

Глобальный запасный вариант; в материковом Китае может завывать таймаут (нужен прокси)

yandex

✅

́

✅

Только за рубежом; силён для русскоязычного/СНГ, хорошая сеть в некоторых окружениях, средний антибот

%

so360

✅

️❌

✅

360 Поиск; ** прямой доступ с дата-центров и китайских IP**, относительно мягкий антибот, нативный китайский движок

baidu

✅

❌

Только Китай; сильный китайский индекс, но строгий антибот (на датацентровом IP всё равно появляется графическая капча wappass)

sogou

✅

❌

Только Китай; хорошее покрытие WeChat, но без сгенерированной JS-сессии SNUID агент может получить 302-редирект

brave

️❌

✅

✅(freshness)

Официальный API, высокое качество, есть бесплатный лимит

tavily

❌

✅

✅(time_range)

Специально разработан для поиска в LLM/RAG сценариях

Сетевые замечания

  • Китай без прокси: по умолчанию SEARCH_ENGINE=auto + SEARCH_REGION=cn-zh → bing → so360 → baidu → sogou, все работают напрямую, ничего настраивать не нужно. Из них 360 Поиск (so360) наиболее терпим к IP дата-центров/машинных залов и является самым надёжным нативным китайским движком.

  • Развернуто за рубежом: не задавайте SEARCH_REGION (или используйте не-cn префикс) → по умолчанию цепь google → bing → duckduckgo → yandex. Google наилучший по качестству, Bing стабильнее всех; при сбое любого движка происходит автоматический переход. Довёр на то, что Google/Yandex недостижимы/перехватываются капчей в Китае — это ожидаемо (под текущей сетью произойдет таймаут или RATE_LIMITED, затем автоматическое переключение).

  • Бесплатные движки имеют лимиты. При 429 возвращается структурированная ошибка (RATE_LIMITED с suggestedEngine и retryAfter); цепочка движков автоматически делает фейловер при 429/таймауте.

  • Некоторые сайты (например, 百度百科, многие китайские порталы) отклоняют скрипты (HTTP 403): fetch_page возвращает структурированную ошибку, research помечает соответствующую страницу как сбой и продолжает работу.

  • Нужен доступ к DuckDuckGo / Brave / Tavily, но вы внутри Китая? Используйте прокси:

SEARCH_ENGINE=duckduckgo SEARCH_HTTP_PROXY=http://127.0.0.1:7890 ai-search-mcp
  • Вежливый краулер: инструмент встроенно ограничивает частоту по движку (по умолчанию 8 запросов/мин) и случайные интервалы между запросами; для Baidu/搜狗 «посев» сессионных cookies на главной/ поисковике (BAIDUID / SUID) повышает успех, но не выполняет обход каптчи, подмену интернетов, смену UA или обход антибот-двига — это соответствие красной линией. При блокировке 403/каптчей стоит снизить частоту или сменить движок.

  • Примечание о доступности Baidu/搜狗 (проверено): эти движки очень чувствительны к сетевой среде — на IP дата-центров/зарубежных IP даже с «посевными» cookies Baidu показывает капчу (wappass), а Sogou при отсутствии сгенерированной JS-сессии SNUID получает 302-редирект (antispider). Поэтому в стандартном окружении они автоматически переключаются на Bing/360. Если у вас жилой IP на материковом Китае и Baidu/Sogou доступны, можно задать SEARCH_LANG_ROUTING=1, чтобы китайские запросы шли через 百度/搜狗/360 (нативные китайские движки с лучшей сегментацией).

  • Мы соблюдаем robots.txt и условия обслуживания целевых сайтов; инструмент возвращает лиSpec search summaries and links, не воспроизводит полные тексты.

Разработка (Development)

npm test          # 126 个单元测试(Node 内置 test runner)
node scripts/smoke-test.js   # 端到端冒烟:search + freshness + research(需要网络)

Пример журнала (stderr, SEARCH_LOG_LEVEL=debug)

[ai-search-mcp] [info] ready (version 0.3.2, engine=auto, region=cn-zh, logLevel=debug)
[ai-search-mcp] [info] rewrite q="2026年 大模型 最新进展" -> q="大模型 最新进展" +freshness=year
[ai-search-mcp] [info] search q="大模型 最新进展" engine=bing cached=false took=972ms total=3 deduped=1
[ai-search-mcp] [info] fetch url=https://example.com/ len=130 mode=summary took=1189ms
[ai-search-mcp] [debug] engine-fail engine=baidu err=RATE_LIMITED took=1203ms
[ai-search-mcp] [warn] fetch-fail url=https://baike.baidu.com/... err=ENGINE_ERROR took=512ms

Лицензия (License)

MIT


Отказ от ответственности: этот проект является независимым открытым исходным проектом и не связан с DuckDuckGo, Bing/Microsoft, Brave, Tavily, 百度, 搜狗, не одобрен ими и не спонсируется. Парсинг Baidu/搜dog основан на публичных HTML; если эти сайты изменят структуру страниц, парсинг может перестать работать.

Available Tools

3 tools
fetch_pageA

Fetch a page and return its content as structured Markdown. Pass either "url" or the "id" returned by search/research (id looks up the already-seen URL). extractMode "summary" returns de-noised mainText (saves tokens); "full" returns the full page Markdown. Output: {"url":str,"title":str,"description":str,"headings":[{level:int,text:str}], "mainText":str,"markdown":str,"length":int,"truncated":bool,"cached":bool}

NameRequiredDescriptionDefault
idNoStable result id from search/research
urlNoThe http(s) URL to fetch (mutually exclusive with id)
maxLengthNoMaximum characters of primary content to return (default 8000)
extractModeNosummary = de-noised main text (token-efficient); full = whole page Markdown (default full)

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that id uses an already-seen URL, summary mode de-noises mainText, and the output includes truncated and cached fields, which inform the agent about caching and truncation behavior. It does not cover failure modes or rate limits, but that is beyond typical selection criteria.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three tight sentences followed by an explicit output shape, with no filler. The core action is front-loaded, and every subsequent sentence adds information an agent needs for correct invocation. The output spec is lengthy but necessary since there is no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no annotations and no output schema, the description fully compensates: it explains purpose, parameter usage, behavioral nuances, and return value structure. The explicit output JSON gives agents a precise contract of what to expect, making the tool effectively self-contained. No critical selection or invocation information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema by clarifying that id looks up the already-seen URL and that summary extractMode 'saves tokens', directly addressing cost implications. The output block also connects maxLength to truncation and cached to caching behavior, which the schema alone does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Fetch a page and return its content as structured Markdown', a precise verb-resource-output statement that leaves no doubt about the tool's function. It also differentiates from siblings by explaining the id comes from search/research, positioning fetch_page as the retrieval step after search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly explains when to pass 'url' versus the 'id' returned by search/research, including that id looks up an already-seen URL. It also gives a clear choice criterion for extractMode: summary saves tokens, full returns the complete page. It stops short of naming explicit alternatives or exclusions, but the workflow context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

researchA

One-call research: search + fetch the top pages and return an evidence brief. Use this instead of chaining search/fetch_page yourself. Pages are selected for domain diversity (top hit per domain, then by rank) so one anti-bot 403 site can't sink the brief. Output: {"query":str,"engine":str,"cached":bool, "overview":{"total":int,"results":[{"id":str,"title":str,"url":str,"snippet":str,"domain":str}]}, "pages":[{"id":str,"url":str,"rank":int,"title":str,"headings":[{level:int,text:str}],"content":str,"length":int,"truncated":bool}|{"url":str,"rank":int,"error":str}]} Base your answer on the pages' content and cite their URLs.

NameRequiredDescriptionDefault
siteNoRestrict to one domain, e.g. github.com (alias for a single includeDomains entry)
queryYesThe web search query (required)
regionNoRegion hint. DuckDuckGo: kl code (cn-zh, us-en). Bing: setlang. Brave: country
fetchTopNNoHow many of the top results to fetch as full pages (default 2, 0 = overview only)
freshnessNoOnly results from the last day|week|month|year (auto-applied as year when a Chinese query drops a 20xx年 year token)
timeRangeNoExact window "YYYY-MM-DD..YYYY-MM-DD" (takes precedence over freshness)
maxResultsNoMax results (1-20, default from SEARCH_MAX_RESULTS)
extractModeNosummary = de-noised main text per page (default, token-efficient); full = whole page Markdown
maxPageLengthNoCharacters of Markdown kept per page (default 8000)
excludeDomainsNoNever return results from these domains, e.g. [baidu.com]
includeDomainsNoOnly return results from these domains, e.g. [github.com, arxiv.org]

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it does so thoroughly. It discloses the domain-diversity selection strategy, the anti-bot 403 resilience reasoning, and the exact output shape including per-page error objects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and use guidance, then adds a compact but necessary output schema. Every sentence earns its place, and the JSON block is justified because there is no separate output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 11-parameter tool with no annotations and no output schema, the description is remarkably complete. It explains the composite workflow, selection behavior, error handling, and return structure, so an agent has enough context to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema description coverage is 100%, so the schema already documents every parameter, including defaults, aliases, and precedence. The description itself adds no parameter-specific meaning beyond what the schema provides, matching the baseline for full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'One-call research: search + fetch the top pages and return an evidence brief,' which clearly identifies the operation, the resource, and the composite behavior. It also explicitly distinguishes itself from the sibling tools by saying to use it 'instead of chaining search/fetch_page yourself.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: use this tool instead of manually chaining search and fetch_page. It names the relevant alternatives, though it does not spell out exclusions such as 'when you only need a single page, use fetch_page.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.3.4
    • First observedfetch_page
    • First observedresearch
    • First observedsearch

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: search for web results, fetch_page for retrieving a specific page's content, and research for combining search and deep-reading. There is no overlap or chance of misselection.

Naming Consistency5/5

All tool names follow the same snake_case, verb_noun pattern (fetch_page, search, research). Although 'search' and 'research' are single-word verbs, the pattern is consistent and predictable.

Tool Count5/5

With only 3 tools, the server is well-scoped for a web search and research workflow. Each tool earns its place with minimal redundancy.

Completeness5/5

The tool surface covers the full research lifecycle: search to discover results, fetch_page to retrieve content, and research to combine both efficiently. No critical gaps exist for the stated purpose.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to perform web research in one tool call by searching, fetching and cleaning full pages, and ranking cited passages. Provides web_research, web_fetch, web_search, and status tools for MCP clients.
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to perform live web searches across 9 engines, scrape web pages into clean formats, and run agentic research with citations via MCP.
    149 PyPI
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to perform web search, extraction, and research across multiple provider backends with persistent multi-key rotation and auditable routing. Supports MCP, CLI, and Agent Skill entry points.
    MIT