@cg3/prior-mcp 0.6.4 → 0.7.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.
@@ -0,0 +1,14 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { PriorApiClient } from "./client.js";
3
+ export declare const OPS_TOOL_NAMES: readonly ["ops_get_summary", "ops_list_attention", "ops_get_attention_item", "ops_get_recent_changes", "ops_get_runbook"];
4
+ export interface RegisterOpsToolsOptions {
5
+ client: PriorApiClient;
6
+ }
7
+ interface OpsToolRequest {
8
+ method: "GET";
9
+ path: string;
10
+ }
11
+ export declare function isOpsToolsEnabled(value?: string | undefined): boolean;
12
+ export declare function buildOpsToolRequest(toolName: string, input?: Record<string, unknown>): OpsToolRequest;
13
+ export declare function registerOpsTools(server: McpServer, { client }: RegisterOpsToolsOptions): void;
14
+ export {};
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.OPS_TOOL_NAMES = void 0;
37
+ exports.isOpsToolsEnabled = isOpsToolsEnabled;
38
+ exports.buildOpsToolRequest = buildOpsToolRequest;
39
+ exports.registerOpsTools = registerOpsTools;
40
+ const crypto = __importStar(require("node:crypto"));
41
+ const zod_1 = require("zod");
42
+ const utils_js_1 = require("./utils.js");
43
+ exports.OPS_TOOL_NAMES = Object.freeze([
44
+ "ops_get_summary",
45
+ "ops_list_attention",
46
+ "ops_get_attention_item",
47
+ "ops_get_recent_changes",
48
+ "ops_get_runbook",
49
+ ]);
50
+ function appendQuery(path, params) {
51
+ const query = new URLSearchParams();
52
+ for (const [key, value] of Object.entries(params)) {
53
+ if (value !== undefined && value !== "")
54
+ query.set(key, String(value));
55
+ }
56
+ const queryString = query.toString();
57
+ return queryString ? `${path}?${queryString}` : path;
58
+ }
59
+ function isOpsToolsEnabled(value = process.env.PRIOR_MCP_ENABLE_OPS_TOOLS) {
60
+ return value === "1" || value?.toLowerCase() === "true";
61
+ }
62
+ function buildOpsToolRequest(toolName, input = {}) {
63
+ switch (toolName) {
64
+ case "ops_get_summary":
65
+ return {
66
+ method: "GET",
67
+ path: appendQuery("/v1/admin/ops/summary", {
68
+ window: typeof input.window === "string" ? input.window : undefined,
69
+ surface: typeof input.surface === "string" ? input.surface : undefined,
70
+ }),
71
+ };
72
+ case "ops_list_attention":
73
+ return {
74
+ method: "GET",
75
+ path: appendQuery("/v1/admin/ops/attention", {
76
+ surface: typeof input.surface === "string" ? input.surface : undefined,
77
+ limit: typeof input.limit === "number" ? input.limit : undefined,
78
+ }),
79
+ };
80
+ case "ops_get_attention_item":
81
+ if (typeof input.id !== "string" || !input.id)
82
+ throw new Error("ops_get_attention_item requires id");
83
+ return { method: "GET", path: `/v1/admin/ops/attention/${encodeURIComponent(input.id)}` };
84
+ case "ops_get_recent_changes":
85
+ return {
86
+ method: "GET",
87
+ path: appendQuery("/v1/admin/ops/recent-changes", {
88
+ window: typeof input.window === "string" ? input.window : undefined,
89
+ surface: typeof input.surface === "string" ? input.surface : undefined,
90
+ }),
91
+ };
92
+ case "ops_get_runbook":
93
+ if (typeof input.id !== "string" || !input.id)
94
+ throw new Error("ops_get_runbook requires id");
95
+ return { method: "GET", path: `/v1/admin/ops/runbooks/${encodeURIComponent(input.id)}` };
96
+ default:
97
+ throw new Error(`Unknown ops tool: ${toolName}`);
98
+ }
99
+ }
100
+ function makeOpsRequestId(toolName) {
101
+ return `ops-${toolName}-${crypto.randomUUID()}`;
102
+ }
103
+ async function callOpsApi(client, toolName, input) {
104
+ const request = buildOpsToolRequest(toolName, input);
105
+ const requestId = makeOpsRequestId(toolName);
106
+ const response = await client.request(request.method, request.path, undefined, undefined, requestId);
107
+ return {
108
+ structuredContent: {
109
+ requestId,
110
+ response,
111
+ },
112
+ content: [{
113
+ type: "text",
114
+ text: `requestId: ${requestId}\n${(0, utils_js_1.formatResults)(response)}`,
115
+ }],
116
+ };
117
+ }
118
+ const opsOutputSchema = {
119
+ requestId: zod_1.z.string(),
120
+ response: zod_1.z.any(),
121
+ };
122
+ const windowSurfaceInput = {
123
+ window: zod_1.z.string().optional().describe("Window such as 24h, 7d, or 30d. Defaults to backend behavior when omitted."),
124
+ surface: zod_1.z.string().optional().describe("Optional ops surface filter such as business, auth, infrastructure, changes, or equip.release."),
125
+ };
126
+ function registerOpsTools(server, { client }) {
127
+ server.registerTool("ops_get_summary", {
128
+ title: "Get CG3 Ops Summary",
129
+ description: "Read-only admin operator summary. Requires opt-in local ops tools and an admin-capable Prior session/API key.",
130
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
131
+ inputSchema: windowSurfaceInput,
132
+ outputSchema: opsOutputSchema,
133
+ }, async (input) => callOpsApi(client, "ops_get_summary", input));
134
+ server.registerTool("ops_list_attention", {
135
+ title: "List CG3 Ops Attention Items",
136
+ description: "Read-only admin attention list for CG3 operator surfaces. Requires admin-capable Prior auth.",
137
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
138
+ inputSchema: {
139
+ surface: zod_1.z.string().optional().describe("Optional ops surface filter."),
140
+ limit: zod_1.z.number().optional().describe("Maximum number of items. Backend bounds the value."),
141
+ },
142
+ outputSchema: opsOutputSchema,
143
+ }, async (input) => callOpsApi(client, "ops_list_attention", input));
144
+ server.registerTool("ops_get_attention_item", {
145
+ title: "Get CG3 Ops Attention Item",
146
+ description: "Read-only admin detail for one ops attention item. Requires admin-capable Prior auth.",
147
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
148
+ inputSchema: {
149
+ id: zod_1.z.string().describe("Stable attention item ID."),
150
+ },
151
+ outputSchema: opsOutputSchema,
152
+ }, async (input) => callOpsApi(client, "ops_get_attention_item", input));
153
+ server.registerTool("ops_get_recent_changes", {
154
+ title: "Get CG3 Ops Recent Changes",
155
+ description: "Read-only admin recent-change projection with evidence links. Requires admin-capable Prior auth.",
156
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
157
+ inputSchema: windowSurfaceInput,
158
+ outputSchema: opsOutputSchema,
159
+ }, async (input) => callOpsApi(client, "ops_get_recent_changes", input));
160
+ server.registerTool("ops_get_runbook", {
161
+ title: "Get CG3 Ops Runbook",
162
+ description: "Read-only admin runbook lookup for an ops attention item or surface. Requires admin-capable Prior auth.",
163
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
164
+ inputSchema: {
165
+ id: zod_1.z.string().describe("Stable runbook ID, e.g. rb-equip-channel-bad-release."),
166
+ },
167
+ outputSchema: opsOutputSchema,
168
+ }, async (input) => callOpsApi(client, "ops_get_runbook", input));
169
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Prior MCP resources shared between local and remote MCP servers.
2
+ * Prior MCP resources shared between local and remote MCP servers.
3
3
  *
4
4
  * Usage:
5
5
  * import { registerResources } from "@cg3/prior-mcp/resources";
package/dist/resources.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * Prior MCP resources shared between local and remote MCP servers.
3
+ * Prior MCP resources shared between local and remote MCP servers.
4
4
  *
5
5
  * Usage:
6
6
  * import { registerResources } from "@cg3/prior-mcp/resources";
@@ -9,151 +9,170 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.registerResources = registerResources;
11
11
  function registerResources(server, { client }) {
12
- // ── Dynamic: Agent Status ───────────────────────────────────────────
13
12
  server.registerResource("agent-status", "prior://agent/status", {
14
- description: "Your current Prior agent status credits, tier, and stats. Auto-updates on every read.",
13
+ description: "Your current Prior auth status: auth mode, credits, tier, and profile summary.",
15
14
  mimeType: "application/json",
16
15
  annotations: { audience: ["assistant"], priority: 0.4 },
17
16
  }, async () => {
18
17
  try {
19
- const data = await client.request("GET", "/v1/agents/me");
20
- const agent = data?.data || data;
21
- return { contents: [{ uri: "prior://agent/status", mimeType: "application/json",
18
+ const status = await client.getStatus();
19
+ return {
20
+ contents: [{
21
+ uri: "prior://agent/status",
22
+ mimeType: "application/json",
22
23
  text: JSON.stringify({
23
- id: agent?.id,
24
- credits: agent?.credits ?? 0,
25
- tier: agent?.tier || "free",
26
- contributions: agent?.contributions,
27
- searches: agent?.searches,
28
- }, null, 2) }] };
24
+ id: status.id,
25
+ authType: status.authType,
26
+ credits: status.credits,
27
+ tier: status.tier,
28
+ contributions: status.contributions,
29
+ displayName: status.displayName,
30
+ }, null, 2),
31
+ }],
32
+ };
29
33
  }
30
34
  catch (err) {
31
- return { contents: [{ uri: "prior://agent/status", mimeType: "application/json",
32
- text: JSON.stringify({ error: err.message }) }] };
35
+ return {
36
+ contents: [{
37
+ uri: "prior://agent/status",
38
+ mimeType: "application/json",
39
+ text: JSON.stringify({ error: err.message }),
40
+ }],
41
+ };
33
42
  }
34
43
  });
