MCP-сервер и командная строка к API Яндекс Директа v5: 113 методов из машиночитаемой схемы, узкая поверхность, изменение выключено по умолчанию
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add yandex-direct-mcp -- npx -y yandex-direct-api-mcp{
"mcpServers": {
"yandex-direct-mcp": {
"command": "npx",
"args": ["-y", "yandex-direct-api-mcp"]
}
}
}MCP Servers overview
# yandex-direct-mcp
MCP-сервер и командная строка к API Яндекс Директа v5. Покрыты все **113 методов**,
порождённые из машиночитаемой схемы; по умолчанию объявляются девять — те, которыми
читают. Остальное включается одной переменной, изменение выключено.
mcp-name: io.github.artgas1/yandex-direct-api-mcp
[](https://www.npmjs.com/package/yandex-direct-api-mcp)
[](https://github.com/artgas1/yandex-direct-mcp/actions/workflows/test.yml)
[](./LICENSE)
*[English](./README.en.md)*
Работает и как MCP-сервер для Claude Code, Cursor, Codex и других клиентов, и как
обычная команда — если MCP не нужен.
## Что это даёт — за пять секунд
<img src="https://raw.githubusercontent.com/artgas1/yandex-direct-mcp/main/assets/demo.gif" alt="Запись прогона в терминале: вызов direct_campaigns_get и две колонки — слева тело ответа, разобранное обычным JSON.parse, справа то же самое после сервера. Бюджет 1000000000 против 1000, идентификатор объявления, испорченный разбором, против точного, обёртка Items против обычного списка и отказ с кодом HTTP 202, распознанный как отказ." width="100%">
<sup>Обе колонки настоящие: левая — тело ответа, разобранное обычным <code>JSON.parse</code>,
то есть так, как его получил бы любой клиент; правая — то, что вернул сервер по JSON-RPC.
Строка с идентификатором самодоказательна: слева он испорчен не потому, что так нарисовано,
а потому что его действительно портит разбор. Ни токена, ни сети: запросы уводятся на локальную
заглушку, поэтому прогон повторяется где угодно, включая CI. Повторить у себя — <code>npm run demo</code>, переснять — <code>npm run demo:record</code>
(нужен <a href="https://github.com/charmbracelet/vhs">vhs</a>).</sup>
```bash
npx -y yandex-direct-api-mcp
```
## Покрытие
| что покрыто | служб | методов | из них в `core` | примеры инструментов |
| --- | ---: | ---: | ---: | --- |
| Кампании и объявления | 9 | 37 | 3 | `direct_adgroups_get`, `direct_ads_get` |
| Таргетинг | 9 | 45 | 1 | `direct_keywords_get` |
| Ставки и стратегии | 4 | 15 | 2 | `direct_bidmodifiers_get`, `direct_keywordbids_get` |
| Отчёты и справочники | 6 | 9 | 2 | `direct_dictionaries_get`, `direct_reports_get` |
| Клиенты и агентства | 2 | 7 | 1 | `direct_clients_get` |
| **всего** | **30** | **113** | **9** | плюс четыре служебных: `direct_catalog`, `direct_fields`, `direct_schema`, `direct_inventory` |
Таблица считается из спеки (`npm run coverage`), а не пишется руками: числа в
прозе расходятся со схемой молча, и неправда выглядит ровно как правда.
## Быстрый старт
Нужен OAuth-токен Яндекса со scope `direct:api` — https://oauth.yandex.ru/
(приложению требуется одобренная заявка на доступ к API Директа).
**MCP:**
```json
{
"mcpServers": {
"yandex-direct": {
"command": "npx",
"args": ["-y", "yandex-direct-api-mcp"],
"env": { "YANDEX_DIRECT_TOKEN": "ваш-токен" }
}
}
}
```
**Командная строка:**
```bash
export YANDEX_DIRECT_TOKEN="ваш-токен"
yandex-direct-mcp catalog --service campaigns
yandex-direct-mcp describe campaigns.get
yandex-direct-mcp call campaigns.get --FieldNames Id --FieldNames Name
```
## Что этот сервер делает за вас
Не удобства. Каждый пункт — место, где прямой запрос к Директу ошибается
**молча**: ответ выглядит нормальным, ошибки нет, а число или вывод неверны.
Всё перечисленное снято прогоном живого API, а не прочитано в документации.
### Суммы приходят умноженными на миллион — всегда
```
DailyBudget.Amount = 1000000000 ← это 1000 единиц валюты счёта
Cost = 1234500000 ← это 1234,50 единицы валюты счёта
```
Ошибка ровно в миллион раз, и она не выглядит ошибкой: число правдоподобное,
его можно сложить, поделить и построить по нему график. Заголовок
`returnMoneyInMicros`, который выключает микро-единицы в отчётах, **на обычные
службы не действует** — проверено на `campaigns`, значение не изменилось.
Сервер приводит суммы к валюте счёта и перечисляет в ответе, какие именно поля
пересчитал:
```json
"_мета": { "суммы_переведены_из_микроединиц": ["Amount", "Refund", "Spend"] }
```
### Идентификаторы объявлений не помещаются в число JavaScript
Типичный `Id` объявления: `1234567890123456789` — девятнадцать цифр.
`JSON.parse` держит пятнадцать и превращает его в `1234567890123456800`.
И это не единичный курьёз: девятнадцатизначные идентификаторы встретились в
каждом проверенном кабинете, а не в одном экземпляре. Схема Яндекса объявляет
358 полей типом `xsd:long` — то есть диапазон до 19 цифр нормален по контракту.
Опасен не сдвиг, а то, как он выходит наружу: **испорченный идентификатор Директ
принимает** и отвечает `HTTP 200` с телом `{"result":{}}`. То есть отказа нет —
есть сообщение «такого объявления нет». Пустота как доказательство отсутствия.
Сервер разбирает тело так, что длинные целые остаются точными. Отдельно
проверено, что API принимает идентификатор строкой, поэтому точность держится
на всём пути — и на чтении, и на записи.
### Успех определяется телом, а не кодом ответа
| что спросили | код | что в теле |
|---|---|---|
| неверный `FieldNames` | **200** | `error_code: 8000` |
| неизвестный метод | **202** | `error_code: 55` |
| ошибка в отчёте | **400** | `error_code: "8000"` — строкой, не числом |
| отчёт поставлен в очередь | **201** | пусто, `retryIn: 1` |
| отчёт считается | **202** | пусто, `retryIn: 10` |
Один и тот же код `202` означает отказ у `campaigns` и «ещё считается» у
`reports`. Проверка `res.ok` пропускает первые три строки таблицы: отказ уходит
модели как удачный ответ.
### Отчёт приходит не сразу
`201` → `202` → `200`. Замер: до готовности потребовалось три запроса. Повтор идёт с тем же
`ReportName` — имя и есть ключ поставленной задачи. Сервер ждёт сам.
### Версия пути меняет данные
Один и тот же запрос:
```
/json/v5/campaigns → N кампаний, у всех Type = TEXT_CAMPAIGN
/json/v501/campaigns → те же N, у всех Type = UNIFIED_CAMPAIGN
```
Это разные представления с разными наборами глубоких полей, и несовпадение
отнимает их без всякого признака:
| путь | набор полей | глубокие поля |
|---|---|---|
| `v5` | `TextCampaignFieldNames` | приходят |
| `v5` | `UnifiedCampaignFieldNames` | **пусто, ошибки нет** |
| `v501` | `TextCampaignFieldNames` | **пусто, ошибки нет** |
| `v501` | `UnifiedCampaignFieldNames` | приходят |
Стратегия, настройки, счётчики просто отсутствуют — читается как «у кампании
ничего не настроено». Умолчание `v501` (документация называет адресом только
его), переключается `DIRECT_API_VERSION=v5`, выбранная версия печатается в
каждом ответе, а несовпадающий набор полей вызывает предупреждение.
### Список кампаний неполон
Кампании Мастера кампаний не отдаются методом `campaigns.get` вовсе — ни
списком, ни по явному `Ids`; ответ пустой и без ошибки. Ни `v5`, ни `v501` этого
не меняют.
Поэтому состав кабинета собирает отдельный инструмент **`direct_inventory`**:
он склеивает список кампаний и отчёт и помечает каждую строку источником.
Предупреждения в описании тут мало — оно требует, чтобы читатель помнил про него
в момент вывода, а вывод делается по данным, которые выглядят нормально.
Прогон на живом кабинете: объединение оказалось на кампанию длиннее списка, и
эта строка была видна только отчёту. Невидимая для `campaigns.get` кампания при
этом откручивается и может нести **основную долю показов** — по списку кампаний
этого не заметить.
```
ВНИМАНИЕ: 1 кампаний откручивались, но методом campaigns.get НЕ отдаются
(10000017). Управлять ими через API нельзя — только в интерфейсе.
```
### Предупреждение — это применено, а не отклонено
В ответе на `add`/`update` каждому входному элементу отвечает выходной.
Различать надо по `Errors`; `Warnings` означает «применено с замечанием».
Счёт по наличию любого содержимого даёт «отклонено всё» там, где применилось
всё. Сервер приводит итог отдельной строкой:
```
UpdateResults: применено 2, отклонено 1, с предупреждениями 1
```
### Форму списка задаёт тип, а не направление
```
RegionIds (maxOccurs=unbounded) → [225, 977]
RestrictedRegionIds (тип ArrayOfLong) → {"Items": [225]}
```
Обе формы одинаковы и на чтении, и на записи. Сервер снимает и ставит обёртку
по графу типов, а не по виду значения, поэтому круг «прочитал → поправил →
записал» не рвётся. Вам обе формы видны как обычные массивы.
### Кабинет называется в каждом ответе
`Client-Login` переключает кабинет по-настоящему, и ошибиться в нём можно молча.
Несуществующий логин отбивается кодом 8800 — это видно сразу. А существующий,
но не тот, отдаёт полные и правильные данные, просто из другого кабинета:
по виду ответа это неотличимо.
Поэтому сервер спрашивает у API, кто отвечает, и пишет ответ в каждый конверт:
```json
"_мета": { "кабинет": "example-login (ClientId 1234567)", "версия_api": "v501" }
```
Спрашивается один раз за запуск и кешируется — `clients.get` стоит 10 баллов.
## Поверхность
Описания всех объявленных инструментов лежат в контексте модели **на каждом
ходу**, вызываете вы их или нет. Поэтому по умолчанию объявляется не всё, что
умеет API, а то, чем пользуются.
<img src="https://raw.githubusercontent.com/artgas1/yandex-direct-mcp/main/assets/surface.gif" alt="Список всех 113 методов API Директа: девять оставлены и выделены, 104 вычеркнуты. Манифест по умолчанию — 27 028 байт против 143 706 у полного каталога." width="100%">
Замер `tools/list` на собранном сервере (`npm run surface`):
| профиль | инструментов | байт | ≈ токенов |
|---|---|---|---|
| **`core`** (умолчание) | 13 | 27 028 | 12 455 |
| `read` | 37 | 61 158 | 28 183 |
| `all` + `DIRECT_ALLOW_WRITES=1` | 117 | 143 706 | 66 224 |
Умолчание в 5,3 раза легче полного набора. Главный рычаг — вложенные типы не
разворачиваются в схему: транзитивно `campaigns.add` это 1083 поля и 54 КБ на
один инструмент. Вместо разворачивания состав типа назван словаWhat people ask about yandex-direct-mcp
What is artgas1/yandex-direct-mcp?
+
artgas1/yandex-direct-mcp is mcp servers for the Claude AI ecosystem. MCP-сервер и командная строка к API Яндекс Директа v5: 113 методов из машиночитаемой схемы, узкая поверхность, изменение выключено по умолчанию It has 0 GitHub stars and its last recorded update is dated 2026-09-09.
How do I install yandex-direct-mcp?
+
You can install yandex-direct-mcp by cloning the repository (https://github.com/artgas1/yandex-direct-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is artgas1/yandex-direct-mcp safe to use?
+
Our security agent has analyzed artgas1/yandex-direct-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains artgas1/yandex-direct-mcp?
+
artgas1/yandex-direct-mcp is maintained by artgas1. The last recorded GitHub activity is dated 2026-09-09, with 0 open issues.
Are there alternatives to yandex-direct-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy yandex-direct-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/artgas1-yandex-direct-mcp)<a href="https://claudewave.com/repo/artgas1-yandex-direct-mcp"><img src="https://claudewave.com/api/badge/artgas1-yandex-direct-mcp" alt="Featured on ClaudeWave: artgas1/yandex-direct-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!