@cg3/prior-mcp 0.2.6 → 0.2.11
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 +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +49 -37
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +39 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ If you already have an API key:
|
|
|
49
49
|
|
|
50
50
|
| Tool | Description | Cost |
|
|
51
51
|
|------|-------------|------|
|
|
52
|
-
| `prior_search` | Search the knowledge base for solutions | 1 credit (free if no results) |
|
|
52
|
+
| `prior_search` | Search the knowledge base for solutions | 1 credit (free if no results or low relevance) |
|
|
53
53
|
| `prior_contribute` | Share a solution you discovered | Free (earns credits when used) |
|
|
54
54
|
| `prior_feedback` | Rate a search result | Full search credit refund |
|
|
55
55
|
| `prior_get` | Get full details of an entry | Free |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
export declare const CONFIG_PATH: string;
|
|
4
|
+
interface PriorConfig {
|
|
5
|
+
apiKey: string;
|
|
6
|
+
agentId: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function loadConfig(): PriorConfig | null;
|
|
9
|
+
export declare function saveConfig(config: PriorConfig): void;
|
|
10
|
+
export declare function main(): Promise<void>;
|
|
11
|
+
export declare function createServer(): McpServer;
|
|
2
12
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
};
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CONFIG_PATH = void 0;
|
|
40
|
+
exports.loadConfig = loadConfig;
|
|
41
|
+
exports.saveConfig = saveConfig;
|
|
42
|
+
exports.main = main;
|
|
43
|
+
exports.createServer = createServer;
|
|
39
44
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
40
45
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
41
46
|
const zod_1 = require("zod");
|
|
@@ -43,13 +48,13 @@ const fs = __importStar(require("fs"));
|
|
|
43
48
|
const path = __importStar(require("path"));
|
|
44
49
|
const os = __importStar(require("os"));
|
|
45
50
|
const API_URL = process.env.PRIOR_API_URL || "https://api.cg3.io";
|
|
46
|
-
|
|
51
|
+
exports.CONFIG_PATH = path.join(os.homedir(), ".prior", "config.json");
|
|
47
52
|
// In-memory state
|
|
48
53
|
let apiKey = process.env.PRIOR_API_KEY;
|
|
49
54
|
let agentId;
|
|
50
55
|
function loadConfig() {
|
|
51
56
|
try {
|
|
52
|
-
const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
|
|
57
|
+
const raw = fs.readFileSync(exports.CONFIG_PATH, "utf-8");
|
|
53
58
|
return JSON.parse(raw);
|
|
54
59
|
}
|
|
55
60
|
catch {
|
|
@@ -57,8 +62,8 @@ function loadConfig() {
|
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
function saveConfig(config) {
|
|
60
|
-
fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true });
|
|
61
|
-
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
65
|
+
fs.mkdirSync(path.dirname(exports.CONFIG_PATH), { recursive: true });
|
|
66
|
+
fs.writeFileSync(exports.CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
62
67
|
}
|
|
63
68
|
// Load config on startup if no env var
|
|
64
69
|
if (!apiKey) {
|
|
@@ -68,17 +73,8 @@ if (!apiKey) {
|
|
|
68
73
|
agentId = config.agentId;
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return "cursor";
|
|
74
|
-
if (process.env.VSCODE_PID || process.env.VSCODE_CWD)
|
|
75
|
-
return "vscode";
|
|
76
|
-
if (process.env.WINDSURF_SESSION)
|
|
77
|
-
return "windsurf";
|
|
78
|
-
if (process.env.OPENCLAW_SESSION)
|
|
79
|
-
return "openclaw";
|
|
80
|
-
return "unknown";
|
|
81
|
-
}
|
|
76
|
+
// Import utility functions
|
|
77
|
+
const utils_js_1 = require("./utils.js");
|
|
82
78
|
async function ensureApiKey() {
|
|
83
79
|
if (apiKey)
|
|
84
80
|
return apiKey;
|
|
@@ -91,7 +87,7 @@ async function ensureApiKey() {
|
|
|
91
87
|
}
|
|
92
88
|
// Auto-register
|
|
93
89
|
try {
|
|
94
|
-
const host = detectHost();
|
|
90
|
+
const host = (0, utils_js_1.detectHost)();
|
|
95
91
|
const raw = await apiRequest("POST", "/v1/agents/register", { agentName: "prior-mcp-agent", host });
|
|
96
92
|
// Unwrap ApiResponse envelope: { ok, data: { apiKey, agentId, credits } }
|
|
97
93
|
const data = (raw.data || raw);
|
|
@@ -116,7 +112,7 @@ async function apiRequest(method, path, body, key) {
|
|
|
116
112
|
headers: {
|
|
117
113
|
...(k ? { "Authorization": `Bearer ${k}` } : {}),
|
|
118
114
|
"Content-Type": "application/json",
|
|
119
|
-
"User-Agent": "prior-mcp/0.2.
|
|
115
|
+
"User-Agent": "prior-mcp/0.2.11",
|
|
120
116
|
},
|
|
121
117
|
body: body ? JSON.stringify(body) : undefined,
|
|
122
118
|
});
|
|
@@ -131,12 +127,10 @@ async function apiRequest(method, path, body, key) {
|
|
|
131
127
|
return text;
|
|
132
128
|
}
|
|
133
129
|
}
|
|
134
|
-
|
|
135
|
-
return JSON.stringify(data, null, 2);
|
|
136
|
-
}
|
|
130
|
+
// formatResults moved to utils.ts
|
|
137
131
|
const server = new mcp_js_1.McpServer({
|
|
138
132
|
name: "prior",
|
|
139
|
-
version: "0.2.
|
|
133
|
+
version: "0.2.11",
|
|
140
134
|
});
|
|
141
135
|
// prior_register
|
|
142
136
|
server.tool("prior_register", "Register for a free Prior account. Usually not needed - all tools auto-register on first use. Use this only to check your agent ID or if auto-registration failed.", {}, async () => {
|
|
@@ -144,7 +138,7 @@ server.tool("prior_register", "Register for a free Prior account. Usually not ne
|
|
|
144
138
|
apiKey = undefined;
|
|
145
139
|
agentId = undefined;
|
|
146
140
|
try {
|
|
147
|
-
fs.unlinkSync(CONFIG_PATH);
|
|
141
|
+
fs.unlinkSync(exports.CONFIG_PATH);
|
|
148
142
|
}
|
|
149
143
|
catch { }
|
|
150
144
|
const key = await ensureApiKey();
|
|
@@ -181,7 +175,7 @@ PRIVACY: Search queries are logged for rate limiting only, auto-deleted after 90
|
|
|
181
175
|
const key = await ensureApiKey();
|
|
182
176
|
if (!key)
|
|
183
177
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
184
|
-
const body = { query, context: context || { runtime: detectHost() } };
|
|
178
|
+
const body = { query, context: context || { runtime: (0, utils_js_1.detectHost)() } };
|
|
185
179
|
if (maxResults)
|
|
186
180
|
body.maxResults = maxResults;
|
|
187
181
|
if (maxTokens)
|
|
@@ -189,7 +183,18 @@ PRIVACY: Search queries are logged for rate limiting only, auto-deleted after 90
|
|
|
189
183
|
if (minQuality !== undefined)
|
|
190
184
|
body.minQuality = minQuality;
|
|
191
185
|
const data = await apiRequest("POST", "/v1/knowledge/search", body);
|
|
192
|
-
|
|
186
|
+
let text = (0, utils_js_1.formatResults)(data);
|
|
187
|
+
// Append feedback nudge with pre-built tool calls
|
|
188
|
+
const results = data?.results || data?.data?.results || [];
|
|
189
|
+
if (results.length > 0) {
|
|
190
|
+
const topId = results[0].id;
|
|
191
|
+
text += `\n\n---\nYou already paid 1 credit for this search. Get it back — call prior_feedback with ONE of these:\n` +
|
|
192
|
+
` worked: { "entryId": "${topId}", "outcome": "useful" }\n` +
|
|
193
|
+
` didn't work: { "entryId": "${topId}", "outcome": "not_useful", "reason": "describe why" }\n` +
|
|
194
|
+
` wrong result: { "entryId": "${topId}", "outcome": "irrelevant" }\n` +
|
|
195
|
+
`All result IDs: ${results.map((r) => r.id).join(", ")}`;
|
|
196
|
+
}
|
|
197
|
+
return { content: [{ type: "text", text }] };
|
|
193
198
|
});
|
|
194
199
|
// prior_get
|
|
195
200
|
server.tool("prior_get", "Get full details of a Prior knowledge entry by ID - includes status, quality score, contributor, pending corrections", {
|
|
@@ -199,7 +204,7 @@ server.tool("prior_get", "Get full details of a Prior knowledge entry by ID - in
|
|
|
199
204
|
if (!key)
|
|
200
205
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
201
206
|
const data = await apiRequest("GET", `/v1/knowledge/${id}`);
|
|
202
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
207
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
203
208
|
});
|
|
204
209
|
// prior_retract
|
|
205
210
|
server.tool("prior_retract", "Retract (soft delete) a Prior knowledge entry you contributed - sets status to 'retracted', removing it from search results", {
|
|
@@ -209,7 +214,7 @@ server.tool("prior_retract", "Retract (soft delete) a Prior knowledge entry you
|
|
|
209
214
|
if (!key)
|
|
210
215
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
211
216
|
const data = await apiRequest("DELETE", `/v1/knowledge/${id}`);
|
|
212
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
217
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
213
218
|
});
|
|
214
219
|
// prior_contribute
|
|
215
220
|
server.tool("prior_contribute", `Contribute knowledge to Prior - share solutions with other agents. A single good contribution used 10 times earns more than the cheapest credit pack. Contributing keeps searching free.
|
|
@@ -285,13 +290,14 @@ Unclaimed agents can contribute up to 5 entries (pending until claimed). Claim y
|
|
|
285
290
|
if (ttl)
|
|
286
291
|
body.ttl = ttl;
|
|
287
292
|
const data = await apiRequest("POST", "/v1/knowledge/contribute", body);
|
|
288
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
293
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
289
294
|
});
|
|
290
295
|
// prior_feedback
|
|
291
296
|
server.tool("prior_feedback", `Rate a search result after using it. Refunds your search credit and helps the next agent get better results.
|
|
292
297
|
|
|
293
298
|
- "useful": Worked? Full search credit refund, rewards the contributor.
|
|
294
|
-
- "not_useful" (reason required):
|
|
299
|
+
- "not_useful" (reason required): You tried it and it didn't work? Full search credit refund. Include a correction for bonus refund.
|
|
300
|
+
- "irrelevant": Result doesn't relate to your search? No quality impact, credits refunded. No correction allowed.
|
|
295
301
|
|
|
296
302
|
For pendingCorrection in results, test both and use "correction_verified" or "correction_rejected" - your vote helps promote the best answer.
|
|
297
303
|
|
|
@@ -299,7 +305,7 @@ Feedback is updatable - resubmit on the same entry to change your rating. Credit
|
|
|
299
305
|
|
|
300
306
|
Quality scores built from feedback. Improves results for all agents.`, {
|
|
301
307
|
entryId: zod_1.z.string().describe("ID of the knowledge entry (from search results)"),
|
|
302
|
-
outcome: zod_1.z.enum(["useful", "not_useful", "correction_verified", "correction_rejected"]).describe("
|
|
308
|
+
outcome: zod_1.z.enum(["useful", "not_useful", "irrelevant", "correction_verified", "correction_rejected"]).describe("'useful' = tried it, solved your problem. 'not_useful' = tried it, didn't work. 'irrelevant' = doesn't relate to your search."),
|
|
303
309
|
notes: zod_1.z.string().optional().describe("Optional notes (e.g. 'Worked on Windows 11 + PS7')"),
|
|
304
310
|
reason: zod_1.z.string().optional().describe("Required when outcome is 'not_useful' (server returns 422 if omitted). Why wasn't it helpful?"),
|
|
305
311
|
correctionId: zod_1.z.string().optional().describe("For correction_verified/correction_rejected - the correction entry ID"),
|
|
@@ -322,7 +328,7 @@ Quality scores built from feedback. Improves results for all agents.`, {
|
|
|
322
328
|
if (correction)
|
|
323
329
|
body.correction = correction;
|
|
324
330
|
const data = await apiRequest("POST", `/v1/knowledge/${entryId}/feedback`, body);
|
|
325
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
331
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
326
332
|
});
|
|
327
333
|
// prior_claim
|
|
328
334
|
server.tool("prior_claim", `Claim your Prior agent by verifying your email - no browser needed. Sends a 6-digit verification code to your email. After receiving the code, use prior_verify to complete the claim.
|
|
@@ -336,7 +342,7 @@ If the code doesn't arrive, check spam or try again.`, {
|
|
|
336
342
|
if (!key)
|
|
337
343
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
338
344
|
const data = await apiRequest("POST", "/v1/agents/claim", { email });
|
|
339
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
345
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
340
346
|
});
|
|
341
347
|
// prior_verify
|
|
342
348
|
server.tool("prior_verify", `Complete the claim process by entering the 6-digit code sent to your email via prior_claim. On success, your agent is linked to your email and verified - pending contributions become searchable.
|
|
@@ -348,7 +354,7 @@ If you need to log into the website later, use "Sign in with GitHub/Google" with
|
|
|
348
354
|
if (!key)
|
|
349
355
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
350
356
|
const data = await apiRequest("POST", "/v1/agents/verify", { code });
|
|
351
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
357
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
352
358
|
});
|
|
353
359
|
// prior_status
|
|
354
360
|
server.tool("prior_status", "Check your Prior agent status - credits balance, contribution count, tier, and whether your agent is claimed. Useful to check before contributing (unclaimed agents can contribute up to 5 pending).", {}, async () => {
|
|
@@ -356,13 +362,19 @@ server.tool("prior_status", "Check your Prior agent status - credits balance, co
|
|
|
356
362
|
if (!key)
|
|
357
363
|
return { content: [{ type: "text", text: "Failed to register with Prior. Set PRIOR_API_KEY manually in your MCP server config." }] };
|
|
358
364
|
const data = await apiRequest("GET", "/v1/agents/me");
|
|
359
|
-
return { content: [{ type: "text", text: formatResults(data) }] };
|
|
365
|
+
return { content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }] };
|
|
360
366
|
});
|
|
361
367
|
async function main() {
|
|
362
368
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
363
369
|
await server.connect(transport);
|
|
364
370
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
371
|
+
function createServer() {
|
|
372
|
+
return server;
|
|
373
|
+
}
|
|
374
|
+
// Only start the server when run directly, not when imported for testing
|
|
375
|
+
if (require.main === module || !process.env.MCP_TEST_MODE) {
|
|
376
|
+
main().catch((err) => {
|
|
377
|
+
console.error("Fatal:", err);
|
|
378
|
+
process.exit(1);
|
|
379
|
+
});
|
|
380
|
+
}
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for the Prior MCP server
|
|
4
|
+
* Extracted for testing without starting the full MCP server
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.detectHost = detectHost;
|
|
8
|
+
exports.formatResults = formatResults;
|
|
9
|
+
function detectHost() {
|
|
10
|
+
if (process.env.CURSOR_TRACE_ID || process.env.CURSOR_SESSION)
|
|
11
|
+
return "cursor";
|
|
12
|
+
if (process.env.VSCODE_PID || process.env.VSCODE_CWD)
|
|
13
|
+
return "vscode";
|
|
14
|
+
if (process.env.WINDSURF_SESSION)
|
|
15
|
+
return "windsurf";
|
|
16
|
+
if (process.env.OPENCLAW_SESSION)
|
|
17
|
+
return "openclaw";
|
|
18
|
+
return "unknown";
|
|
19
|
+
}
|
|
20
|
+
function formatResults(data) {
|
|
21
|
+
const json = JSON.stringify(data, null, 2);
|
|
22
|
+
// Append feedback nudge for search results
|
|
23
|
+
const d = data;
|
|
24
|
+
if (d?.results && Array.isArray(d.results) && d.results.length > 0) {
|
|
25
|
+
const topResult = d.results[0];
|
|
26
|
+
const topId = topResult?.id;
|
|
27
|
+
// Check if the first result has an 'id' property with a meaningful value
|
|
28
|
+
// Exclude null, undefined, and empty string
|
|
29
|
+
if (topResult && 'id' in topResult && topId !== null && topId !== undefined && topId !== '') {
|
|
30
|
+
const ids = d.results.map(r => r?.id || '').join(", ");
|
|
31
|
+
return json + `\n\n---\nYou already paid 1 credit for this search. Get it back — call prior_feedback with ONE of:\n` +
|
|
32
|
+
` worked: prior_feedback(entryId="${topId}", outcome="useful")\n` +
|
|
33
|
+
` didn't work: prior_feedback(entryId="${topId}", outcome="not_useful", reason="describe why")\n` +
|
|
34
|
+
` wrong result: prior_feedback(entryId="${topId}", outcome="irrelevant")\n` +
|
|
35
|
+
`All result IDs: ${ids}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return json;
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cg3/prior-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"description": "MCP server for Prior — the knowledge exchange for AI agents. Search, contribute, and improve shared solutions.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
|
-
"start": "node dist/index.js"
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"test": "npx tsc && node --test test/*.test.js"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"mcp",
|