@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 +2 -2
- package/dist/stdio.cjs +56 -7
- package/dist/stdio.mjs +56 -7
- package/package.json +1 -1
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://
|
|
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://
|
|
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://
|
|
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(
|
|
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
|
|
60
|
-
var MODEL_PRICING = "Pricing: search/citations/rankings/compare are model-specific: Google AI Overview
|
|
61
|
-
var DATA_PRICING = "Pricing: keywords
|
|
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.
|
|
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://
|
|
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(
|
|
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
|
|
59
|
-
var MODEL_PRICING = "Pricing: search/citations/rankings/compare are model-specific: Google AI Overview
|
|
60
|
-
var DATA_PRICING = "Pricing: keywords
|
|
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.
|
|
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.
|
|
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",
|