@cite42/mcp 0.8.2 → 0.9.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/README.md +8 -0
- package/dist/stdio.cjs +39 -6
- package/dist/stdio.mjs +39 -6
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -55,6 +55,14 @@ claude mcp add --transport http --scope user cite42 https://mcp.cite42.dev && cl
|
|
|
55
55
|
|
|
56
56
|
Your browser opens to sign in. Then start Claude Code, or restart it if it was already open, and check with `/mcp`.
|
|
57
57
|
|
|
58
|
+
Or install Cite42 as a plugin from inside Claude Code:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
/plugin install cite42 --marketplace Cite42/mcp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Claude Code versions before 2.1.275 need two steps: `/plugin marketplace add Cite42/mcp`, then `/plugin install cite42@cite42`. Then open `/mcp`, pick the Cite42 server and sign in.
|
|
65
|
+
|
|
58
66
|
### Codex CLI
|
|
59
67
|
|
|
60
68
|
```bash
|
package/dist/stdio.cjs
CHANGED
|
@@ -217,6 +217,15 @@ function optionalShortText(description) {
|
|
|
217
217
|
}
|
|
218
218
|
var modelsInput = import_zod.z.array(modelEnum).nonempty().optional().describe(MODEL_SELECTION_DESCRIPTION);
|
|
219
219
|
var fullSweepInput = import_zod.z.boolean().optional().describe(FULL_SWEEP_DESCRIPTION);
|
|
220
|
+
var AI_MARKETS_ENABLED = true;
|
|
221
|
+
var aiMarketInput = AI_MARKETS_ENABLED ? {
|
|
222
|
+
country: import_zod.z.string().trim().max(8).optional().describe(
|
|
223
|
+
`Optional ISO-2 country to measure from, e.g. "gb". Omit for each surface's default. Gemini has no country setting and ignores it.`
|
|
224
|
+
),
|
|
225
|
+
language: import_zod.z.string().trim().max(8).optional().describe(
|
|
226
|
+
"Optional ISO-2 language for google_ai_overview and chatgpt_app, which read in it. Needs country; defaults to the country's main language."
|
|
227
|
+
)
|
|
228
|
+
} : {};
|
|
220
229
|
var competitorList = import_zod.z.array(shortText("Competitor brand/domain name.")).nonempty().max(20);
|
|
221
230
|
async function fetchBalance() {
|
|
222
231
|
const usage = await aivGet("/usage");
|
|
@@ -277,7 +286,8 @@ var aivSearch = (0, import_tools.createTool)({
|
|
|
277
286
|
inputSchema: import_zod.z.object({
|
|
278
287
|
query: queryText("The concise AI-search/market-research query to run against the selected models."),
|
|
279
288
|
models: modelsInput,
|
|
280
|
-
fullSweep: fullSweepInput
|
|
289
|
+
fullSweep: fullSweepInput,
|
|
290
|
+
...aiMarketInput
|
|
281
291
|
}),
|
|
282
292
|
execute: async (input) => aivPost("/search", input)
|
|
283
293
|
});
|
|
@@ -289,7 +299,8 @@ var aivCitations = (0, import_tools.createTool)({
|
|
|
289
299
|
query: queryText("The concise query to look up cited sources for."),
|
|
290
300
|
url: import_zod.z.string().trim().max(500).optional().describe("Optional URL to check whether it was cited."),
|
|
291
301
|
models: modelsInput,
|
|
292
|
-
fullSweep: fullSweepInput
|
|
302
|
+
fullSweep: fullSweepInput,
|
|
303
|
+
...aiMarketInput
|
|
293
304
|
}),
|
|
294
305
|
execute: async (input) => aivPost("/citations", input)
|
|
295
306
|
});
|
|
@@ -301,7 +312,8 @@ var aivRankings = (0, import_tools.createTool)({
|
|
|
301
312
|
query: queryText("The concise query to measure brand/competitor visibility on."),
|
|
302
313
|
competitors: competitorList.describe("Brand or domain names to track within the AI-generated answers."),
|
|
303
314
|
models: modelsInput,
|
|
304
|
-
fullSweep: fullSweepInput
|
|
315
|
+
fullSweep: fullSweepInput,
|
|
316
|
+
...aiMarketInput
|
|
305
317
|
}),
|
|
306
318
|
execute: async (input) => aivPost("/rankings", input)
|
|
307
319
|
});
|
|
@@ -314,7 +326,8 @@ var aivCompare = (0, import_tools.createTool)({
|
|
|
314
326
|
brand: shortText("Your brand, ranked alongside the competitors."),
|
|
315
327
|
competitors: import_zod.z.array(shortText("Competitor brand/domain name.")).nonempty().max(10).describe("Competitor brand/domain names (up to 10) to rank against your brand."),
|
|
316
328
|
models: modelsInput,
|
|
317
|
-
fullSweep: fullSweepInput
|
|
329
|
+
fullSweep: fullSweepInput,
|
|
330
|
+
...aiMarketInput
|
|
318
331
|
}),
|
|
319
332
|
execute: async (input) => aivPost("/compare", input)
|
|
320
333
|
});
|
|
@@ -326,7 +339,8 @@ var aivSentiment = (0, import_tools.createTool)({
|
|
|
326
339
|
query: queryText("The concise query whose answers are scored for brand sentiment."),
|
|
327
340
|
brand: shortText("The brand to score sentiment for in each model answer."),
|
|
328
341
|
models: modelsInput,
|
|
329
|
-
fullSweep: fullSweepInput
|
|
342
|
+
fullSweep: fullSweepInput,
|
|
343
|
+
...aiMarketInput
|
|
330
344
|
}),
|
|
331
345
|
execute: async (input) => aivPost("/sentiment", input)
|
|
332
346
|
});
|
|
@@ -363,6 +377,24 @@ var aivKeywordsBatch = (0, import_tools.createTool)({
|
|
|
363
377
|
}),
|
|
364
378
|
execute: async (input) => aivPost("/keywords/batch", input)
|
|
365
379
|
});
|
|
380
|
+
var aivKeywordRankings = (0, import_tools.createTool)({
|
|
381
|
+
id: "cite42_keyword_rankings",
|
|
382
|
+
mcp: readOnly("Get Google keyword rankings"),
|
|
383
|
+
description: `Where a site ranks in Google organic results (top 100) for one to five keywords in one country, desktop or mobile: position, ranking URL, competitor positions, the top 10 and whether the AI Overview cites the site. Billed per keyword checked; a keyword that fails is free. Each check is one live sample. ${PAID_TOOL_BILLING}`,
|
|
384
|
+
inputSchema: import_zod.z.object({
|
|
385
|
+
keywords: import_zod.z.array(import_zod.z.string().trim().min(1).max(200)).min(1).max(5).refine(
|
|
386
|
+
(keywords) => new Set(keywords.map((keyword) => keyword.toLowerCase().replace(/\s+/g, " "))).size === keywords.length,
|
|
387
|
+
"Keywords must be distinct."
|
|
388
|
+
).describe("One to five distinct search terms, as people type them into Google. Each is billed separately."),
|
|
389
|
+
domain: import_zod.z.string().trim().max(253).optional().describe("Your site, e.g. example.com. Covers www and subdomains. Omit to get only the top results."),
|
|
390
|
+
url: import_zod.z.string().trim().max(500).optional().describe("Optional page that should rank, as a full URL or a path such as /pricing."),
|
|
391
|
+
competitors: import_zod.z.array(import_zod.z.string().trim().min(1).max(253)).max(5).optional().describe("Up to 5 competitor domains to report positions for."),
|
|
392
|
+
country: import_zod.z.string().trim().max(8).optional().describe('ISO-2 country code of the Google market to check. Defaults to "us".'),
|
|
393
|
+
language: import_zod.z.string().trim().max(8).optional().describe("Optional ISO-2 language code. Defaults to the country's main language."),
|
|
394
|
+
device: import_zod.z.enum(["desktop", "mobile"]).optional().describe("Desktop or mobile results. Defaults to desktop.")
|
|
395
|
+
}),
|
|
396
|
+
execute: async (input) => aivPost("/keywords/rankings", input)
|
|
397
|
+
});
|
|
366
398
|
var aivTrends = (0, import_tools.createTool)({
|
|
367
399
|
id: "cite42_trends",
|
|
368
400
|
mcp: readOnly("Get Google Trends data"),
|
|
@@ -639,6 +671,7 @@ var CITE42_TOOLS = {
|
|
|
639
671
|
cite42_recommendations: aivRecommendations,
|
|
640
672
|
cite42_keywords: aivKeywords,
|
|
641
673
|
cite42_keywords_batch: aivKeywordsBatch,
|
|
674
|
+
cite42_keyword_rankings: aivKeywordRankings,
|
|
642
675
|
cite42_trends: aivTrends,
|
|
643
676
|
cite42_reddit_trends: aivRedditTrends,
|
|
644
677
|
cite42_youtube_trends: aivYoutubeTrends,
|
|
@@ -674,7 +707,7 @@ if (!resolveApiKey()) {
|
|
|
674
707
|
);
|
|
675
708
|
process.exit(1);
|
|
676
709
|
}
|
|
677
|
-
buildCite42Server("0.
|
|
710
|
+
buildCite42Server("0.9.0").startStdio().catch((error) => {
|
|
678
711
|
console.error("[@cite42/mcp] Fatal error:", error);
|
|
679
712
|
process.exit(1);
|
|
680
713
|
});
|
package/dist/stdio.mjs
CHANGED
|
@@ -216,6 +216,15 @@ function optionalShortText(description) {
|
|
|
216
216
|
}
|
|
217
217
|
var modelsInput = z.array(modelEnum).nonempty().optional().describe(MODEL_SELECTION_DESCRIPTION);
|
|
218
218
|
var fullSweepInput = z.boolean().optional().describe(FULL_SWEEP_DESCRIPTION);
|
|
219
|
+
var AI_MARKETS_ENABLED = true;
|
|
220
|
+
var aiMarketInput = AI_MARKETS_ENABLED ? {
|
|
221
|
+
country: z.string().trim().max(8).optional().describe(
|
|
222
|
+
`Optional ISO-2 country to measure from, e.g. "gb". Omit for each surface's default. Gemini has no country setting and ignores it.`
|
|
223
|
+
),
|
|
224
|
+
language: z.string().trim().max(8).optional().describe(
|
|
225
|
+
"Optional ISO-2 language for google_ai_overview and chatgpt_app, which read in it. Needs country; defaults to the country's main language."
|
|
226
|
+
)
|
|
227
|
+
} : {};
|
|
219
228
|
var competitorList = z.array(shortText("Competitor brand/domain name.")).nonempty().max(20);
|
|
220
229
|
async function fetchBalance() {
|
|
221
230
|
const usage = await aivGet("/usage");
|
|
@@ -276,7 +285,8 @@ var aivSearch = createTool({
|
|
|
276
285
|
inputSchema: z.object({
|
|
277
286
|
query: queryText("The concise AI-search/market-research query to run against the selected models."),
|
|
278
287
|
models: modelsInput,
|
|
279
|
-
fullSweep: fullSweepInput
|
|
288
|
+
fullSweep: fullSweepInput,
|
|
289
|
+
...aiMarketInput
|
|
280
290
|
}),
|
|
281
291
|
execute: async (input) => aivPost("/search", input)
|
|
282
292
|
});
|
|
@@ -288,7 +298,8 @@ var aivCitations = createTool({
|
|
|
288
298
|
query: queryText("The concise query to look up cited sources for."),
|
|
289
299
|
url: z.string().trim().max(500).optional().describe("Optional URL to check whether it was cited."),
|
|
290
300
|
models: modelsInput,
|
|
291
|
-
fullSweep: fullSweepInput
|
|
301
|
+
fullSweep: fullSweepInput,
|
|
302
|
+
...aiMarketInput
|
|
292
303
|
}),
|
|
293
304
|
execute: async (input) => aivPost("/citations", input)
|
|
294
305
|
});
|
|
@@ -300,7 +311,8 @@ var aivRankings = createTool({
|
|
|
300
311
|
query: queryText("The concise query to measure brand/competitor visibility on."),
|
|
301
312
|
competitors: competitorList.describe("Brand or domain names to track within the AI-generated answers."),
|
|
302
313
|
models: modelsInput,
|
|
303
|
-
fullSweep: fullSweepInput
|
|
314
|
+
fullSweep: fullSweepInput,
|
|
315
|
+
...aiMarketInput
|
|
304
316
|
}),
|
|
305
317
|
execute: async (input) => aivPost("/rankings", input)
|
|
306
318
|
});
|
|
@@ -313,7 +325,8 @@ var aivCompare = createTool({
|
|
|
313
325
|
brand: shortText("Your brand, ranked alongside the competitors."),
|
|
314
326
|
competitors: z.array(shortText("Competitor brand/domain name.")).nonempty().max(10).describe("Competitor brand/domain names (up to 10) to rank against your brand."),
|
|
315
327
|
models: modelsInput,
|
|
316
|
-
fullSweep: fullSweepInput
|
|
328
|
+
fullSweep: fullSweepInput,
|
|
329
|
+
...aiMarketInput
|
|
317
330
|
}),
|
|
318
331
|
execute: async (input) => aivPost("/compare", input)
|
|
319
332
|
});
|
|
@@ -325,7 +338,8 @@ var aivSentiment = createTool({
|
|
|
325
338
|
query: queryText("The concise query whose answers are scored for brand sentiment."),
|
|
326
339
|
brand: shortText("The brand to score sentiment for in each model answer."),
|
|
327
340
|
models: modelsInput,
|
|
328
|
-
fullSweep: fullSweepInput
|
|
341
|
+
fullSweep: fullSweepInput,
|
|
342
|
+
...aiMarketInput
|
|
329
343
|
}),
|
|
330
344
|
execute: async (input) => aivPost("/sentiment", input)
|
|
331
345
|
});
|
|
@@ -362,6 +376,24 @@ var aivKeywordsBatch = createTool({
|
|
|
362
376
|
}),
|
|
363
377
|
execute: async (input) => aivPost("/keywords/batch", input)
|
|
364
378
|
});
|
|
379
|
+
var aivKeywordRankings = createTool({
|
|
380
|
+
id: "cite42_keyword_rankings",
|
|
381
|
+
mcp: readOnly("Get Google keyword rankings"),
|
|
382
|
+
description: `Where a site ranks in Google organic results (top 100) for one to five keywords in one country, desktop or mobile: position, ranking URL, competitor positions, the top 10 and whether the AI Overview cites the site. Billed per keyword checked; a keyword that fails is free. Each check is one live sample. ${PAID_TOOL_BILLING}`,
|
|
383
|
+
inputSchema: z.object({
|
|
384
|
+
keywords: z.array(z.string().trim().min(1).max(200)).min(1).max(5).refine(
|
|
385
|
+
(keywords) => new Set(keywords.map((keyword) => keyword.toLowerCase().replace(/\s+/g, " "))).size === keywords.length,
|
|
386
|
+
"Keywords must be distinct."
|
|
387
|
+
).describe("One to five distinct search terms, as people type them into Google. Each is billed separately."),
|
|
388
|
+
domain: z.string().trim().max(253).optional().describe("Your site, e.g. example.com. Covers www and subdomains. Omit to get only the top results."),
|
|
389
|
+
url: z.string().trim().max(500).optional().describe("Optional page that should rank, as a full URL or a path such as /pricing."),
|
|
390
|
+
competitors: z.array(z.string().trim().min(1).max(253)).max(5).optional().describe("Up to 5 competitor domains to report positions for."),
|
|
391
|
+
country: z.string().trim().max(8).optional().describe('ISO-2 country code of the Google market to check. Defaults to "us".'),
|
|
392
|
+
language: z.string().trim().max(8).optional().describe("Optional ISO-2 language code. Defaults to the country's main language."),
|
|
393
|
+
device: z.enum(["desktop", "mobile"]).optional().describe("Desktop or mobile results. Defaults to desktop.")
|
|
394
|
+
}),
|
|
395
|
+
execute: async (input) => aivPost("/keywords/rankings", input)
|
|
396
|
+
});
|
|
365
397
|
var aivTrends = createTool({
|
|
366
398
|
id: "cite42_trends",
|
|
367
399
|
mcp: readOnly("Get Google Trends data"),
|
|
@@ -638,6 +670,7 @@ var CITE42_TOOLS = {
|
|
|
638
670
|
cite42_recommendations: aivRecommendations,
|
|
639
671
|
cite42_keywords: aivKeywords,
|
|
640
672
|
cite42_keywords_batch: aivKeywordsBatch,
|
|
673
|
+
cite42_keyword_rankings: aivKeywordRankings,
|
|
641
674
|
cite42_trends: aivTrends,
|
|
642
675
|
cite42_reddit_trends: aivRedditTrends,
|
|
643
676
|
cite42_youtube_trends: aivYoutubeTrends,
|
|
@@ -673,7 +706,7 @@ if (!resolveApiKey()) {
|
|
|
673
706
|
);
|
|
674
707
|
process.exit(1);
|
|
675
708
|
}
|
|
676
|
-
buildCite42Server("0.
|
|
709
|
+
buildCite42Server("0.9.0").startStdio().catch((error) => {
|
|
677
710
|
console.error("[@cite42/mcp] Fatal error:", error);
|
|
678
711
|
process.exit(1);
|
|
679
712
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cite42/mcp",
|
|
3
3
|
"mcpName": "dev.cite42/mcp",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"description": "Cite42 MCP server: AI visibility and SEO data for AI agents. See how the AI models behind ChatGPT, Claude, Perplexity and Gemini, plus Google AI Overviews, mention your brand and which sources they cite, with SEO keyword data, Google, Reddit and YouTube trends, and weekly or monthly trackers that watch a list of prompts over time. Works with Claude Code, Claude Desktop, Codex CLI, Cursor, and any MCP client.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@mastra/core": "^1.68.0",
|
|
28
28
|
"@mastra/mcp": "^1.18.0",
|
|
29
|
-
"zod": "^4.
|
|
29
|
+
"zod": "^4.6.7"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -83,6 +83,10 @@
|
|
|
83
83
|
},
|
|
84
84
|
"overrides": {
|
|
85
85
|
"esbuild": "^0.28.2",
|
|
86
|
-
"@modelcontextprotocol/client": "2.3.1"
|
|
86
|
+
"@modelcontextprotocol/client": "2.3.1",
|
|
87
|
+
"@modelcontextprotocol/server": "2.3.1",
|
|
88
|
+
"@modelcontextprotocol/server-legacy": "2.3.1",
|
|
89
|
+
"@modelcontextprotocol/node": "2.1.1",
|
|
90
|
+
"body-parser@^2.0.0": "^2.4.0"
|
|
87
91
|
}
|
|
88
92
|
}
|