mcp-google-ads 1.0.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.
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/config.example.json +26 -0
- package/dist/build-info.json +1 -0
- package/dist/errors.d.ts +17 -0
- package/dist/errors.js +117 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1751 -0
- package/dist/resilience.d.ts +3 -0
- package/dist/resilience.js +99 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +574 -0
- package/package.json +71 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { retry, circuitBreaker, wrap, handleAll, timeout, TimeoutStrategy, ExponentialBackoff, ConsecutiveBreaker, } from "cockatiel";
|
|
2
|
+
import pino from "pino";
|
|
3
|
+
// ============================================
|
|
4
|
+
// LOGGER
|
|
5
|
+
// ============================================
|
|
6
|
+
export const logger = pino({
|
|
7
|
+
level: process.env.LOG_LEVEL || "info",
|
|
8
|
+
...(process.env.NODE_ENV !== "test" && {
|
|
9
|
+
transport: {
|
|
10
|
+
target: "pino-pretty",
|
|
11
|
+
options: {
|
|
12
|
+
colorize: true,
|
|
13
|
+
singleLine: true,
|
|
14
|
+
translateTime: "SYS:standard",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
// ============================================
|
|
20
|
+
// SAFE RESPONSE (Response Size Limiting)
|
|
21
|
+
// ============================================
|
|
22
|
+
const MAX_RESPONSE_SIZE = 200_000; // 200KB
|
|
23
|
+
export function safeResponse(data, context) {
|
|
24
|
+
const jsonStr = JSON.stringify(data);
|
|
25
|
+
const sizeBytes = Buffer.byteLength(jsonStr, "utf-8");
|
|
26
|
+
if (sizeBytes > MAX_RESPONSE_SIZE) {
|
|
27
|
+
logger.warn({ sizeBytes, maxSize: MAX_RESPONSE_SIZE, context }, `Response exceeds size limit, truncating`);
|
|
28
|
+
// If it's an array, truncate
|
|
29
|
+
if (Array.isArray(data)) {
|
|
30
|
+
const truncated = data.slice(0, Math.max(1, Math.floor(data.length * 0.5)));
|
|
31
|
+
return truncated;
|
|
32
|
+
}
|
|
33
|
+
// If it's an object with items/results, truncate those
|
|
34
|
+
if (typeof data === "object" && data !== null) {
|
|
35
|
+
const obj = data;
|
|
36
|
+
for (const key of ["items", "results", "data", "rows"]) {
|
|
37
|
+
if (Array.isArray(obj[key])) {
|
|
38
|
+
obj[key] = obj[key].slice(0, Math.max(1, Math.floor(obj[key].length * 0.5)));
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
// ============================================
|
|
47
|
+
// RETRY + CIRCUIT BREAKER + TIMEOUT
|
|
48
|
+
// ============================================
|
|
49
|
+
const backoff = new ExponentialBackoff({
|
|
50
|
+
initialDelay: 100,
|
|
51
|
+
maxDelay: 5_000,
|
|
52
|
+
});
|
|
53
|
+
// Individual policies
|
|
54
|
+
const retryPolicy = retry(handleAll, {
|
|
55
|
+
maxAttempts: 3,
|
|
56
|
+
backoff,
|
|
57
|
+
});
|
|
58
|
+
const circuitBreakerPolicy = circuitBreaker(handleAll, {
|
|
59
|
+
halfOpenAfter: 60_000, // 60s to attempt recovery
|
|
60
|
+
breaker: new ConsecutiveBreaker(5), // Open after 5 consecutive failures
|
|
61
|
+
});
|
|
62
|
+
const timeoutPolicy = timeout(30_000, TimeoutStrategy.Cooperative);
|
|
63
|
+
// Combine policies: timeout -> circuit breaker -> retry
|
|
64
|
+
const policy = wrap(timeoutPolicy, circuitBreakerPolicy, retryPolicy);
|
|
65
|
+
// ============================================
|
|
66
|
+
// WRAPPED API CALL WITH LOGGING
|
|
67
|
+
// ============================================
|
|
68
|
+
export async function withResilience(fn, operationName) {
|
|
69
|
+
try {
|
|
70
|
+
logger.debug({ operation: operationName }, "Starting API call");
|
|
71
|
+
const result = await policy.execute(() => fn());
|
|
72
|
+
logger.debug({ operation: operationName }, "API call succeeded");
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
// Extract a useful message from gRPC/google-ads-api errors
|
|
77
|
+
// where String(err) produces "[object Object]"
|
|
78
|
+
let error;
|
|
79
|
+
if (err instanceof Error) {
|
|
80
|
+
error = err;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Try to get message from nested errors array (google-ads-api pattern)
|
|
84
|
+
const nested = err?.errors?.[0];
|
|
85
|
+
const msg = nested?.message
|
|
86
|
+
|| (typeof err?.message === "string" ? err.message : null)
|
|
87
|
+
|| (() => { try {
|
|
88
|
+
return JSON.stringify(err);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return String(err);
|
|
92
|
+
} })();
|
|
93
|
+
error = new Error(msg);
|
|
94
|
+
error.cause = err;
|
|
95
|
+
}
|
|
96
|
+
logger.error({ operation: operationName, error: error.message, stack: error.stack }, "API call failed after retries");
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
package/dist/tools.d.ts
ADDED
package/dist/tools.js
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
export const tools = [
|
|
2
|
+
{
|
|
3
|
+
name: "google_ads_get_client_context",
|
|
4
|
+
description: "Get the current client context based on working directory. Call this first to confirm which Google Ads account you're working with.",
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
working_directory: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "The current working directory",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
required: ["working_directory"],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "google_ads_list_campaigns",
|
|
18
|
+
description: "List all campaigns for the current client account",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
customer_id: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "The customer ID (will use context if not provided)",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "google_ads_list_ad_groups",
|
|
31
|
+
description: "List ad groups, optionally filtered by campaign",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
customer_id: { type: "string" },
|
|
36
|
+
campaign_id: { type: "string" },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "google_ads_get_campaign_tracking",
|
|
42
|
+
description: "Get campaign tracking parameters including tracking URL template, final URL suffix, and custom URL parameters",
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
customer_id: { type: "string" },
|
|
47
|
+
campaign_id: { type: "string", description: "The campaign ID to get tracking info for" },
|
|
48
|
+
},
|
|
49
|
+
required: ["campaign_id"],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "google_ads_list_pending_changes",
|
|
54
|
+
description: "List all pending changes (paused items with claude- label) awaiting review",
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: "object",
|
|
57
|
+
properties: {
|
|
58
|
+
customer_id: { type: "string" },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "google_ads_validate_ad",
|
|
64
|
+
description: "Validate an RSA without creating it. Use this to check for errors before creating.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
headlines: {
|
|
69
|
+
type: "array",
|
|
70
|
+
items: { type: "string" },
|
|
71
|
+
description: "3-15 headlines, max 30 chars each",
|
|
72
|
+
},
|
|
73
|
+
descriptions: {
|
|
74
|
+
type: "array",
|
|
75
|
+
items: { type: "string" },
|
|
76
|
+
description: "2-4 descriptions, max 90 chars each",
|
|
77
|
+
},
|
|
78
|
+
final_urls: {
|
|
79
|
+
type: "array",
|
|
80
|
+
items: { type: "string" },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ["headlines", "descriptions", "final_urls"],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "google_ads_create_campaign",
|
|
88
|
+
description: "Create a new campaign (will be PAUSED until approved). Returns campaign ID.",
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
customer_id: { type: "string" },
|
|
93
|
+
name: { type: "string" },
|
|
94
|
+
daily_budget: { type: "number", description: "Daily budget in dollars" },
|
|
95
|
+
},
|
|
96
|
+
required: ["name", "daily_budget"],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "google_ads_create_ad_group",
|
|
101
|
+
description: "Create a new ad group (will be PAUSED until approved). Returns ad group ID.",
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
customer_id: { type: "string" },
|
|
106
|
+
campaign_id: { type: "string" },
|
|
107
|
+
name: { type: "string" },
|
|
108
|
+
cpc_bid: { type: "number", description: "CPC bid in dollars" },
|
|
109
|
+
},
|
|
110
|
+
required: ["campaign_id", "name"],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "google_ads_create_responsive_search_ad",
|
|
115
|
+
description: "Create a responsive search ad (will be PAUSED until approved). Validates before creating. Headlines/descriptions can be plain strings or objects with pinned_position (1-3 for headlines, 1-2 for descriptions).",
|
|
116
|
+
inputSchema: {
|
|
117
|
+
type: "object",
|
|
118
|
+
properties: {
|
|
119
|
+
customer_id: { type: "string" },
|
|
120
|
+
ad_group_id: { type: "string" },
|
|
121
|
+
final_urls: { type: "array", items: { type: "string" } },
|
|
122
|
+
headlines: {
|
|
123
|
+
type: "array",
|
|
124
|
+
items: {
|
|
125
|
+
oneOf: [
|
|
126
|
+
{ type: "string" },
|
|
127
|
+
{
|
|
128
|
+
type: "object",
|
|
129
|
+
properties: {
|
|
130
|
+
text: { type: "string" },
|
|
131
|
+
pinned_position: { type: "number", description: "Pin to position 1, 2, or 3" },
|
|
132
|
+
},
|
|
133
|
+
required: ["text"],
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
descriptions: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: {
|
|
141
|
+
oneOf: [
|
|
142
|
+
{ type: "string" },
|
|
143
|
+
{
|
|
144
|
+
type: "object",
|
|
145
|
+
properties: {
|
|
146
|
+
text: { type: "string" },
|
|
147
|
+
pinned_position: { type: "number", description: "Pin to position 1 or 2" },
|
|
148
|
+
},
|
|
149
|
+
required: ["text"],
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
path1: { type: "string" },
|
|
155
|
+
path2: { type: "string" },
|
|
156
|
+
},
|
|
157
|
+
required: ["ad_group_id", "final_urls", "headlines", "descriptions"],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "google_ads_create_keywords",
|
|
162
|
+
description: "Create keywords for an ad group (will be PAUSED until approved). Keywords are auto-labeled for easy discovery via google_ads_list_pending_changes.",
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
customer_id: { type: "string" },
|
|
167
|
+
ad_group_id: { type: "string" },
|
|
168
|
+
keywords: {
|
|
169
|
+
type: "array",
|
|
170
|
+
items: {
|
|
171
|
+
type: "object",
|
|
172
|
+
properties: {
|
|
173
|
+
text: { type: "string" },
|
|
174
|
+
match_type: { type: "string", enum: ["BROAD", "PHRASE", "EXACT"] },
|
|
175
|
+
},
|
|
176
|
+
required: ["text", "match_type"],
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
label: {
|
|
180
|
+
type: "string",
|
|
181
|
+
description: "Label to apply to created keywords (default: 'claude-pending'). Use to group and find paused keywords later.",
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
required: ["ad_group_id", "keywords"],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "google_ads_enable_items",
|
|
189
|
+
description: "Enable paused campaigns, ad groups, or ads. REQUIRES USER APPROVAL. Use after reviewing in Google Ads UI.",
|
|
190
|
+
inputSchema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
customer_id: { type: "string" },
|
|
194
|
+
campaign_ids: { type: "array", items: { type: "string" } },
|
|
195
|
+
ad_group_ids: { type: "array", items: { type: "string" } },
|
|
196
|
+
ad_ids: { type: "array", items: { type: "string" } },
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "google_ads_pause_items",
|
|
202
|
+
description: "Pause enabled campaigns, ad groups, or ads. REQUIRES USER APPROVAL. This will stop items from serving.",
|
|
203
|
+
inputSchema: {
|
|
204
|
+
type: "object",
|
|
205
|
+
properties: {
|
|
206
|
+
customer_id: { type: "string" },
|
|
207
|
+
campaign_ids: { type: "array", items: { type: "string" } },
|
|
208
|
+
ad_group_ids: { type: "array", items: { type: "string" } },
|
|
209
|
+
ad_ids: { type: "array", items: { type: "string" } },
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: "google_ads_create_shared_set",
|
|
215
|
+
description: "Create a new shared negative keyword list at account level. Returns the new shared set ID.",
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: "object",
|
|
218
|
+
properties: {
|
|
219
|
+
customer_id: { type: "string" },
|
|
220
|
+
name: { type: "string", description: "Name for the new shared negative keyword list" },
|
|
221
|
+
},
|
|
222
|
+
required: ["name"],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: "google_ads_link_shared_set",
|
|
227
|
+
description: "Link a shared negative keyword list to one or more campaigns. Once linked, all negatives in the list will apply to those campaigns.",
|
|
228
|
+
inputSchema: {
|
|
229
|
+
type: "object",
|
|
230
|
+
properties: {
|
|
231
|
+
customer_id: { type: "string" },
|
|
232
|
+
shared_set_id: { type: "string", description: "The shared set ID to link" },
|
|
233
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Campaign IDs to link the shared set to" },
|
|
234
|
+
},
|
|
235
|
+
required: ["shared_set_id", "campaign_ids"],
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "google_ads_unlink_shared_set",
|
|
240
|
+
description: "Unlink a shared negative keyword list from one or more campaigns. The list's negatives will no longer apply to those campaigns.",
|
|
241
|
+
inputSchema: {
|
|
242
|
+
type: "object",
|
|
243
|
+
properties: {
|
|
244
|
+
customer_id: { type: "string" },
|
|
245
|
+
shared_set_id: { type: "string", description: "The shared set ID to unlink" },
|
|
246
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Campaign IDs to unlink the shared set from" },
|
|
247
|
+
},
|
|
248
|
+
required: ["shared_set_id", "campaign_ids"],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "google_ads_add_shared_negatives",
|
|
253
|
+
description: "Add negative keywords to a shared negative keyword list. Keywords will immediately block matching queries across all campaigns the list is applied to.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: {
|
|
257
|
+
customer_id: { type: "string" },
|
|
258
|
+
shared_set_id: { type: "string", description: "The shared set ID to add keywords to" },
|
|
259
|
+
keywords: {
|
|
260
|
+
type: "array",
|
|
261
|
+
items: {
|
|
262
|
+
type: "object",
|
|
263
|
+
properties: {
|
|
264
|
+
text: { type: "string" },
|
|
265
|
+
match_type: { type: "string", enum: ["BROAD", "PHRASE", "EXACT"] },
|
|
266
|
+
},
|
|
267
|
+
required: ["text", "match_type"],
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
required: ["shared_set_id", "keywords"],
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "google_ads_remove_shared_negatives",
|
|
276
|
+
description: "Remove negative keywords from a shared negative keyword list by their resource names. Get resource names from a GAQL query on shared_criterion.",
|
|
277
|
+
inputSchema: {
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
customer_id: { type: "string" },
|
|
281
|
+
resource_names: {
|
|
282
|
+
type: "array",
|
|
283
|
+
items: { type: "string" },
|
|
284
|
+
description: "Resource names of the shared criteria to remove (e.g. customers/1234/sharedCriteria/5678~9012)",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
required: ["resource_names"],
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: "google_ads_add_campaign_negatives",
|
|
292
|
+
description: "Add negative keywords at the campaign level. Use for campaign-specific negatives that shouldn't be in a shared list.",
|
|
293
|
+
inputSchema: {
|
|
294
|
+
type: "object",
|
|
295
|
+
properties: {
|
|
296
|
+
customer_id: { type: "string" },
|
|
297
|
+
campaign_id: { type: "string" },
|
|
298
|
+
keywords: {
|
|
299
|
+
type: "array",
|
|
300
|
+
items: {
|
|
301
|
+
type: "object",
|
|
302
|
+
properties: {
|
|
303
|
+
text: { type: "string" },
|
|
304
|
+
match_type: { type: "string", enum: ["BROAD", "PHRASE", "EXACT"] },
|
|
305
|
+
},
|
|
306
|
+
required: ["text", "match_type"],
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
required: ["campaign_id", "keywords"],
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: "google_ads_remove_campaign_negatives",
|
|
315
|
+
description: "Remove campaign-level negative keywords by their resource names. Get resource names from a GAQL query on campaign_criterion.",
|
|
316
|
+
inputSchema: {
|
|
317
|
+
type: "object",
|
|
318
|
+
properties: {
|
|
319
|
+
customer_id: { type: "string" },
|
|
320
|
+
resource_names: {
|
|
321
|
+
type: "array",
|
|
322
|
+
items: { type: "string" },
|
|
323
|
+
description: "Resource names of the campaign criteria to remove (e.g. customers/1234/campaignCriteria/5678~9012)",
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
required: ["resource_names"],
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "google_ads_remove_adgroup_negatives",
|
|
331
|
+
description: "Remove ad-group-level negative keywords by their resource names. Get resource names from a GAQL query on ad_group_criterion.",
|
|
332
|
+
inputSchema: {
|
|
333
|
+
type: "object",
|
|
334
|
+
properties: {
|
|
335
|
+
customer_id: { type: "string" },
|
|
336
|
+
resource_names: {
|
|
337
|
+
type: "array",
|
|
338
|
+
items: { type: "string" },
|
|
339
|
+
description: "Resource names of the ad group criteria to remove (e.g. customers/1234/adGroupCriteria/5678~9012)",
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
required: ["resource_names"],
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "google_ads_pause_keywords",
|
|
347
|
+
description: "Pause active keywords by their criterion resource names.",
|
|
348
|
+
inputSchema: {
|
|
349
|
+
type: "object",
|
|
350
|
+
properties: {
|
|
351
|
+
customer_id: { type: "string" },
|
|
352
|
+
criterion_resource_names: { type: "array", items: { type: "string" }, description: "Full resource names like customers/123/adGroupCriteria/456~789" },
|
|
353
|
+
},
|
|
354
|
+
required: ["criterion_resource_names"],
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "google_ads_update_campaign_tracking",
|
|
359
|
+
description: "Update campaign tracking parameters: final URL suffix, tracking URL template, and/or custom URL parameters. Use google_ads_get_campaign_tracking first to see current values.",
|
|
360
|
+
inputSchema: {
|
|
361
|
+
type: "object",
|
|
362
|
+
properties: {
|
|
363
|
+
customer_id: { type: "string" },
|
|
364
|
+
campaign_id: { type: "string", description: "The campaign ID to update" },
|
|
365
|
+
final_url_suffix: { type: "string", description: "New final URL suffix (appended to landing page URLs). Set to empty string to clear." },
|
|
366
|
+
tracking_url_template: { type: "string", description: "New tracking URL template. Set to empty string to clear." },
|
|
367
|
+
url_custom_parameters: {
|
|
368
|
+
type: "array",
|
|
369
|
+
items: {
|
|
370
|
+
type: "object",
|
|
371
|
+
properties: {
|
|
372
|
+
key: { type: "string", description: "Parameter name (without {_ } wrapper)" },
|
|
373
|
+
value: { type: "string", description: "Parameter value (can include ValueTrack macros)" },
|
|
374
|
+
},
|
|
375
|
+
required: ["key", "value"],
|
|
376
|
+
},
|
|
377
|
+
description: "Custom URL parameters (replaces all existing custom params)",
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
required: ["campaign_id"],
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
// ============================================
|
|
384
|
+
// REPORTING TOOLS
|
|
385
|
+
// ============================================
|
|
386
|
+
{
|
|
387
|
+
name: "google_ads_keyword_performance",
|
|
388
|
+
description: "Get keyword performance report with metrics including impressions, clicks, cost, conversions, quality score components (quality score, expected CTR, ad relevance, landing page experience), and impression share metrics.",
|
|
389
|
+
inputSchema: {
|
|
390
|
+
type: "object",
|
|
391
|
+
properties: {
|
|
392
|
+
customer_id: { type: "string" },
|
|
393
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
394
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
395
|
+
keyword_text_contains: { type: "string", description: "Filter keywords containing this text" },
|
|
396
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
397
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
398
|
+
},
|
|
399
|
+
required: ["start_date", "end_date"],
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "google_ads_keyword_performance_by_conversion",
|
|
404
|
+
description: "Get keyword performance broken down by conversion action. Shows which keywords drive which conversion types (e.g., form fills, MQLs, etc.).",
|
|
405
|
+
inputSchema: {
|
|
406
|
+
type: "object",
|
|
407
|
+
properties: {
|
|
408
|
+
customer_id: { type: "string" },
|
|
409
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
410
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
411
|
+
keyword_text_contains: { type: "string", description: "Filter keywords containing this text" },
|
|
412
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
413
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
414
|
+
},
|
|
415
|
+
required: ["start_date", "end_date"],
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
name: "google_ads_search_term_report",
|
|
420
|
+
description: "Get search term report showing actual search queries that triggered ads, with the keyword they matched to.",
|
|
421
|
+
inputSchema: {
|
|
422
|
+
type: "object",
|
|
423
|
+
properties: {
|
|
424
|
+
customer_id: { type: "string" },
|
|
425
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
426
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
427
|
+
keyword_text_contains: { type: "string", description: "Filter by keyword text" },
|
|
428
|
+
search_term_contains: { type: "string", description: "Filter search terms containing this text" },
|
|
429
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
430
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
431
|
+
},
|
|
432
|
+
required: ["start_date", "end_date"],
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
name: "google_ads_search_term_report_by_conversion",
|
|
437
|
+
description: "Get search term report broken down by conversion action. Shows which search queries drive which conversion types.",
|
|
438
|
+
inputSchema: {
|
|
439
|
+
type: "object",
|
|
440
|
+
properties: {
|
|
441
|
+
customer_id: { type: "string" },
|
|
442
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
443
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
444
|
+
keyword_text_contains: { type: "string", description: "Filter by keyword text" },
|
|
445
|
+
search_term_contains: { type: "string", description: "Filter search terms containing this text" },
|
|
446
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
447
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
448
|
+
},
|
|
449
|
+
required: ["start_date", "end_date"],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
name: "google_ads_ad_performance",
|
|
454
|
+
description: "Get ad performance report with metrics, ad copy (headlines/descriptions), final URLs, and ad strength rating.",
|
|
455
|
+
inputSchema: {
|
|
456
|
+
type: "object",
|
|
457
|
+
properties: {
|
|
458
|
+
customer_id: { type: "string" },
|
|
459
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
460
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
461
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
462
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
463
|
+
},
|
|
464
|
+
required: ["start_date", "end_date"],
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: "google_ads_ad_performance_by_conversion",
|
|
469
|
+
description: "Get ad performance broken down by conversion action. Shows which ads drive which conversion types.",
|
|
470
|
+
inputSchema: {
|
|
471
|
+
type: "object",
|
|
472
|
+
properties: {
|
|
473
|
+
customer_id: { type: "string" },
|
|
474
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
475
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
476
|
+
campaign_ids: { type: "array", items: { type: "string" }, description: "Filter by campaign IDs" },
|
|
477
|
+
ad_group_ids: { type: "array", items: { type: "string" }, description: "Filter by ad group IDs" },
|
|
478
|
+
},
|
|
479
|
+
required: ["start_date", "end_date"],
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: "google_ads_list_conversion_actions",
|
|
484
|
+
description: "List all available conversion actions (e.g., form fills, MQLs, etc.) to understand what conversion tracking is set up.",
|
|
485
|
+
inputSchema: {
|
|
486
|
+
type: "object",
|
|
487
|
+
properties: {
|
|
488
|
+
customer_id: { type: "string" },
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
name: "google_ads_search_term_insights",
|
|
494
|
+
description: "Get search term category insights for a campaign. Shows the search categories your ads appeared against (like the Insights panel in the Google Ads UI). Must query one campaign at a time. Optionally compares two date ranges to show trends.",
|
|
495
|
+
inputSchema: {
|
|
496
|
+
type: "object",
|
|
497
|
+
properties: {
|
|
498
|
+
customer_id: { type: "string" },
|
|
499
|
+
campaign_id: { type: "string", description: "The campaign ID to get insights for (required, one campaign at a time)" },
|
|
500
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
501
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
502
|
+
compare_start_date: { type: "string", description: "Comparison period start date (optional, for trend calculation)" },
|
|
503
|
+
compare_end_date: { type: "string", description: "Comparison period end date (optional, for trend calculation)" },
|
|
504
|
+
},
|
|
505
|
+
required: ["campaign_id", "start_date", "end_date"],
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
name: "google_ads_search_term_insight_terms",
|
|
510
|
+
description: "Drill into a specific search term category to see the individual search terms within it. Requires an insight_id from google_ads_search_term_insights.",
|
|
511
|
+
inputSchema: {
|
|
512
|
+
type: "object",
|
|
513
|
+
properties: {
|
|
514
|
+
customer_id: { type: "string" },
|
|
515
|
+
campaign_id: { type: "string", description: "The campaign ID" },
|
|
516
|
+
insight_id: { type: "string", description: "The insight category ID from google_ads_search_term_insights results" },
|
|
517
|
+
start_date: { type: "string", description: "Start date in YYYY-MM-DD format" },
|
|
518
|
+
end_date: { type: "string", description: "End date in YYYY-MM-DD format" },
|
|
519
|
+
},
|
|
520
|
+
required: ["campaign_id", "insight_id", "start_date", "end_date"],
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
name: "google_ads_update_campaign_budget",
|
|
525
|
+
description: "Update the daily budget for a campaign. Can update the existing budget amount or create a new solo budget and reassign the campaign to it (useful for breaking shared budgets).",
|
|
526
|
+
inputSchema: {
|
|
527
|
+
type: "object",
|
|
528
|
+
properties: {
|
|
529
|
+
customer_id: { type: "string" },
|
|
530
|
+
campaign_id: { type: "string", description: "The campaign ID to update" },
|
|
531
|
+
daily_budget: { type: "number", description: "New daily budget in dollars" },
|
|
532
|
+
create_new_budget: { type: "boolean", description: "If true, creates a new budget and reassigns this campaign to it (breaks shared budgets). If false, updates the existing budget amount in place (affects all campaigns sharing it)." },
|
|
533
|
+
},
|
|
534
|
+
required: ["campaign_id", "daily_budget"],
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: "google_ads_gaql_query",
|
|
539
|
+
description: "Execute a raw GAQL (Google Ads Query Language) query. Use this for custom reports or accessing any Google Ads API resource not covered by other tools. See https://developers.google.com/google-ads/api/docs/query/overview for GAQL syntax.",
|
|
540
|
+
inputSchema: {
|
|
541
|
+
type: "object",
|
|
542
|
+
properties: {
|
|
543
|
+
customer_id: { type: "string" },
|
|
544
|
+
query: { type: "string", description: "The GAQL query to execute" },
|
|
545
|
+
},
|
|
546
|
+
required: ["query"],
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
name: "google_ads_keyword_volume",
|
|
551
|
+
description: "Get historical search volume estimates for a list of keywords using the Google Ads Keyword Planner. Returns avg monthly searches, competition level, and CPC bid range for each keyword.",
|
|
552
|
+
inputSchema: {
|
|
553
|
+
type: "object",
|
|
554
|
+
properties: {
|
|
555
|
+
customer_id: { type: "string", description: "The Google Ads customer ID" },
|
|
556
|
+
keywords: {
|
|
557
|
+
type: "array",
|
|
558
|
+
items: { type: "string" },
|
|
559
|
+
description: "List of keywords to get volume estimates for (max 20 per call)",
|
|
560
|
+
},
|
|
561
|
+
geo_target_constants: {
|
|
562
|
+
type: "array",
|
|
563
|
+
items: { type: "string" },
|
|
564
|
+
description: "Geo target resource names, e.g. ['geoTargetConstants/2840'] for US. Defaults to US if omitted.",
|
|
565
|
+
},
|
|
566
|
+
language: {
|
|
567
|
+
type: "string",
|
|
568
|
+
description: "Language resource name, e.g. 'languageConstants/1000' for English. Defaults to English if omitted.",
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
required: ["keywords"],
|
|
572
|
+
},
|
|
573
|
+
},
|
|
574
|
+
];
|