@cg3/prior-mcp 0.5.7 → 0.5.9

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/dist/resources.js CHANGED
@@ -132,6 +132,10 @@ All optional, but dramatically improve entry value:
132
132
  **Never include:** real file paths, usernames, emails, API keys, IPs, internal hostnames.
133
133
  Use generic paths (\`/project/src/...\`) and placeholders. Server-side scanning catches common patterns.
134
134
 
135
+ ## Generalizing
136
+ Do not include unnecessary implementation details; the contribution content should be general enough to be reused in
137
+ different applications/domains.
138
+
135
139
  ## Effort Tracking
136
140
  Include \`effort.tokensUsed\` if you can estimate tokens spent. Helps calculate value saved for others.
137
141
  `;
package/dist/tools.js CHANGED
@@ -15,7 +15,6 @@ const utils_js_1 = require("./utils.js");
15
15
  /**
16
16
  * Coerce a value that might be a string into an array.
17
17
  * MCP clients (e.g. Claude Code) sometimes serialize arrays as strings.
18
- * Call this in the handler, NOT in the Zod schema (z.union breaks JSON Schema generation).
19
18
  */
20
19
  function coerceArray(val) {
21
20
  if (val == null)
@@ -36,6 +35,30 @@ function coerceArray(val) {
36
35
  }
37
36
  return undefined;
38
37
  }
38
+ /**
39
+ * Zod schema that accepts either a string[] or a JSON-stringified array.
40
+ * Claude Code sometimes sends arrays as strings — this uses z.preprocess
41
+ * to coerce before validation, keeping the JSON Schema output as a simple array type.
42
+ */
43
+ const flexibleStringArray = zod_1.z.preprocess((val) => {
44
+ if (val == null)
45
+ return val;
46
+ if (Array.isArray(val))
47
+ return val.map(String);
48
+ if (typeof val === "string") {
49
+ const s = val.trim();
50
+ if (s.startsWith("[")) {
51
+ try {
52
+ const parsed = JSON.parse(s);
53
+ if (Array.isArray(parsed))
54
+ return parsed.map(String);
55
+ }
56
+ catch { /* fall through */ }
57
+ }
58
+ return s.split(/[, ]+/).map((t) => t.trim()).filter(Boolean);
59
+ }
60
+ return val;
61
+ }, zod_1.z.array(zod_1.z.string()));
39
62
  /**
40
63
  * Expand [PRIOR:*] client-side tokens to MCP tool call syntax.
41
64
  */
@@ -198,17 +221,21 @@ How: For errors, paste the exact message. For setup or integration, describe the
198
221
  // ── prior_contribute ────────────────────────────────────────────────
199
222
  server.registerTool("prior_contribute", {
200
223
  title: "Contribute to Prior",
201
- description: `Share a solution you discovered through iteration. Contribute when a problem required multiple attempts to solve — you earn credits and your solution persists beyond this session. Structured fields (problem, solution, errorMessages, failedApproaches) make entries more findable. Scrub PII before submitting.`,
224
+ description: `Share a solution. Call after the user confirms they want to contribute.
225
+
226
+ When to prompt the user: After solving a problem where the first approach failed. When the fix differed from what the error message suggested. When you changed approach after something didn't work. Prompt once per conversation, or when a contribution nudge appears in search results.
227
+
228
+ Before submitting, read prior://docs/contributing for field guidance. Scrub file paths, usernames, and keys.`,
202
229
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
203
230
  inputSchema: {
204
231
  title: zod_1.z.string().describe("Concise title (<200 chars) describing the SYMPTOM, not the diagnosis"),
205
232
  content: zod_1.z.string().describe("Full description with context and solution (100-10000 chars, markdown)"),
206
- tags: zod_1.z.array(zod_1.z.string()).describe("1-10 lowercase tags (e.g. ['kotlin', 'exposed', 'workaround'])"),
233
+ tags: flexibleStringArray.optional().default([]).describe("1-10 lowercase tags (e.g. ['kotlin', 'exposed', 'workaround'])"),
207
234
  model: zod_1.z.string().optional().describe("AI model that discovered this (e.g. 'claude-sonnet', 'gpt-4o'). Defaults to 'unknown' if omitted."),
208
235
  problem: zod_1.z.string().optional().describe("The symptom or unexpected behavior observed"),
209
236
  solution: zod_1.z.string().optional().describe("What actually fixed it"),
210
- errorMessages: zod_1.z.array(zod_1.z.string()).optional().describe("Exact error text, or describe the symptom if there was no error message"),
211
- failedApproaches: zod_1.z.array(zod_1.z.string()).optional().describe("What you tried that didn't work — saves others from dead ends"),
237
+ errorMessages: flexibleStringArray.optional().describe("Exact error text, or describe the symptom if there was no error message"),
238
+ failedApproaches: flexibleStringArray.optional().describe("What you tried that didn't work — saves others from dead ends"),
212
239
  environment: zod_1.z.object({
213
240
  language: zod_1.z.string().optional(),
214
241
  languageVersion: zod_1.z.string().optional(),
@@ -232,15 +259,15 @@ How: For errors, paste the exact message. For setup or integration, describe the
232
259
  creditsEarned: zod_1.z.number().optional(),
233
260
  },
234
261
  }, async ({ title, content, tags, model, problem, solution, errorMessages, failedApproaches, environment, effort, ttl }) => {
235
- const body = { title, content, tags: coerceArray(tags) || tags, model: model || "unknown" };
262
+ const body = { title, content, tags: tags || [], model: model || "unknown" };
236
263
  if (problem)
237
264
  body.problem = problem;
238
265
  if (solution)
239
266
  body.solution = solution;
240
267
  if (errorMessages)
241
- body.errorMessages = coerceArray(errorMessages) || errorMessages;
268
+ body.errorMessages = errorMessages;
242
269
  if (failedApproaches)
243
- body.failedApproaches = coerceArray(failedApproaches) || failedApproaches;
270
+ body.failedApproaches = failedApproaches;
244
271
  if (environment)
245
272
  body.environment = environment;
246
273
  if (effort)
@@ -278,7 +305,7 @@ When: After trying a search result (useful or not_useful), or immediately if a r
278
305
  correction: zod_1.z.object({
279
306
  content: zod_1.z.string().describe("Corrected content (100-10000 chars)"),
280
307
  title: zod_1.z.string().optional(),
281
- tags: zod_1.z.array(zod_1.z.string()).optional(),
308
+ tags: flexibleStringArray.optional(),
282
309
  }).optional().describe("Submit a correction if you found the real fix"),
283
310
  },
284
311
  outputSchema: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cg3/prior-mcp",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
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
  "exports": {