@cite42/mcp 0.1.16 → 0.1.17

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 CHANGED
@@ -6,6 +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 daily or weekly trackers** for rankings, comparisons, citations, and sentiment, then ask your agent for stored run history
9
10
  - **Pull SEO data**: keyword search volume, CPC, competition, and Google Trends
10
11
  - **Mine Reddit and YouTube** for audience questions, pain points, and rising content
11
12
  - **Run full research workflows**: content gaps, topic demand, AI prompt maps, competitor analysis, and content briefs in a single call
@@ -91,7 +92,7 @@ You do not need to keep `npx -y @cite42/mcp` running in a separate terminal. Loc
91
92
  - **Claude Code:** run `claude mcp list` and check that `cite42` shows as ✔ connected. Or type `/mcp` inside a session.
92
93
  - **Claude Desktop:** open **Settings → Connectors** and confirm Cite42 is connected.
93
94
  - **Codex CLI:** run `codex mcp list`.
94
- - **Cursor:** look for `cite42` in the MCP/tools indicator. 15 tools should be listed.
95
+ - **Cursor:** look for `cite42` in the MCP/tools indicator. 26 tools should be listed.
95
96
 
96
97
  If it doesn't appear, see [Troubleshooting](#troubleshooting).
97
98
 
@@ -104,6 +105,7 @@ After connecting or restarting, just ask in plain language. Your agent picks the
104
105
  - *"Get search volume, CPC, and related keywords for 'ai seo tools'."*
105
106
  - *"What are people on Reddit complaining about regarding email marketing tools?"*
106
107
  - *"Run a content brief for the topic 'ai website builder'."*
108
+ - *"Create a weekly Cite42 tracker for our rankings, citations, and sentiment. Show me the estimated credits per run before activating it."*
107
109
 
108
110
  ### Example: what a session looks like
109
111
 
@@ -124,7 +126,15 @@ After connecting or restarting, just ask in plain language. Your agent picks the
124
126
 
125
127
  The exact brands and sources change by query and model. A good result should show the tool used, model/source evidence, and a short summary you can act on.
126
128
 
127
- ## Endpoint tools
129
+ ## Tools
130
+
131
+ Cite42 exposes 26 MCP tools: 3 free account tools, 9 primitive data tools, 6 research workflows, and 8 tracker tools.
132
+
133
+ ### Account & pricing (free)
134
+
135
+ - `cite42_credits`: check the connected account's remaining Cite42 credit balance.
136
+ - `cite42_pricing`: get current per-tool prices and estimate a planned set of calls.
137
+ - `cite42_usage`: read recent call status and cost together with the remaining balance.
128
138
 
129
139
  ### AI search visibility
130
140
 
@@ -150,6 +160,17 @@ The exact brands and sources change by query and model. A good result should sho
150
160
  - `cite42_find_ai_citation_gaps`: find queries where AI answers cite competitors but not your brand, domain, or URL.
151
161
  - `cite42_generate_content_brief`: collect AI answers, citations, keyword demand, and social signals into brief-ready data.
152
162
 
163
+ ### Trackers
164
+
165
+ - `cite42_tracker_create`: create a draft daily or weekly tracker from saved rankings, compare, citations, and sentiment inputs. Creating a draft is free and does not schedule calls.
166
+ - `cite42_tracker_update`: replace a tracker's name, cadence, and saved primitive inputs. Updating configuration 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.
168
+ - `cite42_tracker_pause`: stop future scheduled runs while preserving configuration and history. Pausing is free.
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 from the saved primitive inputs. The underlying primitive calls are billed at their normal rates.
171
+ - `cite42_trackers`: list trackers, schedules, statuses, cost estimates, and last/next run times. Reading the list is free.
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
+
153
174
  ## Configuration
154
175
 
155
176
  - `CITE42_API_KEY`: required. Your API key from [www.cite42.dev/app/keys](https://www.cite42.dev/app/keys).
@@ -163,7 +184,7 @@ npx -y @cite42/mcp --api-key=cite42_live_your_key_here --api-base=https://www.ci
163
184
 
164
185
  ## Billing
165
186
 
166
- Tool calls consume Cite42 credits from your account. 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).
187
+ Primitive and workflow calls consume Cite42 credits from your account. Tracker management and stored-history reads are free; every scheduled or manual tracker run bills its saved primitive calls at their normal rates. 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).
167
188
 
