@cite42/mcp 0.3.0 → 0.5.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 +6 -6
- package/dist/stdio.cjs +30 -12
- package/dist/stdio.mjs +30 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Once connected, Claude Code, Claude Desktop, Codex CLI, or Cursor can:
|
|
|
6
6
|
|
|
7
7
|
- **Query AI models** (ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews) and see each model's answer and the sources it cites
|
|
8
8
|
- **Track brand visibility** in AI answers: rankings, head-to-head comparisons, and sentiment
|
|
9
|
-
- **Schedule
|
|
9
|
+
- **Schedule weekly or monthly trackers**: one measurement — rankings, comparisons, citations, or sentiment — over a list of prompts, with setup confirmation and a useful email after every run, then ask your agent for stored history
|
|
10
10
|
- **Pull SEO data**: keyword search volume, CPC, competition, and Google Trends
|
|
11
11
|
- **Mine Reddit and YouTube** for audience questions, pain points, and rising content
|
|
12
12
|
- **Run full research workflows**: content gaps, topic demand, AI prompt maps, competitor analysis, and content briefs in a single call
|
|
@@ -128,7 +128,7 @@ That is the three default surfaces; ask for `fullSweep` to add Claude and Google
|
|
|
128
128
|
|
|
129
129
|
## Tools
|
|
130
130
|
|
|
131
|
-
Cite42 exposes 26 MCP tools: 3 free account tools, 9
|
|
131
|
+
Cite42 exposes 26 MCP tools: 3 free account tools, 9 data tools, 6 research workflows, and 8 tracker tools.
|
|
132
132
|
|
|
133
133
|
### Account & pricing (free)
|
|
134
134
|
|
|
@@ -162,12 +162,12 @@ Cite42 exposes 26 MCP tools: 3 free account tools, 9 primitive data tools, 6 res
|
|
|
162
162
|
|
|
163
163
|
### Trackers
|
|
164
164
|
|
|
165
|
-
- `cite42_tracker_create`: create a draft
|
|
165
|
+
- `cite42_tracker_create`: create a draft weekly or monthly tracker — one measurement applied to a list of prompts. No prompt list yet? Run `cite42_map_ai_prompts` first. Creating a draft is free and does not schedule calls.
|
|
166
166
|
- `cite42_tracker_update`: replace the whole tracker definition — name, cadence, measurement, prompts and configuration. A tracker read returns the same shape, so read it, change what you need, and send it back. Updating is free.
|
|
167
|
-
- `cite42_tracker_activate`: activate or resume recurring runs. You must pass the exact `estimatedCostMicroPerRun` from the latest tracker record as `maxCostMicroPerRun`; activation authorizes billed scheduled runs until the tracker is paused. The response carries the balance, the cost per run and `runsDryAt` — the date the balance stops covering your active trackers — and activation is refused when the balance cannot cover even the next run.
|
|
167
|
+
- `cite42_tracker_activate`: activate or resume recurring runs. You must pass the exact `estimatedCostMicroPerRun` from the latest tracker record as `maxCostMicroPerRun`; activation authorizes billed scheduled runs until the tracker is paused. The response carries the balance, the cost per run and `runsDryAt` — the date the balance stops covering your active trackers — and activation is refused when the balance cannot cover even the next run. When tracker emails are on, activation also sends a setup summary.
|
|
168
168
|
- `cite42_tracker_pause`: stop future scheduled runs while preserving configuration and history. Pausing is free.
|
|
169
169
|
- `cite42_tracker_delete`: permanently delete a draft or paused tracker and its run history. Active trackers must be paused first, and deletion is rejected while a run is queued or running. Financial usage records remain available.
|
|
170
|
-
- `cite42_tracker_run`: queue one manual run of every saved prompt. Each prompt is billed as its own
|
|
170
|
+
- `cite42_tracker_run`: queue one manual run of every saved prompt. Each prompt is billed as its own tool call at the normal rate, and completion sends the same current-results email as a scheduled run—even for a baseline or an unchanged result.
|
|
171
171
|
- `cite42_trackers`: list trackers, schedules, statuses, cost estimates, and last/next run times. Reading the list is free.
|
|
172
172
|
- `cite42_tracker_report`: read bounded stored run history with results, changes, status, sampled time, and costs (latest 8 by default, up to 20). Reading stored reports is free.
|
|
173
173
|
|
|
@@ -184,7 +184,7 @@ npx -y @cite42/mcp --api-key=cite42_live_your_key_here --api-base=https://www.ci
|
|
|
184
184
|
|
|
185
185
|
## Billing
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
Tool and workflow calls consume Cite42 credits from your account. Tracker management and stored-history reads are free; every scheduled or manual tracker run bills one call per saved prompt at the normal rate. Activating or resuming a tracker requires explicit confirmation of the current maximum credits per run and authorizes recurring billed calls until you pause it. Calls fail with a clear error if the API key is missing or credits run out. See [www.cite42.dev/pricing](https://www.cite42.dev/pricing).
|
|
188
188
|
|
|
189
189
|
## Troubleshooting
|
|
190
190
|
|
package/dist/stdio.cjs
CHANGED
|
@@ -17,10 +17,14 @@ function formatCredits(microCredits) {
|
|
|
17
17
|
Number.isInteger(credits) ? { maximumFractionDigits: 0 } : { minimumFractionDigits: 0, maximumFractionDigits: 2 }
|
|
18
18
|
);
|
|
19
19
|
}
|
|
20
|
+
function isTrackerCommitment(billing) {
|
|
21
|
+
return typeof billing.balanceMicro === "number" && typeof billing.costMicroPerRun === "number";
|
|
22
|
+
}
|
|
20
23
|
function toCite42McpResult(value) {
|
|
21
24
|
if (!isJsonObject(value)) return value;
|
|
22
25
|
const { billing, warning, ...result } = value;
|
|
23
26
|
if (!isJsonObject(billing)) return value;
|
|
27
|
+
if (isTrackerCommitment(billing)) return { ...result, billing };
|
|
24
28
|
const cost = isJsonObject(billing.cost) ? billing.cost.microCredits : void 0;
|
|
25
29
|
const balance = isJsonObject(billing.balance) ? billing.balance.microCredits : void 0;
|
|
26
30
|
if (typeof cost !== "number" || !Number.isFinite(cost) || typeof balance !== "number" || !Number.isFinite(balance)) {
|
|
@@ -148,7 +152,8 @@ var FULL_SWEEP_DESCRIPTION = "Query all five AI surfaces instead of the three de
|
|
|
148
152
|
var MCP_USAGE_GUIDANCE = "Covers AI-search, citation, SEO, keyword, trend, and market-research data. If a plan needs more than 20 endpoint calls or may use more than 500 Cite42 credits, estimate the credits and ask the user before continuing. When a result contains cite42Credits, that figure is Cite42 credits, not a model or host balance. Free (0 credits): cite42_credits for the remaining balance, cite42_pricing for exact per-tool prices and cost estimates, cite42_usage for recent calls.";
|
|
149
153
|
var MODEL_PRICING = "Pricing is per selected AI surface. Omitting models queries the three default surfaces (chatgpt, perplexity, gemini); fullSweep: true queries all five, adding claude and google_ai_overview for more credits. Use the models field when the user names a surface or asks to reduce credit use, and call cite42_pricing for exact current rates.";
|
|
150
154
|
var DATA_PRICING = "Data tools have flat per-call prices; call cite42_pricing for exact current rates.";
|
|
151
|
-
var
|
|
155
|
+
var KEYWORDS_PRICING = "Pricing: billed by outcome \u2014 cheapest when the seed has no search volume, more when it has metrics, most with ideas:true. Call cite42_pricing for exact current rates.";
|
|
156
|
+
var WORKFLOW_PRICING = "Pricing: workflow cost is calculated from the tools that run successfully and the selected model rates.";
|
|
152
157
|
function workflowDescription(description) {
|
|
153
158
|
return `${description} ${MCP_USAGE_GUIDANCE} ${MODEL_PRICING} ${DATA_PRICING} ${WORKFLOW_PRICING}`;
|
|
154
159
|
}
|
|
@@ -235,7 +240,7 @@ var aivSearch = (0, import_tools.createTool)({
|
|
|
235
240
|
var aivCitations = (0, import_tools.createTool)({
|
|
236
241
|
id: "cite42_citations",
|
|
237
242
|
mcp: readOnly("Find AI citations"),
|
|
238
|
-
description: `Find which sources
|
|
243
|
+
description: `Find which sources a model's web search surfaces for a query. Aggregates cited URLs across models with per-model counts; optionally checks whether a specific URL is cited. Measures the retrieval corpus behind a prompt \u2014 which domains own your category in AI search, and where your content is missing \u2014 not the citation links a consumer chat UI renders for a logged-in user. ${MODEL_PRICING} ${MCP_USAGE_GUIDANCE}`,
|
|
239
244
|
inputSchema: import_zod.z.object({
|
|
240
245
|
query: queryText("The concise query to look up cited sources for."),
|
|
241
246
|
url: import_zod.z.string().trim().max(500).optional().describe("Optional URL to check whether it was cited."),
|
|
@@ -284,10 +289,13 @@ var aivSentiment = (0, import_tools.createTool)({
|
|
|
284
289
|
var aivKeywords = (0, import_tools.createTool)({
|
|
285
290
|
id: "cite42_keywords",
|
|
286
291
|
mcp: readOnly("Get SEO keyword data"),
|
|
287
|
-
description: `Classic keyword data for a seed term. Omit ideas when the user only needs that seed's monthly search volume, CPC, or competition. Set ideas:true only when the user asks for related, alternative, or long-tail suggestions from provider candidates.
|
|
292
|
+
description: `Classic keyword data for a seed term. Omit ideas when the user only needs that seed's monthly search volume, CPC, or competition. Set ideas:true only when the user asks for related, alternative, or long-tail suggestions from provider candidates. Not a multi-model AI-search query. The reply echoes requestedKeyword and carries status "exact" or "no_data"; when the seed has no search volume, any related term that does appears under alternatives \u2014 never treat an alternative's metrics as the requested keyword's. ${KEYWORDS_PRICING} ${MCP_USAGE_GUIDANCE}`,
|
|
288
293
|
inputSchema: import_zod.z.object({
|
|
289
294
|
seed: queryText("Seed keyword or concise topic to fetch search volume, CPC, and competition for."),
|
|
290
295
|
country: import_zod.z.string().trim().max(8).optional().describe('ISO-2 country code for localized metrics. Defaults to "us".'),
|
|
296
|
+
language: import_zod.z.string().trim().max(8).optional().describe(
|
|
297
|
+
`Optional ISO-2 language code. Defaults to the country's primary search language, so country "de" searches in German. Only multilingual markets accept an override: us (en, es), ca (en, fr), in (en, hi). Every other country has a single search language and rejects anything else.`
|
|
298
|
+
),
|
|
291
299
|
ideas: import_zod.z.boolean().optional().describe(
|
|
292
300
|
"Omit for volume, CPC, and competition on the seed only. Set true only for related, alternative, or long-tail keyword ideas."
|
|
293
301
|
)
|
|
@@ -420,7 +428,7 @@ var aivGenerateContentBrief = (0, import_tools.createTool)({
|
|
|
420
428
|
});
|
|
421
429
|
var trackerIdInput = import_zod.z.string().trim().min(1).max(128).describe("Cite42 tracker ID returned by a tracker management or report tool.");
|
|
422
430
|
var trackerCadenceInput = import_zod.z.object({
|
|
423
|
-
frequency: import_zod.z.enum(["
|
|
431
|
+
frequency: import_zod.z.enum(["weekly", "monthly"]),
|
|
424
432
|
timezone: import_zod.z.string().trim().min(1).max(100).refine((timezone) => {
|
|
425
433
|
try {
|
|
426
434
|
new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
|
|
@@ -430,7 +438,10 @@ var trackerCadenceInput = import_zod.z.object({
|
|
|
430
438
|
}
|
|
431
439
|
}, "Timezone must be a valid IANA timezone.").describe("IANA timezone, for example Europe/London or America/New_York."),
|
|
432
440
|
time: import_zod.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).describe("Local run time in 24-hour HH:mm format."),
|
|
433
|
-
weekday: import_zod.z.number().int().min(0).max(6).optional().describe("Weekly
|
|
441
|
+
weekday: import_zod.z.number().int().min(0).max(6).optional().describe("Weekly trackers only. Day of week, where 0 is Sunday and 6 is Saturday."),
|
|
442
|
+
monthday: import_zod.z.number().int().min(1).max(31).optional().describe(
|
|
443
|
+
`Monthly trackers only. Day of month 1-31; a value past the end of a shorter month runs on that month's last day, so 31 always means "month end".`
|
|
444
|
+
)
|
|
434
445
|
}).superRefine((cadence, context) => {
|
|
435
446
|
if (cadence.frequency === "weekly" && cadence.weekday === void 0) {
|
|
436
447
|
context.addIssue({
|
|
@@ -439,12 +450,19 @@ var trackerCadenceInput = import_zod.z.object({
|
|
|
439
450
|
message: "weekday is required for a weekly tracker"
|
|
440
451
|
});
|
|
441
452
|
}
|
|
453
|
+
if (cadence.frequency === "monthly" && cadence.monthday === void 0) {
|
|
454
|
+
context.addIssue({
|
|
455
|
+
code: "custom",
|
|
456
|
+
path: ["monthday"],
|
|
457
|
+
message: "monthday is required for a monthly tracker"
|
|
458
|
+
});
|
|
459
|
+
}
|
|
442
460
|
});
|
|
443
461
|
var trackerPrimitiveInput = import_zod.z.enum(["rankings", "compare", "citations", "sentiment"]).describe(
|
|
444
462
|
"What to measure on every prompt: rankings (which brands get named), compare (the brand against named competitors), citations (which sources are cited), or sentiment (how one brand is described). One measurement per tracker."
|
|
445
463
|
);
|
|
446
464
|
var trackerPromptsInput = import_zod.z.array(queryText("A prompt to run on every scheduled run.")).min(1).max(25).describe(
|
|
447
|
-
"Prompts to track, up to
|
|
465
|
+
"Prompts to track, up to 30. Each is billed as its own call on every run. Keep the wording stable so runs stay comparable, avoid dates, and do not repeat a prompt."
|
|
448
466
|
);
|
|
449
467
|
var trackerDefinitionFields = {
|
|
450
468
|
name: import_zod.z.string().trim().min(1).max(100).describe("Human-readable tracker name."),
|
|
@@ -464,7 +482,7 @@ var TRACKER_BILLING_DESCRIPTION = "Tracker management and stored-report reads ar
|
|
|
464
482
|
var aivTrackerCreate = (0, import_tools.createTool)({
|
|
465
483
|
id: "cite42_tracker_create",
|
|
466
484
|
mcp: mutation("Create Cite42 tracker draft"),
|
|
467
|
-
description: "Create a draft
|
|
485
|
+
description: "Create a draft weekly or monthly tracker: one measurement \u2014 rankings, compare, citations, or sentiment \u2014 applied to a list of prompts, with the brand, competitors and AI surfaces set once for all of them. When the user has no prompt list yet, run cite42_map_ai_prompts first and track the prompts it recommends. Creation does not start recurring calls. " + TRACKER_BILLING_DESCRIPTION,
|
|
468
486
|
inputSchema: import_zod.z.object(trackerDefinitionFields),
|
|
469
487
|
execute: async (input) => aivPost("/trackers", input)
|
|
470
488
|
});
|
|
@@ -481,7 +499,7 @@ var aivTrackerActivate = (0, import_tools.createTool)({
|
|
|
481
499
|
openWorldHint: true,
|
|
482
500
|
idempotentHint: true
|
|
483
501
|
}),
|
|
484
|
-
description: `Activate or resume recurring
|
|
502
|
+
description: `Activate or resume recurring weekly or monthly tool calls. maxCostMicroPerRun must equal the tracker estimate being accepted; activation authorizes future billed calls until the tracker is paused. The response carries a billing block with the balance, the cost per run, and runsDryAt \u2014 the date the balance stops covering the account's active trackers \u2014 so relay it. When tracker emails are enabled, activation sends a setup summary and every completed run sends current results and suggested next steps, even when nothing changed. Activation is refused when the balance cannot cover even the next run; tell the user to top up at cite42.dev/app/billing. ${TRACKER_BILLING_DESCRIPTION}`,
|
|
485
503
|
inputSchema: import_zod.z.object({
|
|
486
504
|
trackerId: trackerIdInput,
|
|
487
505
|
maxCostMicroPerRun: import_zod.z.number().int().nonnegative().describe("Exact estimatedCostMicroPerRun returned by the latest tracker record.")
|
|
@@ -511,7 +529,7 @@ var aivTrackerRun = (0, import_tools.createTool)({
|
|
|
511
529
|
openWorldHint: true,
|
|
512
530
|
idempotentHint: true
|
|
513
531
|
}),
|
|
514
|
-
description: `Queue one manual run using the tracker\u2019s saved
|
|
532
|
+
description: `Queue one manual run using the tracker\u2019s saved tool inputs. A repeated requestToken returns the same logical run. ${TRACKER_BILLING_DESCRIPTION}`,
|
|
515
533
|
inputSchema: import_zod.z.object({
|
|
516
534
|
trackerId: trackerIdInput,
|
|
517
535
|
requestToken: import_zod.z.string().trim().min(1).max(200).describe("Stable caller-generated token used to deduplicate a retried manual run.")
|
|
@@ -521,14 +539,14 @@ var aivTrackerRun = (0, import_tools.createTool)({
|
|
|
521
539
|
var aivTrackers = (0, import_tools.createTool)({
|
|
522
540
|
id: "cite42_trackers",
|
|
523
541
|
mcp: readOnly("List Cite42 trackers", false),
|
|
524
|
-
description: "List the connected account\u2019s trackers with status, cadence,
|
|
542
|
+
description: "List the connected account\u2019s trackers with status, cadence, tool configuration, cost estimate, accepted per-run maximum, and next/last run times. Free: costs 0 credits.",
|
|
525
543
|
inputSchema: import_zod.z.object({}),
|
|
526
544
|
execute: async () => aivGet("/trackers")
|
|
527
545
|
});
|
|
528
546
|
var aivTrackerReport = (0, import_tools.createTool)({
|
|
529
547
|
id: "cite42_tracker_report",
|
|
530
548
|
mcp: readOnly("Read Cite42 tracker report", false),
|
|
531
|
-
description: "Read bounded stored run history for one tracker, including per-
|
|
549
|
+
description: "Read bounded stored run history for one tracker, including per-tool results, changes from the prior comparable observation, statuses, sampled times, and costs. Free: costs 0 credits.",
|
|
532
550
|
inputSchema: import_zod.z.object({
|
|
533
551
|
trackerId: trackerIdInput,
|
|
534
552
|
limit: import_zod.z.number().int().min(1).max(20).optional().default(8).describe("Most recent runs to return, capped for LLM context.")
|
|
@@ -582,7 +600,7 @@ if (!resolveApiKey()) {
|
|
|
582
600
|
);
|
|
583
601
|
process.exit(1);
|
|
584
602
|
}
|
|
585
|
-
buildCite42Server("0.
|
|
603
|
+
buildCite42Server("0.5.0").startStdio().catch((error) => {
|
|
586
604
|
console.error("[@cite42/mcp] Fatal error:", error);
|
|
587
605
|
process.exit(1);
|
|
588
606
|
});
|
package/dist/stdio.mjs
CHANGED
|
@@ -16,10 +16,14 @@ function formatCredits(microCredits) {
|
|
|
16
16
|
Number.isInteger(credits) ? { maximumFractionDigits: 0 } : { minimumFractionDigits: 0, maximumFractionDigits: 2 }
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
|
+
function isTrackerCommitment(billing) {
|
|
20
|
+
return typeof billing.balanceMicro === "number" && typeof billing.costMicroPerRun === "number";
|
|
21
|
+
}
|
|
19
22
|
function toCite42McpResult(value) {
|
|
20
23
|
if (!isJsonObject(value)) return value;
|
|
21
24
|
const { billing, warning, ...result } = value;
|
|
22
25
|
if (!isJsonObject(billing)) return value;
|
|
26
|
+
if (isTrackerCommitment(billing)) return { ...result, billing };
|
|
23
27
|
const cost = isJsonObject(billing.cost) ? billing.cost.microCredits : void 0;
|
|
24
28
|
const balance = isJsonObject(billing.balance) ? billing.balance.microCredits : void 0;
|
|
25
29
|
if (typeof cost !== "number" || !Number.isFinite(cost) || typeof balance !== "number" || !Number.isFinite(balance)) {
|
|
@@ -147,7 +151,8 @@ var FULL_SWEEP_DESCRIPTION = "Query all five AI surfaces instead of the three de
|
|
|
147
151
|
var MCP_USAGE_GUIDANCE = "Covers AI-search, citation, SEO, keyword, trend, and market-research data. If a plan needs more than 20 endpoint calls or may use more than 500 Cite42 credits, estimate the credits and ask the user before continuing. When a result contains cite42Credits, that figure is Cite42 credits, not a model or host balance. Free (0 credits): cite42_credits for the remaining balance, cite42_pricing for exact per-tool prices and cost estimates, cite42_usage for recent calls.";
|
|
148
152
|
var MODEL_PRICING = "Pricing is per selected AI surface. Omitting models queries the three default surfaces (chatgpt, perplexity, gemini); fullSweep: true queries all five, adding claude and google_ai_overview for more credits. Use the models field when the user names a surface or asks to reduce credit use, and call cite42_pricing for exact current rates.";
|
|
149
153
|
var DATA_PRICING = "Data tools have flat per-call prices; call cite42_pricing for exact current rates.";
|
|
150
|
-
var
|
|
154
|
+
var KEYWORDS_PRICING = "Pricing: billed by outcome \u2014 cheapest when the seed has no search volume, more when it has metrics, most with ideas:true. Call cite42_pricing for exact current rates.";
|
|
155
|
+
var WORKFLOW_PRICING = "Pricing: workflow cost is calculated from the tools that run successfully and the selected model rates.";
|
|
151
156
|
function workflowDescription(description) {
|
|
152
157
|
return `${description} ${MCP_USAGE_GUIDANCE} ${MODEL_PRICING} ${DATA_PRICING} ${WORKFLOW_PRICING}`;
|
|
153
158
|
}
|
|
@@ -234,7 +239,7 @@ var aivSearch = createTool({
|
|
|
234
239
|
var aivCitations = createTool({
|
|
235
240
|
id: "cite42_citations",
|
|
236
241
|
mcp: readOnly("Find AI citations"),
|
|
237
|
-
description: `Find which sources
|
|
242
|
+
description: `Find which sources a model's web search surfaces for a query. Aggregates cited URLs across models with per-model counts; optionally checks whether a specific URL is cited. Measures the retrieval corpus behind a prompt \u2014 which domains own your category in AI search, and where your content is missing \u2014 not the citation links a consumer chat UI renders for a logged-in user. ${MODEL_PRICING} ${MCP_USAGE_GUIDANCE}`,
|
|
238
243
|
inputSchema: z.object({
|
|
239
244
|
query: queryText("The concise query to look up cited sources for."),
|
|
240
245
|
url: z.string().trim().max(500).optional().describe("Optional URL to check whether it was cited."),
|
|
@@ -283,10 +288,13 @@ var aivSentiment = createTool({
|
|
|
283
288
|
var aivKeywords = createTool({
|
|
284
289
|
id: "cite42_keywords",
|
|
285
290
|
mcp: readOnly("Get SEO keyword data"),
|
|
286
|
-
description: `Classic keyword data for a seed term. Omit ideas when the user only needs that seed's monthly search volume, CPC, or competition. Set ideas:true only when the user asks for related, alternative, or long-tail suggestions from provider candidates.
|
|
291
|
+
description: `Classic keyword data for a seed term. Omit ideas when the user only needs that seed's monthly search volume, CPC, or competition. Set ideas:true only when the user asks for related, alternative, or long-tail suggestions from provider candidates. Not a multi-model AI-search query. The reply echoes requestedKeyword and carries status "exact" or "no_data"; when the seed has no search volume, any related term that does appears under alternatives \u2014 never treat an alternative's metrics as the requested keyword's. ${KEYWORDS_PRICING} ${MCP_USAGE_GUIDANCE}`,
|
|
287
292
|
inputSchema: z.object({
|
|
288
293
|
seed: queryText("Seed keyword or concise topic to fetch search volume, CPC, and competition for."),
|
|
289
294
|
country: z.string().trim().max(8).optional().describe('ISO-2 country code for localized metrics. Defaults to "us".'),
|
|
295
|
+
language: z.string().trim().max(8).optional().describe(
|
|
296
|
+
`Optional ISO-2 language code. Defaults to the country's primary search language, so country "de" searches in German. Only multilingual markets accept an override: us (en, es), ca (en, fr), in (en, hi). Every other country has a single search language and rejects anything else.`
|
|
297
|
+
),
|
|
290
298
|
ideas: z.boolean().optional().describe(
|
|
291
299
|
"Omit for volume, CPC, and competition on the seed only. Set true only for related, alternative, or long-tail keyword ideas."
|
|
292
300
|
)
|
|
@@ -419,7 +427,7 @@ var aivGenerateContentBrief = createTool({
|
|
|
419
427
|
});
|
|
420
428
|
var trackerIdInput = z.string().trim().min(1).max(128).describe("Cite42 tracker ID returned by a tracker management or report tool.");
|
|
421
429
|
var trackerCadenceInput = z.object({
|
|
422
|
-
frequency: z.enum(["
|
|
430
|
+
frequency: z.enum(["weekly", "monthly"]),
|
|
423
431
|
timezone: z.string().trim().min(1).max(100).refine((timezone) => {
|
|
424
432
|
try {
|
|
425
433
|
new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
|
|
@@ -429,7 +437,10 @@ var trackerCadenceInput = z.object({
|
|
|
429
437
|
}
|
|
430
438
|
}, "Timezone must be a valid IANA timezone.").describe("IANA timezone, for example Europe/London or America/New_York."),
|
|
431
439
|
time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).describe("Local run time in 24-hour HH:mm format."),
|
|
432
|
-
weekday: z.number().int().min(0).max(6).optional().describe("Weekly
|
|
440
|
+
weekday: z.number().int().min(0).max(6).optional().describe("Weekly trackers only. Day of week, where 0 is Sunday and 6 is Saturday."),
|
|
441
|
+
monthday: z.number().int().min(1).max(31).optional().describe(
|
|
442
|
+
`Monthly trackers only. Day of month 1-31; a value past the end of a shorter month runs on that month's last day, so 31 always means "month end".`
|
|
443
|
+
)
|
|
433
444
|
}).superRefine((cadence, context) => {
|
|
434
445
|
if (cadence.frequency === "weekly" && cadence.weekday === void 0) {
|
|
435
446
|
context.addIssue({
|
|
@@ -438,12 +449,19 @@ var trackerCadenceInput = z.object({
|
|
|
438
449
|
message: "weekday is required for a weekly tracker"
|
|
439
450
|
});
|
|
440
451
|
}
|
|
452
|
+
if (cadence.frequency === "monthly" && cadence.monthday === void 0) {
|
|
453
|
+
context.addIssue({
|
|
454
|
+
code: "custom",
|
|
455
|
+
path: ["monthday"],
|
|
456
|
+
message: "monthday is required for a monthly tracker"
|
|
457
|
+
});
|
|
458
|
+
}
|
|
441
459
|
});
|
|
442
460
|
var trackerPrimitiveInput = z.enum(["rankings", "compare", "citations", "sentiment"]).describe(
|
|
443
461
|
"What to measure on every prompt: rankings (which brands get named), compare (the brand against named competitors), citations (which sources are cited), or sentiment (how one brand is described). One measurement per tracker."
|
|
444
462
|
);
|
|
445
463
|
var trackerPromptsInput = z.array(queryText("A prompt to run on every scheduled run.")).min(1).max(25).describe(
|
|
446
|
-
"Prompts to track, up to
|
|
464
|
+
"Prompts to track, up to 30. Each is billed as its own call on every run. Keep the wording stable so runs stay comparable, avoid dates, and do not repeat a prompt."
|
|
447
465
|
);
|
|
448
466
|
var trackerDefinitionFields = {
|
|
449
467
|
name: z.string().trim().min(1).max(100).describe("Human-readable tracker name."),
|
|
@@ -463,7 +481,7 @@ var TRACKER_BILLING_DESCRIPTION = "Tracker management and stored-report reads ar
|
|
|
463
481
|
var aivTrackerCreate = createTool({
|
|
464
482
|
id: "cite42_tracker_create",
|
|
465
483
|
mcp: mutation("Create Cite42 tracker draft"),
|
|
466
|
-
description: "Create a draft
|
|
484
|
+
description: "Create a draft weekly or monthly tracker: one measurement \u2014 rankings, compare, citations, or sentiment \u2014 applied to a list of prompts, with the brand, competitors and AI surfaces set once for all of them. When the user has no prompt list yet, run cite42_map_ai_prompts first and track the prompts it recommends. Creation does not start recurring calls. " + TRACKER_BILLING_DESCRIPTION,
|
|
467
485
|
inputSchema: z.object(trackerDefinitionFields),
|
|
468
486
|
execute: async (input) => aivPost("/trackers", input)
|
|
469
487
|
});
|
|
@@ -480,7 +498,7 @@ var aivTrackerActivate = createTool({
|
|
|
480
498
|
openWorldHint: true,
|
|
481
499
|
idempotentHint: true
|
|
482
500
|
}),
|
|
483
|
-
description: `Activate or resume recurring
|
|
501
|
+
description: `Activate or resume recurring weekly or monthly tool calls. maxCostMicroPerRun must equal the tracker estimate being accepted; activation authorizes future billed calls until the tracker is paused. The response carries a billing block with the balance, the cost per run, and runsDryAt \u2014 the date the balance stops covering the account's active trackers \u2014 so relay it. When tracker emails are enabled, activation sends a setup summary and every completed run sends current results and suggested next steps, even when nothing changed. Activation is refused when the balance cannot cover even the next run; tell the user to top up at cite42.dev/app/billing. ${TRACKER_BILLING_DESCRIPTION}`,
|
|
484
502
|
inputSchema: z.object({
|
|
485
503
|
trackerId: trackerIdInput,
|
|
486
504
|
maxCostMicroPerRun: z.number().int().nonnegative().describe("Exact estimatedCostMicroPerRun returned by the latest tracker record.")
|
|
@@ -510,7 +528,7 @@ var aivTrackerRun = createTool({
|
|
|
510
528
|
openWorldHint: true,
|
|
511
529
|
idempotentHint: true
|
|
512
530
|
}),
|
|
513
|
-
description: `Queue one manual run using the tracker\u2019s saved
|
|
531
|
+
description: `Queue one manual run using the tracker\u2019s saved tool inputs. A repeated requestToken returns the same logical run. ${TRACKER_BILLING_DESCRIPTION}`,
|
|
514
532
|
inputSchema: z.object({
|
|
515
533
|
trackerId: trackerIdInput,
|
|
516
534
|
requestToken: z.string().trim().min(1).max(200).describe("Stable caller-generated token used to deduplicate a retried manual run.")
|
|
@@ -520,14 +538,14 @@ var aivTrackerRun = createTool({
|
|
|
520
538
|
var aivTrackers = createTool({
|
|
521
539
|
id: "cite42_trackers",
|
|
522
540
|
mcp: readOnly("List Cite42 trackers", false),
|
|
523
|
-
description: "List the connected account\u2019s trackers with status, cadence,
|
|
541
|
+
description: "List the connected account\u2019s trackers with status, cadence, tool configuration, cost estimate, accepted per-run maximum, and next/last run times. Free: costs 0 credits.",
|
|
524
542
|
inputSchema: z.object({}),
|
|
525
543
|
execute: async () => aivGet("/trackers")
|
|
526
544
|
});
|
|
527
545
|
var aivTrackerReport = createTool({
|
|
528
546
|
id: "cite42_tracker_report",
|
|
529
547
|
mcp: readOnly("Read Cite42 tracker report", false),
|
|
530
|
-
description: "Read bounded stored run history for one tracker, including per-
|
|
548
|
+
description: "Read bounded stored run history for one tracker, including per-tool results, changes from the prior comparable observation, statuses, sampled times, and costs. Free: costs 0 credits.",
|
|
531
549
|
inputSchema: z.object({
|
|
532
550
|
trackerId: trackerIdInput,
|
|
533
551
|
limit: z.number().int().min(1).max(20).optional().default(8).describe("Most recent runs to return, capped for LLM context.")
|
|
@@ -581,7 +599,7 @@ if (!resolveApiKey()) {
|
|
|
581
599
|
);
|
|
582
600
|
process.exit(1);
|
|
583
601
|
}
|
|
584
|
-
buildCite42Server("0.
|
|
602
|
+
buildCite42Server("0.5.0").startStdio().catch((error) => {
|
|
585
603
|
console.error("[@cite42/mcp] Fatal error:", error);
|
|
586
604
|
process.exit(1);
|
|
587
605
|
});
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cite42/mcp",
|
|
3
3
|
"mcpName": "dev.cite42/mcp",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "Cite42 MCP server: query ChatGPT, Claude, Perplexity
|
|
4
|
+
"version": "0.5.0",
|
|
5
|
+
"description": "Cite42 MCP server: query the models behind ChatGPT, Claude, Perplexity & Gemini, plus Google AI Overviews, for brand rankings, AI citations, SEO keyword data, and Reddit/YouTube trends, and schedule 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",
|
|
8
8
|
"bin": {
|