@revclamp/google-ads-transparency-mcp 0.0.0-stage → 1.0.9
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/.actor/actor.json +78 -0
- package/.actor/input_schema.json +79 -0
- package/.well-known/glama.json +6 -0
- package/LICENSE +21 -0
- package/README.md +134 -2
- package/actor_config.json +29 -0
- package/assets/icon-180.png +0 -0
- package/assets/icon-32.png +0 -0
- package/assets/icon.svg +26 -0
- package/assets/playground.css +468 -0
- package/assets/playground.js +817 -0
- package/glama.json +6 -0
- package/index.mjs +316 -0
- package/package.json +55 -4
- package/server.json +45 -0
- package/src/apify_actor.mjs +2208 -0
- package/src/egress_guard.mjs +102 -0
- package/src/mcp_server.mjs +1171 -0
- package/src/rpc_client.mjs +3925 -0
- package/src/web_preview_server.mjs +420 -0
package/glama.json
ADDED
package/index.mjs
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Entrypoint & Barrel Export for RevClamp AdPulse - Google Ads Transparency MCP & Apify Actor (`index.mjs`)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import readline from 'node:readline';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import {
|
|
11
|
+
ALLOWED_GOOGLE_ADS_RPC_HOSTS,
|
|
12
|
+
LIVE_SECRET_GUARD_RE,
|
|
13
|
+
containsLiveSecretToken,
|
|
14
|
+
verifyEgressUrlSsrfSafe,
|
|
15
|
+
assertAllowedGoogleAdsEgress,
|
|
16
|
+
createEphemeralHttpsAgent,
|
|
17
|
+
} from './src/egress_guard.mjs';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
GOOGLE_ADS_RPC_ENDPOINTS,
|
|
21
|
+
ADVERTISER_ID_RE,
|
|
22
|
+
CREATIVE_ID_RE,
|
|
23
|
+
ISO_COUNTRY_RE,
|
|
24
|
+
ISO_COUNTRY_TO_GOOGLE_GEO_ID,
|
|
25
|
+
GOOGLE_GEO_ID_TO_ISO_COUNTRY,
|
|
26
|
+
MAX_RPC_RESPONSE_BYTES,
|
|
27
|
+
DEFAULT_RUN_DEADLINE_MS,
|
|
28
|
+
COMPOSITE_CURSOR_PREFIX,
|
|
29
|
+
MAX_CURSOR_LENGTH,
|
|
30
|
+
MAX_QUERY_LENGTH,
|
|
31
|
+
KNOWN_ADVERTISER_DIRECTORY,
|
|
32
|
+
CORPORATE_LEGAL_SUFFIX_TOKENS,
|
|
33
|
+
collapseDottedAcronyms,
|
|
34
|
+
foldBrandText,
|
|
35
|
+
parseBrandQueryTokens,
|
|
36
|
+
validateBoundedIntegerParam,
|
|
37
|
+
computePaginationScopeHash,
|
|
38
|
+
encodeCompositeCursor,
|
|
39
|
+
decodePaginationCursor,
|
|
40
|
+
computeRewoundCursorForDeliveredPrefix,
|
|
41
|
+
verifyRpcResponseSchemaCanary,
|
|
42
|
+
scoreAdvertiserCandidate,
|
|
43
|
+
executeGoogleAdsRpcPost,
|
|
44
|
+
resolveAdvertiserEntities,
|
|
45
|
+
extractCreativeAssetUrls,
|
|
46
|
+
sanitizeUntrustedAdText,
|
|
47
|
+
createEmptyUntrustedAdContent,
|
|
48
|
+
extractStaticAdCopyFromContentJs,
|
|
49
|
+
fetchAndExtractStaticAdCopy,
|
|
50
|
+
normalizeCreativeRecord,
|
|
51
|
+
fetchAdvertiserCreatives,
|
|
52
|
+
getCreativeDetailsById,
|
|
53
|
+
} from './src/rpc_client.mjs';
|
|
54
|
+
|
|
55
|
+
import {
|
|
56
|
+
ACTOR_PRICING_CONTRACT,
|
|
57
|
+
computeChunkIdempotencyKey,
|
|
58
|
+
computeRunEconomicsTelemetry,
|
|
59
|
+
createApifyPlatformHooks,
|
|
60
|
+
loadApifyActorInput,
|
|
61
|
+
runGoogleAdsTransparencyActor,
|
|
62
|
+
scrapeGoogleAdsTransparency,
|
|
63
|
+
} from './src/apify_actor.mjs';
|
|
64
|
+
|
|
65
|
+
import {
|
|
66
|
+
MCP_MAX_ENVELOPE_BYTES,
|
|
67
|
+
MCP_MAX_ITEMS_LIMIT,
|
|
68
|
+
MCP_MAX_REQ_ID_BYTES,
|
|
69
|
+
SUPPORTED_MCP_PROTOCOL_VERSIONS,
|
|
70
|
+
ENCODED_BRAND_ICON_DATA_URI,
|
|
71
|
+
MCP_SERVER_INFO,
|
|
72
|
+
MCP_TOOLS_MANIFEST,
|
|
73
|
+
sliceUtf8Safe,
|
|
74
|
+
truncateMcpResponseEnvelope,
|
|
75
|
+
validateMcpToolArguments,
|
|
76
|
+
handleMcpJsonRpcRequest,
|
|
77
|
+
} from './src/mcp_server.mjs';
|
|
78
|
+
|
|
79
|
+
import {
|
|
80
|
+
PLAYGROUND_CSP_HEADER,
|
|
81
|
+
MAX_PLAYGROUND_BODY_BYTES,
|
|
82
|
+
PLAYGROUND_REQUEST_TIMEOUT_MS,
|
|
83
|
+
createAdPulsePreviewServer,
|
|
84
|
+
} from './src/web_preview_server.mjs';
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
ALLOWED_GOOGLE_ADS_RPC_HOSTS,
|
|
88
|
+
LIVE_SECRET_GUARD_RE,
|
|
89
|
+
containsLiveSecretToken,
|
|
90
|
+
verifyEgressUrlSsrfSafe,
|
|
91
|
+
assertAllowedGoogleAdsEgress,
|
|
92
|
+
createEphemeralHttpsAgent,
|
|
93
|
+
GOOGLE_ADS_RPC_ENDPOINTS,
|
|
94
|
+
ADVERTISER_ID_RE,
|
|
95
|
+
CREATIVE_ID_RE,
|
|
96
|
+
ISO_COUNTRY_RE,
|
|
97
|
+
ISO_COUNTRY_TO_GOOGLE_GEO_ID,
|
|
98
|
+
GOOGLE_GEO_ID_TO_ISO_COUNTRY,
|
|
99
|
+
MAX_RPC_RESPONSE_BYTES,
|
|
100
|
+
DEFAULT_RUN_DEADLINE_MS,
|
|
101
|
+
COMPOSITE_CURSOR_PREFIX,
|
|
102
|
+
MAX_CURSOR_LENGTH,
|
|
103
|
+
MAX_QUERY_LENGTH,
|
|
104
|
+
KNOWN_ADVERTISER_DIRECTORY,
|
|
105
|
+
CORPORATE_LEGAL_SUFFIX_TOKENS,
|
|
106
|
+
collapseDottedAcronyms,
|
|
107
|
+
foldBrandText,
|
|
108
|
+
parseBrandQueryTokens,
|
|
109
|
+
validateBoundedIntegerParam,
|
|
110
|
+
computePaginationScopeHash,
|
|
111
|
+
encodeCompositeCursor,
|
|
112
|
+
decodePaginationCursor,
|
|
113
|
+
computeRewoundCursorForDeliveredPrefix,
|
|
114
|
+
verifyRpcResponseSchemaCanary,
|
|
115
|
+
scoreAdvertiserCandidate,
|
|
116
|
+
executeGoogleAdsRpcPost,
|
|
117
|
+
resolveAdvertiserEntities,
|
|
118
|
+
extractCreativeAssetUrls,
|
|
119
|
+
sanitizeUntrustedAdText,
|
|
120
|
+
createEmptyUntrustedAdContent,
|
|
121
|
+
extractStaticAdCopyFromContentJs,
|
|
122
|
+
fetchAndExtractStaticAdCopy,
|
|
123
|
+
normalizeCreativeRecord,
|
|
124
|
+
fetchAdvertiserCreatives,
|
|
125
|
+
getCreativeDetailsById,
|
|
126
|
+
ACTOR_PRICING_CONTRACT,
|
|
127
|
+
computeChunkIdempotencyKey,
|
|
128
|
+
computeRunEconomicsTelemetry,
|
|
129
|
+
createApifyPlatformHooks,
|
|
130
|
+
loadApifyActorInput,
|
|
131
|
+
runGoogleAdsTransparencyActor,
|
|
132
|
+
scrapeGoogleAdsTransparency,
|
|
133
|
+
MCP_MAX_ENVELOPE_BYTES,
|
|
134
|
+
MCP_MAX_ITEMS_LIMIT,
|
|
135
|
+
MCP_MAX_REQ_ID_BYTES,
|
|
136
|
+
SUPPORTED_MCP_PROTOCOL_VERSIONS,
|
|
137
|
+
ENCODED_BRAND_ICON_DATA_URI,
|
|
138
|
+
MCP_SERVER_INFO,
|
|
139
|
+
MCP_TOOLS_MANIFEST,
|
|
140
|
+
sliceUtf8Safe,
|
|
141
|
+
truncateMcpResponseEnvelope,
|
|
142
|
+
validateMcpToolArguments,
|
|
143
|
+
handleMcpJsonRpcRequest,
|
|
144
|
+
PLAYGROUND_CSP_HEADER,
|
|
145
|
+
MAX_PLAYGROUND_BODY_BYTES,
|
|
146
|
+
PLAYGROUND_REQUEST_TIMEOUT_MS,
|
|
147
|
+
createAdPulsePreviewServer,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export async function runCli(argv = process.argv.slice(2), options = {}) {
|
|
151
|
+
const args = Array.isArray(argv) ? argv : [];
|
|
152
|
+
const writeStdout =
|
|
153
|
+
typeof options.writeStdout === 'function'
|
|
154
|
+
? options.writeStdout
|
|
155
|
+
: (str) => process.stdout.write(str);
|
|
156
|
+
const exitFn = typeof options.exitFn === 'function' ? options.exitFn : (code) => process.exit(code);
|
|
157
|
+
|
|
158
|
+
if (args.includes('--list-tools')) {
|
|
159
|
+
const out = {
|
|
160
|
+
ok: true,
|
|
161
|
+
serverInfo: MCP_SERVER_INFO,
|
|
162
|
+
tools: MCP_TOOLS_MANIFEST,
|
|
163
|
+
};
|
|
164
|
+
writeStdout(`${JSON.stringify(out, null, 2)}\n`);
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (args.includes('--self-test')) {
|
|
169
|
+
const initRes = await handleMcpJsonRpcRequest({
|
|
170
|
+
jsonrpc: '2.0',
|
|
171
|
+
id: 1,
|
|
172
|
+
method: 'initialize',
|
|
173
|
+
params: { protocolVersion: '2025-06-18' },
|
|
174
|
+
});
|
|
175
|
+
const listRes = await handleMcpJsonRpcRequest({
|
|
176
|
+
jsonrpc: '2.0',
|
|
177
|
+
id: 2,
|
|
178
|
+
method: 'tools/list',
|
|
179
|
+
params: {},
|
|
180
|
+
});
|
|
181
|
+
const secretBlocked = containsLiveSecretToken(['sk', 'live', '1234567890abcdef'].join('_'));
|
|
182
|
+
const ssrfBlocked = !assertAllowedGoogleAdsEgress('http://127.0.0.1/internal').safe;
|
|
183
|
+
const ok =
|
|
184
|
+
Boolean(initRes?.result?.serverInfo?.name) &&
|
|
185
|
+
Array.isArray(listRes?.result?.tools) &&
|
|
186
|
+
listRes.result.tools.length === 3 &&
|
|
187
|
+
secretBlocked &&
|
|
188
|
+
ssrfBlocked;
|
|
189
|
+
const report = {
|
|
190
|
+
ok,
|
|
191
|
+
status: ok ? 'SELF_TEST_PASSED' : 'SELF_TEST_FAILED',
|
|
192
|
+
server: MCP_SERVER_INFO.name,
|
|
193
|
+
version: MCP_SERVER_INFO.version,
|
|
194
|
+
toolsVerified: listRes?.result?.tools?.length || 0,
|
|
195
|
+
secretGuardActive: secretBlocked,
|
|
196
|
+
ssrfGuardActive: ssrfBlocked,
|
|
197
|
+
};
|
|
198
|
+
writeStdout(`${JSON.stringify(report, null, 2)}\n`);
|
|
199
|
+
if (!options.noExit) exitFn(ok ? 0 : 1);
|
|
200
|
+
return report;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const callIdx = args.indexOf('--call');
|
|
204
|
+
if (callIdx !== -1) {
|
|
205
|
+
const toolName = String(args[callIdx + 1] || '').trim();
|
|
206
|
+
const rawJsonArgs = args[callIdx + 2] ? String(args[callIdx + 2]).trim() : '{}';
|
|
207
|
+
let parsedArgs = {};
|
|
208
|
+
try {
|
|
209
|
+
parsedArgs = JSON.parse(rawJsonArgs);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
const errOut = {
|
|
212
|
+
ok: false,
|
|
213
|
+
status: 'INVALID_INPUT',
|
|
214
|
+
reason: `Invalid JSON arguments for --call ${toolName}: ${err.message}`,
|
|
215
|
+
};
|
|
216
|
+
writeStdout(`${JSON.stringify(errOut, null, 2)}\n`);
|
|
217
|
+
if (!options.noExit) exitFn(1);
|
|
218
|
+
return errOut;
|
|
219
|
+
}
|
|
220
|
+
const rpcRes = await handleMcpJsonRpcRequest(
|
|
221
|
+
{
|
|
222
|
+
jsonrpc: '2.0',
|
|
223
|
+
id: 1,
|
|
224
|
+
method: 'tools/call',
|
|
225
|
+
params: { name: toolName, arguments: parsedArgs },
|
|
226
|
+
},
|
|
227
|
+
options
|
|
228
|
+
);
|
|
229
|
+
const out = rpcRes?.result?.structuredContent || rpcRes;
|
|
230
|
+
writeStdout(`${JSON.stringify(out, null, 2)}\n`);
|
|
231
|
+
const isOk = Boolean(out?.ok !== false && !rpcRes?.error && !rpcRes?.result?.isError);
|
|
232
|
+
if (!options.noExit) exitFn(isOk ? 0 : 1);
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (args.includes('--playground') || args.includes('--web-preview')) {
|
|
237
|
+
const portArg = Number(process.env.PORT || 4410);
|
|
238
|
+
const srv = await createAdPulsePreviewServer({ port: portArg });
|
|
239
|
+
writeStdout(`RevClamp AdPulse Web Playground listening on ${srv.url}\n`);
|
|
240
|
+
return srv;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (args.includes('--mcp-stdio') || args.includes('--stdio')) {
|
|
244
|
+
const rl = readline.createInterface({
|
|
245
|
+
input: process.stdin,
|
|
246
|
+
terminal: false,
|
|
247
|
+
});
|
|
248
|
+
for await (const line of rl) {
|
|
249
|
+
const trimmed = line.trim();
|
|
250
|
+
if (!trimmed) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
let parsedReq;
|
|
254
|
+
try {
|
|
255
|
+
parsedReq = JSON.parse(trimmed);
|
|
256
|
+
} catch {
|
|
257
|
+
process.stdout.write(
|
|
258
|
+
`${JSON.stringify({
|
|
259
|
+
jsonrpc: '2.0',
|
|
260
|
+
id: null,
|
|
261
|
+
error: { code: -32700, message: 'Parse error' },
|
|
262
|
+
})}\n`
|
|
263
|
+
);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const res = await handleMcpJsonRpcRequest(parsedReq);
|
|
269
|
+
if (res !== null && res !== undefined) {
|
|
270
|
+
process.stdout.write(`${JSON.stringify(res)}\n`);
|
|
271
|
+
}
|
|
272
|
+
} catch (err) {
|
|
273
|
+
const hasId =
|
|
274
|
+
parsedReq &&
|
|
275
|
+
typeof parsedReq === 'object' &&
|
|
276
|
+
!Array.isArray(parsedReq) &&
|
|
277
|
+
Object.prototype.hasOwnProperty.call(parsedReq, 'id') &&
|
|
278
|
+
parsedReq.id !== undefined;
|
|
279
|
+
if (hasId) {
|
|
280
|
+
process.stdout.write(
|
|
281
|
+
`${JSON.stringify({
|
|
282
|
+
jsonrpc: '2.0',
|
|
283
|
+
id: typeof parsedReq.id === 'string' || typeof parsedReq.id === 'number' ? parsedReq.id : null,
|
|
284
|
+
error: { code: -32603, message: `Internal error: ${err?.message || String(err)}` },
|
|
285
|
+
})}\n`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const inputObj = await loadApifyActorInput(args, process.env);
|
|
294
|
+
const platformHooks = createApifyPlatformHooks(process.env);
|
|
295
|
+
const res = await runGoogleAdsTransparencyActor(inputObj, platformHooks);
|
|
296
|
+
process.stdout.write(`${JSON.stringify(res, null, 2)}\n`);
|
|
297
|
+
process.exit(res.ok ? 0 : 1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function isExecutedAsMainModule(metaUrl) {
|
|
301
|
+
if (!process.argv[1]) return false;
|
|
302
|
+
try {
|
|
303
|
+
const entryPath = fs.realpathSync(process.argv[1]);
|
|
304
|
+
const selfPath = fs.realpathSync(fileURLToPath(metaUrl));
|
|
305
|
+
return entryPath === selfPath;
|
|
306
|
+
} catch {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (isExecutedAsMainModule(import.meta.url)) {
|
|
312
|
+
runCli().catch((err) => {
|
|
313
|
+
process.stderr.write(`Fatal error in RevClamp AdPulse CLI: ${err?.message || String(err)}\n`);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
});
|
|
316
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revclamp/google-ads-transparency-mcp",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"mcpName": "com.revclamp/google-ads-transparency-mcp",
|
|
4
|
+
"version": "1.0.9",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "RevClamp AdPulse - Google Ads Transparency Scraper & MCP. Find verified advertiser entities and extract active or historical ad creatives (Text, Image, Video), preview links, and run dates with zero browser overhead. Independent tool by RevClamp; not affiliated with Google LLC.",
|
|
7
|
+
"homepage": "https://revclamp.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/lhphong09t2/revclamp-mcp.git",
|
|
11
|
+
"directory": "products/google-ads-transparency-mcp"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"main": "./index.mjs",
|
|
15
|
+
"bin": {
|
|
16
|
+
"google-ads-transparency-mcp": "./index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"index.mjs",
|
|
20
|
+
"src/",
|
|
21
|
+
"assets/",
|
|
22
|
+
"actor_config.json",
|
|
23
|
+
"server.json",
|
|
24
|
+
"glama.json",
|
|
25
|
+
".well-known/",
|
|
26
|
+
".actor/",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"mcp",
|
|
32
|
+
"model-context-protocol",
|
|
33
|
+
"google-ads",
|
|
34
|
+
"ads-transparency",
|
|
35
|
+
"ad-intelligence",
|
|
36
|
+
"competitive-intelligence",
|
|
37
|
+
"ad-library",
|
|
38
|
+
"brand-safety",
|
|
39
|
+
"ppc",
|
|
40
|
+
"b2b-marketing",
|
|
41
|
+
"apify",
|
|
42
|
+
"revclamp"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"start": "node ./index.mjs",
|
|
46
|
+
"mcp": "node ./index.mjs --mcp-stdio",
|
|
47
|
+
"playground": "node ./src/web_preview_server.mjs",
|
|
48
|
+
"preview": "node ./index.mjs --web-preview",
|
|
49
|
+
"self-test": "node ./index.mjs --self-test",
|
|
50
|
+
"list-tools": "node ./index.mjs --list-tools",
|
|
51
|
+
"test": "node --test ./test/google_ads_transparency.test.mjs ./test/metamorphic_and_mutation.test.mjs ./test/cdp_zero_false_green_e2e.test.mjs",
|
|
52
|
+
"release:audit": "node ./scripts/release_publisher.mjs --audit"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "com.revclamp/google-ads-transparency-mcp",
|
|
4
|
+
"title": "RevClamp AdPulse - Google Ads Transparency Scraper & MCP",
|
|
5
|
+
"description": "Google Ads Transparency Center advertiser & creative intelligence MCP server by RevClamp.",
|
|
6
|
+
"version": "1.0.9",
|
|
7
|
+
"websiteUrl": "https://revclamp.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/lhphong09t2/revclamp-mcp",
|
|
10
|
+
"source": "github",
|
|
11
|
+
"subfolder": "products/google-ads-transparency-mcp"
|
|
12
|
+
},
|
|
13
|
+
"icons": [
|
|
14
|
+
{
|
|
15
|
+
"src": "https://raw.githubusercontent.com/lhphong09t2/revclamp-mcp/main/products/google-ads-transparency-mcp/assets/icon-180.png",
|
|
16
|
+
"mimeType": "image/png",
|
|
17
|
+
"sizes": ["180x180"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"src": "https://raw.githubusercontent.com/lhphong09t2/revclamp-mcp/main/products/google-ads-transparency-mcp/assets/icon.svg",
|
|
21
|
+
"mimeType": "image/svg+xml",
|
|
22
|
+
"sizes": ["any"]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"packages": [
|
|
26
|
+
{
|
|
27
|
+
"registryType": "npm",
|
|
28
|
+
"registryBaseUrl": "https://registry.npmjs.org",
|
|
29
|
+
"identifier": "@revclamp/google-ads-transparency-mcp",
|
|
30
|
+
"version": "1.0.9",
|
|
31
|
+
"runtimeHint": "npx",
|
|
32
|
+
"transport": {
|
|
33
|
+
"type": "stdio"
|
|
34
|
+
},
|
|
35
|
+
"packageArguments": [
|
|
36
|
+
{
|
|
37
|
+
"type": "named",
|
|
38
|
+
"name": "--mcp-stdio",
|
|
39
|
+
"description": "Start the Model Context Protocol (MCP) JSON-RPC 2.0 server over standard input/output."
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"environmentVariables": []
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|