Как научить ИИ проверять поисковые запросы в Wordstat? Готовый MCP-сервер на Git

—

от автора

ИИ × Wordstat — готовый MCP-сервер

ИИ × Wordstat — готовый MCP-сервер

Всё начиналось в отрыве от реальных данных. ИИ анализировал целевую аудиторию и предлагал поисковые запросы.

Мы подключили Wordstat по API, чтобы агент сам проверял свои предположения и собирал ответ по данным сервиса. Получился read-only-пакет на Python: четыре метода Wordstat, командная строка и MCP-сервер. Код и тесты доступны в открытом репозитории.

Содержание

Агент возвращает фразы с частотностями Wordstat

В примере нас интересовала проверка спроса на автоматизацию маркетинга. Основная часть запроса в чат:

Посмотри в Wordstat, как пользователи в России искалиавтоматизацию маркетинга за последний месяц.Покажи пять самых частотных формулировок.

В ответе Codex — пять формулировок с частотностями из Wordstat. Их написание и числа можно сверить с результатом инструмента:

Ответ Codex: пять поисковых формулировок и их частотности

Ответ Codex: пять поисковых формулировок и их частотности

Раньше после анализа аудитории нам приходилось открывать Wordstat и проверять предложенные моделью формулировки вручную. Теперь агент получает частотности через инструмент и возвращает их в том же диалоге. Проверка спроса больше не требует переноса данных между сервисом и чатом.

Этот пример закрывает одну задачу — получение фраз и частотностей. Для отбора ключей в конкретную кампанию потребуются сведения о продукте, посадочной странице и целях рекламы.

Воспроизвести интеграцию можно из зафиксированного тега

Для статьи мы создали тег wordstat-v0.1.1. Если main изменится, команды и код ниже останутся привязаны к версии статьи.