168
189
  ## Troubleshooting
169
190
 
package/dist/stdio.cjs CHANGED
@@ -87,9 +87,27 @@ function getBaseUrl() {
87
87
  return readFlag("api-base") ?? process.env.CITE42_API_BASE ?? DEFAULT_BASE_URL;
88
88
  }
89
89
  async function aivPost(path, body) {
90
+ return aivWrite("POST", path, body);
91
+ }
92
+ async function aivPatch(path, body) {
93
+ return aivWrite("PATCH", path, body);
94
+ }
95
+ async function aivDelete(path) {
96
+ const url = `${getBaseUrl()}${path.startsWith("/") ? path : `/${path}`}`;
97
+ const res = await fetch(url, {
98
+ method: "DELETE",
99
+ headers: { Authorization: `Bearer ${getApiKey()}` }
100
+ });
101
+ if (!res.ok) {
102
+ const body = await res.text();
103
+ throw new Error(errorMessageForMcp(res.status, path, body));
104
+ }
105
+ return toCite42McpResult(await res.json());
106
+ }
107
+ async function aivWrite(method, path, body) {
90
108
  const url = `${getBaseUrl()}${path.startsWith("/") ? path : `/${path}`}`;
91
109
  const res = await fetch(url, {
92
- method: "POST",
110
+ method,
93
111
  headers: {
94
112
  "Content-Type": "application/json",
95
113
  Authorization: `Bearer ${getApiKey()}`
@@ -136,6 +154,17 @@ function workflowDescription(description) {
136
154
  function readOnly(title, openWorldHint = true) {
137
155
  return { annotations: { title, readOnlyHint: true, openWorldHint } };
138
156
  }
157
+ function mutation(title, options = {}) {
158
+ return {
159
+ annotations: {
160
+ title,
161
+ readOnlyHint: false,
162
+ destructiveHint: options.destructiveHint ?? false,
163
+ openWorldHint: options.openWorldHint ?? false,
164
+ ...options.idempotentHint === void 0 ? {} : { idempotentHint: options.idempotentHint }
165
+ }
166
+ };
167
+ }
139
168
  function queryText(description) {
140
169
  return import_zod.z.string().trim().min(1).max(QUERY_MAX_CHARS).describe(description);
141
170
  }
@@ -381,6 +410,143 @@ var aivGenerateContentBrief = (0, import_tools.createTool)({
381
410
  }),
382
411
  execute: async (input) => aivPost("/workflows/content-brief", input)
383
412
  });
413
+ var trackerIdInput = import_zod.z.string().trim().min(1).max(128).describe("Cite42 tracker ID returned by a tracker management or report tool.");
414
+ var trackerCadenceInput = import_zod.z.object({
415
+ frequency: import_zod.z.enum(["daily", "weekly"]),
416
+ timezone: import_zod.z.string().trim().min(1).max(100).refine((timezone) => {
417
+ try {
418
+ new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
419
+ return true;
420
+ } catch {
421
+ return false;
422
+ }
423
+ }, "Timezone must be a valid IANA timezone.").describe("IANA timezone, for example Europe/London or America/New_York."),
424
+ time: import_zod.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).describe("Local run time in 24-hour HH:mm format."),
425
+ weekday: import_zod.z.number().int().min(0).max(6).optional().describe("Weekly day, where 0 is Sunday and 6 is Saturday.")
426
+ }).superRefine((cadence, context) => {
427
+ if (cadence.frequency === "weekly" && cadence.weekday === void 0) {
428
+ context.addIssue({
429
+ code: "custom",
430
+ path: ["weekday"],
431
+ message: "weekday is required for a weekly tracker"
432
+ });
433
+ }
434
+ });
435
+ var trackerItemInput = import_zod.z.discriminatedUnion("primitive", [
436
+ import_zod.z.object({
437
+ primitive: import_zod.z.literal("rankings"),
438
+ input: import_zod.z.object({
439
+ query: queryText("Prompt to measure brand visibility for."),
440
+ competitors: competitorList,
441
+ models: modelsInput
442
+ })
443
+ }),
444
+ import_zod.z.object({
445
+ primitive: import_zod.z.literal("compare"),
446
+ input: import_zod.z.object({
447
+ query: queryText("Prompt to compare the brand and competitors for."),
448
+ brand: shortText("Primary brand to compare."),
449
+ competitors: import_zod.z.array(shortText("Competitor brand/domain name.")).nonempty().max(10),
450
+ models: modelsInput
451
+ })
452
+ }),
453
+ import_zod.z.object({
454
+ primitive: import_zod.z.literal("citations"),
455
+ input: import_zod.z.object({
456
+ query: queryText("Prompt whose cited sources should be tracked."),
457
+ url: import_zod.z.string().trim().max(500).optional(),
458
+ models: modelsInput
459
+ })
460
+ }),
461
+ import_zod.z.object({
462
+ primitive: import_zod.z.literal("sentiment"),
463
+ input: import_zod.z.object({
464
+ query: queryText("Prompt whose brand sentiment should be tracked."),
465
+ brand: shortText("Brand whose sentiment should be scored."),
466
+ models: modelsInput
467
+ })
468
+ })
469
+ ]);
470
+ var trackerDefinitionFields = {
471
+ name: import_zod.z.string().trim().min(1).max(100),
472
+ cadence: trackerCadenceInput,
473
+ items: import_zod.z.array(trackerItemInput).min(1).max(25).describe("Primitive calls to execute and store on each scheduled run.")
474
+ };
475
+ var TRACKER_BILLING_DESCRIPTION = "Tracker management and stored-report reads are free. Each scheduled or manual run bills the underlying primitive calls at their normal per-model rates; the activation response and tracker record expose the accepted maximum cost per run.";
476
+ var aivTrackerCreate = (0, import_tools.createTool)({
477
+ id: "cite42_tracker_create",
478
+ mcp: mutation("Create Cite42 tracker draft"),
479
+ description: `Create a draft daily or weekly tracker from ordinary rankings, compare, citations, and sentiment primitive inputs. Creation does not start recurring calls. ${TRACKER_BILLING_DESCRIPTION}`,
480
+ inputSchema: import_zod.z.object(trackerDefinitionFields),
481
+ execute: async (input) => aivPost("/trackers", input)
482
+ });
483
+ var aivTrackerUpdate = (0, import_tools.createTool)({
484
+ id: "cite42_tracker_update",
485
+ mcp: mutation("Update Cite42 tracker", { destructiveHint: true }),
486
+ description: `Replace a tracker configuration with a validated name, cadence, and primitive item set. An edit returns the tracker to draft so its new recurring cost can be confirmed. ${TRACKER_BILLING_DESCRIPTION}`,
487
+ inputSchema: import_zod.z.object({ trackerId: trackerIdInput, ...trackerDefinitionFields }),
488
+ execute: async ({ trackerId, ...input }) => aivPatch(`/trackers/${encodeURIComponent(trackerId)}`, input)
489
+ });
490
+ var aivTrackerActivate = (0, import_tools.createTool)({
491
+ id: "cite42_tracker_activate",
492
+ mcp: mutation("Activate Cite42 tracker", {
493
+ openWorldHint: true,
494
+ idempotentHint: true
495
+ }),
496
+ description: `Activate or resume recurring daily or weekly primitive calls. maxCostMicroPerRun must equal the tracker estimate being accepted; activation authorizes future billed calls until the tracker is paused. ${TRACKER_BILLING_DESCRIPTION}`,
497
+ inputSchema: import_zod.z.object({
498
+ trackerId: trackerIdInput,
499
+ maxCostMicroPerRun: import_zod.z.number().int().nonnegative().describe("Exact estimatedCostMicroPerRun returned by the latest tracker record.")
500
+ }),
501
+ execute: async ({ trackerId, maxCostMicroPerRun }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/activate`, { maxCostMicroPerRun })
502
+ });
503
+ var aivTrackerPause = (0, import_tools.createTool)({
504
+ id: "cite42_tracker_pause",
505
+ mcp: mutation("Pause Cite42 tracker", { idempotentHint: true }),
506
+ description: "Pause future recurring calls for a tracker while preserving its configuration and stored run history. Free: costs 0 credits.",
507
+ inputSchema: import_zod.z.object({ trackerId: trackerIdInput }),
508
+ execute: async ({ trackerId }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/pause`, {})
509
+ });
510
+ var aivTrackerDelete = (0, import_tools.createTool)({
511
+ id: "cite42_tracker_delete",
512
+ mcp: mutation("Permanently delete Cite42 tracker", {
513
+ destructiveHint: true,
514
+ idempotentHint: true
515
+ }),
516
+ description: "Permanently delete a draft or paused tracker, including its saved configuration and run history. Active trackers must be paused first, and deletion is rejected while a run is queued or running. Financial usage and credit ledger records are retained. Free: costs 0 credits.",
517
+ inputSchema: import_zod.z.object({ trackerId: trackerIdInput }),
518
+ execute: async ({ trackerId }) => aivDelete(`/trackers/${encodeURIComponent(trackerId)}`)
519
+ });
520
+ var aivTrackerRun = (0, import_tools.createTool)({
521
+ id: "cite42_tracker_run",
522
+ mcp: mutation("Run Cite42 tracker now", {
523
+ openWorldHint: true,
524
+ idempotentHint: true
525
+ }),
526
+ description: `Queue one manual run using the tracker\u2019s saved primitive inputs. A repeated requestToken returns the same logical run. ${TRACKER_BILLING_DESCRIPTION}`,
527
+ inputSchema: import_zod.z.object({
528
+ trackerId: trackerIdInput,
529
+ requestToken: import_zod.z.string().trim().min(1).max(200).describe("Stable caller-generated token used to deduplicate a retried manual run.")
530
+ }),
531
+ execute: async ({ trackerId, requestToken }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/runs`, { requestToken })
532
+ });
533
+ var aivTrackers = (0, import_tools.createTool)({
534
+ id: "cite42_trackers",
535
+ mcp: readOnly("List Cite42 trackers", false),
536
+ description: "List the connected account\u2019s trackers with status, cadence, primitive configuration, cost estimate, accepted per-run maximum, and next/last run times. Free: costs 0 credits.",
537
+ inputSchema: import_zod.z.object({}),
538
+ execute: async () => aivGet("/trackers")
539
+ });
540
+ var aivTrackerReport = (0, import_tools.createTool)({
541
+ id: "cite42_tracker_report",
542
+ mcp: readOnly("Read Cite42 tracker report", false),
543
+ description: "Read bounded stored run history for one tracker, including per-primitive results, changes from the prior comparable observation, statuses, sampled times, and costs. Free: costs 0 credits.",
544
+ inputSchema: import_zod.z.object({
545
+ trackerId: trackerIdInput,
546
+ limit: import_zod.z.number().int().min(1).max(20).optional().default(8).describe("Most recent runs to return, capped for LLM context.")
547
+ }),
548
+ execute: async ({ trackerId, limit }) => aivGet(`/trackers/${encodeURIComponent(trackerId)}/report?limit=${limit}`)
549
+ });
384
550
 
385
551
  // src/server.ts
386
552
  var CITE42_TOOLS = {
@@ -401,7 +567,15 @@ var CITE42_TOOLS = {
401
567
  cite42_map_ai_prompts: aivMapAiPrompts,
402
568
  cite42_analyze_competitor_content: aivAnalyzeCompetitorContent,
403
569
  cite42_find_ai_citation_gaps: aivFindAiCitationGaps,
404
- cite42_generate_content_brief: aivGenerateContentBrief
570
+ cite42_generate_content_brief: aivGenerateContentBrief,
571
+ cite42_tracker_create: aivTrackerCreate,
572
+ cite42_tracker_update: aivTrackerUpdate,
573
+ cite42_tracker_activate: aivTrackerActivate,
574
+ cite42_tracker_pause: aivTrackerPause,
575
+ cite42_tracker_delete: aivTrackerDelete,
576
+ cite42_tracker_run: aivTrackerRun,
577
+ cite42_trackers: aivTrackers,
578
+ cite42_tracker_report: aivTrackerReport
405
579
  };
406
580
  function buildCite42Server(version) {
407
581
  return new import_mcp.MCPServer({
@@ -420,7 +594,7 @@ if (!resolveApiKey()) {
420
594
  );
421
595
  process.exit(1);
422
596
  }
423
- buildCite42Server("0.1.16").startStdio().catch((error) => {
597
+ buildCite42Server("0.1.17").startStdio().catch((error) => {
424
598
  console.error("[@cite42/mcp] Fatal error:", error);
425
599
  process.exit(1);
426
600
  });
package/dist/stdio.mjs CHANGED
@@ -86,9 +86,27 @@ function getBaseUrl() {
86
86
  return readFlag("api-base") ?? process.env.CITE42_API_BASE ?? DEFAULT_BASE_URL;
87
87
  }
88
88
  async function aivPost(path, body) {
89
+ return aivWrite("POST", path, body);
90
+ }
91
+ async function aivPatch(path, body) {
92
+ return aivWrite("PATCH", path, body);
93
+ }
94
+ async function aivDelete(path) {
95
+ const url = `${getBaseUrl()}${path.startsWith("/") ? path : `/${path}`}`;
96
+ const res = await fetch(url, {
97
+ method: "DELETE",
98
+ headers: { Authorization: `Bearer ${getApiKey()}` }
99
+ });
100
+ if (!res.ok) {
101
+ const body = await res.text();
102
+ throw new Error(errorMessageForMcp(res.status, path, body));
103
+ }
104
+ return toCite42McpResult(await res.json());
105
+ }
106
+ async function aivWrite(method, path, body) {
89
107
  const url = `${getBaseUrl()}${path.startsWith("/") ? path : `/${path}`}`;
90
108
  const res = await fetch(url, {
91
- method: "POST",
109
+ method,
92
110
  headers: {
93
111
  "Content-Type": "application/json",
94
112
  Authorization: `Bearer ${getApiKey()}`
@@ -135,6 +153,17 @@ function workflowDescription(description) {
135
153
  function readOnly(title, openWorldHint = true) {
136
154
  return { annotations: { title, readOnlyHint: true, openWorldHint } };
137
155
  }
156
+ function mutation(title, options = {}) {
157
+ return {
158
+ annotations: {
159
+ title,
160
+ readOnlyHint: false,
161
+ destructiveHint: options.destructiveHint ?? false,
162
+ openWorldHint: options.openWorldHint ?? false,
163
+ ...options.idempotentHint === void 0 ? {} : { idempotentHint: options.idempotentHint }
164
+ }
165
+ };
166
+ }
138
167
  function queryText(description) {
139
168
  return z.string().trim().min(1).max(QUERY_MAX_CHARS).describe(description);
140
169
  }
@@ -380,6 +409,143 @@ var aivGenerateContentBrief = createTool({
380
409
  }),
381
410
  execute: async (input) => aivPost("/workflows/content-brief", input)
382
411
  });
412
+ var trackerIdInput = z.string().trim().min(1).max(128).describe("Cite42 tracker ID returned by a tracker management or report tool.");
413
+ var trackerCadenceInput = z.object({
414
+ frequency: z.enum(["daily", "weekly"]),
415
+ timezone: z.string().trim().min(1).max(100).refine((timezone) => {
416
+ try {
417
+ new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
418
+ return true;
419
+ } catch {
420
+ return false;
421
+ }
422
+ }, "Timezone must be a valid IANA timezone.").describe("IANA timezone, for example Europe/London or America/New_York."),
423
+ time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).describe("Local run time in 24-hour HH:mm format."),
424
+ weekday: z.number().int().min(0).max(6).optional().describe("Weekly day, where 0 is Sunday and 6 is Saturday.")
425
+ }).superRefine((cadence, context) => {
426
+ if (cadence.frequency === "weekly" && cadence.weekday === void 0) {
427
+ context.addIssue({
428
+ code: "custom",
429
+ path: ["weekday"],
430
+ message: "weekday is required for a weekly tracker"
431
+ });
432
+ }
433
+ });
434
+ var trackerItemInput = z.discriminatedUnion("primitive", [
435
+ z.object({
436
+ primitive: z.literal("rankings"),
437
+ input: z.object({
438
+ query: queryText("Prompt to measure brand visibility for."),
439
+ competitors: competitorList,
440
+ models: modelsInput
441
+ })
442
+ }),
443
+ z.object({
444
+ primitive: z.literal("compare"),
445
+ input: z.object({
446
+ query: queryText("Prompt to compare the brand and competitors for."),
447
+ brand: shortText("Primary brand to compare."),
448
+ competitors: z.array(shortText("Competitor brand/domain name.")).nonempty().max(10),
449
+ models: modelsInput
450
+ })
451
+ }),
452
+ z.object({
453
+ primitive: z.literal("citations"),
454
+ input: z.object({
455
+ query: queryText("Prompt whose cited sources should be tracked."),
456
+ url: z.string().trim().max(500).optional(),
457
+ models: modelsInput
458
+ })
459
+ }),
460
+ z.object({
461
+ primitive: z.literal("sentiment"),
462
+ input: z.object({
463
+ query: queryText("Prompt whose brand sentiment should be tracked."),
464
+ brand: shortText("Brand whose sentiment should be scored."),
465
+ models: modelsInput
466
+ })
467
+ })
468
+ ]);
469
+ var trackerDefinitionFields = {
470
+ name: z.string().trim().min(1).max(100),
471
+ cadence: trackerCadenceInput,
472
+ items: z.array(trackerItemInput).min(1).max(25).describe("Primitive calls to execute and store on each scheduled run.")
473
+ };
474
+ var TRACKER_BILLING_DESCRIPTION = "Tracker management and stored-report reads are free. Each scheduled or manual run bills the underlying primitive calls at their normal per-model rates; the activation response and tracker record expose the accepted maximum cost per run.";
475
+ var aivTrackerCreate = createTool({
476
+ id: "cite42_tracker_create",
477
+ mcp: mutation("Create Cite42 tracker draft"),
478
+ description: `Create a draft daily or weekly tracker from ordinary rankings, compare, citations, and sentiment primitive inputs. Creation does not start recurring calls. ${TRACKER_BILLING_DESCRIPTION}`,
479
+ inputSchema: z.object(trackerDefinitionFields),
480
+ execute: async (input) => aivPost("/trackers", input)
481
+ });
482
+ var aivTrackerUpdate = createTool({
483
+ id: "cite42_tracker_update",
484
+ mcp: mutation("Update Cite42 tracker", { destructiveHint: true }),
485
+ description: `Replace a tracker configuration with a validated name, cadence, and primitive item set. An edit returns the tracker to draft so its new recurring cost can be confirmed. ${TRACKER_BILLING_DESCRIPTION}`,
486
+ inputSchema: z.object({ trackerId: trackerIdInput, ...trackerDefinitionFields }),
487
+ execute: async ({ trackerId, ...input }) => aivPatch(`/trackers/${encodeURIComponent(trackerId)}`, input)
488
+ });
489
+ var aivTrackerActivate = createTool({
490
+ id: "cite42_tracker_activate",
491
+ mcp: mutation("Activate Cite42 tracker", {
492
+ openWorldHint: true,
493
+ idempotentHint: true
494
+ }),
495
+ description: `Activate or resume recurring daily or weekly primitive calls. maxCostMicroPerRun must equal the tracker estimate being accepted; activation authorizes future billed calls until the tracker is paused. ${TRACKER_BILLING_DESCRIPTION}`,
496
+ inputSchema: z.object({
497
+ trackerId: trackerIdInput,
498
+ maxCostMicroPerRun: z.number().int().nonnegative().describe("Exact estimatedCostMicroPerRun returned by the latest tracker record.")
499
+ }),
500
+ execute: async ({ trackerId, maxCostMicroPerRun }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/activate`, { maxCostMicroPerRun })
501
+ });
502
+ var aivTrackerPause = createTool({
503
+ id: "cite42_tracker_pause",
504
+ mcp: mutation("Pause Cite42 tracker", { idempotentHint: true }),
505
+ description: "Pause future recurring calls for a tracker while preserving its configuration and stored run history. Free: costs 0 credits.",
506
+ inputSchema: z.object({ trackerId: trackerIdInput }),
507
+ execute: async ({ trackerId }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/pause`, {})
508
+ });
509
+ var aivTrackerDelete = createTool({
510
+ id: "cite42_tracker_delete",
511
+ mcp: mutation("Permanently delete Cite42 tracker", {
512
+ destructiveHint: true,
513
+ idempotentHint: true
514
+ }),
515
+ description: "Permanently delete a draft or paused tracker, including its saved configuration and run history. Active trackers must be paused first, and deletion is rejected while a run is queued or running. Financial usage and credit ledger records are retained. Free: costs 0 credits.",
516
+ inputSchema: z.object({ trackerId: trackerIdInput }),
517
+ execute: async ({ trackerId }) => aivDelete(`/trackers/${encodeURIComponent(trackerId)}`)
518
+ });
519
+ var aivTrackerRun = createTool({
520
+ id: "cite42_tracker_run",
521
+ mcp: mutation("Run Cite42 tracker now", {
522
+ openWorldHint: true,
523
+ idempotentHint: true
524
+ }),
525
+ description: `Queue one manual run using the tracker\u2019s saved primitive inputs. A repeated requestToken returns the same logical run. ${TRACKER_BILLING_DESCRIPTION}`,
526
+ inputSchema: z.object({
527
+ trackerId: trackerIdInput,
528
+ requestToken: z.string().trim().min(1).max(200).describe("Stable caller-generated token used to deduplicate a retried manual run.")
529
+ }),
530
+ execute: async ({ trackerId, requestToken }) => aivPost(`/trackers/${encodeURIComponent(trackerId)}/runs`, { requestToken })
531
+ });
532
+ var aivTrackers = createTool({
533
+ id: "cite42_trackers",
534
+ mcp: readOnly("List Cite42 trackers", false),
535
+ description: "List the connected account\u2019s trackers with status, cadence, primitive configuration, cost estimate, accepted per-run maximum, and next/last run times. Free: costs 0 credits.",
536
+ inputSchema: z.object({}),
537
+ execute: async () => aivGet("/trackers")
538
+ });
539
+ var aivTrackerReport = createTool({
540
+ id: "cite42_tracker_report",
541
+ mcp: readOnly("Read Cite42 tracker report", false),
542
+ description: "Read bounded stored run history for one tracker, including per-primitive results, changes from the prior comparable observation, statuses, sampled times, and costs. Free: costs 0 credits.",
543
+ inputSchema: z.object({
544
+ trackerId: trackerIdInput,
545
+ limit: z.number().int().min(1).max(20).optional().default(8).describe("Most recent runs to return, capped for LLM context.")
546
+ }),
547
+ execute: async ({ trackerId, limit }) => aivGet(`/trackers/${encodeURIComponent(trackerId)}/report?limit=${limit}`)
548
+ });
383
549
 
384
550
  // src/server.ts
385
551
  var CITE42_TOOLS = {
@@ -400,7 +566,15 @@ var CITE42_TOOLS = {
400
566
  cite42_map_ai_prompts: aivMapAiPrompts,
401
567
  cite42_analyze_competitor_content: aivAnalyzeCompetitorContent,
402
568
  cite42_find_ai_citation_gaps: aivFindAiCitationGaps,
403
- cite42_generate_content_brief: aivGenerateContentBrief
569
+ cite42_generate_content_brief: aivGenerateContentBrief,
570
+ cite42_tracker_create: aivTrackerCreate,
571
+ cite42_tracker_update: aivTrackerUpdate,
572
+ cite42_tracker_activate: aivTrackerActivate,
573
+ cite42_tracker_pause: aivTrackerPause,
574
+ cite42_tracker_delete: aivTrackerDelete,
575
+ cite42_tracker_run: aivTrackerRun,
576
+ cite42_trackers: aivTrackers,
577
+ cite42_tracker_report: aivTrackerReport
404
578
  };
405
579
  function buildCite42Server(version) {
406
580
  return new MCPServer({
@@ -419,7 +593,7 @@ if (!resolveApiKey()) {
419
593
  );
420
594
  process.exit(1);
421
595
  }
422
- buildCite42Server("0.1.16").startStdio().catch((error) => {
596
+ buildCite42Server("0.1.17").startStdio().catch((error) => {
423
597
  console.error("[@cite42/mcp] Fatal error:", error);
424
598
  process.exit(1);
425
599
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cite42/mcp",
3
3
  "mcpName": "dev.cite42/mcp",
4
- "version": "0.1.16",
4
+ "version": "0.1.17",
5
5
  "description": "Cite42 MCP server: query ChatGPT, Claude, Perplexity, Gemini & Google AI Overviews for brand rankings, AI citations, SEO keyword data, and Reddit/YouTube trends. Works with Claude Code, Claude Desktop, Codex CLI, Cursor, and any MCP client.",
6
6
  "license": "MIT",
7
7
  "type": "module",