mcp-google-ads 1.0.4 → 1.0.5
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/build-info.json +1 -1
- package/dist/index.js +21 -10
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"sha":"
|
|
1
|
+
{"sha":"82b0bbb","builtAt":"2026-04-09T19:59:25.007Z"}
|
package/dist/index.js
CHANGED
|
@@ -80,6 +80,17 @@ function getClientFromWorkingDir(config, cwd) {
|
|
|
80
80
|
return null;
|
|
81
81
|
}
|
|
82
82
|
// ============================================
|
|
83
|
+
// GAQL SANITIZATION
|
|
84
|
+
// ============================================
|
|
85
|
+
/** Strip non-numeric characters from IDs used in GAQL WHERE clauses. */
|
|
86
|
+
function sanitizeNumericId(id) {
|
|
87
|
+
return id.replace(/[^0-9]/g, "");
|
|
88
|
+
}
|
|
89
|
+
/** Escape single quotes in strings used in GAQL WHERE clauses. */
|
|
90
|
+
function escapeGaqlString(s) {
|
|
91
|
+
return s.replace(/'/g, "\\'");
|
|
92
|
+
}
|
|
93
|
+
// ============================================
|
|
83
94
|
// TYPED ERRORS & VALIDATION (extracted to errors.ts)
|
|
84
95
|
// ============================================
|
|
85
96
|
import { GoogleAdsAuthError, GoogleAdsRateLimitError, GoogleAdsServiceError, validateCredentials, classifyError, } from "./errors.js";
|
|
@@ -193,7 +204,7 @@ class GoogleAdsManager {
|
|
|
193
204
|
WHERE ad_group.status != 'REMOVED'
|
|
194
205
|
`;
|
|
195
206
|
if (campaignId) {
|
|
196
|
-
query += ` AND campaign.id = ${campaignId}`;
|
|
207
|
+
query += ` AND campaign.id = ${sanitizeNumericId(campaignId)}`;
|
|
197
208
|
}
|
|
198
209
|
query += ` ORDER BY campaign.name, ad_group.name`;
|
|
199
210
|
const result = await withResilience(() => customer.query(query), "listAdGroups");
|
|
@@ -219,7 +230,7 @@ class GoogleAdsManager {
|
|
|
219
230
|
WHERE ad_group_ad.status != 'REMOVED'
|
|
220
231
|
`;
|
|
221
232
|
if (options.campaignId) {
|
|
222
|
-
query += ` AND campaign.id = ${options.campaignId}`;
|
|
233
|
+
query += ` AND campaign.id = ${sanitizeNumericId(options.campaignId)}`;
|
|
223
234
|
}
|
|
224
235
|
if (options.adGroupId) {
|
|
225
236
|
query += ` AND ad_group.id = ${options.adGroupId}`;
|
|
@@ -297,7 +308,7 @@ class GoogleAdsManager {
|
|
|
297
308
|
const existing = await withResilience(() => customer.query(`
|
|
298
309
|
SELECT label.resource_name, label.name
|
|
299
310
|
FROM label
|
|
300
|
-
WHERE label.name = '${labelName}'
|
|
311
|
+
WHERE label.name = '${escapeGaqlString(labelName)}'
|
|
301
312
|
AND label.status = 'ENABLED'
|
|
302
313
|
`), "ensureLabelExists.query");
|
|
303
314
|
if (existing.length > 0) {
|
|
@@ -308,7 +319,7 @@ class GoogleAdsManager {
|
|
|
308
319
|
if (result.existing) {
|
|
309
320
|
// Race condition: re-query
|
|
310
321
|
const requery = await withResilience(() => customer.query(`
|
|
311
|
-
SELECT label.resource_name FROM label WHERE label.name = '${labelName}' AND label.status = 'ENABLED'
|
|
322
|
+
SELECT label.resource_name FROM label WHERE label.name = '${escapeGaqlString(labelName)}' AND label.status = 'ENABLED'
|
|
312
323
|
`), "ensureLabelExists.requery");
|
|
313
324
|
return requery[0].label.resource_name;
|
|
314
325
|
}
|
|
@@ -711,7 +722,7 @@ class GoogleAdsManager {
|
|
|
711
722
|
query += ` AND ad_group_criterion.keyword.text LIKE '%${options.keywordTextContains}%'`;
|
|
712
723
|
}
|
|
713
724
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
714
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
725
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
715
726
|
}
|
|
716
727
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
717
728
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
|
@@ -751,7 +762,7 @@ class GoogleAdsManager {
|
|
|
751
762
|
query += ` AND ad_group_criterion.keyword.text LIKE '%${options.keywordTextContains}%'`;
|
|
752
763
|
}
|
|
753
764
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
754
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
765
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
755
766
|
}
|
|
756
767
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
757
768
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
|
@@ -789,7 +800,7 @@ class GoogleAdsManager {
|
|
|
789
800
|
query += ` AND search_term_view.search_term LIKE '%${options.searchTermContains}%'`;
|
|
790
801
|
}
|
|
791
802
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
792
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
803
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
793
804
|
}
|
|
794
805
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
795
806
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
|
@@ -825,7 +836,7 @@ class GoogleAdsManager {
|
|
|
825
836
|
query += ` AND search_term_view.search_term LIKE '%${options.searchTermContains}%'`;
|
|
826
837
|
}
|
|
827
838
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
828
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
839
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
829
840
|
}
|
|
830
841
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
831
842
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
|
@@ -870,7 +881,7 @@ class GoogleAdsManager {
|
|
|
870
881
|
AND ad_group_ad.status != 'REMOVED'
|
|
871
882
|
`;
|
|
872
883
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
873
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
884
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
874
885
|
}
|
|
875
886
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
876
887
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
|
@@ -913,7 +924,7 @@ class GoogleAdsManager {
|
|
|
913
924
|
AND ad_group_ad.status != 'REMOVED'
|
|
914
925
|
`;
|
|
915
926
|
if (options.campaignIds && options.campaignIds.length > 0) {
|
|
916
|
-
query += ` AND campaign.id IN (${options.campaignIds.join(",")})`;
|
|
927
|
+
query += ` AND campaign.id IN (${options.campaignIds.map(sanitizeNumericId).join(",")})`;
|
|
917
928
|
}
|
|
918
929
|
if (options.adGroupIds && options.adGroupIds.length > 0) {
|
|
919
930
|
query += ` AND ad_group.id IN (${options.adGroupIds.join(",")})`;
|
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.0.
|
|
4
|
+
"version": "1.0.5",
|
|
5
5
|
"description": "MCP server for Google Ads API with MCC support, 35 tools for campaign management, reporting, and optimization. Safe by default — all changes created PAUSED.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|