35
- // ── Static: Search Tips ─────────────────────────────────────────────
36
44
  server.registerResource("search-tips", "prior://docs/search-tips", {
37
- description: "How to search Prior effectively query formulation, when to search, interpreting results, giving feedback.",
45
+ description: "How to search Prior effectively: query formulation, when to search, interpreting results, and giving feedback.",
38
46
  mimeType: "text/markdown",
39
47
  annotations: { audience: ["assistant"], priority: 0.9 },
40
48
  }, async () => ({
41
49
  contents: [{ uri: "prior://docs/search-tips", mimeType: "text/markdown", text: SEARCH_TIPS }],
42
50
  }));
43
- // ── Static: Contributing Guide ──────────────────────────────────────
44
51
  server.registerResource("contributing-guide", "prior://docs/contributing", {
45
- description: "How to write high-value Prior contributions structured fields, PII rules, title guidance.",
52
+ description: "How to write high-value Prior contributions: structured fields, PII rules, and title guidance.",
46
53
  mimeType: "text/markdown",
47
54
  annotations: { audience: ["assistant"], priority: 0.6 },
48
55
  }, async () => ({
49
56
  contents: [{ uri: "prior://docs/contributing", mimeType: "text/markdown", text: CONTRIBUTING_GUIDE }],
50
57
  }));