git clone --branch wordstat-v0.1.1 --depth 1 `  https://github.com/akulemin/ai-marketing-integrations.gitcd ai-marketing-integrations\packages\yandex-wordstatpython -m venv .venv.\.venv\Scripts\python.exe -m pip install -e ".[dev]"Copy-Item .env.example .env

В .env нужны тип авторизации, ключ и ID каталога:

WORDSTAT_AUTH_TYPE=api_keyWORDSTAT_API_KEY=<secret>WORDSTAT_FOLDER_ID=<folder-id>

Сервисному аккаунту назначается роль search-api.webSearch.user, а API-ключ создаётся со scope yc.search-api.execute. Контрольный запрос из каталога пакета:

.\.venv\Scripts\wordstat.exe top "автоматизация маркетинга" --region 225 --limit 5

Для подключения к Codex настройка добавляется в проектный .codex/config.toml:

[mcp_servers.yandex-wordstat]command = 'C:\absolute\path\ai-marketing-integrations\packages\yandex-wordstat\.venv\Scripts\wordstat-mcp.exe'cwd = 'C:\absolute\path\ai-marketing-integrations\packages\yandex-wordstat'enabled_tools = [  "wordstat_top",  "wordstat_dynamics",  "wordstat_regions_distribution",  "wordstat_regions_tree",]

Пути заменяются на абсолютные пути установки. cwd указывает на каталог пакета с локальным .env; ключей в TOML нет. Запуск проверен через stdio: инициализация MCP, список инструментов и чтение тестового кэша без HTTP-обращений. Формат command, args, cwd и списка разрешённых инструментов описан в документации Codex MCP.

Агенту нужен узкий инструмент с предсказуемым ответом

Для этого понадобилось отделить получение данных от их интерпретации. В ответе инструмента должны сохраняться исходные фразы и частотности, чтобы можно было сопоставить с ними выводы модели.

Мы решили дать агенту четыре отдельных инструмента, которые повторяют методы официального Wordstat API:

Инструмент

Что возвращает

Для чего используем

wordstat_top

Популярные и связанные фразы за последние 30 дней

Проверить формулировки спроса и найти соседние запросы

wordstat_dynamics

Частотность по дням, неделям или месяцам

Увидеть сезонность и не принять месячный всплеск за постоянный спрос

wordstat_regions_distribution

Количество, долю и индекс интереса по регионам

Проверить, где запрос выражен сильнее

wordstat_regions_tree

Иерархию поддерживаемых регионов

Преобразовать название территории в ID для следующего вызова

Все четыре операции только читают данные. Пакет не меняет рекламные кампании и не требует контура согласования, который нужен для записи в Директ.

Архитектура получилась короткой:

ИИ-клиент ── MCP ──┐                   ├── WordstatService ── WordstatClient ── Yandex Cloudтерминал ─── CLI ──┘          │                 │                              │                 ├── повтор временных ошибокPython-код ───────────────────┘                 └── файловый кэш

CLI и MCP вызывают один сервисный слой. Поэтому в них одинаковая валидация, кэш и обработка ошибок, а расхождения между «ручным» и агентным запросом проще ловить в тестах.

Один полный проход по Wordstat стоит 9 копеек

По тарифу Yandex Search API, проверенному 23 октября 2026 года, цены в рублях включают НДС и указаны за 1000 вызовов:

Метод

За 1000 вызовов

За один вызов

GetTop

20 ₽

0,02 ₽

GetDynamics

20 ₽

0,02 ₽

GetRegionsDistribution

50 ₽

0,05 ₽

GetRegionsTree

Без оплаты

Без оплаты

По одному успешному вызову трёх платных методов — 0,09 ₽: 0,02 + 0,02 + 0,05 ₽. Это стоимость Wordstat; расходы на ИИ-клиент и модель считаются отдельно.

Десять одинаковых исследовательских проходов стоят 0,90 ₽, а 10 000 проходов — 900 ₽. На ручной проверке экономия невелика, но автономный агент может повторять один и тот же вызов в цикле. Поэтому кэш появился в первой версии: он ограничивает лишние обращения к API и фиксирует снимок данных для текущего разбора.

Ключ кэша — SHA256 от имени метода и нормализованного JSON-запроса:

material = json.dumps(    {"method": method, "payload": payload},    ensure_ascii=False,    sort_keys=True,    separators=(",", ":"),)digest = hashlib.sha256(material.encode("utf-8")).hexdigest()

По умолчанию обычные ответы хранятся семь дней, дерево регионов — 30 дней. Пока запись действительна, одинаковые параметры возвращают локальный результат без обращения к API. Изменение лимита, региона или фильтра устройств создаёт другой ключ. Флаг refresh=true явно обходит кэш.

Кэш сохраняет один снимок для повторного разбора. Он также сокращает лишние обращения, но отдельного лимита расходов у пакета пока нет: агент может обходить кэш или менять параметры.

Клиент валидирует ответ до того, как его увидит модель

Yandex Cloud принимает REST-запросы синхронно. Для доступа нужны каталог, API-ключ или IAM-токен и роль search-api.webSearch.user. Секреты читаются из переменных окружения и не входят в параметры MCP-инструментов.

Внутри клиент собирает типизированную модель запроса, проверяет кэш и только затем обращается к API:

def get_top(self, phrase, *, num_phrases=50, regions=None, devices=None, refresh=False):    request = TopRequest(        phrase=phrase,        numPhrases=num_phrases,        regions=regions or [],        devices=devices or [],        folderId=self.settings.folder_id,    )    return self._call("topRequests", request, TopResponse, refresh=refresh)

Pydantic проверяет типы полей и ограничения запроса. Например, неподдерживаемое значение устройства вызывает ошибку валидации до отправки HTTP-запроса. Проверка не доказывает полноту ответа: дополнительные поля допускаются, а у некоторых полей есть значения по умолчанию. Изменения API всё равно требуют проверки контракта.

Для кодов 429, 500, 502, 503 и 504 клиент повторяет запрос с экспоненциальной задержкой. Числовой Retry-After имеет приоритет. Сообщение об ошибке проходит отдельную очистку: API-ключ, IAM-токен и folder ID заменяются на <redacted> до того, как исключение попадёт в терминал или чат.

Пользователь отвечает за .env, права сервисного аккаунта и логи ИИ-клиента. Пакет не добавляет секреты в схему инструмента и очищает известные значения из текста HTTP-ошибок. Это не изоляция ключей от агента, у которого есть доступ к файлам локального проекта.

MCP получает четыре инструмента вместо универсального HTTP-доступа

Можно было дать агенту URL, заголовки и общий инструмент http_post. Мы отказались от этого варианта: модели пришлось бы каждый раз собирать служебный JSON, а область доступа стала бы шире.

MCP-сервер публикует четыре функции с явными параметрами. Например, инструмент топа выглядит так:

@mcp.tool()def wordstat_top(    phrase: str,    regions: list[str] | None = None,    devices: list[str] | None = None,    limit: int = 50,    refresh: bool = False,) -> dict:    if limit > 200:        raise ValueError(            "MCP output is limited to 200 phrases; use the CLI for larger exports"        )    return _service().top(        phrase,        limit=limit,        regions=regions,        devices=devices,        refresh=refresh,    )

Лимит в 200 относится к параметру топа в MCP. Ассоциации API возвращает отдельным массивом; ограничения общего объёма ответа в токенах у сервера нет. Для больших выборок в CLI доступно до 2000 фраз: результат можно сохранить в JSON или CSV, а в контекст модели передать нужную часть.

Агенту предстоит выбрать метод и превратить описание территории в ID. Карточка вызова показывает, какие параметры он собрал, — здесь их можно проверить независимо от последующего объяснения.

В первой сессии агент ошибся в параметре устройства

В сессии Codex 20 октября модель передала devices: ["all"]. Клиент ожидает значения перечисления Device, в том числе DEVICE_ALL, и отклонил запрос до обращения к Wordstat. В той сессии данные в итоге получили через CLI. Поэтому сам факт появления инструмента в клиенте ещё не подтверждал, что агент правильно им пользуется.

23 октября мы повторили вызов через MCP с корректными параметрами:

{  "phrase": "автоматизация маркетинга",  "regions": ["225"],  "limit": 5,  "refresh": false}

Фильтр устройств здесь не задан. Перед вызовом мы отдельно проверили доступность записи кэша, запретив HTTP-обращения в проверочном клиенте. MCP вернул тот же снимок, сохранённый 20 октября. Это подтверждает работу MCP и повторное чтение данных; доступность API на 23 октября этим вызовом не проверялась.

Эта ошибка подсказала следующую доработку: описать допустимые устройства прямо в схеме MCP-инструмента через enum. Сейчас публичная функция принимает list[str], поэтому модель узнаёт об ограничении только из ошибки внутренней валидации.

Тесты не ходят в платный API

В опубликованном теге wordstat-v0.1.1 двенадцать модульных тестов. Они проверяют модели, заголовок авторизации, кэш, повтор запросов после 429, очистку секретов, состав и схему MCP-инструментов. HTTP-ответы замоканы, поэтому этот набор не обращается к платному API.

.\.venv\Scripts\python.exe -m pytest -q

Контрольный прогон публичного пакета 23 октября: 12 passed in 2.03s. Дополнительно мы запустили сервер через stdio, выполнили MCP-инициализацию и вызвали инструмент чтения дерева регионов из тестового кэша. Все четыре инструмента доступны; HTTP-обращения в этой проверке были запрещены.

Ограничения текущей версии

Пакет поддерживает все четыре REST-метода Wordstat, два типа авторизации, JSON и CSV, повтор временных ошибок и локальный кэш. У первой версии остаются ограничения:

  • нет общей схемы исследовательского отчёта, которая объединяет топ, динамику и географию;

  • нет автоматической кластеризации фраз;

  • параметр топа в MCP ограничен 200 фразами; общего ограничения объёма ответов нет;

  • схема MCP пока принимает устройства как строки; допустимые значения проверяет внутренний клиент;

  • интеграционный тест с живым API нельзя безопасно запускать в публичном CI без секрета и оплаты;

  • файловый кэш рассчитан на одного пользователя и не координирует параллельные процессы на нескольких машинах.

Следующая доработка — уточнить схему устройств. Для исследовательского отчёта также нужно явно возвращать дату получения данных и признак попадания в кэш. Сейчас сам JSON-ответ этих полей не содержит, поэтому их приходится проверять отдельно.

Код версии статьи доступен в репозитории ai-marketing-integrations. Начать можно с одной фразы и пяти результатов: проверить параметры вызова, сверить числа с ответом инструмента и посмотреть, какие выводы модель сделала сверх этих данных.

ссылка на оригинал статьи https://habr.com/ru/articles/1099528/