Яндекс Директ API v5

io.github.artgas1由 GitHub 账号 artgas1 发布v1.1.1更新于 Oct 24, 2026

MCP server for Yandex Direct API v5: 113 methods from the machine-readable schema

已验证STDIO仅桌面数据与分析商业与电商

概览

AI 生成的概览

面向 Yandex Direct API v5 的 MCP 服务器与命令行工具,暴露 113 个由模式生成的接口,让助手读取广告账户数据,并在开启后修改。

可以做什么
  • 读取广告系列、广告组、广告、关键词与定向设置
  • 读取出价、出价修正与投放策略
  • 生成报表并获取字典与参考数据
  • 列出客户与代理商账户,并提供目录、字段与模式查询工具
  • 结合广告系列列表与报表汇总完整账户清单
  • 开启写入后可新增、修改、暂停、归档或删除对象
适用场景
适合需要查看或管理 Yandex Direct 广告账户的场景:广告系列结构、定向、出价、报表与代理商客户。也适合希望由服务器处理接口隐性陷阱(微单位金额、超长 ID、HTTP 200 却含错误、报表延迟)而非直接面对原始响应的用户。
运行要求
通过 npx 在本地运行(需要 Node.js)。需要具备 direct:api 权限范围的 Yandex OAuth 令牌,放在 YANDEX_DIRECT_TOKEN 中,并需已获批的 Direct API 应用。可选设置:YANDEX_DIRECT_LOGIN(代理商账户)、DIRECT_PROFILE、DIRECT_TOOLS、DIRECT_API_VERSION、DIRECT_SANDBOX、DIRECT_ALLOW_WRITES、DIRECT_MAX_OUTPUT_CHARS。需要访问 Yandex Direct API 的网络。
安装前请注意
YANDEX_DIRECT_TOKEN 中的令牌可访问真实广告账户及其预算。写入默认关闭;设置 DIRECT_ALLOW_WRITES=1 会暴露 80 个修改方法和 16 个删除方法,且没有确认步骤,删除不可撤销。YANDEX_DIRECT_LOGIN 可能在同一令牌下静默切换到另一个账户。测试时请用 DIRECT_SANDBOX=1 并配独立令牌。接口调用消耗点数并涉及真实资金。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Яндекс Директ API v5,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

yandex-direct-mcp

MCP-сервер и командная строка к API Яндекс Директа v5. Покрыты все 113 методов, порождённые из машиночитаемой схемы; по умолчанию объявляются девять — те, которыми читают. Остальное включается одной переменной, изменение выключено.

mcp-name: io.github.artgas1/yandex-direct-api-mcp

[npm] [CI] [License: MIT]

English

Работает и как MCP-сервер для Claude Code, Cursor, Codex и других клиентов, и как обычная команда — если MCP не нужен.

Что это даёт — за пять секунд

[Запись прогона в терминале: вызов direct_campaigns_get и две колонки — слева тело ответа, разобранное обычным JSON.parse, справа то же самое после сервера. Бюджет 1000000000 против 1000, идентификатор объявления, испорченный разбором, против точного, обёртка Items против обычного списка и отказ с кодом HTTP 202, распознанный как отказ.]

Обе колонки настоящие: левая — тело ответа, разобранное обычным JSON.parse, то есть так, как его получил бы любой клиент; правая — то, что вернул сервер по JSON-RPC. Строка с идентификатором самодоказательна: слева он испорчен не потому, что так нарисовано, а потому что его действительно портит разбор. Ни токена, ни сети: запросы уводятся на локальную заглушку, поэтому прогон повторяется где угодно, включая CI. Повторить у себя — npm run demo, переснять — npm run demo:record (нужен vhs).

bash
npx -y yandex-direct-api-mcp

Покрытие

что покрытослужбметодовиз них в coreпримеры инструментов
Кампании и объявления9373direct_adgroups_get, direct_ads_get
Таргетинг9451direct_keywords_get
Ставки и стратегии4152direct_bidmodifiers_get, direct_keywordbids_get
Отчёты и справочники692direct_dictionaries_get, direct_reports_get
Клиенты и агентства271direct_clients_get
всего301139плюс четыре служебных: 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 campaignsyandex-direct-mcp describe campaigns.getyandex-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 принимает идентификатор строкой, поэтому точность держится на всём пути — и на чтении, и на записи.

Успех определяется телом, а не кодом ответа

что спросиликодчто в теле
неверный FieldNames200error_code: 8000
неизвестный метод202error_code: 55
ошибка в отчёте400error_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

Это разные представления с разными наборами глубоких полей, и несовпадение отнимает их без всякого признака:

путьнабор полейглубокие поля
v5TextCampaignFieldNamesприходят
v5UnifiedCampaignFieldNamesпусто, ошибки нет
v501TextCampaignFieldNamesпусто, ошибки нет
v501UnifiedCampaignFieldNamesприходят

Стратегия, настройки, счётчики просто отсутствуют — читается как «у кампании ничего не настроено». Умолчание 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, а то, чем пользуются.