51
- // ── Static: API Keys Guide ──────────────────────────────────────────
52
58
  server.registerResource("api-keys-guide", "prior://docs/api-keys", {
53
- description: "API key setup where keys are stored, env vars, client-specific config for Claude Code, Cursor, VS Code.",
59
+ description: "API key setup, local browser login guidance, and client-specific config examples.",
54
60
  mimeType: "text/markdown",
55
61
  annotations: { audience: ["assistant", "user"], priority: 0.7 },
56
62
  }, async () => ({
57
63
  contents: [{ uri: "prior://docs/api-keys", mimeType: "text/markdown", text: API_KEYS_GUIDE }],
58
64
  }));
59
- // ── Static: Getting Started Guide ───────────────────────────────────
60
65
  server.registerResource("getting-started", "prior://docs/getting-started", {
61
- description: "How to set up your Prior account and authenticate.",
66
+ description: "How to create your Prior account and choose local OIDC or API-key auth.",
62
67
  mimeType: "text/markdown",
63
68
  annotations: { audience: ["assistant", "user"], priority: 0.5 },
64
69
  }, async () => ({
65
70
  contents: [{ uri: "prior://docs/getting-started", mimeType: "text/markdown", text: GETTING_STARTED_GUIDE }],
66
71
  }));
67
- // ── Static: Agent Guide (comprehensive) ─────────────────────────────
68
72
  server.registerResource("agent-guide", "prior://docs/agent-guide", {
69
- description: "Complete Prior integration guide full workflow, all features, detailed best practices. Read search-tips and contributing first for the essentials.",
73
+ description: "Complete Prior integration guide with the full workflow and best practices.",
70
74
  mimeType: "text/markdown",
71
75
  annotations: { audience: ["assistant"], priority: 0.4 },
72
76
  }, async () => ({
73
77
  contents: [{ uri: "prior://docs/agent-guide", mimeType: "text/markdown", text: AGENT_GUIDE }],
74
78
  }));
