vantage-peers-mcp 2.3.0 → 2.3.2
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/CHANGELOG.md +26 -0
- package/dist/src/tools.d.ts +91 -0
- package/dist/src/tools.js +184 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.3.2 — 2026-05-28
|
|
4
|
+
|
|
5
|
+
**Hotfix** — Expose `fields="lite"` + `status` array/aliases in MCP tool schemas (Day 82 sprint gap).
|
|
6
|
+
|
|
7
|
+
Backend support for these params shipped in v2.3.1 but the MCP wrapper Zod schemas never exposed them, so MCP clients couldn't pass them. Fixed for 4 list tools:
|
|
8
|
+
|
|
9
|
+
- `list_tasks`: + `fields`, status now accepts aliases (`"open"`, `"active"`, `"all"`) and arrays
|
|
10
|
+
- `list_tasks_by_mission`: same
|
|
11
|
+
- `list_missions`: + `fields`, status accepts aliases and arrays
|
|
12
|
+
- `list_briefing_notes`: + `fields`
|
|
13
|
+
|
|
14
|
+
Aliases NOT permitted inside arrays (matches backend rejection contract).
|
|
15
|
+
|
|
16
|
+
Tests: 14 new cases (`src/__tests__/list-queries-schema-v2.3.2.test.ts`), 0 regression on 295+ existing.
|
|
17
|
+
|
|
18
|
+
Fix-pattern (fleet-wide): When backend query supports a new param, ALWAYS update the MCP wrapper tool schema in the SAME PR.
|
|
19
|
+
|
|
20
|
+
VP task: `k17e09ng1tf217n93z9m4tr0mx87hfe0`.
|
|
21
|
+
|
|
22
|
+
## 2.3.1 — 2026-05-26
|
|
23
|
+
|
|
24
|
+
### Fixed (Eta PR #530 delta-review)
|
|
25
|
+
- `status="all"` now actually returns every row (no filter applied). Previously advertised in 2.3.0 docs but the Convex `expandTaskStatuses` / `expandMissionStatuses` helpers rejected it as invalid.
|
|
26
|
+
- `status=["all"]` (alias inside an array) now correctly throws `ConvexError` — same conservative-rejection rule as `"open"` / `"active"`.
|
|
27
|
+
- `setPendingAliasReleases` on the Convex backend converted from `mutation` to `internalMutation`. It was a public DoS surface against the auto-IRP pipeline; it is a lifecycle operation only and must not be reachable via MCP.
|
|
28
|
+
|
|
3
29
|
## 2.3.0 — 2026-05-26
|
|
4
30
|
|
|
5
31
|
### Added
|
package/dist/src/tools.d.ts
CHANGED
|
@@ -46,4 +46,95 @@ export declare const updateBriefingNoteSchema: z.ZodObject<{
|
|
|
46
46
|
decisions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
47
47
|
linkedMemoryIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
48
48
|
}, z.core.$strip>;
|
|
49
|
+
export declare const taskStatusSchema: z.ZodEnum<{
|
|
50
|
+
todo: "todo";
|
|
51
|
+
in_progress: "in_progress";
|
|
52
|
+
review: "review";
|
|
53
|
+
blocked: "blocked";
|
|
54
|
+
done: "done";
|
|
55
|
+
}>;
|
|
56
|
+
export declare const missionStatusSchema: z.ZodEnum<{
|
|
57
|
+
brainstorm: "brainstorm";
|
|
58
|
+
plan: "plan";
|
|
59
|
+
execute: "execute";
|
|
60
|
+
validate: "validate";
|
|
61
|
+
complete: "complete";
|
|
62
|
+
}>;
|
|
63
|
+
export declare const taskStatusFilterSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
64
|
+
todo: "todo";
|
|
65
|
+
in_progress: "in_progress";
|
|
66
|
+
review: "review";
|
|
67
|
+
blocked: "blocked";
|
|
68
|
+
done: "done";
|
|
69
|
+
active: "active";
|
|
70
|
+
open: "open";
|
|
71
|
+
all: "all";
|
|
72
|
+
}>, z.ZodArray<z.ZodEnum<{
|
|
73
|
+
todo: "todo";
|
|
74
|
+
in_progress: "in_progress";
|
|
75
|
+
review: "review";
|
|
76
|
+
blocked: "blocked";
|
|
77
|
+
done: "done";
|
|
78
|
+
}>>]>;
|
|
79
|
+
export declare const missionStatusFilterSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
80
|
+
brainstorm: "brainstorm";
|
|
81
|
+
plan: "plan";
|
|
82
|
+
execute: "execute";
|
|
83
|
+
validate: "validate";
|
|
84
|
+
complete: "complete";
|
|
85
|
+
active: "active";
|
|
86
|
+
open: "open";
|
|
87
|
+
all: "all";
|
|
88
|
+
}>, z.ZodArray<z.ZodEnum<{
|
|
89
|
+
brainstorm: "brainstorm";
|
|
90
|
+
plan: "plan";
|
|
91
|
+
execute: "execute";
|
|
92
|
+
validate: "validate";
|
|
93
|
+
complete: "complete";
|
|
94
|
+
}>>]>;
|
|
95
|
+
export declare const fieldsSchema: z.ZodEnum<{
|
|
96
|
+
lite: "lite";
|
|
97
|
+
full: "full";
|
|
98
|
+
}>;
|
|
99
|
+
export interface ParsedConvexError {
|
|
100
|
+
code: string;
|
|
101
|
+
message: string;
|
|
102
|
+
path: string | null;
|
|
103
|
+
hint: string | null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse a Convex error message string into a structured object.
|
|
107
|
+
*
|
|
108
|
+
* Input example (from ConvexHttpClient):
|
|
109
|
+
* "[CONVEX M(briefingNotes:create)] ArgumentValidationError: Found ID
|
|
110
|
+
* \"js72ewf0m...\" from table briefingNotes, which does not match the table
|
|
111
|
+
* name in validator v.id(\"memories\"). Path: .linkedMemoryIds[4]"
|
|
112
|
+
*
|
|
113
|
+
* Returns { code, message, path, hint } where:
|
|
114
|
+
* - code = "ArgumentValidationError" (or the parsed error type)
|
|
115
|
+
* - message = the full human-readable error description after the code prefix
|
|
116
|
+
* - path = e.g. ".linkedMemoryIds[4]" extracted from "Path: ..." suffix
|
|
117
|
+
* - hint = a concise guidance string derived from the error, or null
|
|
118
|
+
*
|
|
119
|
+
* For unrecognised error strings, code = "ServerError" and path/hint = null.
|
|
120
|
+
*
|
|
121
|
+
* Exported for unit testing.
|
|
122
|
+
*/
|
|
123
|
+
export declare function parseConvexError(rawMessage: string): ParsedConvexError;
|
|
124
|
+
/**
|
|
125
|
+
* Produce a structured MCP error response for any error thrown by a Convex
|
|
126
|
+
* operation. For ConvexError / ArgumentValidationError the response body
|
|
127
|
+
* contains a JSON object with { code, message, path, hint } so the MCP client
|
|
128
|
+
* can display actionable diagnostics instead of a bare "Server Error" string.
|
|
129
|
+
*
|
|
130
|
+
* For unrecognised errors the response falls back to the plain text format
|
|
131
|
+
* used by `mcpError`.
|
|
132
|
+
*/
|
|
133
|
+
export declare function mcpConvexError(error: unknown): {
|
|
134
|
+
content: Array<{
|
|
135
|
+
type: "text";
|
|
136
|
+
text: string;
|
|
137
|
+
}>;
|
|
138
|
+
isError: true;
|
|
139
|
+
};
|
|
49
140
|
export declare function registerTools(server: McpServer, convex: ConvexHttpClient, oauthCtx?: OAuthContext): void;
|
package/dist/src/tools.js
CHANGED
|
@@ -101,7 +101,9 @@ export const updateBriefingNoteSchema = z.object({
|
|
|
101
101
|
linkedMemoryIds: z
|
|
102
102
|
.array(memoryIdSchema)
|
|
103
103
|
.optional()
|
|
104
|
-
.describe("Optional new linkedMemoryIds array — full replace, not append.
|
|
104
|
+
.describe("Optional new linkedMemoryIds array — full replace, not append. " +
|
|
105
|
+
"DISCLAIMER: Memory IDs only — NOT briefingNotes IDs or any other table. " +
|
|
106
|
+
"Passing a briefingNotes ID causes ArgumentValidationError at path .linkedMemoryIds[N]."),
|
|
105
107
|
});
|
|
106
108
|
const assigneeSchema = z
|
|
107
109
|
.string()
|
|
@@ -113,12 +115,53 @@ const prioritySchema = z
|
|
|
113
115
|
const componentTypeSchema = z
|
|
114
116
|
.enum(["agent", "skill", "hook", "plugin"])
|
|
115
117
|
.describe("Component type");
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
const taskStatusValues = [
|
|
119
|
+
"todo",
|
|
120
|
+
"in_progress",
|
|
121
|
+
"review",
|
|
122
|
+
"blocked",
|
|
123
|
+
"done",
|
|
124
|
+
];
|
|
125
|
+
const taskStatusAliases = ["open", "active", "all"];
|
|
126
|
+
export const taskStatusSchema = z.enum(taskStatusValues).describe("Task status");
|
|
127
|
+
const missionStatusValues = [
|
|
128
|
+
"brainstorm",
|
|
129
|
+
"plan",
|
|
130
|
+
"execute",
|
|
131
|
+
"validate",
|
|
132
|
+
"complete",
|
|
133
|
+
];
|
|
134
|
+
const missionStatusAliases = ["open", "active", "all"];
|
|
135
|
+
export const missionStatusSchema = z
|
|
136
|
+
.enum(missionStatusValues)
|
|
121
137
|
.describe("Mission lifecycle status");
|
|
138
|
+
// v2.3.2 — filter-only schemas: expose status aliases ("open"/"active"/"all")
|
|
139
|
+
// AND multi-status arrays to the MCP client. Backend (convex/tasks.ts +
|
|
140
|
+
// convex/missions.ts) handles alias expansion + array validation.
|
|
141
|
+
// Aliases NOT allowed inside arrays (matches backend rejection).
|
|
142
|
+
export const taskStatusFilterSchema = z
|
|
143
|
+
.union([
|
|
144
|
+
z.enum([...taskStatusValues, ...taskStatusAliases]),
|
|
145
|
+
z.array(z.enum(taskStatusValues)).min(1),
|
|
146
|
+
])
|
|
147
|
+
.describe('Task status filter. Single status ("todo"|"in_progress"|"review"|"blocked"|"done"), ' +
|
|
148
|
+
'alias ("open" = todo+in_progress+review+blocked, "active" = todo+in_progress, "all" = no filter), ' +
|
|
149
|
+
'or array of direct statuses (no aliases inside array).');
|
|
150
|
+
export const missionStatusFilterSchema = z
|
|
151
|
+
.union([
|
|
152
|
+
z.enum([...missionStatusValues, ...missionStatusAliases]),
|
|
153
|
+
z.array(z.enum(missionStatusValues)).min(1),
|
|
154
|
+
])
|
|
155
|
+
.describe('Mission status filter. Single status ("brainstorm"|"plan"|"execute"|"validate"|"complete"), ' +
|
|
156
|
+
'alias ("open" = brainstorm+plan+execute+validate, "active" = plan+execute, "all" = no filter), ' +
|
|
157
|
+
'or array of direct statuses (no aliases inside array).');
|
|
158
|
+
// v2.3.2 — fields projection toggle. "lite" returns compact projection
|
|
159
|
+
// (5-10× smaller payload), "full" (default) returns full doc.
|
|
160
|
+
export const fieldsSchema = z
|
|
161
|
+
.enum(["lite", "full"])
|
|
162
|
+
.describe('Field projection — "lite" returns compact fields only ' +
|
|
163
|
+
'(typical 5-10× smaller payload for large list scans), ' +
|
|
164
|
+
'"full" (default) returns the full document.');
|
|
122
165
|
const mandateStatusSchema = z
|
|
123
166
|
.enum(["requested", "accepted", "in_progress", "delivered", "settled"])
|
|
124
167
|
.describe("Mandate lifecycle status");
|
|
@@ -180,6 +223,103 @@ function mcpError(message) {
|
|
|
180
223
|
isError: true,
|
|
181
224
|
};
|
|
182
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Parse a Convex error message string into a structured object.
|
|
228
|
+
*
|
|
229
|
+
* Input example (from ConvexHttpClient):
|
|
230
|
+
* "[CONVEX M(briefingNotes:create)] ArgumentValidationError: Found ID
|
|
231
|
+
* \"js72ewf0m...\" from table briefingNotes, which does not match the table
|
|
232
|
+
* name in validator v.id(\"memories\"). Path: .linkedMemoryIds[4]"
|
|
233
|
+
*
|
|
234
|
+
* Returns { code, message, path, hint } where:
|
|
235
|
+
* - code = "ArgumentValidationError" (or the parsed error type)
|
|
236
|
+
* - message = the full human-readable error description after the code prefix
|
|
237
|
+
* - path = e.g. ".linkedMemoryIds[4]" extracted from "Path: ..." suffix
|
|
238
|
+
* - hint = a concise guidance string derived from the error, or null
|
|
239
|
+
*
|
|
240
|
+
* For unrecognised error strings, code = "ServerError" and path/hint = null.
|
|
241
|
+
*
|
|
242
|
+
* Exported for unit testing.
|
|
243
|
+
*/
|
|
244
|
+
export function parseConvexError(rawMessage) {
|
|
245
|
+
// Known Convex validation/runtime error codes surfaced as plaintext
|
|
246
|
+
const knownCodes = [
|
|
247
|
+
"ArgumentValidationError",
|
|
248
|
+
"AuthorizationError",
|
|
249
|
+
"ConvexError",
|
|
250
|
+
"SchemaValidationError",
|
|
251
|
+
"QueryError",
|
|
252
|
+
"MutationError",
|
|
253
|
+
"ActionError",
|
|
254
|
+
];
|
|
255
|
+
// Strip the [CONVEX M(path)] / [CONVEX Q(path)] prefix if present
|
|
256
|
+
const stripped = rawMessage.replace(/^\[CONVEX [A-Z]+\([^\]]*\)\]\s*/, "");
|
|
257
|
+
// Detect the error code
|
|
258
|
+
let code = "ServerError";
|
|
259
|
+
let remainder = stripped;
|
|
260
|
+
for (const candidate of knownCodes) {
|
|
261
|
+
if (stripped.startsWith(candidate + ":") || stripped.startsWith(candidate + " ")) {
|
|
262
|
+
code = candidate;
|
|
263
|
+
remainder = stripped.slice(candidate.length).replace(/^[:\s]+/, "");
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Extract "Path: .<fieldPath>" from the tail of the message
|
|
268
|
+
// Convex appends this as the last sentence: "Path: .linkedMemoryIds[4]"
|
|
269
|
+
let path = null;
|
|
270
|
+
const pathMatch = remainder.match(/\bPath:\s*([\w.\[\]"']+)\s*$/);
|
|
271
|
+
if (pathMatch) {
|
|
272
|
+
path = pathMatch[1];
|
|
273
|
+
remainder = remainder.slice(0, pathMatch.index).trim().replace(/\.\s*$/, "");
|
|
274
|
+
}
|
|
275
|
+
// Build a concise hint for common patterns
|
|
276
|
+
let hint = null;
|
|
277
|
+
if (code === "ArgumentValidationError") {
|
|
278
|
+
const tableMatch = remainder.match(/from table (\w+),.*validator v\.id\("(\w+)"\)/);
|
|
279
|
+
if (tableMatch) {
|
|
280
|
+
hint = `ID belongs to table "${tableMatch[1]}" but validator expects v.id("${tableMatch[2]}"). Check that you are passing the correct document ID from the "${tableMatch[2]}" table.`;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return { code, message: remainder || rawMessage, path, hint };
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Produce a structured MCP error response for any error thrown by a Convex
|
|
287
|
+
* operation. For ConvexError / ArgumentValidationError the response body
|
|
288
|
+
* contains a JSON object with { code, message, path, hint } so the MCP client
|
|
289
|
+
* can display actionable diagnostics instead of a bare "Server Error" string.
|
|
290
|
+
*
|
|
291
|
+
* For unrecognised errors the response falls back to the plain text format
|
|
292
|
+
* used by `mcpError`.
|
|
293
|
+
*/
|
|
294
|
+
export function mcpConvexError(error) {
|
|
295
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
296
|
+
const parsed = parseConvexError(rawMessage);
|
|
297
|
+
// For ArgumentValidationError and other known Convex codes, return structured JSON
|
|
298
|
+
if (parsed.code !== "ServerError") {
|
|
299
|
+
const payload = {
|
|
300
|
+
code: parsed.code,
|
|
301
|
+
message: parsed.message,
|
|
302
|
+
};
|
|
303
|
+
if (parsed.path !== null)
|
|
304
|
+
payload.path = parsed.path;
|
|
305
|
+
if (parsed.hint !== null)
|
|
306
|
+
payload.hint = parsed.hint;
|
|
307
|
+
return {
|
|
308
|
+
content: [
|
|
309
|
+
{
|
|
310
|
+
type: "text",
|
|
311
|
+
text: JSON.stringify(payload, null, 2),
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
isError: true,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
// Fallback: generic error, preserve existing plain-text format
|
|
318
|
+
return {
|
|
319
|
+
content: [{ type: "text", text: `Error: ${rawMessage}` }],
|
|
320
|
+
isError: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
183
323
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
184
324
|
// Main export: register all tools against a server + convex client pair
|
|
185
325
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -991,7 +1131,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
991
1131
|
.string()
|
|
992
1132
|
.optional()
|
|
993
1133
|
.describe("Filter by instance — e.g. 'pi-vps'. Returns only tasks assigned to that instance."),
|
|
994
|
-
status:
|
|
1134
|
+
status: taskStatusFilterSchema
|
|
1135
|
+
.optional()
|
|
1136
|
+
.describe("Filter by status (single, alias, or array)"),
|
|
995
1137
|
project: z.string().optional().describe("Filter by project name"),
|
|
996
1138
|
limit: z
|
|
997
1139
|
.number()
|
|
@@ -1001,7 +1143,10 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1001
1143
|
.optional()
|
|
1002
1144
|
.default(50)
|
|
1003
1145
|
.describe("Maximum number of tasks to return (default 50)"),
|
|
1004
|
-
|
|
1146
|
+
fields: fieldsSchema
|
|
1147
|
+
.optional()
|
|
1148
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1149
|
+
}, async ({ assignedTo, assignedToInstance, status, project, limit, fields, }) => {
|
|
1005
1150
|
try {
|
|
1006
1151
|
const tasks = await convex.query("tasks:list", {
|
|
1007
1152
|
assignedTo,
|
|
@@ -1009,6 +1154,7 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1009
1154
|
status,
|
|
1010
1155
|
project,
|
|
1011
1156
|
limit: limit ?? 50,
|
|
1157
|
+
fields,
|
|
1012
1158
|
});
|
|
1013
1159
|
return {
|
|
1014
1160
|
content: [
|
|
@@ -1315,7 +1461,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1315
1461
|
// ── list_tasks_by_mission ───────────────────────────────────────────────────
|
|
1316
1462
|
server.tool("list_tasks_by_mission", "List all tasks linked to a specific mission. Optionally filter by status.", {
|
|
1317
1463
|
missionId: z.string().describe("Convex document ID of the mission"),
|
|
1318
|
-
status:
|
|
1464
|
+
status: taskStatusFilterSchema
|
|
1465
|
+
.optional()
|
|
1466
|
+
.describe("Filter by task status (single, alias, or array)"),
|
|
1319
1467
|
limit: z
|
|
1320
1468
|
.number()
|
|
1321
1469
|
.int()
|
|
@@ -1324,12 +1472,16 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1324
1472
|
.optional()
|
|
1325
1473
|
.default(50)
|
|
1326
1474
|
.describe("Maximum number of tasks to return (default 50)"),
|
|
1327
|
-
|
|
1475
|
+
fields: fieldsSchema
|
|
1476
|
+
.optional()
|
|
1477
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1478
|
+
}, async ({ missionId, status, limit, fields }) => {
|
|
1328
1479
|
try {
|
|
1329
1480
|
const tasks = await convex.query("tasks:listByMission", {
|
|
1330
1481
|
missionId: missionId,
|
|
1331
1482
|
status,
|
|
1332
1483
|
limit: limit ?? 50,
|
|
1484
|
+
fields,
|
|
1333
1485
|
});
|
|
1334
1486
|
return {
|
|
1335
1487
|
content: [
|
|
@@ -1404,7 +1556,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1404
1556
|
"Filter by project, pilot, and/or status. Returns newest first.", {
|
|
1405
1557
|
project: z.string().optional().describe("Filter by project name"),
|
|
1406
1558
|
pilot: creatorSchema.optional().describe("Filter by pilot orchestrator"),
|
|
1407
|
-
status:
|
|
1559
|
+
status: missionStatusFilterSchema
|
|
1560
|
+
.optional()
|
|
1561
|
+
.describe("Filter by status (single, alias, or array)"),
|
|
1408
1562
|
limit: z
|
|
1409
1563
|
.number()
|
|
1410
1564
|
.int()
|
|
@@ -1413,13 +1567,17 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1413
1567
|
.optional()
|
|
1414
1568
|
.default(50)
|
|
1415
1569
|
.describe("Maximum number of missions to return (default 50)"),
|
|
1416
|
-
|
|
1570
|
+
fields: fieldsSchema
|
|
1571
|
+
.optional()
|
|
1572
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1573
|
+
}, async ({ project, pilot, status, limit, fields }) => {
|
|
1417
1574
|
try {
|
|
1418
1575
|
const missions = await convex.query("missions:list", {
|
|
1419
1576
|
project,
|
|
1420
1577
|
pilot,
|
|
1421
1578
|
status,
|
|
1422
1579
|
limit: limit ?? 50,
|
|
1580
|
+
fields,
|
|
1423
1581
|
});
|
|
1424
1582
|
return {
|
|
1425
1583
|
content: [
|
|
@@ -1630,7 +1788,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1630
1788
|
// ── create_briefing_note ────────────────────────────────────────────────────
|
|
1631
1789
|
server.tool("create_briefing_note", "Create a briefing note — a structured record of a topic discussion, with participants, " +
|
|
1632
1790
|
"content, optional decisions, and optional links to existing memories. " +
|
|
1633
|
-
"linkedMemoryIds MUST contain IDs from the memories table only — NOT briefingNotes IDs or IDs from any other table."
|
|
1791
|
+
"linkedMemoryIds MUST contain IDs from the memories table only — NOT briefingNotes IDs or IDs from any other table. " +
|
|
1792
|
+
"IMPORTANT: If you need to cross-link briefing notes together, use linkedBriefingIds (not yet shipped) — " +
|
|
1793
|
+
"passing a briefingNotes document ID into linkedMemoryIds will produce an ArgumentValidationError at the Convex validator boundary.", {
|
|
1634
1794
|
title: z.string().describe("Briefing note title"),
|
|
1635
1795
|
topic: z
|
|
1636
1796
|
.string()
|
|
@@ -1643,7 +1803,10 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1643
1803
|
linkedMemoryIds: z
|
|
1644
1804
|
.array(memoryIdSchema)
|
|
1645
1805
|
.optional()
|
|
1646
|
-
.describe("Convex document IDs of related memories — each must be a 32-char ID from the memories table, NOT briefingNotes or any other table"
|
|
1806
|
+
.describe("Convex document IDs of related memories — each must be a 32-char ID from the memories table, NOT briefingNotes or any other table. " +
|
|
1807
|
+
"DISCLAIMER: Memory IDs only. Do NOT pass briefingNotes IDs here — they share the same 32-char alphanumeric format but belong to a different table. " +
|
|
1808
|
+
"Passing a briefingNotes ID will fail with ArgumentValidationError at path .linkedMemoryIds[N]. " +
|
|
1809
|
+
"If cross-linking briefings is needed, request the linkedBriefingIds feature instead."),
|
|
1647
1810
|
createdBy: creatorSchema,
|
|
1648
1811
|
}, async ({ title, topic, participants, content, decisions, linkedMemoryIds, createdBy, }) => {
|
|
1649
1812
|
let contentBytes = 0;
|
|
@@ -1680,7 +1843,7 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1680
1843
|
title,
|
|
1681
1844
|
errorMessage: error?.message ?? String(error),
|
|
1682
1845
|
});
|
|
1683
|
-
return
|
|
1846
|
+
return mcpConvexError(error);
|
|
1684
1847
|
}
|
|
1685
1848
|
});
|
|
1686
1849
|
// ── update_briefing_note ────────────────────────────────────────────────────
|
|
@@ -1721,7 +1884,7 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1721
1884
|
noteId,
|
|
1722
1885
|
errorMessage: error?.message ?? String(error),
|
|
1723
1886
|
});
|
|
1724
|
-
return
|
|
1887
|
+
return mcpConvexError(error);
|
|
1725
1888
|
}
|
|
1726
1889
|
});
|
|
1727
1890
|
// ── list_briefing_notes ─────────────────────────────────────────────────────
|
|
@@ -1738,11 +1901,15 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1738
1901
|
.optional()
|
|
1739
1902
|
.default(20)
|
|
1740
1903
|
.describe("Maximum notes to return (default 20)"),
|
|
1741
|
-
|
|
1904
|
+
fields: fieldsSchema
|
|
1905
|
+
.optional()
|
|
1906
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1907
|
+
}, async ({ topic, limit, fields }) => {
|
|
1742
1908
|
try {
|
|
1743
1909
|
const notes = await convex.query("briefingNotes:list", {
|
|
1744
1910
|
topic,
|
|
1745
1911
|
limit: limit ?? 20,
|
|
1912
|
+
fields,
|
|
1746
1913
|
});
|
|
1747
1914
|
return {
|
|
1748
1915
|
content: [
|
package/package.json
CHANGED