[Список всех 113 методов API Директа: девять оставлены и выделены, 104 вычеркнуты. Манифест по умолчанию — 27 028 байт против 143 706 у полного каталога.]

Замер tools/list на собранном сервере (npm run surface):

профильинструментовбайт≈ токенов
core (умолчание)1327 02812 455
read3761 15828 183
all + DIRECT_ALLOW_WRITES=1117143 70666 224

Умолчание в 5,3 раза легче полного набора. Главный рычаг — вложенные типы не разворачиваются в схему: транзитивно campaigns.add это 1083 поля и 54 КБ на один инструмент. Вместо разворачивания состав типа назван словами в описании, а точная схема выдаётся инструментом direct_schema по запросу.

Чего не видно — расскажет сам сервер: инструмент direct_catalog перечисляет все 113 методов и говорит, какие скрыты и как их включить.

Изменение выключено по умолчанию

Из 113 методов 80 меняют данные, 16 удаляют. У Директа нет подтверждающего шага: suspend останавливает показы в момент вызова, archive убирает кампанию из работы, delete необратим, а на другом конце — деньги.

Меняющие инструменты не объявляются вовсе, пока не задан DIRECT_ALLOW_WRITES=1. Объявлять их и отказывать на вызове — худший вариант: контекст за них платится полностью, а позвать всё равно нельзя.

Неизвестное имя профиля — отказ на старте, а не откат к полной поверхности: неверная настройка ограничения не должна превращаться в отсутствие ограничения.

Есть песочница: DIRECT_SANDBOX=1 (нужны отдельная регистрация и отдельный токен). Факт включения печатается при старте и в каждом ответе.

Настройки

переменнаяпо умолчаниючто делает
YANDEX_DIRECT_TOKEN—OAuth-токен, scope direct:api. Обязательна
YANDEX_DIRECT_LOGIN—логин кабинета (не почта). Переключает кабинет по-настоящему: под одним токеном отдаёт другой аккаунт со своей квотой. Фактический кабинет сервер называет в каждом ответе
DIRECT_PROFILEcorecore, read, all
DIRECT_TOOLS—явный список служб или инструментов, побеждает профиль
DIRECT_ALLOW_WRITESвыкл.объявить меняющие данные инструменты
DIRECT_API_VERSIONv501v501 или v5 — меняет представление кампаний
DIRECT_SANDBOXвыкл.песочница вместо боевого кабинета
DIRECT_MAX_OUTPUT_CHARS60000потолок ответа; усечение называется вслух

Откуда берутся инструменты

Ни один метод не описан руками.

источникчто даётпочему нужен
WSDL 29 служб + 3 общие XSDсостав, типы, обязательность, массивность, перечисленияединственный полный: в индексе документации нет vcards, smartadtargets, dynamictextadtargets, dynamicfeedadtargets
страницы документациичеловекочитаемые описанияв WSDL нет ни одного xs:documentation
описано явнослужба reportsWSDL для неё Директ не отдаёт (404)

Итог: 30 служб, 113 методов, 609 типов, 240 перечислений.

bash
npm run spec:fetch    # скачать WSDL и документацию в .cache/npm run spec:build    # собрать spec/direct-api.json

⚠️ Перечисления из схемы отстают от живого API и поэтому не становятся жёстким фильтром, а идут подсказкой в описание. Сверка с живым API: campaigns принимает CreateTime, keywords — AutotargetingBrief, AutotargetingBriefSuggests, AutotargetingMode, которых в схеме нет. Фильтр по отстающему списку запретил бы то, что API умеет, и отказ выглядел бы как отсутствие возможности. Право решать остаётся за API.

Проверки

bash
npm test         # 70 тестов, включая отрицательные контролиnpm run surface  # замер поверхности по профилямnpm run coverage # таблица покрытия для READMEnpm run graphic  # пересобрать графику поверхности (SVG и GIF)npm run smoke    # прогон собранного сервера против живого API (нужен токен)

Тесты содержат отрицательные контроли на каждый инвариант — то есть могут упасть на том дефекте, ради которого написаны: на порче идентификатора, на ошибке с кодом 202, на пустой схеме get, на пропаже службы и на чтении предупреждений как отказов.

Скилл — работа без MCP

Для агентов, которым MCP не нужен или недоступен:

bash
npx skills add artgas1/yandex-direct-mcp

Ставит один канонический экземпляр в .agents/skills/yandex-direct/ и связывает его с каталогами агентов. Скилл — тонкая надстройка над той же командой: своей логики у него нет, поэтому расходиться с сервером ему нечем.

Если выбираете между серверами

Серверов к Директу написано много. Полезные вопросы к любому из них — те же, что перечислены выше: приводит ли суммы из микро-единиц; переживают ли девятнадцатизначные идентификаторы разбор; считается ли HTTP 200 с телом error успехом; ждёт ли он отчёт после 201; отличает ли Warnings от Errors; что делает при опечатке в имени профиля. Ответы стоят одного вызова.

Лицензия

MIT.

来源:README.md,提交 086ec45

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v1.1.1最新Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分