mcp-google-ads 1.2.2 → 1.2.4

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/dist/auth-cli.js CHANGED
@@ -264,33 +264,39 @@ async function pickAccount(accounts, presetCustomerId) {
264
264
  return match;
265
265
  }
266
266
  if (accounts.length === 1) {
267
+ const only = accounts[0];
268
+ if (only.isManager) {
269
+ throw new Error(
270
+ `Only one accessible account and it is a Manager (MCC): ${only.name} (${only.id}). Most tools need a child (leaf) customer account. Grant your Google user direct access to a specific client account under that MCC and re-run the auth helper.`
271
+ );
272
+ }
267
273
  process.stderr.write(
268
274
  `
269
- Only one account accessible: ${accounts[0].name} (${accounts[0].id}). Auto-selecting.
275
+ Only one account accessible: ${only.name} (${only.id}). Auto-selecting.
270
276
  `
271
277
  );
272
- return accounts[0];
278
+ return only;
273
279
  }
274
- const sorted = [...accounts].sort((a, b) => {
275
- const aKey = a.parentMccId ? `${a.parentMccId}:1:${a.name}` : `${a.id}:0:${a.name}`;
276
- const bKey = b.parentMccId ? `${b.parentMccId}:1:${b.name}` : `${b.id}:0:${b.name}`;
277
- return aKey.localeCompare(bKey);
278
- });
279
- const choices = sorted.map((acct) => {
280
- const prefix = acct.parentMccId ? " \u21B3 " : acct.isManager ? "\u{1F4C1} " : "\u2022 ";
281
- const mccSuffix = acct.parentMccId ? "" : acct.isManager ? " (MCC)" : "";
282
- return {
283
- title: `${prefix}${acct.name} \u2014 ${acct.id}${mccSuffix}`,
284
- value: acct,
285
- disabled: acct.isManager && accounts.some((a) => a.parentMccId === acct.id) ? false : false
286
- };
280
+ const leafChildren = (mccId) => accounts.filter((a) => a.parentMccId === mccId);
281
+ const topLevel = accounts.filter((a) => {
282
+ if (a.parentMccId) return false;
283
+ if (a.isManager && leafChildren(a.id).length > 0) return false;
284
+ return true;
287
285
  });
288
- const response = await prompts(
286
+ const topLevelChoices = topLevel.map((acct) => ({
287
+ title: acct.isManager ? `\u{1F4C1} ${acct.name} \u2014 ${acct.id} (MCC, no enumerated children)` : `\u2022 ${acct.name} \u2014 ${acct.id}`,
288
+ value: { kind: "leaf", account: acct }
289
+ }));
290
+ const mccChoices = accounts.filter((a) => a.isManager && leafChildren(a.id).length > 0).map((mcc2) => ({
291
+ title: `\u{1F4C1} ${mcc2.name} \u2014 ${mcc2.id} (${leafChildren(mcc2.id).length} children)`,
292
+ value: { kind: "mcc", account: mcc2 }
293
+ }));
294
+ const first = await prompts(
289
295
  {
290
296
  type: "select",
291
- name: "account",
297
+ name: "choice",
292
298
  message: "Which Google Ads account should Claude use?",
293
- choices,
299
+ choices: [...topLevelChoices, ...mccChoices],
294
300
  initial: 0
295
301
  },
296
302
  {
@@ -299,10 +305,32 @@ Only one account accessible: ${accounts[0].name} (${accounts[0].id}). Auto-selec
299
305
  }
300
306
  }
301
307
  );
302
- if (!response.account) {
303
- throw new Error("No account selected");
308
+ if (!first.choice) throw new Error("No account selected");
309
+ if (first.choice.kind === "leaf") {
310
+ return first.choice.account;
304
311
  }
305
- return response.account;
312
+ const mcc = first.choice.account;
313
+ const children = leafChildren(mcc.id);
314
+ const childChoices = children.map((child) => ({
315
+ title: `\u2022 ${child.name} \u2014 ${child.id}`,
316
+ value: child
317
+ }));
318
+ const second = await prompts(
319
+ {
320
+ type: "select",
321
+ name: "account",
322
+ message: `Pick the client account under ${mcc.name}:`,
323
+ choices: childChoices,
324
+ initial: 0
325
+ },
326
+ {
327
+ onCancel: () => {
328
+ throw new Error("Cancelled by user");
329
+ }
330
+ }
331
+ );
332
+ if (!second.account) throw new Error("No account selected");
333
+ return second.account;
306
334
  }
307
335
  async function run(argv = process.argv.slice(2)) {
308
336
  const args = parseArgs(argv);
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha": "d3b40c7",
3
- "builtAt": "2026-04-17T20:02:21.153Z",
2
+ "sha": "ce9ba28",
3
+ "builtAt": "2026-04-17T21:01:16.463Z",
4
4
  "embeddedSecrets": true
5
5
  }
@@ -21,13 +21,11 @@ const logger = pino(
21
21
  singleLine: true,
22
22
  translateTime: "SYS:standard",
23
23
  destination: 2
24
- // stderr -- stdout is reserved for MCP JSON-RPC
25
24
  }
26
25
  }
27
26
  }
28
27
  },
29
- // When no transport (test mode), write to stderr directly
30
- process.env.NODE_ENV === "test" ? pino.destination(2) : void 0
28
+ pino.destination(2)
31
29
  );
32
30
  const MAX_RESPONSE_SIZE = 2e5;
33
31
  function safeResponse(data, context) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mcp-google-ads",
3
3
  "mcpName": "io.github.mharnett/google-ads",
4
- "version": "1.2.2",
4
+ "version": "1.2.4",
5
5
  "description": "MCP server for Google Ads API with MCC support, 36 tools for campaign management, reporting, and optimization -- now includes Demand Gen campaign creation end-to-end. Safe by default -- all changes created PAUSED.",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -33,7 +33,7 @@
33
33
  "dev:auth": "tsx src/auth-cli.ts",
34
34
  "test": "vitest run",
35
35
  "test:portability": "vitest run src/portability.test.ts",
36
- "prepublishOnly": "npm run build && npm test"
36
+ "prepublishOnly": "node scripts/check-embedded.mjs && npm run build && npm test"
37
37
  },
38
38
  "keywords": [
39
39
  "mcp",