mcp-google-ads 1.1.0 → 1.2.2
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/README.md +55 -4
- package/dist/adGroupBuilder.d.ts +26 -0
- package/dist/adGroupBuilder.js +17 -0
- package/dist/assetHelpers.d.ts +55 -0
- package/dist/assetHelpers.js +129 -0
- package/dist/auth-cli.js +13 -2
- package/dist/build-info.json +2 -2
- package/dist/campaignBuilder.d.ts +39 -0
- package/dist/campaignBuilder.js +65 -0
- package/dist/imageAsset.d.ts +51 -0
- package/dist/imageAsset.js +153 -0
- package/dist/index.js +714 -58
- package/dist/removeHelpers.d.ts +41 -0
- package/dist/removeHelpers.js +68 -0
- package/dist/tools.js +268 -8
- package/dist/validateDemandGenAd.d.ts +62 -0
- package/dist/validateDemandGenAd.js +96 -0
- package/dist/validateRsa.d.ts +11 -0
- package/dist/validateRsa.js +23 -18
- package/package.json +3 -2
package/dist/validateRsa.js
CHANGED
|
@@ -5,7 +5,9 @@ const MIN_DESCRIPTIONS = 2;
|
|
|
5
5
|
const MAX_DESCRIPTIONS = 4;
|
|
6
6
|
const MAX_DESCRIPTION_LENGTH = 90;
|
|
7
7
|
const MAX_PATH_LENGTH = 15;
|
|
8
|
-
const
|
|
8
|
+
const KEYWORD_INSERT_PATTERN = /\{(?:KeyWord|Keyword|keyword|KEYWORD):([^}]*)\}/g;
|
|
9
|
+
const CUSTOMIZER_WITH_DEFAULT = /\{CUSTOMIZER\.[^:}]+:([^}]*)\}/g;
|
|
10
|
+
const CUSTOMIZER_NO_DEFAULT = /\{CUSTOMIZER\.[^:}]+\}/g;
|
|
9
11
|
const CUSTOMIZER_RENDER_LEN = 16;
|
|
10
12
|
function validateRsa(ad) {
|
|
11
13
|
const errors = [];
|
|
@@ -16,8 +18,9 @@ function validateRsa(ad) {
|
|
|
16
18
|
errors.push(`Maximum ${MAX_HEADLINES} headlines, got ${ad.headlines.length}`);
|
|
17
19
|
}
|
|
18
20
|
(ad.headlines ?? []).forEach((h, i) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
const effectiveLen = effectiveTextLength(h);
|
|
22
|
+
if (effectiveLen > MAX_HEADLINE_LENGTH) {
|
|
23
|
+
errors.push(`Headline ${i + 1} too long (${effectiveLen}/${MAX_HEADLINE_LENGTH}): "${h}"`);
|
|
21
24
|
}
|
|
22
25
|
});
|
|
23
26
|
if (!ad.descriptions || ad.descriptions.length < MIN_DESCRIPTIONS) {
|
|
@@ -29,7 +32,7 @@ function validateRsa(ad) {
|
|
|
29
32
|
errors.push(`Maximum ${MAX_DESCRIPTIONS} descriptions, got ${ad.descriptions.length}`);
|
|
30
33
|
}
|
|
31
34
|
(ad.descriptions ?? []).forEach((d, i) => {
|
|
32
|
-
const effectiveLen =
|
|
35
|
+
const effectiveLen = effectiveTextLength(d);
|
|
33
36
|
if (effectiveLen > MAX_DESCRIPTION_LENGTH) {
|
|
34
37
|
errors.push(
|
|
35
38
|
`Description ${i + 1} too long (${effectiveLen}/${MAX_DESCRIPTION_LENGTH}): "${d}"`
|
|
@@ -41,13 +44,19 @@ function validateRsa(ad) {
|
|
|
41
44
|
}
|
|
42
45
|
if (!isNonEmpty(ad.path1)) {
|
|
43
46
|
errors.push("path1 is required (display URL path segment)");
|
|
44
|
-
} else
|
|
45
|
-
|
|
47
|
+
} else {
|
|
48
|
+
const effectiveLen = effectiveTextLength(ad.path1);
|
|
49
|
+
if (effectiveLen > MAX_PATH_LENGTH) {
|
|
50
|
+
errors.push(`path1 too long (${effectiveLen}/${MAX_PATH_LENGTH}): "${ad.path1}"`);
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
if (!isNonEmpty(ad.path2)) {
|
|
48
54
|
errors.push("path2 is required (display URL path segment)");
|
|
49
|
-
} else
|
|
50
|
-
|
|
55
|
+
} else {
|
|
56
|
+
const effectiveLen = effectiveTextLength(ad.path2);
|
|
57
|
+
if (effectiveLen > MAX_PATH_LENGTH) {
|
|
58
|
+
errors.push(`path2 too long (${effectiveLen}/${MAX_PATH_LENGTH}): "${ad.path2}"`);
|
|
59
|
+
}
|
|
51
60
|
}
|
|
52
61
|
const nonEmptyLabels = (ad.labels ?? []).filter((l) => isNonEmpty(l));
|
|
53
62
|
if (nonEmptyLabels.length === 0) {
|
|
@@ -61,18 +70,14 @@ function validateRsa(ad) {
|
|
|
61
70
|
function isNonEmpty(s) {
|
|
62
71
|
return typeof s === "string" && s.trim().length > 0;
|
|
63
72
|
}
|
|
64
|
-
function
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
effectiveLen -= m.length;
|
|
70
|
-
effectiveLen += CUSTOMIZER_RENDER_LEN;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return effectiveLen;
|
|
73
|
+
function effectiveTextLength(text) {
|
|
74
|
+
let rendered = text.replace(KEYWORD_INSERT_PATTERN, "$1");
|
|
75
|
+
rendered = rendered.replace(CUSTOMIZER_WITH_DEFAULT, "$1");
|
|
76
|
+
rendered = rendered.replace(CUSTOMIZER_NO_DEFAULT, " ".repeat(CUSTOMIZER_RENDER_LEN));
|
|
77
|
+
return rendered.length;
|
|
74
78
|
}
|
|
75
79
|
export {
|
|
80
|
+
effectiveTextLength,
|
|
76
81
|
validateRsa
|
|
77
82
|
};
|
|
78
83
|
//# sourceMappingURL=validateRsa.js.map
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-ads",
|
|
3
3
|
"mcpName": "io.github.mharnett/google-ads",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"description": "MCP server for Google Ads API with MCC support,
|
|
4
|
+
"version": "1.2.2",
|
|
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": {
|
|
8
8
|
"mcp-google-ads": "dist/index.js",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"zod": "^3.22.4"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
+
"@drak-marketing/mcp-test-harness": "^0.1.2",
|
|
76
77
|
"@types/node": "^20.10.0",
|
|
77
78
|
"@types/prompts": "^2.4.9",
|
|
78
79
|
"esbuild": "^0.28.0",
|