@cite42/mcp 0.1.13 → 0.1.15

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
@@ -140,12 +140,12 @@ The exact brands and sources change by query and model. A good result should sho
140
140
  ## Configuration
141
141
 
142
142
  - `CITE42_API_KEY`: required. Your API key from [www.cite42.dev/app/keys](https://www.cite42.dev/app/keys).
143
- - `CITE42_API_BASE`: optional. Defaults to `https://api.cite42.dev/v1`.
143
+ - `CITE42_API_BASE`: optional. Defaults to `https://www.cite42.dev/api/v1`.
144
144
 
145
145
  You can also pass these as CLI flags instead of environment variables:
146
146
 
147
147
  ```bash
148
- npx -y @cite42/mcp --api-key=cite42_live_your_key_here --api-base=https://api.cite42.dev/v1
148
+ npx -y @cite42/mcp --api-key=cite42_live_your_key_here --api-base=https://www.cite42.dev/api/v1
149
149
  ```
150
150
 
151
151
  ## Billing
package/dist/stdio.cjs CHANGED
@@ -5,7 +5,56 @@
5
5
  var import_mcp = require("@mastra/mcp");
6
6
 
7
7
  // src/client.ts
8
- var DEFAULT_BASE_URL = "https://api.cite42.dev/v1";
8
+ var DEFAULT_BASE_URL = "https://www.cite42.dev/api/v1";
9
+ var MICRO_CREDITS_PER_CREDIT = 1e3;
10
+ function isJsonObject(value) {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+ function toCredits(microCredits) {
14
+ return microCredits / MICRO_CREDITS_PER_CREDIT;
15
+ }
16
+ function formatCredits(microCredits) {
17
+ const credits = toCredits(microCredits);
18
+ return credits.toLocaleString(
19
+ "en-US",
20
+ Number.isInteger(credits) ? { maximumFractionDigits: 0 } : { minimumFractionDigits: 0, maximumFractionDigits: 2 }
21
+ );
22
+ }
23
+ function toCite42McpResult(value) {
24
+ if (!isJsonObject(value)) return value;
25
+ const { billing, warning, ...result } = value;
26
+ if (!isJsonObject(billing)) return value;
27
+ const cost = isJsonObject(billing.cost) ? billing.cost.microCredits : void 0;
28
+ const balance = isJsonObject(billing.balance) ? billing.balance.microCredits : void 0;
29
+ if (typeof cost !== "number" || !Number.isFinite(cost) || typeof balance !== "number" || !Number.isFinite(balance)) {
30
+ return result;
31
+ }
32
+ const lowCredits = typeof warning === "string";
33
+ const message = `Cite42 credits: ${formatCredits(cost)} charged; ${formatCredits(balance)} remaining.`;
34
+ return {
35
+ ...result,
36
+ cite42Credits: {
37
+ charged: toCredits(cost),
38
+ remaining: toCredits(balance),
39
+ message: lowCredits ? `${message} Low Cite42 credit balance.` : message
40
+ }
41
+ };
42
+ }
43
+ function errorMessageForMcp(status, path, body) {
44
+ try {
45
+ const payload = JSON.parse(body);
46
+ if (isJsonObject(payload) && isJsonObject(payload.error) && typeof payload.error.code === "string") {
47
+ if (payload.error.code === "daily_limit_exceeded" || payload.error.code === "monthly_limit_exceeded") {
48
+ return "Cite42 credit limit reached. Adjust your limit at https://www.cite42.dev/app/billing.";
49
+ }
50
+ if (payload.error.code === "insufficient_credits") {
51
+ return "Insufficient Cite42 credits. Top up at https://www.cite42.dev/app/billing.";
52
+ }
53
+ }
54
+ } catch {
55
+ }
56
+ return `Cite42 API ${status} ${path}: ${body}`;
57
+ }
9
58
  function readFlag(name) {
10
59
  const argv = process.argv.slice(2);
11
60
  const prefix = `--${name}=`;
@@ -43,9 +92,9 @@ async function aivPost(path, body) {
43
92
  });
44
93
  if (!res.ok) {
45
94
  const text = await res.text();
46
- throw new Error(`Cite42 API ${res.status} ${path}: ${text}`);
95
+ throw new Error(errorMessageForMcp(res.status, path, text));
47
96
  }
48
- return res.json();
97
+ return toCite42McpResult(await res.json());
49
98
  }
50
99
 
51
100
  // src/tools.ts
@@ -56,9 +105,9 @@ var QUERY_MAX_CHARS = 2e3;
56
105
  var SHORT_TEXT_MAX_CHARS = 200;
57
106
  var TIMEFRAME_MAX_CHARS = 80;
58
107
  var MODEL_SELECTION_DESCRIPTION = 'Optional model subset. Omit to query all five AI surfaces (chatgpt, claude, perplexity, gemini, google_ai_overview). Pass ["perplexity"] or ["perplexity","claude"] when the user asks for specific surfaces or wants to reduce cost.';
59
- var MCP_USAGE_GUIDANCE = "Use Cite42 for AI-search, citation, SEO, keyword, trend, and market-research data. Do not use it as a general coding or writing assistant; code-related research is fine when the goal is to compare what AI models recommend or cite. If a plan needs more than 20 endpoint calls or may cost over $5, estimate the cost and ask the user before continuing.";
60
- var MODEL_PRICING = "Pricing: search/citations/rankings/compare are model-specific: Google AI Overview $0.01, Gemini $0.02, ChatGPT/Claude $0.04, Perplexity $0.05 per selected model. Sentiment: Google AI Overview $0.03, Gemini $0.04, ChatGPT/Claude $0.06, Perplexity $0.07. Omitting models queries all five AI surfaces. Use the models field when the user names a specific surface or asks to reduce cost.";
61
- var DATA_PRICING = "Pricing: keywords $0.15/call, trends $0.01/call, Reddit trends $0.05/call, YouTube trends $0.05/call.";
108
+ var MCP_USAGE_GUIDANCE = "Use Cite42 for AI-search, citation, SEO, keyword, trend, and market-research data. Do not use it as a general coding or writing assistant; code-related research is fine when the goal is to compare what AI models recommend or cite. 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, use its message if reporting it: it is Cite42 credits, not a model or host balance.";
109
+ var MODEL_PRICING = "Pricing in Cite42 credits: search/citations/rankings/compare are model-specific: Google AI Overview 1, Gemini 2, ChatGPT/Claude 4, Perplexity 5 per selected model. Sentiment: Google AI Overview 3, Gemini 4, ChatGPT/Claude 6, Perplexity 7. Omitting models queries all five AI surfaces. Use the models field when the user names a specific surface or asks to reduce credit use.";
110
+ var DATA_PRICING = "Pricing in Cite42 credits: keywords 15/call, trends 1/call, Reddit trends 5/call, YouTube trends 5/call.";
62
111
  function queryText(description) {
63
112
  return import_zod.z.string().trim().min(1).max(QUERY_MAX_CHARS).describe(description);
64
113
  }
@@ -243,7 +292,7 @@ if (!resolveApiKey()) {
243
292
  var server = new import_mcp.MCPServer({
244
293
  id: "cite42",
245
294
  name: "Cite42",
246
- version: "0.1.13",
295
+ version: "0.1.15",
247
296
  description: "AI market data API: AI search, citations, SEO keywords, trends, and workflows.",
248
297
  tools: {
249
298
  cite42_search: aivSearch,
package/dist/stdio.mjs CHANGED
@@ -4,7 +4,56 @@
4
4
  import { MCPServer } from "@mastra/mcp";
5
5
 
6
6
  // src/client.ts
7
- var DEFAULT_BASE_URL = "https://api.cite42.dev/v1";
7
+ var DEFAULT_BASE_URL = "https://www.cite42.dev/api/v1";
8
+ var MICRO_CREDITS_PER_CREDIT = 1e3;
9
+ function isJsonObject(value) {
10
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11
+ }
12
+ function toCredits(microCredits) {
13
+ return microCredits / MICRO_CREDITS_PER_CREDIT;
14
+ }
15
+ function formatCredits(microCredits) {
16
+ const credits = toCredits(microCredits);
17
+ return credits.toLocaleString(
18
+ "en-US",
19
+ Number.isInteger(credits) ? { maximumFractionDigits: 0 } : { minimumFractionDigits: 0, maximumFractionDigits: 2 }
20
+ );
21
+ }
22
+ function toCite42McpResult(value) {
23
+ if (!isJsonObject(value)) return value;
24
+ const { billing, warning, ...result } = value;
25
+ if (!isJsonObject(billing)) return value;
26
+ const cost = isJsonObject(billing.cost) ? billing.cost.microCredits : void 0;
27
+ const balance = isJsonObject(billing.balance) ? billing.balance.microCredits : void 0;
28
+ if (typeof cost !== "number" || !Number.isFinite(cost) || typeof balance !== "number" || !Number.isFinite(balance)) {
29
+ return result;
30
+ }
31
+ const lowCredits = typeof warning === "string";
32
+ const message = `Cite42 credits: ${formatCredits(cost)} charged; ${formatCredits(balance)} remaining.`;
33
+ return {
34
+ ...result,
35
+ cite42Credits: {
36
+ charged: toCredits(cost),
37
+ remaining: toCredits(balance),
38
+ message: lowCredits ? `${message} Low Cite42 credit balance.` : message
39
+ }
40
+ };
41
+ }
42
+ function errorMessageForMcp(status, path, body) {
43
+ try {
44
+ const payload = JSON.parse(body);
45
+ if (isJsonObject(payload) && isJsonObject(payload.error) && typeof payload.error.code === "string") {
46
+ if (payload.error.code === "daily_limit_exceeded" || payload.error.code === "monthly_limit_exceeded") {
47
+ return "Cite42 credit limit reached. Adjust your limit at https://www.cite42.dev/app/billing.";
48
+ }
49
+ if (payload.error.code === "insufficient_credits") {
50
+ return "Insufficient Cite42 credits. Top up at https://www.cite42.dev/app/billing.";
51
+ }
52
+ }
53
+ } catch {
54
+ }
55
+ return `Cite42 API ${status} ${path}: ${body}`;
56
+ }
8
57
  function readFlag(name) {
9
58
  const argv = process.argv.slice(2);
10
59
  const prefix = `--${name}=`;
@@ -42,9 +91,9 @@ async function aivPost(path, body) {
42
91
  });
43
92
  if (!res.ok) {
44
93
  const text = await res.text();
45
- throw new Error(`Cite42 API ${res.status} ${path}: ${text}`);
94
+ throw new Error(errorMessageForMcp(res.status, path, text));
46
95
  }
47
- return res.json();
96
+ return toCite42McpResult(await res.json());
48
97
  }
49
98
 
50
99
  // src/tools.ts
@@ -55,9 +104,9 @@ var QUERY_MAX_CHARS = 2e3;
55
104
  var SHORT_TEXT_MAX_CHARS = 200;
56
105
  var TIMEFRAME_MAX_CHARS = 80;
57
106
  var MODEL_SELECTION_DESCRIPTION = 'Optional model subset. Omit to query all five AI surfaces (chatgpt, claude, perplexity, gemini, google_ai_overview). Pass ["perplexity"] or ["perplexity","claude"] when the user asks for specific surfaces or wants to reduce cost.';
58
- var MCP_USAGE_GUIDANCE = "Use Cite42 for AI-search, citation, SEO, keyword, trend, and market-research data. Do not use it as a general coding or writing assistant; code-related research is fine when the goal is to compare what AI models recommend or cite. If a plan needs more than 20 endpoint calls or may cost over $5, estimate the cost and ask the user before continuing.";
59
- var MODEL_PRICING = "Pricing: search/citations/rankings/compare are model-specific: Google AI Overview $0.01, Gemini $0.02, ChatGPT/Claude $0.04, Perplexity $0.05 per selected model. Sentiment: Google AI Overview $0.03, Gemini $0.04, ChatGPT/Claude $0.06, Perplexity $0.07. Omitting models queries all five AI surfaces. Use the models field when the user names a specific surface or asks to reduce cost.";
60
- var DATA_PRICING = "Pricing: keywords $0.15/call, trends $0.01/call, Reddit trends $0.05/call, YouTube trends $0.05/call.";
107
+ var MCP_USAGE_GUIDANCE = "Use Cite42 for AI-search, citation, SEO, keyword, trend, and market-research data. Do not use it as a general coding or writing assistant; code-related research is fine when the goal is to compare what AI models recommend or cite. 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, use its message if reporting it: it is Cite42 credits, not a model or host balance.";
108
+ var MODEL_PRICING = "Pricing in Cite42 credits: search/citations/rankings/compare are model-specific: Google AI Overview 1, Gemini 2, ChatGPT/Claude 4, Perplexity 5 per selected model. Sentiment: Google AI Overview 3, Gemini 4, ChatGPT/Claude 6, Perplexity 7. Omitting models queries all five AI surfaces. Use the models field when the user names a specific surface or asks to reduce credit use.";
109
+ var DATA_PRICING = "Pricing in Cite42 credits: keywords 15/call, trends 1/call, Reddit trends 5/call, YouTube trends 5/call.";
61
110
  function queryText(description) {
62
111
  return z.string().trim().min(1).max(QUERY_MAX_CHARS).describe(description);
63
112
  }
@@ -242,7 +291,7 @@ if (!resolveApiKey()) {
242
291
  var server = new MCPServer({
243
292
  id: "cite42",
244
293
  name: "Cite42",
245
- version: "0.1.13",
294
+ version: "0.1.15",
246
295
  description: "AI market data API: AI search, citations, SEO keywords, trends, and workflows.",
247
296
  tools: {
248
297
  cite42_search: aivSearch,
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.13",
4
+ "version": "0.1.15",
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",