75
79
  }
76
- // ── Resource Content ────────────────────────────────────────────────────
77
- // Highest-value, most actionable content first in each resource.
78
80
  const SEARCH_TIPS = `# Prior Search Tips
79
81
 
80
82
  ## Quick Reference
81
- - Search the **ERROR**, not the goal: "ECONNREFUSED localhost:5432" not "how to connect to postgres"
82
- - Include framework/version: "Ktor 3.0 routing conflict" not "routing broken"
83
- - Paste **exact error strings** they match best
84
- - \`relevanceScore > 0.5\` = strong match, worth trying
85
- - \`failedApproaches\` = what NOT to try read these first
83
+ - Search the **error**, not the goal: "ECONNREFUSED localhost:5432" not "how to connect to postgres"
84
+ - Include framework or version details when they matter
85
+ - Paste exact error strings for the best matches
86
+ - \`relevanceScore > 0.5\` is usually worth trying first
87
+ - Read \`failedApproaches\` before you try a result
86
88
 
87
89
  ## When to Search
88
- - Error you don't recognize search immediately
89
- - New framework/tool/config → search before trial-and-error
90
- - 3+ failed attempts on the same issue search mid-debug
91
- - 2+ fixes tried, none worked → definitely search
90
+ - Search immediately when you hit an unfamiliar error
91
+ - Search before trial-and-error on new frameworks, tools, or config
92
+ - Search again if you have already tried a couple of fixes and none worked
92
93
 
93
94
  ## Giving Feedback
94
- After trying a search result, use the \`feedbackActions\` from the result to call prior_feedback:
95
- - **useful** tried it, solved your problem
96
- - **not_useful** tried it, didn't work. You must explain what you tried and why it failed
97
- - **irrelevant** result doesn't relate to your search (you did NOT try it)
95
+ After trying a search result, use the \`feedbackActions\` from the result to call \`prior_feedback\`:
96
+ - \`useful\`: you tried it and it solved the problem
97
+ - \`not_useful\`: you tried it and it failed; explain what you tried
98
+ - \`irrelevant\`: the result did not match your problem
98
99
 
99
- Feedback directly improves what you and other agents see in future searches.
100
+ Feedback improves future search quality and refunds the search credit.
100
101
 
101
102
  ## Interpreting Scores
102
- - \`relevanceScore > 0.5\` Strong match
103
- - \`relevanceScore 0.30.5\` Partial match, worth skimming
104
- - \`relevanceScore < 0.3\` Weak match
105
- - \`qualityScore\` — Community-verified quality (higher = more confirmed)
106
- `;
103
+ - \`relevanceScore > 0.5\`: strong match
104
+ - \`relevanceScore 0.3-0.5\`: partial match, worth skimming
105
+ - \`relevanceScore < 0.3\`: weak match
106
+ - \`qualityScore\`: community-verified quality`;
107
107
  const CONTRIBUTING_GUIDE = `# Prior Contributing Guide
108
108
 
109
109
  ## When to Contribute
110
- - Fix was non-obvious from the error message
111
- - Took 3+ attempts to figure out
112
- - Required reading source code or obscure docs
113
- - Specific to a version/tool combination
114
- - You thought "this should have been easier"
110
+ - The fix was not obvious from the error message
111
+ - It took multiple attempts to figure out
112
+ - You had to read source code or obscure docs
113
+ - The issue depended on a specific version or tool combination
115
114
 
116
115
  ## Writing Titles
117
- Describe **symptoms**, not diagnoses:
118
- - "Duplicate route handlers shadow each other"
119
- - "Route handler returns wrong response despite correct source code"
116
+ Describe symptoms, not diagnoses:
117
+ - Bad: "Duplicate route handlers shadow each other"
118
+ - Good: "Route handler returns wrong response despite correct source code"
120
119
 
121
- Ask: "What would I have searched **before** knowing the answer?"
120
+ Ask yourself: what would I have searched before I knew the answer?
122
121
 
123
122
  ## Required Fields
124
- - **title** Concise symptom description (<200 chars). What would you have searched before knowing the answer?
125
- - **content** The full markdown write-up. Context, what happened, and the fix. This is the primary field that gets indexed and shown to searchers. Do not skip it in favor of structured fields.
123
+ - **title**: concise symptom description
124
+ - **content**: the full markdown write-up with context, what happened, and the fix
126
125
 
127
126
  ## Optional Structured Fields
128
- These supplement content they are not replacements for it:
129
- - **problem** Short summary of the symptom or unexpected behavior
130
- - **solution** Short summary of what actually fixed it
131
- - **errorMessages** Exact error text. If there was no error (silent bug), describe the symptom instead
132
- - **failedApproaches** What you tried that didn't work. Most valuable field for other agents.
133
- - **environment** — Language, framework, runtime versions
127
+ - **problem**: short symptom summary
128
+ - **solution**: short fix summary
129
+ - **errorMessages**: exact error text
130
+ - **failedApproaches**: what did not work
131
+ - **environment**: language, framework, runtime versions
134
132
 
135
133
  ## PII Rules
136
- **Never include:** real file paths, usernames, emails, API keys, IPs, internal hostnames.
137
- Use generic paths (\`/project/src/...\`) and placeholders. Server-side scanning catches common patterns.
134
+ Never include real file paths, usernames, emails, API keys, IPs, or internal hostnames.
135
+ Use generic placeholders like \`/project/src/...\`.
138
136
 
139
- ## Generalizing (Critical)
140
- Prior is a **public** knowledge base. Write for strangers on unrelated projects, not your team.
141
- - Replace project-specific class/table/service names with generic equivalents
142
- - Describe the **pattern**, not your architecture (e.g., "two DB rows shared the same key hash" not "our SubscriptionService left duplicates in the agents table")
143
- - Test: would a developer on a completely different stack find this useful?
144
- - If it reads like an internal postmortem, it's too specific — abstract it
137
+ ## Generalizing
138
+ Prior is a public knowledge base. Replace project-specific names with generic patterns and write for someone on a different codebase.
145
139
 
146
140
  ## Effort Tracking
147
- Include \`effort.tokensUsed\` if you can estimate tokens spent. Helps calculate value saved for others.
148
- `;
149
- const API_KEYS_GUIDE = `# Prior API Key Setup
141
+ Include \`effort.tokensUsed\` when you can estimate it.`;
142
+ const API_KEYS_GUIDE = `# Prior Auth Setup
150
143
 
151
144
  ## Quick Start
152
- Get your API key at https://prior.cg3.io/account, then configure it below.
145
+ Get your API key at https://prior.cg3.io/account, then choose the auth mode that fits the client:
146
+
147
+ - Human local MCP session: run \`prior-mcp --login\` once and let the local stdio server use browser OIDC
148
+ - Durable machine workflow: set \`PRIOR_API_KEY\`
149
+ - OAuth-capable remote MCP client: connect to the hosted MCP server and follow the browser prompt
150
+
151
+ API keys remain the right choice for unattended or durable machine workflows.
152
+
153
+ ## Environment Variables
154
+ \`\`\`bash
155
+ export PRIOR_API_KEY=ask_your_key_here
156
+ \`\`\`
157
+
158
+ Optional token-based overrides for advanced setups:
159
+
160
+ \`\`\`bash
161
+ export PRIOR_IDENTITY_ACCESS_TOKEN=eyJ...
162
+ export PRIOR_REFRESH_TOKEN=rt_...
163
+ \`\`\`
164
+
165
+ \`PRIOR_IDENTITY_ACCESS_TOKEN\` is a delegated OIDC access token issued by Prior Identity. It is not a durable API key and not a generic Prior Knowledge credential; its JWT audience and scopes define which resource server can accept it and what it can do.
166
+
167
+ ## Local Browser Login
168
+ \`\`\`bash
169
+ npx -y @cg3/prior-mcp --login
170
+ \`\`\`
171
+
172
+ To clear the stored browser session and keep any saved API key config:
153
173
 
154
- ## Environment Variable (overrides config file)
155
174
  \`\`\`bash
156
- export PRIOR_API_KEY=prior_your_key_here
175
+ npx -y @cg3/prior-mcp --logout
157
176
  \`\`\`
158
177
 
159
178
  ## Client Setup
@@ -166,7 +185,7 @@ In \`claude_code_config.json\` or project \`.mcp.json\`:
166
185
  "prior": {
167
186
  "command": "npx",
168
187
  "args": ["-y", "@cg3/prior-mcp"],
169
- "env": { "PRIOR_API_KEY": "prior_your_key_here" }
188
+ "env": { "PRIOR_API_KEY": "ask_your_key_here" }
170
189
  }
171
190
  }
172
191
  }
@@ -180,7 +199,7 @@ In \`.cursor/mcp.json\`:
180
199
  "prior": {
181
200
  "command": "npx",
182
201
  "args": ["-y", "@cg3/prior-mcp"],
183
- "env": { "PRIOR_API_KEY": "prior_your_key_here" }
202
+ "env": { "PRIOR_API_KEY": "ask_your_key_here" }
184
203
  }
185
204
  }
186
205
  }
@@ -195,7 +214,7 @@ In MCP settings:
195
214
  "prior": {
196
215
  "command": "npx",
197
216
  "args": ["-y", "@cg3/prior-mcp"],
198
- "env": { "PRIOR_API_KEY": "prior_your_key_here" }
217
+ "env": { "PRIOR_API_KEY": "ask_your_key_here" }
199
218
  }
200
219
  }
201
220
  }
@@ -206,67 +225,56 @@ In MCP settings:
206
225
  Command: \`npx -y @cg3/prior-mcp\`
207
226
  Or install globally: \`npm install -g @cg3/prior-mcp\` then run \`prior-mcp\`
208
227
 
209
- ## Key Recovery
210
- Sign into https://prior.cg3.io/account your API key is in settings.
211
-
212
- ## Team Tier: Sub-Keys
213
- Subscribers can create sub-keys at https://prior.cg3.io/account/keys.
214
- `;
228
+ ## Recovery
229
+ Sign into https://prior.cg3.io/account to manage API keys and account settings.`;
215
230
  const GETTING_STARTED_GUIDE = `# Getting Started with Prior
216
231
 
217
232
  ## Create Your Account
218
233
  Sign up at https://prior.cg3.io/register with GitHub or Google.
219
- This creates your account and agent together you'll get an API key.
234
+ This creates your Prior account. API keys are available in account settings, and local OIDC login is available from the CLI.
235
+
236
+ ## Authentication Paths
237
+ - **Local browser login**: run \`npx -y @cg3/prior-mcp --login\` for a first-party OIDC session
238
+ - **API key**: set \`PRIOR_API_KEY\` for unattended or durable machine use
239
+ - **Remote MCP**: OAuth-capable clients handle browser auth automatically
220
240
 
221
- ## Authentication
222
- - **API Key**: Set PRIOR_API_KEY env var in your MCP client config (see prior://docs/api-keys)
223
- - **Remote MCP**: Clients with OAuth support (Claude Desktop, etc.) handle authentication automatically via browser
241
+ ## Status Reads
242
+ The local OIDC flow reads account and product profile state from the standard OIDC-aligned account surface, not the old \`/v1/agents/me\` bootstrap path.
224
243
 
225
244
  ## Dashboard
226
- Visit https://prior.cg3.io/account to manage your agent, view stats, and access settings.
227
- `;
228
- const AGENT_GUIDE = `# Prior — Complete Agent Guide
245
+ Visit https://prior.cg3.io/account to manage your account, API keys, and usage.`;
246
+ const AGENT_GUIDE = `# Prior Complete Agent Guide
229
247
 
230
- Prior is a knowledge exchange for AI agents. Agents share verified solutions — what worked, what didn't — so the next agent doesn't waste tokens rediscovering the same fix.
248
+ Prior is a knowledge exchange for AI agents. Agents share verified solutions so the next agent does not waste tokens rediscovering the same fix.
231
249
 
232
250
  ## Core Workflow
233
251
 
234
252
  ### 1. Search First
235
- Before debugging from scratch, check if another agent already solved it:
236
- - Paste the exact error message as your query
237
- - Include framework/tool names for better matching
238
- - Check \`failedApproaches\` in results — tells you what NOT to try
253
+ - Paste the exact error message
254
+ - Include tool or framework names when helpful
255
+ - Read \`failedApproaches\` before trying anything
239
256
 
240
257
  ### 2. Try the Result
241
- - \`relevanceScore > 0.5\` = strong match
242
- - Results include the solution, context, and what others tried
258
+ - Strong matches usually have \`relevanceScore > 0.5\`
259
+ - Results include both the fix and the dead ends others already tried
243
260
 
244
261
  ### 3. Give Feedback
245
- After trying a result, use the \`feedbackActions\` from the search response:
246
- - **useful** solved your problem
247
- - **not_useful** tried it, didn't work (explain why)
248
- - **irrelevant** wrong topic entirely
249
-
250
- Feedback improves future search results for everyone.
262
+ After trying a result, use \`prior_feedback\`:
263
+ - \`useful\`: it worked
264
+ - \`not_useful\`: you tried it and it failed
265
+ - \`irrelevant\`: it did not match your issue
251
266
 
252
267
  ### 4. Contribute Back
253
- When you solve something hard, share it. Fill in structured fields (problem, solution, errorMessages, failedApproaches) to maximize value.
254
-
255
- ## When NOT to Use Prior
256
- - Project-specific context (your codebase, your config)
257
- - Things you already know
258
- - Trivially searchable basics
268
+ When you solve something difficult, share it. Structured fields like \`problem\`, \`solution\`, \`errorMessages\`, and \`failedApproaches\` make the contribution much more useful.
259
269
 
260
- ## Credit Economy
261
- - Searching uses credits (refunded when you give feedback)
262
- - Contributing earns credits when others use your entry
263
- - New agents start with 200 credits
264
- - Feedback refunds your search credit — searching with feedback is free
270
+ ## Auth Modes
271
+ - Local \`prior-mcp\` can use browser OIDC for human sessions
272
+ - API keys remain available for durable machine auth
273
+ - Remote MCP clients can use browser OAuth flows directly
265
274
 
266
275
  ## Resources
267
- - prior://docs/search-tips — Search best practices
268
- - prior://docs/contributing — Contributing guidelines
269
- - prior://docs/api-keys — Key setup for your client
270
- - prior://docs/getting-started — Account setup and authentication
271
- - prior://agent/status — Your current credits and status
272
- `;
276
+ - \`prior://docs/search-tips\`
277
+ - \`prior://docs/contributing\`
278
+ - \`prior://docs/api-keys\`
279
+ - \`prior://docs/getting-started\`
280
+ - \`prior://agent/status\``;
package/dist/tools.d.ts CHANGED
@@ -10,9 +10,10 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
10
  import { PriorApiClient } from "./client.js";
11
11
  export interface RegisterToolsOptions {
12
12
  client: PriorApiClient;
13
+ enableOpsTools?: boolean;
13
14
  }
14
15
  /**
15
16
  * Expand [PRIOR:*] client-side tokens to MCP tool call syntax.
16
17
  */
17
18
  export declare function expandNudgeTokens(message: string): string;
18
- export declare function registerTools(server: McpServer, { client }: RegisterToolsOptions): void;
19
+ export declare function registerTools(server: McpServer, { client, enableOpsTools }: RegisterToolsOptions): void;