Полное покрытие API Яндекс Метрики: Stat, Management и Logs — 108 методов, 108 инструментов
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
и в свою страницу документации.
Сервер переписан из-за двух наблюдавшихся отказов: он отдавал не то, что просили, и молча подмешивал фильтр. Отсюда четыре правила, каждое закрыто тестом.
{"_meta": {...}, "data": {...}}, где _meta.applied_by_server перечисляет добавленное,
а _meta.notes — принятые за вызывающего решения.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 Яндекса, тот же, что используется для Директа и Вебмастера.
{
"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-токен. Без него сервер не стартует. |
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. |
Инструмент 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 — тоже, потому что заменяет сущность целиком.openWorldHint: true, а в _meta.notes отчётов и выгрузок едет напоминание, что это данные,
а не инструкции.Сервер не собирает, не хранит и никуда не передаёт данные о вас. Ни телеметрии, ни аналитики, ни обращений к серверам автора — их не существует: под этот пакет не поднято никакой инфраструктуры.
Единственный сетевой адресат — https://api-metrika.yandex.net. Токен читается из
YANDEX_API_KEY в память процесса и никуда не пишется: ни в файл, ни в stdout, ни в тело
ответа. Данные отчётов не кэшируются на диск и не переживают процесс.
Данные, которые вы запрашиваете, обрабатывает Яндекс как оператор Метрики — на это распространяется его политика, а не эта.
Полный текст: PRIVACY.md.
Для Claude Desktop и других клиентов, понимающих MCP-бандлы, есть .mcpb-файл — он лежит в
релизах. Открываете файл, вводите
токен в окне установки — всё.
Бандл собирается из того же кода тем же тегом (npm run mcpb), а его манифест генерируется
из package.json и профиля — не пишется руками, поэтому разойтись с сервером ему негде; это
проверяется тестом.
⚠️ В бандле нельзя включить запись. Цена ошибочного вызова — удалённый счётчик или цель без возможности восстановить историю, и щёлкать таким переключателем в окне установки нечего. Нужна запись — ставьте пакет с npm и включайте её осознанно, переменной окружения.
MCP подходит не всем и не всегда: клиент может не уметь MCP вовсе, а описания инструментов занимают контекст постоянно — они лежат в нём, пока сервер подключён, вызываешь ты их или нет.
Для этого случая тот же сервер умеет запускаться командой:
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
Поверх этого лежит скилл — папка с инструкцией для агента, которая ставится одной строкой:
npx skills add artgas1/yandex-metrika-mcp # в текущий проект
npx skills add artgas1/yandex-metrika-mcp -g # глобально, во все проекты
Скилл не добавляет клиенту инструментов и ничего не держит в контексте: он читается только когда речь зашла о Метрике. Внутри — та же команда, справочник всех 108 методов и словарь измерений.
Где он работает. Установщик кладёт один экземпляр в .agents/skills/yandex-metrika/
и симлинкует его в папки конкретных агентов. Проверено запуском на двух:
| агент | обнаружение | чем проверено |
|---|---|---|
| Claude Code | .claude/skills/ → симлинк | /yandex-metrika отвечает из содержимого скилла |
| Codex | .agents/skills/ напрямую | называет путь к SKILL.md; ни строки в AGENTS.md, ни настройки в config.toml для этого не нужно |
Установщик заявляет ещё около двадцати агентов через тот же универсальный каталог (Amp, Cline, Antigravity, Augment и другие) — там мы не проверяли.
Почему это не вторая реализация. CLI не делает ни одного собственного запроса: он разбирает
аргументы и зовёт executeMethod — ту же функцию, что и MCP-инструменты. Отсюда одинаковые
гарантии: фильтр роботов в отчётах, потолок ответа с распиской об урезании, вычистка секретов
из показываемого URL, повтор по статусу. Разойтись им негде, потому что расходиться нечему.
Справочник методов внутри скилла генерируется из spec/metrika-api.json — той самой спеки,
которая обновляется из документации Яндекса ежедневно. Тест сверяет закоммиченный файл с тем,
что сгенерировалось бы сейчас, поэтому «скилл отстал от API» здесь красное, а не незаметное.
Два сознательных отличия команды от MCP:
| MCP | команда | |
|---|---|---|
METRIKA_PROFILE | действует, по умолчанию core | не действует — доступны все 108 методов |
METRIKA_ALLOW_WRITES | нужен для меняющих данные | нужен так же |
Профиль существует, чтобы не платить контекстом за описания невызванных инструментов; у команды в терминале такой цены нет. Гейт записи — про другое: удалённую цель нечем восстановить, и послабление здесь было бы дырой в обход сервера.
npm run demo
Всё на записи приходит из ответа сервера по JSON-RPC: строка добавленного фильтра — из _meta.applied_by_server, строки отчёта — из тела ответа. Ни токена, ни сети: запросы уводятся на локальную заглушку, поэтому прогон повторяется где угодно, включая CI. Переснять запись — npm run demo:record.
npm test # 87 тестов: спека, схемы, протокол MCP, поверхность, бандл, демо
npm run protocol # только протокольные: stdio, tools/list, tools/call, отказы
npm run smoke # живые вызовы к API (нужен YANDEX_API_KEY)
Протокольные тесты поднимают сервер как подпроцесс и говорят с ним по JSON-RPC — тем же
способом, каким это делает клиент. Сеть при этом не нужна: METRIKA_API_BASE уводит запросы
на заглушку. Проверяется в том числе то, чего не видно изнутри: что в stdout не попадает
ничего, кроме JSON-RPC, что отказ API приезжает как isError, а не как успешный текст, и что
запись действительно заблокирована.
Евала выбора инструмента. Это единственная проверка, которую не заменяют ни снапшот схемы, ни протокольный тест: описания могут быть синтаксически безупречны, а модель всё равно возьмёт не тот инструмент. Тесты этого не видят по построению — они зовут инструмент по имени, то есть выбор уже сделан за модель.
Здесь это осознанный пропуск, а не забытый пункт. Профиль по умолчанию — десять инструментов, из них шесть отчётов Stat различаются формой ответа, а не темой, и путать их модели особо не с чем. Евал становится нужен, когда поверхность по умолчанию расширяется или когда в неё попадают инструменты с пересекающимися описаниями, — тогда его надо писать до расширения, а не после.
Удалены 26 инструментов-обёрток над пресетами Stat API (get_visits, sources_summary,
get_page_performance и прочие). Они покрывали малую часть API, зашивали измерения и период
в код и не давали задать произвольный запрос. Их заменяют metrika_stat_*, принимающие
параметры Stat API как есть.
Появились методы, которых не было вовсе: список счётчиков, цели, сегменты, фильтры, разрешения, расходы, офлайн-конверсии и весь Logs API. Раньше идентификатор счётчика приходилось знать заранее — теперь его можно найти.
Сервер довели до состояния, в котором его не страшно оставить агенту.
metrika_counter_list
от metrika_counter_delete.METRIKA_ALLOW_WRITES).goal
у создания и правки цели, grant у выдачи доступа) собирались как z.unknown(), а он
в zod необязателен, — обязательное поле уезжало клиенту как опциональное. Теперь это
объединение реальных форм, и обязательность на месте.request_url.Retry-After.npm audit --audit-level=high теперь часть CI.| tee без pipefail, поэтому
код возврата брался у tee и джоба оставалась зелёной при любом падении теста.Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y yandex-metrika-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-artgas1-yandex-metrika-mcp-server": {
"command": "npx",
"args": [
"-y",
"yandex-metrika-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceyandex-metrika-mcp-servernpmio.github.artgas1/yandex-metrika-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.