Yandex Metrika
Cobertura completa de la API de Yandex Metrika (Stat, Management, Logs) con definiciones de herramientas generadas a partir de la documentación oficial de Yandex. Diez herramientas expuestas por defecto para no saturar el contexto; nunca reescribe tu consulta silenciosamente.
Documentación
Yandex Metrika MCP Server
MCP-сервер к API Яндекс Метрики. Покрыты все 108 методов; по умолчанию объявляются десять — те, которыми считают. Остальное включается одной переменной.
mcp-name: io.github.artgas1/yandex-metrika-mcp-server
npx -y yandex-metrika-mcp-server
Форк atomkraft/yandex-metrika-mcp (апстрим — Vadim Bezymianyi, MIT). С версии 2.0.0 инструменты не пишутся руками, а порождаются из спеки, собранной по официальной документации.
Покрытие
| API | методов | из них в профиле core | примеры инструментов |
|---|---|---|---|
| Management | 95 (21 ресурс) | 4 | metrika_counter_list, metrika_goal_create, metrika_segment_update |
| Logs | 7 | — | metrika_logs_create, metrika_logs_get, metrika_logs_download |
| Stat | 6 | 6 | metrika_stat_data, metrika_stat_bytime, metrika_stat_pivot |
Имя инструмента — metrika_<ресурс>_<действие>, где ресурс взят из URL самого API без переименований.
Поэтому metrika_goal_list однозначно отображается в GET /management/v1/counter/{id}/goals
и в свою страницу документации.
Контракт
Сервер переписан из-за двух наблюдавшихся отказов: он отдавал не то, что просили, и молча подмешивал фильтр. Отсюда четыре правила, каждое закрыто тестом.
- Никакой молчаливой подмены. Что попросили — то и уходит в API. Сервер не досочиняет ни измерений, ни периода, ни фильтров.
- Всё, что сервер добавил от себя, видно в ответе. Ответ приходит как
{"_meta": {...}, "data": {...}}, где_meta.applied_by_serverперечисляет добавленное, а_meta.notes— принятые за вызывающего решения. - Отказ остаётся отказом. Ошибка API возвращается с
isError: trueи телом ответа Метрики. Повтор делается по статусу (429/500/502/503/504 и сетевые сбои), а не по подстроке в тексте; у 429 соблюдаетсяRetry-Afterс потолком 30 секунд. Число повторов всегда видно в_meta.retries. - Обрезание выдачи видно. В
_metaедутrows_returned,rows_totalиtruncated— Метрика режет ответ по умолчанию, и молчать об этом нельзя. Если сервер сам урезал ответ по потолку длины, это отдельно объявлено в_meta.truncated_by_serverс числом выброшенных строк. - Секреты не уезжают в ответ. У
metrika_measurement_deleteесть параметрtoken; в показанном_meta.request_urlего значение заменено наREDACTED. Сам OAuth-токен уходит только заголовком и в ответе не появляется никогда.
Фильтр роботов
В отчётах Stat API по умолчанию применяется собственный флаг робота Метрики, и только он:
ym:s:isRobot=='no'
Он объявлен: виден в схеме инструмента, отключается параметром human_traffic_only: false
и всегда перечислен в _meta.applied_by_server. Если в запросе есть метрики ym:ad: или
ym:ev:, фильтр не применяется (Метрика отвечает на такое сочетание 400) — и это попадает
в _meta.notes, а не остаётся молчаливым исключением.
Своё условие задаётся переменной METRIKA_TRAFFIC_FILTER — целиком, включая isRobot,
если он нужен:
METRIKA_TRAFFIC_FILTER="ym:s:isRobot=='no' AND ym:s:browserName!='HeadlessChrome'"
Это образец формы, а не рекомендация. Какой рез верен — зависит от того, какие боты ходят именно к вам: отсечка по стране, по заголовку браузера или по подсети осмысленна только на своих данных. Копировать чужой список бессмысленно и опасно: он вырежет живой трафик.
Заданное своё условие сервер называет в stderr при старте — оно меняет числа в каждом отчёте, и молчать об этом нельзя.
Сравнение периодов: ответ, который выглядит валидным
У metrika_stat_comparison и metrika_stat_comparison_drilldown даты периодов
необязательны, и Метрика на их отсутствие не ругается. Она подставляет собственное окно
(последняя неделя) в оба набора и возвращает сравнение периода с самим собой:
metrika_stat_comparison(ids, metrics) → totals a == b
query date1_a == date1_b
Отказывать сервер не будет — запрос ушёл ровно тем, каким его собрали. Но такой ответ
приходит с пометкой в _meta.notes: и когда даты не заданы, и когда периоды совпали явно.
Как устроена спека
Публичного openapi.json у Метрики нет, но каждая страница метода сгенерирована из OpenAPI
движком Diplodoc и отдаётся как text/markdown. Семантика (тип, required, комбинатор,
ассертация) лежит в CSS-классах вида {.json-schema-property}, поэтому спека собирается
построчным сканером по классам, а не markdown-парсером.
npm run spec:fetch # скачать llms.txt и 108 страниц в .cache/docs/
npm run spec:build # разобрать их в spec/metrika-api.json
npm test # тесты спеки и схем инструментов
npm run smoke # живые вызовы к API (нужен YANDEX_API_KEY)
spec/metrika-api.json коммитится — это состав API на момент сборки. Тест на дрейф сверяет
его с llms.txt: Яндекс добавил или удалил метод — тест краснеет.
Разбор привязан к версии генератора (Diplodoc Platform v5.57.3): вся семантика висит на его
классах, поэтому расхождение версии останавливает сборку спеки, а не молча портит её.
Запуск
По умолчанию объявляются десять инструментов из 108 — те, которыми считают. Управление счётчиками и целями, доступы и Logs API включаются переменной
METRIKA_PROFILE; подробности ниже, в разделе «Почему по умолчанию не всё».Спросить у самого сервера тоже можно: инструмент
metrika_catalog_listперечисляет, что объявлено, что скрыто и как это включить.
npm install
npm run build
YANDEX_API_KEY=<OAuth-токен с scope direct:api / metrika> npm start
Токен — OAuth Яндекса, тот же, что используется для Директа и Вебмастера.
По умолчанию сервер сохраняет stdio-режим. Для одного локального процесса, к которому подключаются несколько MCP-клиентов, включите stateless Streamable HTTP:
YANDEX_API_KEY=<OAuth-токен> \
MCP_TRANSPORT=http MCP_HOST=127.0.0.1 MCP_PORT=13404 \
npm start
Endpoint — http://127.0.0.1:13404/mcp. При loopback-привязке сервер также
проверяет Host, чтобы локальный endpoint нельзя было вызвать через DNS rebinding.
Подключение к клиенту
{
"mcpServers": {
"yandex-metrika-mcp": {
"command": "npx",
"args": ["-y", "yandex-metrika-mcp-server@3"],
"env": { "YANDEX_API_KEY": "..." }
}
}
}
Из локальной сборки — то же самое, но "command": "node" и путь до build/index.js.
Мажор в строке запуска закреплён намеренно: смена мажорной версии меняет набор инструментов по умолчанию, и получать это молча при старте агента не нужно.
Переменные окружения
| Переменная | По умолчанию | Что делает |
|---|---|---|
YANDEX_API_KEY | — | OAuth-токен. Без него сервер не стартует. |
MCP_TRANSPORT | stdio | Транспорт: stdio или stateless Streamable http. |
MCP_HOST | 127.0.0.1 | Адрес HTTP listener. Используется только при MCP_TRANSPORT=http. |
MCP_PORT | 3000 | Порт HTTP listener, целое число от 1 до 65535. |
METRIKA_PROFILE | core | Какая часть каталога объявляется: core (10 инструментов), read (все 51 читающих), all (все 108). Неизвестное значение роняет старт. |
METRIKA_ALLOW_WRITES | не задана | 1 разрешает и объявляет 57 инструментов, меняющих данные. Пока не задана — их нет в tools/list вовсе. |
METRIKA_TOOLS | пусто | Своя выборка через запятую: раздел (stat, logs, management), префикс имени (metrika_goal) или точное имя. Задана — побеждает профиль. |
METRIKA_TRAFFIC_FILTER | ym:s:isRobot=='no' | Условие сегментации, добавляемое к отчётам Stat. Задаётся целиком. |
METRIKA_MAX_OUTPUT_CHARS | 120000 | Потолок длины ответа одного вызова. Выгрузка Logs API в него обычно не помещается — сутки визитов это сотни тысяч символов; урезание объявляется в _meta.truncated_by_server. |
METRIKA_API_BASE | пусто | Подмена адреса API (прокси, заглушка в тестах). Факт подмены печатается в stderr. |
Как узнать, что скрыто, не открывая README
Инструмент metrika_catalog_list объявлен в любом профиле и отвечает из спеки, лежащей в
пакете, — ни токена, ни сети ему не нужно:
{
"profile": "METRIKA_PROFILE=core",
"api_methods_total": 108,
"api_methods_declared": 10,
"api_methods_hidden": 98,
"writes_enabled": false,
"declared_tools": { "Stat API — отчёты": ["metrika_stat_data", "…"] },
"hidden_tools": { "Management API — …": ["metrika_goal_create", "…"] },
"how_to_widen": ["METRIKA_PROFILE=read — …", "METRIKA_PROFILE=all вместе с METRIKA_ALLOW_WRITES=1 — …"]
}
Он существует по простой причине: сервер, который что-то скрыл, обязан уметь сказать, что
именно и как это включить. instructions видит модель, но не человек — в интерфейс клиента
они не показываются; стартовую строку в stderr в обычной работе тоже никто не открывает. Без
этого инструмента узнать про остальные 98 можно было только придя сюда.
Список инструментов в ответе строится из того же отбора, по которому они регистрируются, — разойтись с реальностью ему негде, и это проверено тестом.
Почему по умолчанию не всё
Описания объявленных инструментов лежат в контексте модели, когда клиент их загрузил. Это
цена сервера, которую платят за сам факт подключения, а не за вызовы. Замер tools/list
(09.09.2026):
| Профиль | Инструментов | tools/list | токенов |
|---|---|---|---|
core (по умолчанию) | 10 + каталог | 32 181 Б | 14,8 тыс. |
read | 51 + каталог | 68 074 Б | ~31 тыс. — оценка |
all + METRIKA_ALLOW_WRITES=1 | 108 + каталог | 158 301 Б | ~73 тыс. — оценка |
Замер core — 14,5 тысячи до появления каталога и 14,8 после: сам инструмент стоит около
670 байт схемы, примерно 2% набора. Его ответ не входит в эту цену — он платится только при
вызове.
Байты точные, их воспроизведёт любой: сериализуй ответ tools/list и посчитай длину.
С токенами сложнее, и здесь стоит сказать прямо.
⚠️ Замер честный только у core — его дал /context клиента, который считает
собственным токенизатором. Две другие строки пересчитаны из байтов по калибровке
2,17 байта на токен, снятой с той же строки core.
Ходовая эвристика «4 символа на токен» здесь врёт почти вдвое: она выведена на
английском тексте, а описания у этого сервера русские, и кириллица в BPE токенизируется
примерно вдвое хуже латиницы. Первая редакция этой таблицы была построена именно на ней и
называла для core 7,9k вместо 14,5k. Если считаешь бюджет контекста для сервера с
не-английскими описаниями — считай токенизатором, а не делением на четыре.
Состав core выведен из замера реального использования, а не из вкуса: шесть отчётов Stat
плюс справочники, без которых отчёт не собрать (metrika_counter_list, metrika_counter_get,
metrika_goal_list, metrika_segment_list). Порог веса стоит тестом — манифест не может
подорожать молча. Порог в тесте стоит на байтах: они не зависят ни от токенизатора, ни
от языка описаний.
Безопасность
- Запись выключена по умолчанию, и меняющие инструменты не объявляются вовсе. Среди
методов четырнадцать
DELETEи пять удаляющихPOST(.../measurement/delete,.../expense/delete,.../logrequest/{id}/cleanи т. д.). Цена ошибочного вызова — удалённый счётчик или цель без возможности восстановить историю. Модель не может позвать то, чего не видит вtools/list; как включить — сказано вinstructionsсервера. - Аннотации проставлены на всех инструментах (
readOnlyHint,destructiveHint,idempotentHint,openWorldHint). Клиент по ним отличает чтение от удаления: удаление под глаголомPOSTпомечено разрушающим,PUT— тоже, потому что заменяет сущность целиком. - Ответы Метрики — недоверенные данные. В отчётах лежат поисковые фразы, заголовки
страниц, реферера и значения UTM, то есть строки, которые пишут посетители сайта. Любой
может зайти на сайт по ссылке с текстом внутри и увидеть его в отчёте. У всех инструментов
openWorldHint: true, а в_meta.notesотчётов и выгрузок едет напоминание, что это данные, а не инструкции. - stdio остаётся транспортом по умолчанию. HTTP включается только явно через
MCP_TRANSPORT=http; безопасный дефолт слушает127.0.0.1и проверяетHost.
Политика приватности
Сервер не собирает, не хранит и никуда не передаёт данные о вас. Ни телеметрии, ни аналитики, ни обращений к серверам автора — их не существует: под этот пакет не поднято никакой инфраструктуры.
Единственный сетевой адресат — https://api-metrika.yandex.net. Токен читается из
YANDEX_API_KEY в память процесса и никуда не пишется: ни в файл, ни в stdout, ни в тело
ответа. Данные отчётов не кэшируются на диск и не переживают процесс.
Данные, которые вы запрашиваете, обрабатывает Яндекс как оператор Метрики — на это распространяется его политика, а не эта.
Полный текст: PRIVACY.md.
Установка одним файлом (MCPB)
Para Claude Desktop y otros clientes que entienden los paquetes MCP, hay un archivo .mcpb — está en los
releases. Abres el archivo, introduces el
token en la ventana de instalación — listo.
El paquete se compila desde el mismo código con la misma etiqueta (npm run mcpb), y su manifiesto se genera
a partir de package.json y del perfil — no se escribe a mano, por lo que no hay forma de que diverja del servidor; esto
se verifica con una prueba.
⚠️ En el paquete no se puede habilitar la grabación. El costo de una llamada errónea es un contador o una meta eliminados sin posibilidad de recuperar el historial, y no hay nada que alternar en la ventana de instalación. ¿Necesitas grabación? Instala el paquete con npm y actívala conscientemente mediante una variable de entorno.
Sin MCP: skill y línea de comandos
MCP no es adecuado para todos ni siempre: el cliente puede no soportar MCP en absoluto, y las descripciones de las herramientas ocupan contexto constantemente — permanecen en él mientras el servidor está conectado, las llames o no.
Para este caso, el mismo servidor puede ejecutarse con el comando:
npx -y yandex-metrika-mcp-server catalog --search goal
npx -y yandex-metrika-mcp-server describe metrika_stat_data
npx -y yandex-metrika-mcp-server call metrika_stat_data \
--ids <ID счётчика> --dimensions ym:s:trafficSource \
--metrics ym:s:visits,ym:s:users --date1 7daysAgo --date2 today
Sobre esto se encuentra un skill — una carpeta con instrucciones para el agente que se instala con una sola línea:
npx skills add artgas1/yandex-metrika-mcp # в текущий проект
npx skills add artgas1/yandex-metrika-mcp -g # глобально, во все проекты
El skill no agrega herramientas al cliente ni mantiene nada en el contexto: se lee solo cuando se menciona Metrika. Dentro está el mismo comando, la referencia de los 108 métodos y el diccionario de dimensiones.
Dónde funciona. El instalador coloca una instancia en .agents/skills/yandex-metrika/
y crea un enlace simbólico en las carpetas de agentes específicos. Verificado ejecutándolo en dos:
| agente | detección | cómo se verificó |
|---|---|---|
| Claude Code | .claude/skills/ → enlace simbólico | /yandex-metrika responde desde el contenido del skill |
| Codex | .agents/skills/ directamente | nombra la ruta a SKILL.md; no se necesitan ni líneas en AGENTS.md ni configuración en config.toml para esto |
El instalador declara unos veinte agentes más a través del mismo catálogo universal (Amp, Cline, Antigravity, Augment y otros) — allí no lo hemos verificado.
Por qué esto no es una segunda implementación. La CLI no hace ninguna solicitud propia: analiza los
argumentos y llama a executeMethod — la misma función que usan las herramientas MCP. De ahí las mismas
garantías: filtro de robots en los informes, límite de respuesta con aviso de truncamiento, limpieza de secretos
de la URL mostrada, reintento según el estado. No hay forma de que diverjan, porque no hay nada que diverja.
La referencia de métodos dentro del skill se genera a partir de spec/metrika-api.json — la misma especificación
que se actualiza diariamente desde la documentación de Yandex. Una prueba compara el archivo confirmado con lo que
se generaría ahora, por lo que «el skill está desactualizado respecto a la API» aquí es algo visible, no imperceptible.
Dos diferencias conscientes del comando respecto a MCP:
| MCP | comando | |
|---|---|---|
METRIKA_PROFILE | activo, por defecto core | no activo — los 108 métodos están disponibles |
METRIKA_ALLOW_WRITES | necesario para operaciones que modifican datos | necesario igualmente |
El perfil existe para no pagar con contexto las descripciones de herramientas no invocadas; el comando en la terminal no tiene ese costo. La restricción de grabación es otra cosa: una meta eliminada no se puede restaurar, y una flexibilización aquí sería un agujero que elude el servidor.
Verificaciones
No es una maqueta — pruébalo tú mismo
npm run demo
Todo lo grabado proviene de la respuesta del servidor por JSON-RPC: la línea del filtro agregado — de _meta.applied_by_server, las líneas del informe — del cuerpo de la respuesta. Ni token ni red: las solicitudes se redirigen a un stub local, por lo que la ejecución se puede repetir en cualquier lugar, incluido CI. Regrabar — npm run demo:record.
npm test # 87 тестов: спека, схемы, протокол MCP, поверхность, бандл, демо
npm run protocol # только протокольные: stdio, tools/list, tools/call, отказы
npm run smoke # живые вызовы к API (нужен YANDEX_API_KEY)
Las pruebas de protocolo levantan el servidor como subproceso y se comunican con él por JSON-RPC — de la misma
manera que lo hace el cliente. No se necesita red: METRIKA_API_BASE redirige las solicitudes
al stub. Se verifica también lo que no se ve desde dentro: que en stdout no llegue
nada más que JSON-RPC, que un fallo de la API llegue como isError, no como texto de éxito, y que
la grabación esté realmente bloqueada.
Lo que NO está en las verificaciones
Evaluación de selección de herramienta. Esta es la única verificación que no se reemplaza ni con una instantánea del esquema ni con una prueba de protocolo: las descripciones pueden ser sintácticamente impecables, pero el modelo aun así puede elegir la herramienta equivocada. Las pruebas no ven esto por construcción — llaman a la herramienta por nombre, es decir, la selección ya está hecha por el modelo.
Aquí es una omisión consciente, no un punto olvidado. El perfil por defecto — diez herramientas, de las cuales seis informes de Stat se diferencian por la forma de la respuesta, no por el tema, y los modelos no tienen mucho con qué confundirlas. La evaluación se vuelve necesaria cuando la superficie por defecto se amplía o cuando entran herramientas con descripciones superpuestas — entonces hay que escribirla antes de la ampliación, no después.
Qué cambió en 2.0.0
Se eliminaron 26 herramientas envoltorio sobre los ajustes predefinidos de la API Stat (get_visits, sources_summary,
get_page_performance y otras). Cubrían una pequeña parte de la API, fijaban dimensiones y período
en el código y no permitían especificar una solicitud arbitraria. Las reemplazan metrika_stat_*, que aceptan
los parámetros de la API Stat tal cual.
Aparecieron métodos que no existían en absoluto: lista de contadores, metas, segmentos, filtros, permisos, gastos, conversiones offline y todo el Logs API. Antes había que conocer el identificador del contador de antemano — ahora se puede encontrar.
Qué cambió en 2.1.0
El servidor se llevó a un estado en el que no da miedo dejarlo a un agente.
- Anotaciones en los 108 instrumentos. Antes el cliente no distinguía
metrika_counter_listdemetrika_counter_delete. - Grabación desactivada por defecto (
METRIKA_ALLOW_WRITES). - Se encontró y corrigió un defecto en el análisis de la documentación. Las aserciones están marcadas con una línea donde el valor está después del paréntesis de cierre de la clase — el reconocedor de propiedades está anclado al final de la línea y no coincidía con esas líneas. Como resultado, a la especificación no llegaba ningún ejemplo, valor por defecto o límite, y parte de ellos caía en la descripción del campo vecino. Ahora la especificación tiene 288 ejemplos, 69 valores por defecto y 155 límites; los límites se trasladan al esquema de la herramienta, los ejemplos y valores por defecto — a las descripciones de parámetros.
- Se encontró y corrigió la pérdida de obligatoriedad. Los parámetros del tipo «uno de N tipos» (
goalen la creación y edición de metas,granten la concesión de acceso) se recopilaban comoz.unknown(), y este es opcional en zod — el campo obligatorio llegaba al cliente como opcional. Ahora es una unión de formas reales, y la obligatoriedad está en su lugar. - Las referencias a entidades se expanden un nivel: en 23 parámetros del cuerpo, en lugar de un objeto libre, se ven los campos reales.
- Flexibilizaciones en la entrada donde son inofensivas. Número como cadena, booleano como palabra, lista separada por comas en la cadena de consulta — se aceptan; en el cuerpo de la solicitud, donde importa un JSON exacto, no se aceptan.
- Límite de longitud de respuesta con truncamiento declarado: la descarga del Logs API puede tener cientos de megabytes.
- Limpieza de secretos del
request_urlmostrado. - Reintento en 429 respetando
Retry-After. - SDK actualizado a 1.30 — en 1.17 había tres vulnerabilidades publicadas, dos altas;
npm audit --audit-level=highahora es parte de CI. - Se corrigió el trabajo de deriva en CI. Ejecutaba las pruebas a través de
| teesinpipefail, por lo que el código de retorno se tomaba deteey el trabajo permanecía verde ante cualquier fallo de prueba.