yandex-direct-mcp-plus 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +186 -0
  3. package/dist/app/index.d.ts +2 -0
  4. package/dist/app/index.js +15 -0
  5. package/dist/app/registry.d.ts +2 -0
  6. package/dist/app/registry.js +83 -0
  7. package/dist/app/server.d.ts +4 -0
  8. package/dist/app/server.js +30 -0
  9. package/dist/shared/api/client.d.ts +1 -0
  10. package/dist/shared/api/client.js +16 -0
  11. package/dist/shared/api/errors.d.ts +2 -0
  12. package/dist/shared/api/errors.js +21 -0
  13. package/dist/shared/api/fetch.d.ts +5 -0
  14. package/dist/shared/api/fetch.js +62 -0
  15. package/dist/shared/api/json.d.ts +2 -0
  16. package/dist/shared/api/json.js +13 -0
  17. package/dist/shared/api/parse.d.ts +2 -0
  18. package/dist/shared/api/parse.js +10 -0
  19. package/dist/shared/api/reports.d.ts +6 -0
  20. package/dist/shared/api/reports.js +45 -0
  21. package/dist/shared/api/v4.d.ts +1 -0
  22. package/dist/shared/api/v4.js +18 -0
  23. package/dist/shared/config/endpoints.d.ts +3 -0
  24. package/dist/shared/config/endpoints.js +8 -0
  25. package/dist/shared/config/enums.d.ts +30 -0
  26. package/dist/shared/config/enums.js +137 -0
  27. package/dist/shared/config/env.d.ts +2 -0
  28. package/dist/shared/config/env.js +14 -0
  29. package/dist/shared/config/limits.d.ts +58 -0
  30. package/dist/shared/config/limits.js +54 -0
  31. package/dist/shared/lib/campaign-type.d.ts +12 -0
  32. package/dist/shared/lib/campaign-type.js +20 -0
  33. package/dist/shared/lib/date.d.ts +3 -0
  34. package/dist/shared/lib/date.js +17 -0
  35. package/dist/shared/lib/format.d.ts +3 -0
  36. package/dist/shared/lib/format.js +51 -0
  37. package/dist/shared/lib/id.d.ts +4 -0
  38. package/dist/shared/lib/id.js +21 -0
  39. package/dist/shared/lib/money.d.ts +6 -0
  40. package/dist/shared/lib/money.js +21 -0
  41. package/dist/shared/lib/pagination.d.ts +9 -0
  42. package/dist/shared/lib/pagination.js +26 -0
  43. package/dist/shared/lib/report.d.ts +1 -0
  44. package/dist/shared/lib/report.js +5 -0
  45. package/dist/shared/lib/tool.d.ts +24 -0
  46. package/dist/shared/lib/tool.js +20 -0
  47. package/dist/tools/account/handler.d.ts +3 -0
  48. package/dist/tools/account/handler.js +12 -0
  49. package/dist/tools/account/schema.d.ts +4 -0
  50. package/dist/tools/account/schema.js +7 -0
  51. package/dist/tools/account/tool.d.ts +1 -0
  52. package/dist/tools/account/tool.js +11 -0
  53. package/dist/tools/ad-extensions/handler.d.ts +5 -0
  54. package/dist/tools/ad-extensions/handler.js +35 -0
  55. package/dist/tools/ad-extensions/schema.d.ts +14 -0
  56. package/dist/tools/ad-extensions/schema.js +37 -0
  57. package/dist/tools/ad-extensions/tool.d.ts +3 -0
  58. package/dist/tools/ad-extensions/tool.js +27 -0
  59. package/dist/tools/ad-groups/handler.d.ts +5 -0
  60. package/dist/tools/ad-groups/handler.js +33 -0
  61. package/dist/tools/ad-groups/schema.d.ts +14 -0
  62. package/dist/tools/ad-groups/schema.js +27 -0
  63. package/dist/tools/ad-groups/tool.d.ts +3 -0
  64. package/dist/tools/ad-groups/tool.js +27 -0
  65. package/dist/tools/ad-images/handler.d.ts +5 -0
  66. package/dist/tools/ad-images/handler.js +47 -0
  67. package/dist/tools/ad-images/schema.d.ts +13 -0
  68. package/dist/tools/ad-images/schema.js +37 -0
  69. package/dist/tools/ad-images/tool.d.ts +1 -0
  70. package/dist/tools/ad-images/tool.js +11 -0
  71. package/dist/tools/ads/handler.d.ts +7 -0
  72. package/dist/tools/ads/handler.js +54 -0
  73. package/dist/tools/ads/schema.d.ts +27 -0
  74. package/dist/tools/ads/schema.js +68 -0
  75. package/dist/tools/ads/tool.d.ts +5 -0
  76. package/dist/tools/ads/tool.js +43 -0
  77. package/dist/tools/audience-targets/handler.d.ts +6 -0
  78. package/dist/tools/audience-targets/handler.js +96 -0
  79. package/dist/tools/audience-targets/schema.d.ts +29 -0
  80. package/dist/tools/audience-targets/schema.js +84 -0
  81. package/dist/tools/audience-targets/tool.d.ts +2 -0
  82. package/dist/tools/audience-targets/tool.js +19 -0
  83. package/dist/tools/bid-adjustments/handler.d.ts +4 -0
  84. package/dist/tools/bid-adjustments/handler.js +43 -0
  85. package/dist/tools/bid-adjustments/schema.d.ts +16 -0
  86. package/dist/tools/bid-adjustments/schema.js +50 -0
  87. package/dist/tools/bid-adjustments/tool.d.ts +2 -0
  88. package/dist/tools/bid-adjustments/tool.js +19 -0
  89. package/dist/tools/businesses/handler.d.ts +3 -0
  90. package/dist/tools/businesses/handler.js +26 -0
  91. package/dist/tools/businesses/schema.d.ts +6 -0
  92. package/dist/tools/businesses/schema.js +12 -0
  93. package/dist/tools/businesses/tool.d.ts +1 -0
  94. package/dist/tools/businesses/tool.js +11 -0
  95. package/dist/tools/campaigns/handler.d.ts +11 -0
  96. package/dist/tools/campaigns/handler.js +200 -0
  97. package/dist/tools/campaigns/schema.d.ts +46 -0
  98. package/dist/tools/campaigns/schema.js +109 -0
  99. package/dist/tools/campaigns/tool.d.ts +7 -0
  100. package/dist/tools/campaigns/tool.js +61 -0
  101. package/dist/tools/changes/handler.d.ts +5 -0
  102. package/dist/tools/changes/handler.js +33 -0
  103. package/dist/tools/changes/schema.d.ts +9 -0
  104. package/dist/tools/changes/schema.js +35 -0
  105. package/dist/tools/changes/tool.d.ts +1 -0
  106. package/dist/tools/changes/tool.js +11 -0
  107. package/dist/tools/dictionaries/handler.d.ts +5 -0
  108. package/dist/tools/dictionaries/handler.js +66 -0
  109. package/dist/tools/dictionaries/schema.d.ts +9 -0
  110. package/dist/tools/dictionaries/schema.js +23 -0
  111. package/dist/tools/dictionaries/tool.d.ts +2 -0
  112. package/dist/tools/dictionaries/tool.js +19 -0
  113. package/dist/tools/dynamic-targets/handler.d.ts +6 -0
  114. package/dist/tools/dynamic-targets/handler.js +96 -0
  115. package/dist/tools/dynamic-targets/schema.d.ts +33 -0
  116. package/dist/tools/dynamic-targets/schema.js +91 -0
  117. package/dist/tools/dynamic-targets/tool.d.ts +2 -0
  118. package/dist/tools/dynamic-targets/tool.js +19 -0
  119. package/dist/tools/feeds/handler.d.ts +3 -0
  120. package/dist/tools/feeds/handler.js +29 -0
  121. package/dist/tools/feeds/schema.d.ts +6 -0
  122. package/dist/tools/feeds/schema.js +12 -0
  123. package/dist/tools/feeds/tool.d.ts +1 -0
  124. package/dist/tools/feeds/tool.js +11 -0
  125. package/dist/tools/keywords/handler.d.ts +6 -0
  126. package/dist/tools/keywords/handler.js +53 -0
  127. package/dist/tools/keywords/schema.d.ts +21 -0
  128. package/dist/tools/keywords/schema.js +41 -0
  129. package/dist/tools/keywords/tool.d.ts +4 -0
  130. package/dist/tools/keywords/tool.js +35 -0
  131. package/dist/tools/negative-keywords/handler.d.ts +8 -0
  132. package/dist/tools/negative-keywords/handler.js +135 -0
  133. package/dist/tools/negative-keywords/merge.d.ts +2 -0
  134. package/dist/tools/negative-keywords/merge.js +36 -0
  135. package/dist/tools/negative-keywords/schema.d.ts +37 -0
  136. package/dist/tools/negative-keywords/schema.js +139 -0
  137. package/dist/tools/negative-keywords/shared-set-link.d.ts +3 -0
  138. package/dist/tools/negative-keywords/shared-set-link.js +21 -0
  139. package/dist/tools/negative-keywords/tool.d.ts +6 -0
  140. package/dist/tools/negative-keywords/tool.js +51 -0
  141. package/dist/tools/retargeting/handler.d.ts +4 -0
  142. package/dist/tools/retargeting/handler.js +47 -0
  143. package/dist/tools/retargeting/schema.d.ts +19 -0
  144. package/dist/tools/retargeting/schema.js +57 -0
  145. package/dist/tools/retargeting/tool.d.ts +2 -0
  146. package/dist/tools/retargeting/tool.js +19 -0
  147. package/dist/tools/search-queries/handler.d.ts +3 -0
  148. package/dist/tools/search-queries/handler.js +28 -0
  149. package/dist/tools/search-queries/schema.d.ts +7 -0
  150. package/dist/tools/search-queries/schema.js +17 -0
  151. package/dist/tools/search-queries/tool.d.ts +1 -0
  152. package/dist/tools/search-queries/tool.js +11 -0
  153. package/dist/tools/sitelinks/handler.d.ts +4 -0
  154. package/dist/tools/sitelinks/handler.js +28 -0
  155. package/dist/tools/sitelinks/schema.d.ts +13 -0
  156. package/dist/tools/sitelinks/schema.js +35 -0
  157. package/dist/tools/sitelinks/tool.d.ts +2 -0
  158. package/dist/tools/sitelinks/tool.js +19 -0
  159. package/dist/tools/statistics/handler.d.ts +3 -0
  160. package/dist/tools/statistics/handler.js +20 -0
  161. package/dist/tools/statistics/schema.d.ts +7 -0
  162. package/dist/tools/statistics/schema.js +17 -0
  163. package/dist/tools/statistics/tool.d.ts +1 -0
  164. package/dist/tools/statistics/tool.js +11 -0
  165. package/dist/tools/time-targeting/handler.d.ts +6 -0
  166. package/dist/tools/time-targeting/handler.js +124 -0
  167. package/dist/tools/time-targeting/schema.d.ts +19 -0
  168. package/dist/tools/time-targeting/schema.js +73 -0
  169. package/dist/tools/time-targeting/tool.d.ts +2 -0
  170. package/dist/tools/time-targeting/tool.js +20 -0
  171. package/dist/tools/vcards/handler.d.ts +4 -0
  172. package/dist/tools/vcards/handler.js +105 -0
  173. package/dist/tools/vcards/schema.d.ts +27 -0
  174. package/dist/tools/vcards/schema.js +43 -0
  175. package/dist/tools/vcards/tool.d.ts +2 -0
  176. package/dist/tools/vcards/tool.js +19 -0
  177. package/package.json +121 -0
