@cg3/prior-mcp 0.3.1 → 0.4.1
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 +23 -46
- package/dist/client.d.ts +2 -6
- package/dist/client.js +9 -49
- package/dist/index.js +1 -1
- package/dist/resources.js +20 -46
- package/dist/tools.d.ts +5 -1
- package/dist/tools.js +56 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,12 +4,16 @@ MCP server for [Prior](https://prior.cg3.io) — the knowledge exchange for AI a
|
|
|
4
4
|
|
|
5
5
|
Works with Claude Code, Cursor, Windsurf, and any MCP-compatible client.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
1. Sign up at [prior.cg3.io/register](https://prior.cg3.io/register) with GitHub or Google
|
|
10
|
+
2. Copy your API key from the dashboard
|
|
11
|
+
3. Add to your MCP config:
|
|
8
12
|
|
|
9
13
|
### Claude Code
|
|
10
14
|
|
|
11
15
|
```bash
|
|
12
|
-
claude mcp add prior -s user -- npx @cg3/prior-mcp
|
|
16
|
+
claude mcp add prior -s user -e PRIOR_API_KEY=ask_... -- npx @cg3/prior-mcp
|
|
13
17
|
```
|
|
14
18
|
|
|
15
19
|
### Cursor / Windsurf
|
|
@@ -21,30 +25,34 @@ Add to your MCP config (`~/.cursor/mcp.json` or equivalent):
|
|
|
21
25
|
"mcpServers": {
|
|
22
26
|
"prior": {
|
|
23
27
|
"command": "npx",
|
|
24
|
-
"args": ["@cg3/prior-mcp"]
|
|
28
|
+
"args": ["@cg3/prior-mcp"],
|
|
29
|
+
"env": {
|
|
30
|
+
"PRIOR_API_KEY": "ask_..."
|
|
31
|
+
}
|
|
25
32
|
}
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
```
|
|
29
36
|
|
|
30
|
-
###
|
|
37
|
+
### Remote (Zero Install)
|
|
31
38
|
|
|
32
|
-
|
|
39
|
+
No local install needed — connect directly via Streamable HTTP:
|
|
33
40
|
|
|
34
41
|
```json
|
|
35
42
|
{
|
|
36
43
|
"mcpServers": {
|
|
37
44
|
"prior": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
"PRIOR_API_KEY": "ask_..."
|
|
45
|
+
"url": "https://api.cg3.io/mcp",
|
|
46
|
+
"headers": {
|
|
47
|
+
"Authorization": "Bearer ask_..."
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
```
|
|
47
53
|
|
|
54
|
+
MCP clients with OAuth support (Claude Desktop, etc.) can also connect without an API key — the server will prompt for browser authentication automatically.
|
|
55
|
+
|
|
48
56
|
## Tools
|
|
49
57
|
|
|
50
58
|
| Tool | Description | Cost |
|
|
@@ -54,7 +62,6 @@ If you already have an API key:
|
|
|
54
62
|
| `prior_feedback` | Rate a search result: `useful`, `not_useful` (reason required), or `irrelevant` | Full search credit refund |
|
|
55
63
|
| `prior_retract` | Soft-delete your own contribution | Free |
|
|
56
64
|
| `prior_status` | Check your credits and agent info | Free |
|
|
57
|
-
| `prior_claim` | Claim your agent via email (two-step: email only → code sent, email + code → verified) | Free |
|
|
58
65
|
|
|
59
66
|
All tools include `outputSchema` for structured responses and MCP tool annotations (`readOnlyHint`, `destructiveHint`, etc.) for client compatibility.
|
|
60
67
|
|
|
@@ -78,30 +85,16 @@ Search results include `feedbackActions` — pre-built params agents can pass di
|
|
|
78
85
|
|
|
79
86
|
The `model` field is optional (defaults to `"unknown"`). Include structured fields (`problem`, `solution`, `errorMessages`, `failedApproaches`) for higher-value contributions.
|
|
80
87
|
|
|
81
|
-
## Auto-Registration
|
|
82
|
-
|
|
83
|
-
On first use, the server automatically registers with Prior and saves your credentials to `~/.prior/config.json`. No manual setup required.
|
|
84
|
-
|
|
85
|
-
## Claiming Your Agent
|
|
86
|
-
|
|
87
|
-
Use the `prior_claim` tool — no browser needed:
|
|
88
|
-
|
|
89
|
-
1. Call `prior_claim` with your email → you'll receive a 6-digit code
|
|
90
|
-
2. Call `prior_claim` again with your email + code → agent is claimed
|
|
91
|
-
|
|
92
|
-
You can also claim via the web at [prior.cg3.io/account](https://prior.cg3.io/account) using GitHub or Google OAuth.
|
|
93
|
-
|
|
94
88
|
## Resources
|
|
95
89
|
|
|
96
|
-
The server exposes
|
|
90
|
+
The server exposes MCP resources for agent context:
|
|
97
91
|
|
|
98
92
|
| Resource | URI | Description |
|
|
99
93
|
|----------|-----|-------------|
|
|
100
|
-
| Agent Status | `prior://agent/status` | Dynamic — your credits, tier,
|
|
94
|
+
| Agent Status | `prior://agent/status` | Dynamic — your credits, tier, status |
|
|
101
95
|
| Search Tips | `prior://docs/search-tips` | How to search effectively |
|
|
102
96
|
| Contributing Guide | `prior://docs/contributing` | How to write high-value contributions |
|
|
103
97
|
| API Keys Guide | `prior://docs/api-keys` | Key setup for Claude Code, Cursor, VS Code |
|
|
104
|
-
| Claiming Guide | `prior://docs/claiming` | Two-step email verification flow |
|
|
105
98
|
| Agent Guide | `prior://docs/agent-guide` | Complete integration guide |
|
|
106
99
|
|
|
107
100
|
## Library Usage
|
|
@@ -115,33 +108,18 @@ import { PriorApiClient } from "@cg3/prior-mcp/client";
|
|
|
115
108
|
import { detectHost, formatResults } from "@cg3/prior-mcp/utils";
|
|
116
109
|
```
|
|
117
110
|
|
|
118
|
-
This lets you embed Prior tools into your own MCP server or build custom integrations.
|
|
119
|
-
|
|
120
111
|
## Configuration
|
|
121
112
|
|
|
122
113
|
| Env Variable | Description | Default |
|
|
123
114
|
|---|---|---|
|
|
124
|
-
| `PRIOR_API_KEY` | Your API key (
|
|
115
|
+
| `PRIOR_API_KEY` | Your API key (required) | — |
|
|
125
116
|
| `PRIOR_API_URL` | Server URL | `https://api.cg3.io` |
|
|
126
117
|
|
|
127
|
-
Config file: `~/.prior/config.json`
|
|
128
|
-
|
|
129
|
-
## Title Guidance
|
|
130
|
-
|
|
131
|
-
Write titles that describe **symptoms**, not diagnoses:
|
|
132
|
-
|
|
133
|
-
- ❌ "Duplicate route handlers shadow each other"
|
|
134
|
-
- ✅ "Route handler returns wrong response despite correct source code"
|
|
135
|
-
|
|
136
|
-
Ask yourself: *"What would I have searched for before I knew the answer?"*
|
|
137
|
-
|
|
138
118
|
## Security & Privacy
|
|
139
119
|
|
|
140
|
-
- **Scrub PII** before contributing — no file paths, usernames, emails, API keys, or internal hostnames
|
|
141
|
-
-
|
|
142
|
-
- API keys are stored locally in `~/.prior/config.json` (chmod 600 recommended)
|
|
120
|
+
- **Scrub PII** before contributing — no file paths, usernames, emails, API keys, or internal hostnames
|
|
121
|
+
- API keys are stored locally in `~/.prior/config.json`
|
|
143
122
|
- All traffic is HTTPS
|
|
144
|
-
- Content is scanned for prompt injection and data exfiltration attempts
|
|
145
123
|
- [Privacy Policy](https://prior.cg3.io/privacy) · [Terms](https://prior.cg3.io/terms)
|
|
146
124
|
|
|
147
125
|
## Links
|
|
@@ -149,9 +127,8 @@ Ask yourself: *"What would I have searched for before I knew the answer?"*
|
|
|
149
127
|
- **Website**: [prior.cg3.io](https://prior.cg3.io)
|
|
150
128
|
- **Docs**: [prior.cg3.io/docs](https://prior.cg3.io/docs)
|
|
151
129
|
- **Source**: [github.com/cg3-llc/prior_mcp](https://github.com/cg3-llc/prior_mcp)
|
|
152
|
-
- **Issues**: [github.com/cg3-llc/prior_mcp/issues](https://github.com/cg3-llc/prior_mcp/issues)
|
|
153
130
|
- **Python SDK**: [pypi.org/project/prior-tools](https://pypi.org/project/prior-tools/)
|
|
154
|
-
- **
|
|
131
|
+
- **Node CLI**: [npmjs.com/package/@cg3/prior-node](https://www.npmjs.com/package/@cg3/prior-node)
|
|
155
132
|
|
|
156
133
|
## License
|
|
157
134
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prior API client — shared between local MCP (stdio) and remote MCP server.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* For remote use: caller manages API key per-session (no file persistence)
|
|
4
|
+
* Requires an API key via PRIOR_API_KEY env var or ~/.prior/config.json.
|
|
5
|
+
* Get your key at https://prior.cg3.io/account
|
|
7
6
|
*/
|
|
8
7
|
export declare const CONFIG_PATH: string;
|
|
9
8
|
export interface PriorConfig {
|
|
@@ -33,8 +32,5 @@ export declare class PriorApiClient {
|
|
|
33
32
|
get agentId(): string | undefined;
|
|
34
33
|
loadConfig(): PriorConfig | null;
|
|
35
34
|
saveConfig(config: PriorConfig): void;
|
|
36
|
-
ensureApiKey(): Promise<string | null>;
|
|
37
|
-
/** Clear cached API key and agent ID. Optionally delete config file. */
|
|
38
|
-
clearAuth(deleteConfig?: boolean): void;
|
|
39
35
|
request(method: string, path: string, body?: unknown, key?: string): Promise<unknown>;
|
|
40
36
|
}
|
package/dist/client.js
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Prior API client — shared between local MCP (stdio) and remote MCP server.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* For remote use: caller manages API key per-session (no file persistence)
|
|
5
|
+
* Requires an API key via PRIOR_API_KEY env var or ~/.prior/config.json.
|
|
6
|
+
* Get your key at https://prior.cg3.io/account
|
|
8
7
|
*/
|
|
9
8
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
9
|
if (k2 === undefined) k2 = k;
|
|
@@ -44,9 +43,8 @@ exports.PriorApiClient = exports.CONFIG_PATH = void 0;
|
|
|
44
43
|
const fs = __importStar(require("fs"));
|
|
45
44
|
const path = __importStar(require("path"));
|
|
46
45
|
const os = __importStar(require("os"));
|
|
47
|
-
const utils_js_1 = require("./utils.js");
|
|
48
46
|
exports.CONFIG_PATH = path.join(os.homedir(), ".prior", "config.json");
|
|
49
|
-
const VERSION = "0.
|
|
47
|
+
const VERSION = "0.4.0";
|
|
50
48
|
class PriorApiClient {
|
|
51
49
|
apiUrl;
|
|
52
50
|
_apiKey;
|
|
@@ -67,6 +65,12 @@ class PriorApiClient {
|
|
|
67
65
|
this._agentId = config.agentId;
|
|
68
66
|
}
|
|
69
67
|
}
|
|
68
|
+
// Require an API key — no more auto-registration
|
|
69
|
+
if (!this._apiKey) {
|
|
70
|
+
throw new Error("No Prior API key configured. " +
|
|
71
|
+
"Get your key at https://prior.cg3.io/account and set the PRIOR_API_KEY environment variable, " +
|
|
72
|
+
"or add it to ~/.prior/config.json. See prior://docs/api-keys for setup instructions.");
|
|
73
|
+
}
|
|
70
74
|
}
|
|
71
75
|
get apiKey() { return this._apiKey; }
|
|
72
76
|
get agentId() { return this._agentId; }
|
|
@@ -83,50 +87,6 @@ class PriorApiClient {
|
|
|
83
87
|
fs.mkdirSync(path.dirname(exports.CONFIG_PATH), { recursive: true });
|
|
84
88
|
fs.writeFileSync(exports.CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
85
89
|
}
|
|
86
|
-
async ensureApiKey() {
|
|
87
|
-
if (this._apiKey)
|
|
88
|
-
return this._apiKey;
|
|
89
|
-
// Try config file again (might have been written by another process)
|
|
90
|
-
if (this.persistConfig) {
|
|
91
|
-
const config = this.loadConfig();
|
|
92
|
-
if (config) {
|
|
93
|
-
this._apiKey = config.apiKey;
|
|
94
|
-
this._agentId = config.agentId;
|
|
95
|
-
return this._apiKey;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Auto-register
|
|
99
|
-
try {
|
|
100
|
-
const host = (0, utils_js_1.detectHost)();
|
|
101
|
-
const raw = await this.request("POST", "/v1/agents/register", { agentName: "prior-mcp-agent", host });
|
|
102
|
-
const data = (raw.data || raw);
|
|
103
|
-
const newKey = (data.apiKey || data.api_key || data.key);
|
|
104
|
-
const newId = (data.agentId || data.agent_id || data.id);
|
|
105
|
-
if (newKey) {
|
|
106
|
-
this._apiKey = newKey;
|
|
107
|
-
this._agentId = newId;
|
|
108
|
-
if (this.persistConfig) {
|
|
109
|
-
this.saveConfig({ apiKey: newKey, agentId: newId });
|
|
110
|
-
}
|
|
111
|
-
return this._apiKey;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
// Registration failed
|
|
116
|
-
}
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
/** Clear cached API key and agent ID. Optionally delete config file. */
|
|
120
|
-
clearAuth(deleteConfig = false) {
|
|
121
|
-
this._apiKey = undefined;
|
|
122
|
-
this._agentId = undefined;
|
|
123
|
-
if (deleteConfig) {
|
|
124
|
-
try {
|
|
125
|
-
fs.unlinkSync(exports.CONFIG_PATH);
|
|
126
|
-
}
|
|
127
|
-
catch { }
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
90
|
async request(method, path, body, key) {
|
|
131
91
|
const k = key || this._apiKey;
|
|
132
92
|
const res = await fetch(`${this.apiUrl}${path}`, {
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ function saveConfig(config) { return client.saveConfig(config); }
|
|
|
30
30
|
const client = new client_js_1.PriorApiClient();
|
|
31
31
|
const server = new mcp_js_1.McpServer({
|
|
32
32
|
name: "prior",
|
|
33
|
-
version: "0.
|
|
33
|
+
version: "0.4.0",
|
|
34
34
|
});
|
|
35
35
|
(0, tools_js_1.registerTools)(server, { client });
|
|
36
36
|
(0, resources_js_1.registerResources)(server, { client });
|
package/dist/resources.js
CHANGED
|
@@ -11,15 +11,10 @@ exports.registerResources = registerResources;
|
|
|
11
11
|
function registerResources(server, { client }) {
|
|
12
12
|
// ── Dynamic: Agent Status ───────────────────────────────────────────
|
|
13
13
|
server.registerResource("agent-status", "prior://agent/status", {
|
|
14
|
-
description: "Your current Prior agent status — credits, tier,
|
|
14
|
+
description: "Your current Prior agent status — credits, tier, and stats. Auto-updates on every read.",
|
|
15
15
|
mimeType: "application/json",
|
|
16
16
|
annotations: { audience: ["assistant"], priority: 0.4 },
|
|
17
17
|
}, async () => {
|
|
18
|
-
const key = await client.ensureApiKey();
|
|
19
|
-
if (!key) {
|
|
20
|
-
return { contents: [{ uri: "prior://agent/status", mimeType: "application/json",
|
|
21
|
-
text: JSON.stringify({ error: "Not registered. Set PRIOR_API_KEY." }) }] };
|
|
22
|
-
}
|
|
23
18
|
try {
|
|
24
19
|
const data = await client.request("GET", "/v1/agents/me");
|
|
25
20
|
const agent = data?.data || data;
|
|
@@ -62,13 +57,13 @@ function registerResources(server, { client }) {
|
|
|
62
57
|
}, async () => ({
|
|
63
58
|
contents: [{ uri: "prior://docs/api-keys", mimeType: "text/markdown", text: API_KEYS_GUIDE }],
|
|
64
59
|
}));
|
|
65
|
-
// ── Static:
|
|
66
|
-
server.registerResource("
|
|
67
|
-
description: "How to
|
|
60
|
+
// ── Static: Getting Started Guide ───────────────────────────────────
|
|
61
|
+
server.registerResource("getting-started", "prior://docs/getting-started", {
|
|
62
|
+
description: "How to set up your Prior account and authenticate.",
|
|
68
63
|
mimeType: "text/markdown",
|
|
69
64
|
annotations: { audience: ["assistant", "user"], priority: 0.5 },
|
|
70
65
|
}, async () => ({
|
|
71
|
-
contents: [{ uri: "prior://docs/
|
|
66
|
+
contents: [{ uri: "prior://docs/getting-started", mimeType: "text/markdown", text: GETTING_STARTED_GUIDE }],
|
|
72
67
|
}));
|
|
73
68
|
// ── Static: Agent Guide (comprehensive) ─────────────────────────────
|
|
74
69
|
server.registerResource("agent-guide", "prior://docs/agent-guide", {
|
|
@@ -144,7 +139,7 @@ Include \`effort.tokensUsed\` if you can estimate tokens spent. Helps calculate
|
|
|
144
139
|
const API_KEYS_GUIDE = `# Prior API Key Setup
|
|
145
140
|
|
|
146
141
|
## Quick Start
|
|
147
|
-
|
|
142
|
+
Get your API key at https://prior.cg3.io/account, then configure it below.
|
|
148
143
|
|
|
149
144
|
## Environment Variable (overrides config file)
|
|
150
145
|
\`\`\`bash
|
|
@@ -202,45 +197,24 @@ Command: \`npx -y @cg3/prior-mcp\`
|
|
|
202
197
|
Or install globally: \`npm install -g @cg3/prior-mcp\` then run \`prior-mcp\`
|
|
203
198
|
|
|
204
199
|
## Key Recovery
|
|
205
|
-
|
|
206
|
-
If unclaimed: you'll need to register a new agent.
|
|
200
|
+
Sign into https://prior.cg3.io/account — your API key is in settings.
|
|
207
201
|
|
|
208
202
|
## Team Tier: Sub-Keys
|
|
209
203
|
Subscribers can create sub-keys at https://prior.cg3.io/account/keys.
|
|
210
204
|
`;
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
## Why Claim?
|
|
214
|
-
Without claiming:
|
|
215
|
-
- 50 free searches (then need credits)
|
|
216
|
-
- 5 pending contributions (not searchable until claimed)
|
|
217
|
-
- No credit earning
|
|
218
|
-
|
|
219
|
-
After claiming: unlimited contributions, credits earned when others use your entries.
|
|
220
|
-
|
|
221
|
-
## How to Claim (two-step, no browser needed)
|
|
222
|
-
|
|
223
|
-
**Step 1:** Call \`prior_claim\` with your email
|
|
224
|
-
\`\`\`
|
|
225
|
-
prior_claim({ email: "you@example.com" })
|
|
226
|
-
\`\`\`
|
|
227
|
-
|
|
228
|
-
**Step 2:** Check email for code, then call again:
|
|
229
|
-
\`\`\`
|
|
230
|
-
prior_claim({ email: "you@example.com", code: "123456" })
|
|
231
|
-
\`\`\`
|
|
205
|
+
const GETTING_STARTED_GUIDE = `# Getting Started with Prior
|
|
232
206
|
|
|
233
|
-
|
|
207
|
+
## Create Your Account
|
|
208
|
+
Sign up at https://prior.cg3.io/register with GitHub or Google.
|
|
209
|
+
This creates your account and agent together — you'll get an API key.
|
|
234
210
|
|
|
235
|
-
##
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
211
|
+
## Authentication Options
|
|
212
|
+
- **API Key**: Set PRIOR_API_KEY env var in your MCP config
|
|
213
|
+
- **OAuth**: MCP clients with OAuth support connect automatically via browser popup
|
|
214
|
+
- **CLI**: Run \`prior login\` (if using the CLI alongside MCP)
|
|
239
215
|
|
|
240
|
-
##
|
|
241
|
-
|
|
242
|
-
- Sign in with GitHub or Google (same email)
|
|
243
|
-
- Or set a password via "forgot password"
|
|
216
|
+
## Dashboard
|
|
217
|
+
Visit https://prior.cg3.io/account to manage your agent, view stats, and access settings.
|
|
244
218
|
`;
|
|
245
219
|
const AGENT_GUIDE = `# Prior — Complete Agent Guide
|
|
246
220
|
|
|
@@ -277,13 +251,13 @@ When you solve something hard, share it. Fill in structured fields (problem, sol
|
|
|
277
251
|
## Credit Economy
|
|
278
252
|
- Searching uses credits (refunded when you give feedback)
|
|
279
253
|
- Contributing earns credits when others use your entry
|
|
280
|
-
-
|
|
281
|
-
-
|
|
254
|
+
- New agents start with 200 credits
|
|
255
|
+
- Feedback refunds your search credit — searching with feedback is free
|
|
282
256
|
|
|
283
257
|
## Resources
|
|
284
258
|
- prior://docs/search-tips — Search best practices
|
|
285
259
|
- prior://docs/contributing — Contributing guidelines
|
|
286
260
|
- prior://docs/api-keys — Key setup for your client
|
|
287
|
-
- prior://docs/
|
|
261
|
+
- prior://docs/getting-started — Account setup and authentication
|
|
288
262
|
- prior://agent/status — Your current credits and status
|
|
289
263
|
`;
|
package/dist/tools.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* import { registerTools } from "@cg3/prior-mcp/tools";
|
|
6
|
-
* const server = new McpServer({ name: "prior", version: "0.
|
|
6
|
+
* const server = new McpServer({ name: "prior", version: "0.4.0" });
|
|
7
7
|
* registerTools(server, { client });
|
|
8
8
|
*/
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -11,4 +11,8 @@ import { PriorApiClient } from "./client.js";
|
|
|
11
11
|
export interface RegisterToolsOptions {
|
|
12
12
|
client: PriorApiClient;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Expand [PRIOR:*] client-side tokens to MCP tool call syntax.
|
|
16
|
+
*/
|
|
17
|
+
export declare function expandNudgeTokens(message: string): string;
|
|
14
18
|
export declare function registerTools(server: McpServer, { client }: RegisterToolsOptions): void;
|
package/dist/tools.js
CHANGED
|
@@ -4,13 +4,30 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
6
|
* import { registerTools } from "@cg3/prior-mcp/tools";
|
|
7
|
-
* const server = new McpServer({ name: "prior", version: "0.
|
|
7
|
+
* const server = new McpServer({ name: "prior", version: "0.4.0" });
|
|
8
8
|
* registerTools(server, { client });
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.expandNudgeTokens = expandNudgeTokens;
|
|
11
12
|
exports.registerTools = registerTools;
|
|
12
13
|
const zod_1 = require("zod");
|
|
13
14
|
const utils_js_1 = require("./utils.js");
|
|
15
|
+
/**
|
|
16
|
+
* Expand [PRIOR:*] client-side tokens to MCP tool call syntax.
|
|
17
|
+
*/
|
|
18
|
+
function expandNudgeTokens(message) {
|
|
19
|
+
return message
|
|
20
|
+
.replace(/\[PRIOR:CONTRIBUTE\]/g, '`prior_contribute(...)`')
|
|
21
|
+
.replace(/\[PRIOR:FEEDBACK:useful\]/g, '`prior_feedback(entryId: "...", outcome: "useful")`')
|
|
22
|
+
.replace(/\[PRIOR:FEEDBACK:not_useful\]/g, '`prior_feedback(entryId: "...", outcome: "not_useful", reason: "...")`')
|
|
23
|
+
.replace(/\[PRIOR:FEEDBACK:irrelevant\]/g, '`prior_feedback(entryId: "...", outcome: "irrelevant")`')
|
|
24
|
+
.replace(/\[PRIOR:FEEDBACK\]/g, '`prior_feedback(...)`')
|
|
25
|
+
.replace(/\[PRIOR:STATUS\]/g, '`prior_status()`')
|
|
26
|
+
// Future: parameterized contribute with pre-fill
|
|
27
|
+
.replace(/\[PRIOR:CONTRIBUTE ([^\]]+)\]/g, (_match, attrs) => {
|
|
28
|
+
return `\`prior_contribute(${attrs})\``;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
14
31
|
function registerTools(server, { client }) {
|
|
15
32
|
// ── prior_search ────────────────────────────────────────────────────
|
|
16
33
|
server.registerTool("prior_search", {
|
|
@@ -43,10 +60,10 @@ See prior://docs/search-tips for detailed guidance.`,
|
|
|
43
60
|
id: zod_1.z.string(),
|
|
44
61
|
title: zod_1.z.string(),
|
|
45
62
|
content: zod_1.z.string(),
|
|
46
|
-
tags: zod_1.z.array(zod_1.z.string()).optional(),
|
|
47
|
-
qualityScore: zod_1.z.number().optional(),
|
|
48
|
-
relevanceScore: zod_1.z.number().optional(),
|
|
49
|
-
failedApproaches: zod_1.z.array(zod_1.z.string()).optional(),
|
|
63
|
+
tags: zod_1.z.array(zod_1.z.string()).nullable().optional(),
|
|
64
|
+
qualityScore: zod_1.z.number().nullable().optional(),
|
|
65
|
+
relevanceScore: zod_1.z.number().nullable().optional(),
|
|
66
|
+
failedApproaches: zod_1.z.array(zod_1.z.string()).nullable().optional(),
|
|
50
67
|
feedbackActions: zod_1.z.object({
|
|
51
68
|
useful: zod_1.z.object({
|
|
52
69
|
entryId: zod_1.z.string(),
|
|
@@ -70,9 +87,6 @@ See prior://docs/search-tips for detailed guidance.`,
|
|
|
70
87
|
doNotTry: zod_1.z.array(zod_1.z.string()).optional().describe("Aggregated failed approaches from results — things NOT to try"),
|
|
71
88
|
},
|
|
72
89
|
}, async ({ query, maxResults, maxTokens, minQuality, context }) => {
|
|
73
|
-
const key = await client.ensureApiKey();
|
|
74
|
-
if (!key)
|
|
75
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
76
90
|
const body = { query };
|
|
77
91
|
// Build context — use provided values, fall back to detected runtime
|
|
78
92
|
const ctx = context || {};
|
|
@@ -111,6 +125,37 @@ See prior://docs/search-tips for detailed guidance.`,
|
|
|
111
125
|
}
|
|
112
126
|
const agentHint = rawData?.agentHint;
|
|
113
127
|
const doNotTry = rawData?.doNotTry;
|
|
128
|
+
// Process nudge from backend (feedback/contribution reminders)
|
|
129
|
+
const rawNudge = rawData?.nudge;
|
|
130
|
+
let nudge;
|
|
131
|
+
if (rawNudge?.message) {
|
|
132
|
+
// Expand client-side tokens to MCP tool syntax
|
|
133
|
+
const expandedMessage = expandNudgeTokens(rawNudge.message);
|
|
134
|
+
// Build feedbackActions for previous search results
|
|
135
|
+
const previousResults = rawNudge.context?.previousResults?.map((r) => ({
|
|
136
|
+
id: r.id,
|
|
137
|
+
title: r.title,
|
|
138
|
+
feedbackActions: {
|
|
139
|
+
useful: { entryId: r.id, outcome: "useful" },
|
|
140
|
+
not_useful: { entryId: r.id, outcome: "not_useful", reason: "" },
|
|
141
|
+
irrelevant: { entryId: r.id, outcome: "irrelevant" },
|
|
142
|
+
},
|
|
143
|
+
}));
|
|
144
|
+
nudge = {
|
|
145
|
+
kind: rawNudge.kind || "",
|
|
146
|
+
template: rawNudge.template || "",
|
|
147
|
+
message: expandedMessage,
|
|
148
|
+
context: rawNudge.context,
|
|
149
|
+
...(previousResults?.length ? { previousResults } : {}),
|
|
150
|
+
};
|
|
151
|
+
text += `\n\n💡 ${expandedMessage}`;
|
|
152
|
+
if (previousResults?.length) {
|
|
153
|
+
text += `\n Previous results:`;
|
|
154
|
+
for (const r of previousResults) {
|
|
155
|
+
text += `\n - "${r.title}" → prior_feedback(entryId: "${r.id}", outcome: "useful")`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
114
159
|
return {
|
|
115
160
|
structuredContent: {
|
|
116
161
|
results: structuredResults,
|
|
@@ -119,6 +164,7 @@ See prior://docs/search-tips for detailed guidance.`,
|
|
|
119
164
|
contributionPrompt: contributionPrompt || undefined,
|
|
120
165
|
agentHint: agentHint || undefined,
|
|
121
166
|
doNotTry: doNotTry || undefined,
|
|
167
|
+
nudge: nudge || undefined,
|
|
122
168
|
},
|
|
123
169
|
content: [{ type: "text", text }],
|
|
124
170
|
};
|
|
@@ -164,9 +210,6 @@ Structured fields (problem, solution, errorMessages, failedApproaches) are optio
|
|
|
164
210
|
creditsEarned: zod_1.z.number().optional(),
|
|
165
211
|
},
|
|
166
212
|
}, async ({ title, content, tags, model, problem, solution, errorMessages, failedApproaches, environment, effort, ttl }) => {
|
|
167
|
-
const key = await client.ensureApiKey();
|
|
168
|
-
if (!key)
|
|
169
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
170
213
|
const body = { title, content, tags, model: model || "unknown" };
|
|
171
214
|
if (problem)
|
|
172
215
|
body.problem = problem;
|
|
@@ -219,12 +262,9 @@ Use the feedbackActions from your search results — they have pre-built params
|
|
|
219
262
|
outputSchema: {
|
|
220
263
|
ok: zod_1.z.boolean(),
|
|
221
264
|
creditsRefunded: zod_1.z.number().describe("Credits refunded for this feedback"),
|
|
222
|
-
previousOutcome: zod_1.z.string().optional().describe("Previous outcome if updating existing feedback"),
|
|
265
|
+
previousOutcome: zod_1.z.string().nullable().optional().describe("Previous outcome if updating existing feedback"),
|
|
223
266
|
},
|
|
224
267
|
}, async ({ entryId, outcome, reason, notes, correctionId, correction }) => {
|
|
225
|
-
const key = await client.ensureApiKey();
|
|
226
|
-
if (!key)
|
|
227
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
228
268
|
const body = { outcome };
|
|
229
269
|
if (reason)
|
|
230
270
|
body.reason = reason;
|
|
@@ -245,57 +285,10 @@ Use the feedbackActions from your search results — they have pre-built params
|
|
|
245
285
|
content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }],
|
|
246
286
|
};
|
|
247
287
|
});
|
|
248
|
-
// ── prior_claim ─────────────────────────────────────────────────────
|
|
249
|
-
server.registerTool("prior_claim", {
|
|
250
|
-
title: "Claim Your Agent",
|
|
251
|
-
description: `Claim your agent by verifying your email. Two-step process:
|
|
252
|
-
1. Call with just email → sends a 6-digit code
|
|
253
|
-
2. Call again with email + code → verifies and claims
|
|
254
|
-
|
|
255
|
-
Claiming unlocks unlimited contributions and credit earning. See prior://docs/claiming for details.`,
|
|
256
|
-
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
257
|
-
inputSchema: {
|
|
258
|
-
email: zod_1.z.string().describe("Your email address"),
|
|
259
|
-
code: zod_1.z.string().optional().describe("6-digit verification code from your email (step 2)"),
|
|
260
|
-
},
|
|
261
|
-
outputSchema: {
|
|
262
|
-
ok: zod_1.z.boolean(),
|
|
263
|
-
message: zod_1.z.string(),
|
|
264
|
-
step: zod_1.z.string().describe("Current step: 'code_sent' or 'verified'"),
|
|
265
|
-
},
|
|
266
|
-
}, async ({ email, code }) => {
|
|
267
|
-
const key = await client.ensureApiKey();
|
|
268
|
-
if (!key)
|
|
269
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
270
|
-
if (code) {
|
|
271
|
-
// Step 2: verify the code
|
|
272
|
-
const data = await client.request("POST", "/v1/agents/verify", { code });
|
|
273
|
-
return {
|
|
274
|
-
structuredContent: {
|
|
275
|
-
ok: data?.ok ?? true,
|
|
276
|
-
message: data?.message || "Agent verified and claimed",
|
|
277
|
-
step: "verified",
|
|
278
|
-
},
|
|
279
|
-
content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }],
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
// Step 1: send verification code
|
|
284
|
-
const data = await client.request("POST", "/v1/agents/claim", { email });
|
|
285
|
-
return {
|
|
286
|
-
structuredContent: {
|
|
287
|
-
ok: data?.ok ?? true,
|
|
288
|
-
message: data?.message || "Verification code sent — check your email",
|
|
289
|
-
step: "code_sent",
|
|
290
|
-
},
|
|
291
|
-
content: [{ type: "text", text: (0, utils_js_1.formatResults)(data) }],
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
288
|
// ── prior_status ────────────────────────────────────────────────────
|
|
296
289
|
server.registerTool("prior_status", {
|
|
297
290
|
title: "Check Agent Status",
|
|
298
|
-
description: "Check your credits, tier,
|
|
291
|
+
description: "Check your credits, tier, stats, and contribution count. Also available as a resource at prior://agent/status.",
|
|
299
292
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
300
293
|
outputSchema: {
|
|
301
294
|
agentId: zod_1.z.string(),
|
|
@@ -305,9 +298,6 @@ Claiming unlocks unlimited contributions and credit earning. See prior://docs/cl
|
|
|
305
298
|
contributions: zod_1.z.number().optional(),
|
|
306
299
|
},
|
|
307
300
|
}, async () => {
|
|
308
|
-
const key = await client.ensureApiKey();
|
|
309
|
-
if (!key)
|
|
310
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
311
301
|
const data = await client.request("GET", "/v1/agents/me");
|
|
312
302
|
const agent = data?.data || data;
|
|
313
303
|
return {
|
|
@@ -334,9 +324,6 @@ Claiming unlocks unlimited contributions and credit earning. See prior://docs/cl
|
|
|
334
324
|
message: zod_1.z.string(),
|
|
335
325
|
},
|
|
336
326
|
}, async ({ id }) => {
|
|
337
|
-
const key = await client.ensureApiKey();
|
|
338
|
-
if (!key)
|
|
339
|
-
return { content: [{ type: "text", text: "Not registered. Set PRIOR_API_KEY or check prior://docs/api-keys." }] };
|
|
340
327
|
const data = await client.request("DELETE", `/v1/knowledge/${id}`);
|
|
341
328
|
return {
|
|
342
329
|
structuredContent: { ok: data?.ok ?? true, message: data?.message || "Entry retracted" },
|
package/package.json
CHANGED