Open source · Сентябрь 2026. Кейс описывает опубликованную реализацию. Примеры и проверки выполнены на коммите fad9a869, ссылки на код закреплены на этой версии.
Рабочий контекст
Я собираю SEO Agent для своих сайтов: он по расписанию получает поисковые метрики и сопоставляет их с историей страниц. Для Google у меня уже есть отдельный MCP-сервер. Следующим источником стал Яндекс Вебмастер: мне нужны его сведения об индексировании, страницах в поиске и диагностике, чтобы агент мог объяснить, на каких данных основан вывод.
Я написал Webmaster MCP на Go. Это отдельный self-hosted сервис со Streamable HTTP, MCP-инструментами и доступом к REST API Яндекса. Он получает данные, а интерпретация и хранение истории остаются задачей SEO Agent. В самом MCP-сервере нет постоянной базы: такое разделение позволяет проверять интеграцию независимо от сборщика.
- SEO AgentРасписание, анализ и история в PostgreSQL
- Webmaster MCPGo, доступ к отчётам, полномочия и ограничения запросов
- API ЯндексаДанные Вебмастера и очередь переобхода
Агент подключается с MCP bearer-токеном. Отдельный OAuth-токен Яндекса хранится на стороне MCP-сервера. Даты сбора и историю сохраняет SEO Agent.
Сценарий: проверить индексирование сайта
Работу я начинаю с list_hosts. Агент получает доступные сайты и использует host_id ровно в том виде, в котором его вернул Вебмастер, например https:example.com:443. Протокол и порт здесь существенны: самостоятельно составленный идентификатор может привести к запросу другого хоста.
get_summaryдаёт общую картину: сведения о сайте, страницах и проблемах.get_diagnosticsпозволяет прочитать диагностические сообщения, вместо того чтобы предполагать причину изменения показателей.get_insearch_historyпоказывает историю страниц в поиске, аget_insearch_samples— доступную выборку URL для дальнейшей проверки.
Я разделяю скачивание страницы роботом и её присутствие в поиске: для первого есть инструменты get_indexing_*, для второго — get_insearch_*. Выборка URL не является полной картой индекса, а пустой ответ сам по себе не доказывает отсутствие страниц. В отчёте должны сохраняться выбранный хост, период и ограничения источника.
Применение на opatsay.com: данные перед рекомендацией
12 сентября 2026 года в 14:29:23 UTC я выполнил четыре операции чтения через работающий Webmaster MCP: list_hosts, get_summary, get_diagnostics и get_insearch_history. Хост https:opatsay.com:443 был получен из discovery и подтверждён в Яндексе.
Сводка вернула 50 страниц в поиске и 4 исключённые. История за запрошенный период 29 августа — 11 сентября содержала три точки: 19 страниц 7 сентября, 48 — 9 сентября и 50 — 10 сентября. Диагностика дала 32 состояния ABSENT, ни одного PRESENT и UNDEFINED для NOT_MOBILE_FRIENDLY.
Этот пример проверяет полезность границ данных: агент может сообщить изменение числа страниц, но не назвать его ростом трафика, приписать редизайну или объявить все проверки успешными. Следующие действия — выяснить причины исключения URL и отдельно проверить мобильную верстку; сам отчёт не требует записи в Яндекс.
Параметры, исходные ответы и разбор результата. Это живое наблюдение собственного сайта, не данные демо и не измеренный SEO-эффект продукта. Время запроса сохранено отдельно от дат истории.
Решение 1: режим чтения как исполняемое правило
Плановому сборщику нужны отчёты. Отправка страницы на переобход меняет состояние внешней системы и расходует суточную квоту, поэтому для SEO Agent я предусмотрел MCP_READ_ONLY=true.
В этом режиме каталог содержит 33 инструмента. submit_recrawl исключён из списка, а прямой вызов по известному имени тоже отклоняется. Именно второй случай важен для границы доступа: одного скрытия инструмента из discovery недостаточно. Поведение проверяет отдельный тест через MCP. В обычном режиме доступны 34 инструмента, включая отправку на переобход.
Решение 2: тайм-аут записи не означает отказ
Если запрос на переобход ушёл в Яндекс, а ответ не пришёл вовремя, сервер уже мог принять URL. Автоматическая повторная отправка в таком состоянии способна создать лишнюю операцию. Поэтому клиент никогда автоматически не повторяет отправку на переобход.
Тайм-аут или отмена после отправки получают результат outcome_unknown с retryable: false. Это не подтверждение успеха и не подтверждение отказа. Прежде чем решать, отправлять ли URL повторно, нужно проверить get_recrawl_queue и, когда известен идентификатор задания, get_recrawl_task. Я вынес этот сценарий в регрессионный тест, чтобы общая политика повторов не начала незаметно распространяться на запись.
Решение 3: ограничивать чтение целиком
У запросов к Яндексу есть общий бюджет времени: по умолчанию 30 секунд, включая ожидание свободного слота и повторные попытки. При временных ошибках чтение может повторяться, но новая попытка не получает отдельные полные 30 секунд. Отмена охватывает и очередь, и обращение к внешнему API.
По умолчанию один процесс допускает восемь параллельных операций с Яндексом, а размер ответа ограничен 8 MiB. Эти границы помогают управлять ожиданием и потреблением памяти. Они не заменяют квоты провайдера: при запуске нескольких реплик суммарная нагрузка возрастёт, поскольку ограничитель у каждой реплики собственный.
Как я проверяю результат
В публичном репозитории есть воспроизводимый деморежим с явно обозначенными синтетическими данными. Он не обращается к Яндексу и позволяет проверить подключение без OAuth-токена. Интеграционные HTTP-тесты используют настоящий MCP SDK, проверку bearer-токена и подставной внешний транспорт; так я проверяю успешные вызовы, валидацию и ошибки интеграции.
Проверки разделены по смыслу. /health подтверждает, что процесс работает. Встроенный smoke проверяет обнаружение инструментов и представительный набор вызовов; в живой конфигурации он также проверяет доступ к данным Яндекса. Успешное демо не подтверждает права OAuth, доступ к конкретному сайту или настройку HTTPS на сервере.
Реализован и проверен следующий контракт: 33 инструмента для автоматического чтения, 34 в обычном режиме, явная ошибка для неопределённого результата записи и ограниченная работа с внешним API. Влияние на поисковый трафик здесь не измерялось.
Открытый код позволяет проверить каталог и регистрацию инструментов, пределы запросов и политику повторов, а также интеграцию HTTP → авторизация → MCP → API.
При подготовке кейса прошли тесты пакетов internal/webmaster, internal/mcpserver и cmd/mcp-server, включая отдельные проверки запрета прямого переобхода и тайм-аута записи. Изолированное демо прошло smoke с девятью вызовами. Проверки выполнены на опубликованном коммите fad9a869.
- 33 инструмента и запрет прямого вызова переобхода
- Одна отправка при неопределённом результате записи
- Тайм-аут записи с outcome_unknown и retryable: false
Ограничения и следующий шаг
Одна установка использует один OAuth-токен. Здесь нет изоляции независимых пользователей, распределённого ограничения запросов и браузерного входа в Яндекс. Для разных владельцев сайтов нужны отдельные установки. Сам сервис также не устанавливает причинную связь между изменением статьи и поисковыми показателями.
Дальше я развиваю сопоставление отчётов с историей страниц в SEO Agent: хочу видеть, какой материал изменился, какие данные уже обновились и где пока недостаточно наблюдений. Webmaster MCP остаётся источником проверяемых сведений, на которые этот анализ может ссылаться.
Попробовать публичное демо
Нужны Git и Docker с Compose. Команды собирают опубликованный исходный код. Демо использует синтетические данные и не обращается к Яндексу.
git clone https://github.com/tenqz/webmaster-mcp.git
cd webmaster-mcp
docker compose -f compose.demo.yml up -d --build
docker compose -f compose.demo.yml exec mcp /mcp-server --smoke http://127.0.0.1:8080/mcpПодключение: http://localhost:8080/mcp, заголовок Authorization: Bearer demo-token. Это публичный демонстрационный токен. Compose-демо по умолчанию показывает 34 инструмента. Его параметр read_only относится к файловой системе контейнера — режим инструментов задаёт MCP_READ_ONLY.
После проверки остановите демо:
docker compose -f compose.demo.yml downДля работы со своим сайтом продолжите со статьёй о подключении и использовании. Полный код доступен в репозитории Webmaster MCP.