@@ -0,0 +1,137 @@
1
+ // Перечисления Директа, по набору на предметную область. Схема — единственная
2
+ // документация, которую видит модель: допустимые значения обязаны быть типом.
3
+ //
4
+ // Список фиксируется здесь ТОЛЬКО когда он закрыт — подтверждён справочником API
5
+ // (сверка 03.09.2026) или ограничен нашей же реализацией. Директ пополняет
6
+ // перечисления без предупреждения, и неполный литерал отклонял бы валидный вызов,
7
+ // поэтому неподтверждённое остаётся строкой с перечислением в описании.
8
+ // CampaignsService.get, SelectionCriteria.Statuses. UNKNOWN — только в ответе.
9
+ export const CAMPAIGN_STATUSES = ["ACCEPTED", "DRAFT", "MODERATION", "REJECTED"];
10
+ // Действия над ключевыми фразами: имя действия и есть метод сервиса keywords.
11
+ export const KEYWORD_ACTIONS = ["suspend", "resume", "delete"];
12
+ // Действия над объявлениями: тоже методы сервиса ads.
13
+ export const AD_ACTIONS = ["suspend", "resume", "archive", "unarchive", "moderate", "delete"];
14
+ // Действия над кампанией: отдельные методы API, набор закрыт.
15
+ export const CAMPAIGN_ACTIONS = ["suspend", "resume", "archive", "unarchive"];
16
+ // То же действие в update_campaign исторически принимается в верхнем регистре.
17
+ // Регистр — часть внешнего контракта, менять его нельзя: он зашит в чужие сценарии.
18
+ export const CAMPAIGN_STATUS_ACTIONS = ["SUSPEND", "RESUME", "ARCHIVE", "UNARCHIVE"];
19
+ // Типы, которые умеет создавать create_campaign. Список ограничен нашей реализацией,
20
+ // а не API: хендлер собирает только TextCampaign и DynamicTextCampaign.
21
+ export const CAMPAIGN_TYPES_CREATABLE = ["TEXT_CAMPAIGN", "DYNAMIC_TEXT_CAMPAIGN"];
22
+ // Типы кампаний для фильтра list_campaigns: CampaignTypeGetEnum без UNKNOWN —
23
+ // это значение приходит в ответе для неизвестного клиенту типа, фильтровать по нему нечего.
24
+ export const CAMPAIGN_TYPES = [
25
+ "TEXT_CAMPAIGN",
26
+ "MOBILE_APP_CAMPAIGN",
27
+ "DYNAMIC_TEXT_CAMPAIGN",
28
+ "CPM_BANNER_CAMPAIGN",
29
+ "SMART_CAMPAIGN",
30
+ "UNIFIED_CAMPAIGN"
31
+ ];
32
+ // TextCampaignSearchStrategyTypeEnum без UNKNOWN. Набор шире, чем перечисляет
33
+ // страница add: схема допускает и AVERAGE_ROI, и MAX_PROFIT, и *_MULTIPLE_GOALS.
34
+ // Стратегии динамических кампаний — подмножество этого набора.
35
+ export const SEARCH_STRATEGIES = [
36
+ "HIGHEST_POSITION",
37
+ "IMPRESSIONS_BELOW_SEARCH",
38
+ "WB_MAXIMUM_CLICKS",
39
+ "WB_MAXIMUM_CONVERSION_RATE",
40
+ "WEEKLY_CLICK_PACKAGE",
41
+ "AVERAGE_CPC",
42
+ "AVERAGE_CPA",
43
+ "AVERAGE_CPA_MULTIPLE_GOALS",
44
+ "AVERAGE_ROI",
45
+ "AVERAGE_CRR",
46
+ "PAY_FOR_CONVERSION",
47
+ "PAY_FOR_CONVERSION_CRR",
48
+ "PAY_FOR_CONVERSION_MULTIPLE_GOALS",
49
+ "MAX_PROFIT",
50
+ "SERVING_OFF"
51
+ ];
52
+ // TextCampaignNetworkStrategyTypeEnum без UNKNOWN. От поисковой отличается началом:
53
+ // вместо HIGHEST_POSITION — NETWORK_DEFAULT и MAXIMUM_COVERAGE.
54
+ export const NETWORK_STRATEGIES = [
55
+ "NETWORK_DEFAULT",
56
+ "MAXIMUM_COVERAGE",
57
+ "WB_MAXIMUM_CLICKS",
58
+ "WB_MAXIMUM_CONVERSION_RATE",
59
+ "WEEKLY_CLICK_PACKAGE",
60
+ "AVERAGE_CPC",
61
+ "AVERAGE_CPA",
62
+ "AVERAGE_CPA_MULTIPLE_GOALS",
63
+ "AVERAGE_ROI",
64
+ "AVERAGE_CRR",
65
+ "PAY_FOR_CONVERSION",
66
+ "PAY_FOR_CONVERSION_CRR",
67
+ "PAY_FOR_CONVERSION_MULTIPLE_GOALS",
68
+ "MAX_PROFIT",
69
+ "SERVING_OFF"
70
+ ];
71
+ // Действия над общими наборами минус-фраз: методы сервиса negativekeywordsharedsets.
72
+ export const NEGATIVE_KEYWORD_SET_ACTIONS = ["add", "update", "delete"];
73
+ // Состояния и статусы уточнений (AdExtensions.get, SelectionCriteria).
74
+ export const AD_EXTENSION_STATES = ["ON", "DELETED"];
75
+ export const AD_EXTENSION_STATUSES = ["ACCEPTED", "DRAFT", "MODERATION", "REJECTED"];
76
+ // AdImageAddTypeEnum: AUTO просит Директ определить тип по размеру картинки.
77
+ export const AD_IMAGE_TYPES = ["REGULAR", "WIDE", "FIXED_IMAGE", "AUTO"];
78
+ // Что делает manage_ad_images: методы сервиса adimages.
79
+ export const AD_IMAGE_ACTIONS = ["add", "get", "delete"];
80
+ // Признак «привязан к объявлению» в SelectionCriteria ряда сервисов.
81
+ export const ASSOCIATED_FLAGS = ["YES", "NO"];
82
+ // RetargetingListTypeEnum и RetargetingListRuleOperatorEnum.
83
+ export const RETARGETING_TYPES = ["RETARGETING", "AUDIENCE"];
84
+ export const RETARGETING_RULE_OPERATORS = ["ALL", "ANY", "NONE"];
85
+ // Типы корректировок, которые читает get_bid_adjustments. BidModifierTypeEnum шире
86
+ // (регионы, видео, доход, SERP-раскладка) — эти сервер пока не покрывает, см. roadmap.
87
+ export const BID_ADJUSTMENT_TYPES = [
88
+ "MOBILE_ADJUSTMENT",
89
+ "TABLET_ADJUSTMENT",
90
+ "DESKTOP_ADJUSTMENT",
91
+ "DESKTOP_ONLY_ADJUSTMENT",
92
+ "DEMOGRAPHICS_ADJUSTMENT"
93
+ ];
94
+ // BidModifierLevelEnum.
95
+ export const BID_ADJUSTMENT_LEVELS = ["CAMPAIGN", "AD_GROUP"];
96
+ // AudienceTargetStateEnum и действия сервиса audiencetargets (setBids — наш set_bids).
97
+ export const AUDIENCE_TARGET_STATES = ["ON", "SUSPENDED"];
98
+ export const AUDIENCE_TARGET_ACTIONS = ["add", "set_bids", "suspend", "resume", "delete"];
99
+ // Приоритет цели для автоматических стратегий.
100
+ export const STRATEGY_PRIORITIES = ["LOW", "NORMAL", "HIGH"];
101
+ // Динамические цели: действия сервиса dynamictextadtargets и условия отбора страниц
102
+ // (WebpageConditionOperandEnum, StringConditionOperatorEnum).
103
+ export const DYNAMIC_TARGET_ACTIONS = ["add", "set_bids", "suspend", "resume", "delete"];
104
+ export const WEBPAGE_CONDITION_OPERANDS = ["URL", "DOMAIN", "PAGE_TITLE", "PAGE_CONTENT", "OFFERS_LIST_URL"];
105
+ export const WEBPAGE_CONDITION_OPERATORS = ["EQUALS_ANY", "NOT_EQUALS_ALL", "CONTAINS_ANY", "NOT_CONTAINS_ALL"];
106
+ // Режимы get_changes (наши имена методов checkCampaigns/check) и CheckFieldEnum.
107
+ export const CHANGES_MODES = ["campaigns", "objects"];
108
+ export const CHANGES_FIELD_NAMES = ["CampaignIds", "AdGroupIds", "AdIds", "CampaignsStat"];
109
+ // Стратегии, которые умеет выставлять set_strategy. Список по-прежнему уже полного
110
+ // (в TextCampaignStrategyBase двенадцать структур настроек), но покрывает переход
111
+ // «клики → конверсии»: ручная, максимум кликов, средняя цена клика, средняя цена
112
+ // конверсии и оплата за конверсию. Ограничение наше, не Директа — хендлер собирает
113
+ // настройки только для этих типов.
114
+ //
115
+ // Сочетание сторон схемой не проверяется: таблица совместимости живёт у Директа
116
+ // и меняется без нас, а лишний запрет здесь отклонял бы валидный вызов.
117
+ export const SETTABLE_SEARCH_STRATEGIES = [
118
+ "HIGHEST_POSITION",
119
+ "WB_MAXIMUM_CLICKS",
120
+ "AVERAGE_CPC",
121
+ "AVERAGE_CPA",
122
+ "PAY_FOR_CONVERSION",
123
+ "SERVING_OFF"
124
+ ];
125
+ export const SETTABLE_NETWORK_STRATEGIES = [
126
+ "NETWORK_DEFAULT",
127
+ "MAXIMUM_COVERAGE",
128
+ "WB_MAXIMUM_CLICKS",
129
+ "AVERAGE_CPC",
130
+ "AVERAGE_CPA",
131
+ "PAY_FOR_CONVERSION",
132
+ "SERVING_OFF"
133
+ ];
134
+ // Дни недели расписания показов. В API день — первое число строки Schedule
135
+ // (1 — понедельник … 7 — воскресенье); наружу отдаются буквенные коды: число
136
+ // модель путает с часом, а порядок дней в неделе Директа не совпадает с ISO-датой.
137
+ export const WEEKDAYS = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
@@ -0,0 +1,2 @@
1
+ export declare function getToken(): string;
2
+ export declare function getClientLogin(): string | undefined;
@@ -0,0 +1,14 @@
1
+ // Чтение окружения. Токен читается на каждый запрос, а не при импорте модуля:
2
+ // иначе тест не смог бы подменить его между кейсами, а сервер — стартовать без него.
3
+ export function getToken() {
4
+ const token = process.env.YANDEX_DIRECT_TOKEN;
5
+ if (!token) {
6
+ throw new Error("Переменная окружения YANDEX_DIRECT_TOKEN не задана");
7
+ }
8
+ return token;
9
+ }
10
+ // Client-Login обязателен для агентских токенов.
11
+ // Док: https://yandex.ru/dev/direct/doc/en/concepts/headers
12
+ export function getClientLogin() {
13
+ return process.env.YANDEX_DIRECT_LOGIN;
14
+ }
@@ -0,0 +1,58 @@
1
+ export declare const REQUEST_TIMEOUT_MS = 15000;
2
+ export declare const MAX_RETRIES = 3;
3
+ export declare const MAX_RETRY_DELAY_MS = 8000;
4
+ export declare const REPORT_MAX_POLLS = 6;
5
+ export declare const REPORT_DEFAULT_RETRY_IN_SEC = 5;
6
+ export declare const REPORT_MAX_RETRY_IN_SEC = 15;
7
+ export declare const PAGE_MAX_LIMIT = 10000;
8
+ export declare const MAX_CAMPAIGNS_PER_CALL = 1000;
9
+ export declare const MAX_AD_GROUPS_PER_CALL = 1000;
10
+ export declare const MAX_ADS_PER_MODERATION = 10000;
11
+ export declare const MAX_SHARED_SETS_PER_CALL = 30;
12
+ export declare const MAX_SHARED_SETS_PER_AD_GROUP = 3;
13
+ export declare const SHARED_SET_NAME_MAX = 255;
14
+ export declare const MAX_IDS_PER_CALL = 10000;
15
+ export declare const AD_TEXT_LIMITS: {
16
+ readonly title: 56;
17
+ readonly title2: 30;
18
+ readonly text: 81;
19
+ };
20
+ export declare const SITELINK_LIMITS: {
21
+ readonly title: 30;
22
+ readonly href: 1024;
23
+ readonly description: 60;
24
+ readonly perSet: 8;
25
+ };
26
+ export declare const CALLOUT_TEXT_MAX = 25;
27
+ export declare const MAX_CALLOUTS_PER_CALL = 1000;
28
+ export declare const AD_IMAGE_NAME_MAX = 255;
29
+ export declare const MAX_IMAGES_PER_CALL = 100;
30
+ export declare const RETARGETING_LIMITS: {
31
+ readonly name: 250;
32
+ readonly description: 4096;
33
+ readonly membershipDays: 540;
34
+ };
35
+ export declare const BID_MODIFIER_RANGE: {
36
+ readonly min: 0;
37
+ readonly max: 1300;
38
+ };
39
+ export declare const MAX_CAMPAIGNS_PER_ADJUSTMENT_CALL = 10;
40
+ export declare const MAX_CAMPAIGNS_PER_AUDIENCE_CALL = 100;
41
+ export declare const MAX_CAMPAIGNS_PER_CHANGES_CALL = 3000;
42
+ export declare const MAX_AD_GROUPS_PER_CHANGES_CALL = 10000;
43
+ export declare const MAX_ADS_PER_CHANGES_CALL = 50000;
44
+ export declare const REGIONS_DEFAULT_LIMIT = 50;
45
+ export declare const REGIONS_MAX_LIMIT = 500;
46
+ export declare const HOURS_IN_DAY = 24;
47
+ export declare const HOURLY_BID_RANGE: {
48
+ readonly min: 0;
49
+ readonly max: 200;
50
+ readonly step: 10;
51
+ };
52
+ export declare const HOLIDAY_BID_RANGE: {
53
+ readonly min: 10;
54
+ readonly max: 200;
55
+ readonly step: 10;
56
+ };
57
+ export declare const TIME_ZONES_DEFAULT_LIMIT = 50;
58
+ export declare const TIME_ZONES_MAX_LIMIT = 500;
@@ -0,0 +1,54 @@
1
+ // Настройки транспорта и выборок: крутилки живут здесь. Структурные константы
2
+ // (вроде «список не пуст») остаются на месте объявления, в схеме инструмента.
3
+ export const REQUEST_TIMEOUT_MS = 15_000;
4
+ export const MAX_RETRIES = 3;
5
+ export const MAX_RETRY_DELAY_MS = 8_000;
6
+ // Отчёт формируется офлайн: сервер отвечает 201/202 и просит повторить позже.
7
+ export const REPORT_MAX_POLLS = 6;
8
+ export const REPORT_DEFAULT_RETRY_IN_SEC = 5;
9
+ export const REPORT_MAX_RETRY_IN_SEC = 15;
10
+ // Page.Limit в v5 ограничен десятью тысячами.
11
+ export const PAGE_MAX_LIMIT = 10_000;
12
+ // Ограничения самого Директа на размер выборки в одном вызове.
13
+ export const MAX_CAMPAIGNS_PER_CALL = 1_000;
14
+ export const MAX_AD_GROUPS_PER_CALL = 1_000;
15
+ export const MAX_ADS_PER_MODERATION = 10_000;
16
+ export const MAX_SHARED_SETS_PER_CALL = 30;
17
+ export const MAX_SHARED_SETS_PER_AD_GROUP = 3;
18
+ export const SHARED_SET_NAME_MAX = 255;
19
+ // Универсальный потолок на список ID в SelectionCriteria большинства сервисов.
20
+ export const MAX_IDS_PER_CALL = 10_000;
21
+ // Длины текстов объявления, справочник TextAd.
22
+ export const AD_TEXT_LIMITS = { title: 56, title2: 30, text: 81 };
23
+ // Быстрые ссылки: длины полей и размер набора.
24
+ export const SITELINK_LIMITS = { title: 30, href: 1024, description: 60, perSet: 8 };
25
+ // Уточнения (Callout).
26
+ export const CALLOUT_TEXT_MAX = 25;
27
+ export const MAX_CALLOUTS_PER_CALL = 1_000;
28
+ // Изображения объявлений.
29
+ export const AD_IMAGE_NAME_MAX = 255;
30
+ export const MAX_IMAGES_PER_CALL = 100;
31
+ // Ретаргетинг: длины полей и срок учёта цели.
32
+ export const RETARGETING_LIMITS = { name: 250, description: 4096, membershipDays: 540 };
33
+ // Коэффициент корректировки ставки, в процентах.
34
+ export const BID_MODIFIER_RANGE = { min: 0, max: 1300 };
35
+ // Корректировки читаются не больше чем по десяти кампаниям за вызов.
36
+ export const MAX_CAMPAIGNS_PER_ADJUSTMENT_CALL = 10;
37
+ // Аудиторные цели читаются не больше чем по сотне кампаний за вызов.
38
+ export const MAX_CAMPAIGNS_PER_AUDIENCE_CALL = 100;
39
+ // Ограничения ChangesService на размер выборки.
40
+ export const MAX_CAMPAIGNS_PER_CHANGES_CALL = 3_000;
41
+ export const MAX_AD_GROUPS_PER_CHANGES_CALL = 10_000;
42
+ export const MAX_ADS_PER_CHANGES_CALL = 50_000;
43
+ // Выдача справочника регионов: сколько строк отдавать модели за раз.
44
+ export const REGIONS_DEFAULT_LIMIT = 50;
45
+ export const REGIONS_MAX_LIMIT = 500;
46
+ // Временной таргетинг: почасовой коэффициент задаётся в процентах от текущей ставки,
47
+ // шаг 10, ноль — показов в этот час нет. Праздничный коэффициент начинается с 10:
48
+ // ноль там запрещён, показы в праздники отключает отдельный флаг.
49
+ export const HOURS_IN_DAY = 24;
50
+ export const HOURLY_BID_RANGE = { min: 0, max: 200, step: 10 };
51
+ export const HOLIDAY_BID_RANGE = { min: 10, max: 200, step: 10 };
52
+ // Выдача справочника часовых поясов: сколько строк отдавать модели за раз.
53
+ export const TIME_ZONES_DEFAULT_LIMIT = 50;
54
+ export const TIME_ZONES_MAX_LIMIT = 500;
@@ -0,0 +1,12 @@
1
+ declare const CAMPAIGN_SETTINGS_KEYS: {
2
+ readonly TEXT_CAMPAIGN: "TextCampaign";
3
+ readonly DYNAMIC_TEXT_CAMPAIGN: "DynamicTextCampaign";
4
+ readonly MOBILE_APP_CAMPAIGN: "MobileAppCampaign";
5
+ readonly SMART_CAMPAIGN: "SmartCampaign";
6
+ readonly UNIFIED_CAMPAIGN: "UnifiedCampaign";
7
+ readonly CPM_BANNER_CAMPAIGN: "CpmBannerCampaign";
8
+ };
9
+ export type CampaignSettingsKey = (typeof CAMPAIGN_SETTINGS_KEYS)[keyof typeof CAMPAIGN_SETTINGS_KEYS];
10
+ /** Имя объекта настроек кампании; у типа, которого нет в таблице, — `undefined`. */
11
+ export declare const getCampaignSettingsKey: (type?: string) => CampaignSettingsKey | undefined;
12
+ export {};
@@ -0,0 +1,20 @@
1
+ // Часть полей кампании лежит не на верхнем уровне, а внутри объекта настроек, имя
2
+ // которого зависит от типа кампании: TrackingParams, BiddingStrategy,
3
+ // NegativeKeywordSharedSetIds и прочие. Тип в запросе на изменение не передаётся, поэтому
4
+ // сценарий читает его через campaigns.get и приводит сюда.
5
+ //
6
+ // Таблица отвечает только на вопрос «как называется объект настроек», и ответ этот общий
7
+ // для всех полей. А вот какие типы поддерживают конкретное поле — знание не общее:
8
+ // TrackingParams есть у SMART_CAMPAIGN, но нет у MOBILE_APP_CAMPAIGN, у
9
+ // NegativeKeywordSharedSetIds ровно наоборот. Поэтому список поддерживаемых типов
10
+ // остаётся у того, кто это поле пишет, а сюда не переезжает.
11
+ const CAMPAIGN_SETTINGS_KEYS = {
12
+ TEXT_CAMPAIGN: "TextCampaign",
13
+ DYNAMIC_TEXT_CAMPAIGN: "DynamicTextCampaign",
14
+ MOBILE_APP_CAMPAIGN: "MobileAppCampaign",
15
+ SMART_CAMPAIGN: "SmartCampaign",
16
+ UNIFIED_CAMPAIGN: "UnifiedCampaign",
17
+ CPM_BANNER_CAMPAIGN: "CpmBannerCampaign"
18
+ };
19
+ /** Имя объекта настроек кампании; у типа, которого нет в таблице, — `undefined`. */
20
+ export const getCampaignSettingsKey = (type) => CAMPAIGN_SETTINGS_KEYS[type];
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ export declare function dateField(description: string): z.ZodString;
3
+ export declare function timestampField(description: string): z.ZodString;
@@ -0,0 +1,17 @@
1
+ // Даты Директа: календарный день YYYY-MM-DD и момент времени ISO 8601.
2
+ import { z } from "zod";
3
+ const DATE = /^\d{4}-\d{2}-\d{2}$/;
4
+ const TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
5
+ export function dateField(description) {
6
+ return z
7
+ .string()
8
+ .check(z.regex(DATE, { error: "Дата указывается в формате YYYY-MM-DD" }))
9
+ .meta({ description });
10
+ }
11
+ export function timestampField(description) {
12
+ return z
13
+ .string()
14
+ .check(z.regex(TIMESTAMP, { error: "Момент времени указывается в формате YYYY-MM-DDThh:mm:ssZ" }))
15
+ .refine((value) => !Number.isNaN(Date.parse(value)), { error: "Такой даты не существует" })
16
+ .meta({ description });
17
+ }
@@ -0,0 +1,3 @@
1
+ export declare function formatResult(data: unknown, opts?: {
2
+ money?: boolean;
3
+ }): string;
@@ -0,0 +1,51 @@
1
+ // biome-ignore-all lint/plugin: слой вывода — ID сюда приходят уже строками из shared/api
2
+ // Единый формат ответа инструментов: деньги в рублях, сверху — уведомления Директа.
3
+ import { microsToRubles } from "#shared/lib/money";
4
+ // Поля v5, приезжающие в микроединицах. Набор консервативный: только заведомо
5
+ // денежные ключи, иначе под конвертацию попали бы счётчики и ID.
6
+ const MONEY_KEYS = new Set(["Amount", "Bid", "ContextBid", "WeeklySpendLimit", "BidCeiling"]);
7
+ function convertMoney(value) {
8
+ if (Array.isArray(value))
9
+ return value.map(convertMoney);
10
+ if (value && typeof value === "object") {
11
+ const converted = {};
12
+ for (const [key, nested] of Object.entries(value)) {
13
+ converted[key] = MONEY_KEYS.has(key) && typeof nested === "number" ? microsToRubles(nested) : convertMoney(nested);
14
+ }
15
+ return converted;
16
+ }
17
+ return value;
18
+ }
19
+ function formatNotice(prefix, key, index, notification) {
20
+ const detail = notification.Details ? ` — ${notification.Details}` : "";
21
+ return `${prefix} ${key}[${index}] [${notification.Code ?? "?"}] ${notification.Message ?? ""}${detail}`;
22
+ }
23
+ // Частичный успех Директ хранит в теле: per-item ошибки и предупреждения лежат
24
+ // в массивах *Results, обрезанная выборка — в LimitedBy. Без этой шапки модель
25
+ // увидела бы «успех» там, где половина элементов не прошла.
26
+ function collectNotices(data) {
27
+ const lines = [];
28
+ const result = data?.result;
29
+ if (!result || typeof result !== "object")
30
+ return "";
31
+ if (typeof result.LimitedBy === "number") {
32
+ lines.push(`ℹ️ Результат обрезан (LimitedBy=${result.LimitedBy}). Для следующей страницы передайте offset=${result.LimitedBy}.`);
33
+ }
34
+ for (const [key, value] of Object.entries(result)) {
35
+ if (!/Results$/.test(key) || !Array.isArray(value))
36
+ continue;
37
+ value.forEach((item, index) => {
38
+ for (const error of (item?.Errors ?? []))
39
+ lines.push(formatNotice("❌", key, index, error));
40
+ for (const warning of (item?.Warnings ?? []))
41
+ lines.push(formatNotice("⚠️", key, index, warning));
42
+ });
43
+ }
44
+ return lines.join("\n");
45
+ }
46
+ export function formatResult(data, opts = {}) {
47
+ const payload = opts.money === false ? data : convertMoney(data);
48
+ const notices = collectNotices(data);
49
+ const body = JSON.stringify(payload, null, 2);
50
+ return notices ? `${notices}\n\n${body}` : body;
51
+ }
@@ -0,0 +1,4 @@
1
+ import { z } from "zod";
2
+ export declare function idField(description: string): z.ZodString;
3
+ export declare function apiId(id: string): bigint;
4
+ export declare function apiIds(ids: string[]): bigint[];
@@ -0,0 +1,21 @@
1
+ // ID Директа наружу — десятичные строки, внутрь API — BigInt.
2
+ // z.coerce здесь запрещён: он принял бы уже округлённое число и превратил его
3
+ // в правдоподобную строку, заменив явную ошибку валидации тихо неверным ID.
4
+ import { z } from "zod";
5
+ const DECIMAL_ID = /^[1-9]\d*$/;
6
+ export function idField(description) {
7
+ return z
8
+ .string({
9
+ error: (issue) => issue.input === undefined
10
+ ? "ID обязателен"
11
+ : "ID пришёл числом и уже потерял точность: 19-значные ID Директа не помещаются в число JavaScript. Передавайте строкой."
12
+ })
13
+ .check(z.regex(DECIMAL_ID, { error: "ID должен быть положительным целым числом в виде строки" }))
14
+ .meta({ description });
15
+ }
16
+ export function apiId(id) {
17
+ return BigInt(id);
18
+ }
19
+ export function apiIds(ids) {
20
+ return ids.map(apiId);
21
+ }
@@ -0,0 +1,6 @@
1
+ import { z } from "zod";
2
+ export declare function rublesToMicros(rubles: number): number;
3
+ export declare function microsToRubles(micros: number): number;
4
+ export declare function rublesField(description: string, opts?: {
5
+ allowZero?: boolean;
6
+ }): z.ZodPipe<z.ZodNumber, z.ZodTransform<number, number>>;
@@ -0,0 +1,21 @@
1
+ // API Директа оперирует микроединицами (сумма в валюте × 1 000 000).
2
+ // Наружу сервер отдаёт и принимает рубли: вход конвертирует схема, выход — format.
3
+ import { z } from "zod";
4
+ export function rublesToMicros(rubles) {
5
+ return Math.round(rubles * 1_000_000);
6
+ }
7
+ export function microsToRubles(micros) {
8
+ return micros / 1_000_000;
9
+ }
10
+ // Денежное поле схемы: наружу рубли, в хендлер приезжают уже микроединицы.
11
+ // Все суммы объявляются через него — иначе конвертация расползётся по хендлерам
12
+ // и рано или поздно случится дважды.
13
+ // allowZero нужен ставкам, где ноль — осмысленное значение «не задана».
14
+ export function rublesField(description, opts = {}) {
15
+ const amount = z
16
+ .number({ error: "Сумма указывается числом в рублях" })
17
+ .check(opts.allowZero
18
+ ? z.nonnegative({ error: "Сумма не может быть отрицательной" })
19
+ : z.positive({ error: "Сумма должна быть больше нуля" }));
20
+ return amount.transform(rublesToMicros).meta({ description });
21
+ }
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export declare const pageFields: {
3
+ limit: z.ZodOptional<z.ZodInt>;
4
+ offset: z.ZodOptional<z.ZodInt>;
5
+ };
6
+ export declare function buildPage(params: {
7
+ limit?: number;
8
+ offset?: number;
9
+ }): Record<string, number> | undefined;
@@ -0,0 +1,26 @@
1
+ // Общие поля пагинации для list-инструментов: Page.Limit / Page.Offset.
2
+ // Обрезанную выборку сервер помечает LimitedBy — его подсказывает format.
3
+ import { z } from "zod";
4
+ import { PAGE_MAX_LIMIT } from "#shared/config/limits";
5
+ export const pageFields = {
6
+ limit: z
7
+ .int()
8
+ .check(z.positive(), z.lte(PAGE_MAX_LIMIT))
9
+ .optional()
10
+ .meta({ description: `Сколько объектов вернуть (максимум ${PAGE_MAX_LIMIT})` }),
11
+ offset: z
12
+ .int()
13
+ .check(z.nonnegative())
14
+ .optional()
15
+ .meta({ description: "Смещение выборки: сюда передаётся LimitedBy предыдущей страницы" })
16
+ };
17
+ export function buildPage(params) {
18
+ if (params.limit === undefined && params.offset === undefined)
19
+ return undefined;
20
+ const page = {};
21
+ if (params.limit !== undefined)
22
+ page.Limit = params.limit;
23
+ if (params.offset !== undefined)
24
+ page.Offset = params.offset;
25
+ return page;
26
+ }
@@ -0,0 +1 @@
1
+ export declare function reportName(prefix: string, now?: () => number): string;
@@ -0,0 +1,5 @@
1
+ // ReportName обязан быть уникальным в пределах аккаунта, поэтому в него идёт время.
2
+ // Часы вынесены параметром: Date.now() внутри хендлера сделал бы его непроверяемым.
3
+ export function reportName(prefix, now = Date.now) {
4
+ return `${prefix}_${now()}`;
5
+ }
@@ -0,0 +1,24 @@
1
+ import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
2
+ import type { z } from "zod";
3
+ export declare const READ: ToolAnnotations;
4
+ export declare const WRITE: ToolAnnotations;
5
+ export declare const IDEMPOTENT: ToolAnnotations;
6
+ export declare const DESTRUCTIVE: ToolAnnotations;
7
+ export type ToolDescriptor = {
8
+ readonly name: string;
9
+ readonly title: string;
10
+ readonly description: string;
11
+ readonly annotations: ToolAnnotations;
12
+ readonly schema: z.ZodObject;
13
+ readonly run: (params: unknown) => Promise<string>;
14
+ };
15
+ type ToolInput<Schema extends z.ZodObject> = {
16
+ name: string;
17
+ title: string;
18
+ description: string;
19
+ annotations: ToolAnnotations;
20
+ schema: Schema;
21
+ handler: (params: z.infer<Schema>) => Promise<string>;
22
+ };
23
+ export declare function defineTool<Schema extends z.ZodObject>(tool: ToolInput<Schema>): ToolDescriptor;
24
+ export {};
@@ -0,0 +1,20 @@
1
+ // Подсказки клиенту о природе операции: по ним он решает, спрашивать ли пользователя.
2
+ // Выбираются по реальному действию, а не по имени метода: manage_*, умеющий удалять, —
3
+ // DESTRUCTIVE, даже если обычно только обновляет.
4
+ export const READ = { readOnlyHint: true, openWorldHint: true };
5
+ export const WRITE = { readOnlyHint: false, openWorldHint: true };
6
+ export const IDEMPOTENT = { readOnlyHint: false, idempotentHint: true, openWorldHint: true };
7
+ export const DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true, openWorldHint: true };
8
+ export function defineTool(tool) {
9
+ return {
10
+ name: tool.name,
11
+ title: tool.title,
12
+ description: tool.description,
13
+ annotations: tool.annotations,
14
+ schema: tool.schema,
15
+ // Единственное приведение типа на весь реестр, и оно обосновано: SDK валидирует
16
+ // аргументы этой же схемой до вызова. Повторный parse здесь был бы не просто
17
+ // лишним — он второй раз применил бы .transform, умножив рубли на миллион дважды.
18
+ run: (params) => tool.handler(params)
19
+ };
20
+ }
@@ -0,0 +1,3 @@
1
+ import type { z } from "zod";
2
+ import type { getAccountBalanceSchema } from "./schema.js";
3
+ export declare function handleGetAccountBalance(params: z.infer<typeof getAccountBalanceSchema>): Promise<string>;
@@ -0,0 +1,12 @@
1
+ import { apiV4 } from "#shared/api/v4";
2
+ import { getClientLogin } from "#shared/config/env";
3
+ import { formatResult } from "#shared/lib/format";
4
+ export async function handleGetAccountBalance(params) {
5
+ const param = { Action: "Get" };
6
+ const clientLogin = getClientLogin();
7
+ const logins = params.logins ?? (clientLogin ? [clientLogin] : undefined);
8
+ if (logins?.length)
9
+ param.SelectionCriteria = { Logins: logins };
10
+ // money: false — v4 отдаёт Amount уже в валюте аккаунта, микроединиц здесь нет.
11
+ return formatResult(await apiV4("AccountManagement", param), { money: false });
12
+ }
@@ -0,0 +1,4 @@
1
+ import { z } from "zod";
2
+ export declare const getAccountBalanceSchema: z.ZodObject<{
3
+ logins: z.ZodOptional<z.ZodArray<z.ZodString>>;
4
+ }, z.core.$strip>;
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ export const getAccountBalanceSchema = z.object({
3
+ logins: z
4
+ .array(z.string().check(z.minLength(1, { error: "Логин не может быть пустым" })))
5
+ .optional()
6
+ .meta({ description: "Логины аккаунтов для агентского токена; по умолчанию — аккаунт самого токена" })
7
+ });
@@ -0,0 +1 @@
1
+ export declare const getAccountBalanceTool: import("#shared/lib/tool").ToolDescriptor;
@@ -0,0 +1,11 @@
1
+ import { defineTool, READ } from "#shared/lib/tool";
2
+ import { handleGetAccountBalance } from "./handler.js";
3
+ import { getAccountBalanceSchema } from "./schema.js";
4
+ export const getAccountBalanceTool = defineTool({
5
+ name: "get_account_balance",
6
+ title: "Баланс аккаунта",
7
+ description: "Баланс и финансовая информация аккаунта (Amount, Currency) через Live API v4.",
8
+ annotations: READ,
9
+ schema: getAccountBalanceSchema,
10
+ handler: handleGetAccountBalance
11
+ });
@@ -0,0 +1,5 @@
1
+ import type { z } from "zod";
2
+ import type { addAdExtensionsSchema, deleteAdExtensionsSchema, listAdExtensionsSchema } from "./schema.js";
3
+ export declare function handleListAdExtensions(params: z.infer<typeof listAdExtensionsSchema>): Promise<string>;
4
+ export declare function handleAddAdExtensions(params: z.infer<typeof addAdExtensionsSchema>): Promise<string>;
5
+ export declare function handleDeleteAdExtensions(params: z.infer<typeof deleteAdExtensionsSchema>): Promise<string>;
@@ -0,0 +1,35 @@
1
+ import { apiPost } from "#shared/api/client";
2
+ import { formatResult } from "#shared/lib/format";
3
+ import { apiIds } from "#shared/lib/id";
4
+ import { buildPage } from "#shared/lib/pagination";
5
+ const NO_MONEY = { money: false };
6
+ export async function handleListAdExtensions(params) {
7
+ const selection = { Types: ["CALLOUT"] };
8
+ if (params.ad_extension_ids?.length)
9
+ selection.Ids = apiIds(params.ad_extension_ids);
10
+ if (params.states?.length)
11
+ selection.States = params.states;
12
+ if (params.statuses?.length)
13
+ selection.Statuses = params.statuses;
14
+ const request = {
15
+ SelectionCriteria: selection,
16
+ FieldNames: ["Id", "Type", "Status", "StatusClarification", "Associated"],
17
+ CalloutFieldNames: ["CalloutText"]
18
+ };
19
+ const page = buildPage(params);
20
+ if (page)
21
+ request.Page = page;
22
+ return formatResult(await apiPost("adextensions", "get", request), NO_MONEY);
23
+ }
24
+ export async function handleAddAdExtensions(params) {
25
+ const data = await apiPost("adextensions", "add", {
26
+ AdExtensions: params.callouts.map((calloutText) => ({ Callout: { CalloutText: calloutText } }))
27
+ });
28
+ return formatResult(data, NO_MONEY);
29
+ }
30
+ export async function handleDeleteAdExtensions(params) {
31
+ const data = await apiPost("adextensions", "delete", {
32
+ SelectionCriteria: { Ids: apiIds(params.ad_extension_ids) }
33
+ });
34
+ return formatResult(data, NO_MONEY);
35
+ }