vantage-peers-mcp 2.3.1 → 2.3.3
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 +41 -0
- package/dist/src/tools.d.ts +92 -0
- package/dist/src/tools.js +216 -29
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.3.3 — 2026-05-28
|
|
4
|
+
|
|
5
|
+
**Follow-up to v2.3.2 (Day 84 scope élargi)** — Extend list queries with `createdBy` + `updatedSince` filters + auto-clamp safeguard.
|
|
6
|
+
|
|
7
|
+
Backend (Convex) :
|
|
8
|
+
- `tasks.list` + `tasks.listByMission` : + `createdBy` (filter by task creator) + `updatedSince` (Unix ms window) + auto-clamp limit=30 when `fields="full"` and no explicit limit
|
|
9
|
+
- `missions.list` : + `updatedSince` + auto-clamp (30)
|
|
10
|
+
- `briefingNotes.list` : + `updatedSince` + auto-clamp (15 when fields=full)
|
|
11
|
+
|
|
12
|
+
MCP wrapper :
|
|
13
|
+
- 4 list tools forward the new params
|
|
14
|
+
- New export `updatedSinceSchema` (positive integer ms)
|
|
15
|
+
- `limit` `.default()` removed on the 4 list tools so absent limit flows to backend → enables auto-clamp
|
|
16
|
+
|
|
17
|
+
Tests : 15 new MCP schema cases (`src/__tests__/list-queries-v2.3.3-createdby-updatedsince.test.ts`) + 6 new Convex round-trip cases.
|
|
18
|
+
|
|
19
|
+
Pi pull cycle unblocked : `list_tasks createdBy="pi" status="review" fields="lite"` returns only Pi-dispatched tasks recently moved to review, payload 5-10× smaller.
|
|
20
|
+
|
|
21
|
+
Cap fleet : 0 overflow tolérance future (auto-clamp).
|
|
22
|
+
|
|
23
|
+
VP task: `k1796s5j6jfkvkx0tn5n926ftd87jx9p`. Successor of `k17e09ng1tf217n93z9m4tr0mx87hfe0` (v2.3.2 PR #537).
|
|
24
|
+
|
|
25
|
+
## v2.3.2 — 2026-05-28
|
|
26
|
+
|
|
27
|
+
**Hotfix** — Expose `fields="lite"` + `status` array/aliases in MCP tool schemas (Day 82 sprint gap).
|
|
28
|
+
|
|
29
|
+
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:
|
|
30
|
+
|
|
31
|
+
- `list_tasks`: + `fields`, status now accepts aliases (`"open"`, `"active"`, `"all"`) and arrays
|
|
32
|
+
- `list_tasks_by_mission`: same
|
|
33
|
+
- `list_missions`: + `fields`, status accepts aliases and arrays
|
|
34
|
+
- `list_briefing_notes`: + `fields`
|
|
35
|
+
|
|
36
|
+
Aliases NOT permitted inside arrays (matches backend rejection contract).
|
|
37
|
+
|
|
38
|
+
Tests: 14 new cases (`src/__tests__/list-queries-schema-v2.3.2.test.ts`), 0 regression on 295+ existing.
|
|
39
|
+
|
|
40
|
+
Fix-pattern (fleet-wide): When backend query supports a new param, ALWAYS update the MCP wrapper tool schema in the SAME PR.
|
|
41
|
+
|
|
42
|
+
VP task: `k17e09ng1tf217n93z9m4tr0mx87hfe0`.
|
|
43
|
+
|
|
3
44
|
## 2.3.1 — 2026-05-26
|
|
4
45
|
|
|
5
46
|
### Fixed (Eta PR #530 delta-review)
|
package/dist/src/tools.d.ts
CHANGED
|
@@ -46,4 +46,96 @@ 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 declare const updatedSinceSchema: z.ZodNumber;
|
|
100
|
+
export interface ParsedConvexError {
|
|
101
|
+
code: string;
|
|
102
|
+
message: string;
|
|
103
|
+
path: string | null;
|
|
104
|
+
hint: string | null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse a Convex error message string into a structured object.
|
|
108
|
+
*
|
|
109
|
+
* Input example (from ConvexHttpClient):
|
|
110
|
+
* "[CONVEX M(briefingNotes:create)] ArgumentValidationError: Found ID
|
|
111
|
+
* \"js72ewf0m...\" from table briefingNotes, which does not match the table
|
|
112
|
+
* name in validator v.id(\"memories\"). Path: .linkedMemoryIds[4]"
|
|
113
|
+
*
|
|
114
|
+
* Returns { code, message, path, hint } where:
|
|
115
|
+
* - code = "ArgumentValidationError" (or the parsed error type)
|
|
116
|
+
* - message = the full human-readable error description after the code prefix
|
|
117
|
+
* - path = e.g. ".linkedMemoryIds[4]" extracted from "Path: ..." suffix
|
|
118
|
+
* - hint = a concise guidance string derived from the error, or null
|
|
119
|
+
*
|
|
120
|
+
* For unrecognised error strings, code = "ServerError" and path/hint = null.
|
|
121
|
+
*
|
|
122
|
+
* Exported for unit testing.
|
|
123
|
+
*/
|
|
124
|
+
export declare function parseConvexError(rawMessage: string): ParsedConvexError;
|
|
125
|
+
/**
|
|
126
|
+
* Produce a structured MCP error response for any error thrown by a Convex
|
|
127
|
+
* operation. For ConvexError / ArgumentValidationError the response body
|
|
128
|
+
* contains a JSON object with { code, message, path, hint } so the MCP client
|
|
129
|
+
* can display actionable diagnostics instead of a bare "Server Error" string.
|
|
130
|
+
*
|
|
131
|
+
* For unrecognised errors the response falls back to the plain text format
|
|
132
|
+
* used by `mcpError`.
|
|
133
|
+
*/
|
|
134
|
+
export declare function mcpConvexError(error: unknown): {
|
|
135
|
+
content: Array<{
|
|
136
|
+
type: "text";
|
|
137
|
+
text: string;
|
|
138
|
+
}>;
|
|
139
|
+
isError: true;
|
|
140
|
+
};
|
|
49
141
|
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,61 @@ 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.');
|
|
165
|
+
// v2.3.3 — Unix timestamp ms filter for "updated since".
|
|
166
|
+
// Pass `Date.now() - 24*60*60*1000` for "last 24h" pattern.
|
|
167
|
+
export const updatedSinceSchema = z
|
|
168
|
+
.number()
|
|
169
|
+
.int()
|
|
170
|
+
.positive()
|
|
171
|
+
.describe("Unix timestamp (ms) — return only rows whose updatedAt >= this value. " +
|
|
172
|
+
"Typical usage: Date.now() - 24*60*60*1000 for last-24h window.");
|
|
122
173
|
const mandateStatusSchema = z
|
|
123
174
|
.enum(["requested", "accepted", "in_progress", "delivered", "settled"])
|
|
124
175
|
.describe("Mandate lifecycle status");
|
|
@@ -180,6 +231,103 @@ function mcpError(message) {
|
|
|
180
231
|
isError: true,
|
|
181
232
|
};
|
|
182
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Parse a Convex error message string into a structured object.
|
|
236
|
+
*
|
|
237
|
+
* Input example (from ConvexHttpClient):
|
|
238
|
+
* "[CONVEX M(briefingNotes:create)] ArgumentValidationError: Found ID
|
|
239
|
+
* \"js72ewf0m...\" from table briefingNotes, which does not match the table
|
|
240
|
+
* name in validator v.id(\"memories\"). Path: .linkedMemoryIds[4]"
|
|
241
|
+
*
|
|
242
|
+
* Returns { code, message, path, hint } where:
|
|
243
|
+
* - code = "ArgumentValidationError" (or the parsed error type)
|
|
244
|
+
* - message = the full human-readable error description after the code prefix
|
|
245
|
+
* - path = e.g. ".linkedMemoryIds[4]" extracted from "Path: ..." suffix
|
|
246
|
+
* - hint = a concise guidance string derived from the error, or null
|
|
247
|
+
*
|
|
248
|
+
* For unrecognised error strings, code = "ServerError" and path/hint = null.
|
|
249
|
+
*
|
|
250
|
+
* Exported for unit testing.
|
|
251
|
+
*/
|
|
252
|
+
export function parseConvexError(rawMessage) {
|
|
253
|
+
// Known Convex validation/runtime error codes surfaced as plaintext
|
|
254
|
+
const knownCodes = [
|
|
255
|
+
"ArgumentValidationError",
|
|
256
|
+
"AuthorizationError",
|
|
257
|
+
"ConvexError",
|
|
258
|
+
"SchemaValidationError",
|
|
259
|
+
"QueryError",
|
|
260
|
+
"MutationError",
|
|
261
|
+
"ActionError",
|
|
262
|
+
];
|
|
263
|
+
// Strip the [CONVEX M(path)] / [CONVEX Q(path)] prefix if present
|
|
264
|
+
const stripped = rawMessage.replace(/^\[CONVEX [A-Z]+\([^\]]*\)\]\s*/, "");
|
|
265
|
+
// Detect the error code
|
|
266
|
+
let code = "ServerError";
|
|
267
|
+
let remainder = stripped;
|
|
268
|
+
for (const candidate of knownCodes) {
|
|
269
|
+
if (stripped.startsWith(candidate + ":") || stripped.startsWith(candidate + " ")) {
|
|
270
|
+
code = candidate;
|
|
271
|
+
remainder = stripped.slice(candidate.length).replace(/^[:\s]+/, "");
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Extract "Path: .<fieldPath>" from the tail of the message
|
|
276
|
+
// Convex appends this as the last sentence: "Path: .linkedMemoryIds[4]"
|
|
277
|
+
let path = null;
|
|
278
|
+
const pathMatch = remainder.match(/\bPath:\s*([\w.\[\]"']+)\s*$/);
|
|
279
|
+
if (pathMatch) {
|
|
280
|
+
path = pathMatch[1];
|
|
281
|
+
remainder = remainder.slice(0, pathMatch.index).trim().replace(/\.\s*$/, "");
|
|
282
|
+
}
|
|
283
|
+
// Build a concise hint for common patterns
|
|
284
|
+
let hint = null;
|
|
285
|
+
if (code === "ArgumentValidationError") {
|
|
286
|
+
const tableMatch = remainder.match(/from table (\w+),.*validator v\.id\("(\w+)"\)/);
|
|
287
|
+
if (tableMatch) {
|
|
288
|
+
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.`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return { code, message: remainder || rawMessage, path, hint };
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Produce a structured MCP error response for any error thrown by a Convex
|
|
295
|
+
* operation. For ConvexError / ArgumentValidationError the response body
|
|
296
|
+
* contains a JSON object with { code, message, path, hint } so the MCP client
|
|
297
|
+
* can display actionable diagnostics instead of a bare "Server Error" string.
|
|
298
|
+
*
|
|
299
|
+
* For unrecognised errors the response falls back to the plain text format
|
|
300
|
+
* used by `mcpError`.
|
|
301
|
+
*/
|
|
302
|
+
export function mcpConvexError(error) {
|
|
303
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
304
|
+
const parsed = parseConvexError(rawMessage);
|
|
305
|
+
// For ArgumentValidationError and other known Convex codes, return structured JSON
|
|
306
|
+
if (parsed.code !== "ServerError") {
|
|
307
|
+
const payload = {
|
|
308
|
+
code: parsed.code,
|
|
309
|
+
message: parsed.message,
|
|
310
|
+
};
|
|
311
|
+
if (parsed.path !== null)
|
|
312
|
+
payload.path = parsed.path;
|
|
313
|
+
if (parsed.hint !== null)
|
|
314
|
+
payload.hint = parsed.hint;
|
|
315
|
+
return {
|
|
316
|
+
content: [
|
|
317
|
+
{
|
|
318
|
+
type: "text",
|
|
319
|
+
text: JSON.stringify(payload, null, 2),
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
isError: true,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// Fallback: generic error, preserve existing plain-text format
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: `Error: ${rawMessage}` }],
|
|
328
|
+
isError: true,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
183
331
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
184
332
|
// Main export: register all tools against a server + convex client pair
|
|
185
333
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -991,7 +1139,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
991
1139
|
.string()
|
|
992
1140
|
.optional()
|
|
993
1141
|
.describe("Filter by instance — e.g. 'pi-vps'. Returns only tasks assigned to that instance."),
|
|
994
|
-
status:
|
|
1142
|
+
status: taskStatusFilterSchema
|
|
1143
|
+
.optional()
|
|
1144
|
+
.describe("Filter by status (single, alias, or array)"),
|
|
995
1145
|
project: z.string().optional().describe("Filter by project name"),
|
|
996
1146
|
limit: z
|
|
997
1147
|
.number()
|
|
@@ -999,16 +1149,25 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
999
1149
|
.min(1)
|
|
1000
1150
|
.max(200)
|
|
1001
1151
|
.optional()
|
|
1002
|
-
.
|
|
1003
|
-
|
|
1004
|
-
|
|
1152
|
+
.describe("Maximum number of tasks to return. Default 50 with fields=lite, auto-clamped to 30 when fields=full and no explicit limit (overflow protection)."),
|
|
1153
|
+
fields: fieldsSchema
|
|
1154
|
+
.optional()
|
|
1155
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1156
|
+
createdBy: assigneeSchema
|
|
1157
|
+
.optional()
|
|
1158
|
+
.describe("Filter by task creator (e.g. 'pi' to find Pi-dispatched tasks)"),
|
|
1159
|
+
updatedSince: updatedSinceSchema.optional(),
|
|
1160
|
+
}, async ({ assignedTo, assignedToInstance, status, project, limit, fields, createdBy, updatedSince, }) => {
|
|
1005
1161
|
try {
|
|
1006
1162
|
const tasks = await convex.query("tasks:list", {
|
|
1007
1163
|
assignedTo,
|
|
1008
1164
|
assignedToInstance,
|
|
1009
1165
|
status,
|
|
1010
1166
|
project,
|
|
1011
|
-
limit
|
|
1167
|
+
limit,
|
|
1168
|
+
fields,
|
|
1169
|
+
createdBy,
|
|
1170
|
+
updatedSince,
|
|
1012
1171
|
});
|
|
1013
1172
|
return {
|
|
1014
1173
|
content: [
|
|
@@ -1315,21 +1474,32 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1315
1474
|
// ── list_tasks_by_mission ───────────────────────────────────────────────────
|
|
1316
1475
|
server.tool("list_tasks_by_mission", "List all tasks linked to a specific mission. Optionally filter by status.", {
|
|
1317
1476
|
missionId: z.string().describe("Convex document ID of the mission"),
|
|
1318
|
-
status:
|
|
1477
|
+
status: taskStatusFilterSchema
|
|
1478
|
+
.optional()
|
|
1479
|
+
.describe("Filter by task status (single, alias, or array)"),
|
|
1319
1480
|
limit: z
|
|
1320
1481
|
.number()
|
|
1321
1482
|
.int()
|
|
1322
1483
|
.min(1)
|
|
1323
1484
|
.max(200)
|
|
1324
1485
|
.optional()
|
|
1325
|
-
.
|
|
1326
|
-
|
|
1327
|
-
|
|
1486
|
+
.describe("Maximum number of tasks to return. Default 50 with fields=lite, auto-clamped to 30 when fields=full and no explicit limit."),
|
|
1487
|
+
fields: fieldsSchema
|
|
1488
|
+
.optional()
|
|
1489
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1490
|
+
createdBy: assigneeSchema
|
|
1491
|
+
.optional()
|
|
1492
|
+
.describe("Filter by task creator"),
|
|
1493
|
+
updatedSince: updatedSinceSchema.optional(),
|
|
1494
|
+
}, async ({ missionId, status, limit, fields, createdBy, updatedSince }) => {
|
|
1328
1495
|
try {
|
|
1329
1496
|
const tasks = await convex.query("tasks:listByMission", {
|
|
1330
1497
|
missionId: missionId,
|
|
1331
1498
|
status,
|
|
1332
|
-
limit
|
|
1499
|
+
limit,
|
|
1500
|
+
fields,
|
|
1501
|
+
createdBy,
|
|
1502
|
+
updatedSince,
|
|
1333
1503
|
});
|
|
1334
1504
|
return {
|
|
1335
1505
|
content: [
|
|
@@ -1404,22 +1574,29 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1404
1574
|
"Filter by project, pilot, and/or status. Returns newest first.", {
|
|
1405
1575
|
project: z.string().optional().describe("Filter by project name"),
|
|
1406
1576
|
pilot: creatorSchema.optional().describe("Filter by pilot orchestrator"),
|
|
1407
|
-
status:
|
|
1577
|
+
status: missionStatusFilterSchema
|
|
1578
|
+
.optional()
|
|
1579
|
+
.describe("Filter by status (single, alias, or array)"),
|
|
1408
1580
|
limit: z
|
|
1409
1581
|
.number()
|
|
1410
1582
|
.int()
|
|
1411
1583
|
.min(1)
|
|
1412
1584
|
.max(200)
|
|
1413
1585
|
.optional()
|
|
1414
|
-
.
|
|
1415
|
-
|
|
1416
|
-
|
|
1586
|
+
.describe("Maximum number of missions to return. Default 50 with fields=lite, auto-clamped to 30 when fields=full and no explicit limit."),
|
|
1587
|
+
fields: fieldsSchema
|
|
1588
|
+
.optional()
|
|
1589
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1590
|
+
updatedSince: updatedSinceSchema.optional(),
|
|
1591
|
+
}, async ({ project, pilot, status, limit, fields, updatedSince }) => {
|
|
1417
1592
|
try {
|
|
1418
1593
|
const missions = await convex.query("missions:list", {
|
|
1419
1594
|
project,
|
|
1420
1595
|
pilot,
|
|
1421
1596
|
status,
|
|
1422
|
-
limit
|
|
1597
|
+
limit,
|
|
1598
|
+
fields,
|
|
1599
|
+
updatedSince,
|
|
1423
1600
|
});
|
|
1424
1601
|
return {
|
|
1425
1602
|
content: [
|
|
@@ -1630,7 +1807,9 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1630
1807
|
// ── create_briefing_note ────────────────────────────────────────────────────
|
|
1631
1808
|
server.tool("create_briefing_note", "Create a briefing note — a structured record of a topic discussion, with participants, " +
|
|
1632
1809
|
"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."
|
|
1810
|
+
"linkedMemoryIds MUST contain IDs from the memories table only — NOT briefingNotes IDs or IDs from any other table. " +
|
|
1811
|
+
"IMPORTANT: If you need to cross-link briefing notes together, use linkedBriefingIds (not yet shipped) — " +
|
|
1812
|
+
"passing a briefingNotes document ID into linkedMemoryIds will produce an ArgumentValidationError at the Convex validator boundary.", {
|
|
1634
1813
|
title: z.string().describe("Briefing note title"),
|
|
1635
1814
|
topic: z
|
|
1636
1815
|
.string()
|
|
@@ -1643,7 +1822,10 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1643
1822
|
linkedMemoryIds: z
|
|
1644
1823
|
.array(memoryIdSchema)
|
|
1645
1824
|
.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"
|
|
1825
|
+
.describe("Convex document IDs of related memories — each must be a 32-char ID from the memories table, NOT briefingNotes or any other table. " +
|
|
1826
|
+
"DISCLAIMER: Memory IDs only. Do NOT pass briefingNotes IDs here — they share the same 32-char alphanumeric format but belong to a different table. " +
|
|
1827
|
+
"Passing a briefingNotes ID will fail with ArgumentValidationError at path .linkedMemoryIds[N]. " +
|
|
1828
|
+
"If cross-linking briefings is needed, request the linkedBriefingIds feature instead."),
|
|
1647
1829
|
createdBy: creatorSchema,
|
|
1648
1830
|
}, async ({ title, topic, participants, content, decisions, linkedMemoryIds, createdBy, }) => {
|
|
1649
1831
|
let contentBytes = 0;
|
|
@@ -1680,7 +1862,7 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1680
1862
|
title,
|
|
1681
1863
|
errorMessage: error?.message ?? String(error),
|
|
1682
1864
|
});
|
|
1683
|
-
return
|
|
1865
|
+
return mcpConvexError(error);
|
|
1684
1866
|
}
|
|
1685
1867
|
});
|
|
1686
1868
|
// ── update_briefing_note ────────────────────────────────────────────────────
|
|
@@ -1721,7 +1903,7 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1721
1903
|
noteId,
|
|
1722
1904
|
errorMessage: error?.message ?? String(error),
|
|
1723
1905
|
});
|
|
1724
|
-
return
|
|
1906
|
+
return mcpConvexError(error);
|
|
1725
1907
|
}
|
|
1726
1908
|
});
|
|
1727
1909
|
// ── list_briefing_notes ─────────────────────────────────────────────────────
|
|
@@ -1736,13 +1918,18 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
1736
1918
|
.min(1)
|
|
1737
1919
|
.max(100)
|
|
1738
1920
|
.optional()
|
|
1739
|
-
.
|
|
1740
|
-
|
|
1741
|
-
|
|
1921
|
+
.describe("Maximum notes to return. Default 20 with fields=lite, auto-clamped to 15 when fields=full and no explicit limit."),
|
|
1922
|
+
fields: fieldsSchema
|
|
1923
|
+
.optional()
|
|
1924
|
+
.describe('Field projection ("lite"|"full")'),
|
|
1925
|
+
updatedSince: updatedSinceSchema.optional(),
|
|
1926
|
+
}, async ({ topic, limit, fields, updatedSince }) => {
|
|
1742
1927
|
try {
|
|
1743
1928
|
const notes = await convex.query("briefingNotes:list", {
|
|
1744
1929
|
topic,
|
|
1745
|
-
limit
|
|
1930
|
+
limit,
|
|
1931
|
+
fields,
|
|
1932
|
+
updatedSince,
|
|
1746
1933
|
});
|
|
1747
1934
|
return {
|
|
1748
1935
|
content: [
|
package/package.json
CHANGED