@critical-path/mcp 0.11.6 → 0.11.8
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/package.json +13 -9
- package/CHANGELOG.md +0 -421
- package/dist/bin/args.test.d.ts +0 -2
- package/dist/bin/args.test.d.ts.map +0 -1
- package/dist/bin/args.test.js +0 -24
- package/dist/bin/args.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -274
- package/dist/index.test.js.map +0 -1
- package/dist/tools/definitions.test.d.ts +0 -2
- package/dist/tools/definitions.test.d.ts.map +0 -1
- package/dist/tools/definitions.test.js +0 -24
- package/dist/tools/definitions.test.js.map +0 -1
- package/src/bin/args.test.ts +0 -28
- package/src/bin/args.ts +0 -50
- package/src/bin/cli.ts +0 -75
- package/src/index.test.ts +0 -347
- package/src/index.ts +0 -3
- package/src/server/index.ts +0 -275
- package/src/tools/definitions.test.ts +0 -29
- package/src/tools/definitions.ts +0 -472
- package/src/web/index.ts +0 -162
- package/tsconfig.json +0 -8
- package/tsconfig.tsbuildinfo +0 -1
package/src/tools/definitions.ts
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
-
import type { CriticalPathEngine } from '@critical-path/core';
|
|
4
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
5
|
-
|
|
6
|
-
export type BackendContext = CriticalPathEngine | CriticalPathClient;
|
|
7
|
-
|
|
8
|
-
export interface ToolDefinition<TParams = any, TResult = any> {
|
|
9
|
-
name: string;
|
|
10
|
-
title: string;
|
|
11
|
-
description: string;
|
|
12
|
-
zodSchema: z.ZodObject<any>;
|
|
13
|
-
/** JSON Schema shown to MCP clients. Generated from `zodSchema` by `defineTool`. */
|
|
14
|
-
inputSchema: Record<string, unknown>;
|
|
15
|
-
annotations?: {
|
|
16
|
-
readOnlyHint?: boolean;
|
|
17
|
-
requiresConfirmation?: boolean;
|
|
18
|
-
};
|
|
19
|
-
execute: (args: TParams, target: BackendContext, ambientContext?: { projectId?: string }) => Promise<TResult>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Declares a tool, generating its JSON Schema `inputSchema` from `zodSchema` so the schema the
|
|
24
|
-
* model sees and the one arguments are validated against cannot drift apart.
|
|
25
|
-
*/
|
|
26
|
-
export function defineTool<TParams = any, TResult = any>(
|
|
27
|
-
spec: Omit<ToolDefinition<TParams, TResult>, 'inputSchema'>
|
|
28
|
-
): ToolDefinition<TParams, TResult> {
|
|
29
|
-
const { $schema: _schema, ...inputSchema } = zodToJsonSchema(spec.zodSchema, { $refStrategy: 'none' }) as Record<string, unknown>;
|
|
30
|
-
return { ...spec, inputSchema };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class ToolArgumentError extends Error {
|
|
34
|
-
constructor(toolName: string, details: string) {
|
|
35
|
-
super(`Invalid arguments for tool "${toolName}": ${details}`);
|
|
36
|
-
this.name = 'ToolArgumentError';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Validates raw tool arguments against the tool's zod schema. Unknown keys are rejected,
|
|
42
|
-
* so callers cannot pass fields the tool does not declare.
|
|
43
|
-
*/
|
|
44
|
-
export function parseToolArgs<TParams>(tool: ToolDefinition<TParams>, args: unknown): TParams {
|
|
45
|
-
// Strict: unknown arguments are reported to the model instead of being silently dropped.
|
|
46
|
-
const result = tool.zodSchema.strict().safeParse(args ?? {});
|
|
47
|
-
if (!result.success) {
|
|
48
|
-
const details = result.error.issues
|
|
49
|
-
.map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)
|
|
50
|
-
.join('; ');
|
|
51
|
-
throw new ToolArgumentError(tool.name, details);
|
|
52
|
-
}
|
|
53
|
-
return result.data as TParams;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Helper to normalize calling engine vs client
|
|
57
|
-
export async function resolveBackend(target: BackendContext) {
|
|
58
|
-
const isEngine = 'store' in target && typeof (target as any).store === 'object';
|
|
59
|
-
return { isEngine };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const listProjectsTool = defineTool({
|
|
63
|
-
name: 'list_projects',
|
|
64
|
-
title: 'List Projects',
|
|
65
|
-
description: 'Retrieve all projects in the workspace.',
|
|
66
|
-
zodSchema: z.object({}),
|
|
67
|
-
annotations: { readOnlyHint: true },
|
|
68
|
-
execute: async (_args, target) => {
|
|
69
|
-
return target.getProjects();
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
export const getProjectTool = defineTool<{ id: string }>({
|
|
74
|
-
name: 'get_project',
|
|
75
|
-
title: 'Get Project',
|
|
76
|
-
description: 'Get details of a specific project by its ID.',
|
|
77
|
-
zodSchema: z.object({
|
|
78
|
-
id: z.string().describe('The project ID')
|
|
79
|
-
}),
|
|
80
|
-
annotations: { readOnlyHint: true },
|
|
81
|
-
execute: async (args, target) => {
|
|
82
|
-
return target.getProject(args.id);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
export const createProjectTool = defineTool<{ name: string; description?: string; key?: string }>({
|
|
87
|
-
name: 'create_project',
|
|
88
|
-
title: 'Create Project',
|
|
89
|
-
description: 'Create a new project workspace.',
|
|
90
|
-
zodSchema: z.object({
|
|
91
|
-
name: z.string().describe('Name of the project'),
|
|
92
|
-
description: z.string().optional().describe('Description of the project'),
|
|
93
|
-
key: z.string().optional().describe('Short project key/prefix (e.g. "PROJ")')
|
|
94
|
-
}),
|
|
95
|
-
execute: async (args, target) => {
|
|
96
|
-
return target.createProject(args);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
export const listTasksTool = defineTool<{
|
|
101
|
-
projectId?: string;
|
|
102
|
-
status?: string;
|
|
103
|
-
priority?: string;
|
|
104
|
-
assigneeId?: string;
|
|
105
|
-
iterationId?: string;
|
|
106
|
-
limit?: number;
|
|
107
|
-
cursor?: string;
|
|
108
|
-
}>({
|
|
109
|
-
name: 'list_tasks',
|
|
110
|
-
title: 'List Tasks',
|
|
111
|
-
description:
|
|
112
|
-
'List tasks (oldest first), optionally filtered by project, status, priority, assignee or iteration. Returns { tasks, nextCursor }; pass nextCursor back as cursor to get the next page.',
|
|
113
|
-
zodSchema: z.object({
|
|
114
|
-
projectId: z.string().optional().describe('Filter by project ID'),
|
|
115
|
-
status: z.string().optional().describe('Filter by task status key'),
|
|
116
|
-
priority: z.enum(['urgent', 'high', 'medium', 'low', 'none']).optional().describe('Filter by priority'),
|
|
117
|
-
assigneeId: z.string().optional().describe('Filter by assignee ID'),
|
|
118
|
-
iterationId: z.string().optional().describe('Filter by iteration (sprint) ID'),
|
|
119
|
-
limit: z.number().int().min(1).max(500).optional().describe('Page size (default 100)'),
|
|
120
|
-
cursor: z.string().optional().describe('nextCursor from a previous call')
|
|
121
|
-
}),
|
|
122
|
-
annotations: { readOnlyHint: true },
|
|
123
|
-
execute: async (args, target, ambientContext) => {
|
|
124
|
-
const page = await target.queryTasks({
|
|
125
|
-
projectId: args.projectId || ambientContext?.projectId,
|
|
126
|
-
status: args.status ? [args.status] : undefined,
|
|
127
|
-
priority: args.priority ? [args.priority] : undefined,
|
|
128
|
-
assigneeId: args.assigneeId,
|
|
129
|
-
iterationId: args.iterationId,
|
|
130
|
-
limit: args.limit,
|
|
131
|
-
cursor: args.cursor
|
|
132
|
-
});
|
|
133
|
-
return { tasks: page.items, nextCursor: page.nextCursor };
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
export const getTaskTool = defineTool<{ id: string }>({
|
|
138
|
-
name: 'get_task',
|
|
139
|
-
title: 'Get Task',
|
|
140
|
-
description: 'Get task details by ID.',
|
|
141
|
-
zodSchema: z.object({
|
|
142
|
-
id: z.string().describe('The task ID')
|
|
143
|
-
}),
|
|
144
|
-
annotations: { readOnlyHint: true },
|
|
145
|
-
execute: async (args, target) => {
|
|
146
|
-
return target.getTask(args.id);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
export const createTaskTool = defineTool<{
|
|
151
|
-
projectId?: string;
|
|
152
|
-
title: string;
|
|
153
|
-
description?: string;
|
|
154
|
-
status?: string;
|
|
155
|
-
priority?: 'urgent' | 'high' | 'medium' | 'low' | 'none';
|
|
156
|
-
assigneeId?: string;
|
|
157
|
-
dueDate?: string;
|
|
158
|
-
tags?: string[];
|
|
159
|
-
estimatedHours?: number;
|
|
160
|
-
isBlocked?: boolean;
|
|
161
|
-
blockedReason?: string;
|
|
162
|
-
}>({
|
|
163
|
-
name: 'create_task',
|
|
164
|
-
title: 'Create Task',
|
|
165
|
-
description: 'Create a new task within a project.',
|
|
166
|
-
zodSchema: z.object({
|
|
167
|
-
projectId: z.string().optional().describe('Project ID (inferred from active view in browser if omitted)'),
|
|
168
|
-
title: z.string().describe('Title of the task'),
|
|
169
|
-
description: z.string().optional().describe('Detailed description / markdown'),
|
|
170
|
-
status: z.string().optional().describe('Status (defaults to "todo" or first workflow status)'),
|
|
171
|
-
priority: z.enum(['urgent', 'high', 'medium', 'low', 'none']).optional().default('none').describe('Task priority'),
|
|
172
|
-
assigneeId: z.string().optional().describe('User ID to assign task to'),
|
|
173
|
-
dueDate: z.string().optional().describe('Due date (ISO string)'),
|
|
174
|
-
tags: z.array(z.string()).optional().describe('Tags for categorization'),
|
|
175
|
-
estimatedHours: z.number().optional().describe('Estimated hours to complete'),
|
|
176
|
-
isBlocked: z.boolean().optional().describe('Whether the task is blocked'),
|
|
177
|
-
blockedReason: z.string().optional().describe('Reason why the task is blocked')
|
|
178
|
-
}),
|
|
179
|
-
execute: async (args, target, ambientContext) => {
|
|
180
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
181
|
-
if (!projectId) {
|
|
182
|
-
throw new Error('projectId is required to create a task, but none was provided or active in context.');
|
|
183
|
-
}
|
|
184
|
-
const input: any = {
|
|
185
|
-
projectId,
|
|
186
|
-
title: args.title,
|
|
187
|
-
description: args.description,
|
|
188
|
-
status: args.status || 'todo',
|
|
189
|
-
priority: args.priority || 'none',
|
|
190
|
-
assigneeId: args.assigneeId,
|
|
191
|
-
dueDate: args.dueDate,
|
|
192
|
-
tags: args.tags || [],
|
|
193
|
-
estimatedHours: args.estimatedHours,
|
|
194
|
-
isBlocked: args.isBlocked,
|
|
195
|
-
blockedReason: args.blockedReason
|
|
196
|
-
};
|
|
197
|
-
return target.createTask(input);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
export const updateTaskTool = defineTool<{
|
|
202
|
-
id: string;
|
|
203
|
-
title?: string;
|
|
204
|
-
description?: string;
|
|
205
|
-
status?: string;
|
|
206
|
-
priority?: 'urgent' | 'high' | 'medium' | 'low' | 'none';
|
|
207
|
-
assigneeId?: string;
|
|
208
|
-
dueDate?: string;
|
|
209
|
-
tags?: string[];
|
|
210
|
-
estimatedHours?: number;
|
|
211
|
-
loggedHours?: number;
|
|
212
|
-
isBlocked?: boolean;
|
|
213
|
-
blockedReason?: string;
|
|
214
|
-
}>({
|
|
215
|
-
name: 'update_task',
|
|
216
|
-
title: 'Update Task',
|
|
217
|
-
description: 'Update fields of an existing task (e.g. title, status, priority, assignee).',
|
|
218
|
-
zodSchema: z.object({
|
|
219
|
-
id: z.string().describe('The task ID'),
|
|
220
|
-
title: z.string().optional(),
|
|
221
|
-
description: z.string().optional(),
|
|
222
|
-
status: z.string().optional(),
|
|
223
|
-
priority: z.enum(['urgent', 'high', 'medium', 'low', 'none']).optional(),
|
|
224
|
-
assigneeId: z.string().optional(),
|
|
225
|
-
dueDate: z.string().optional(),
|
|
226
|
-
tags: z.array(z.string()).optional(),
|
|
227
|
-
estimatedHours: z.number().optional(),
|
|
228
|
-
loggedHours: z.number().optional(),
|
|
229
|
-
isBlocked: z.boolean().optional().describe('Whether the task is blocked'),
|
|
230
|
-
blockedReason: z.string().optional().describe('Reason why the task is blocked')
|
|
231
|
-
}),
|
|
232
|
-
execute: async (args, target) => {
|
|
233
|
-
const { id, ...updates } = args;
|
|
234
|
-
return target.updateTask(id, updates);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
export const deleteTaskTool = defineTool<{ id: string }>({
|
|
239
|
-
name: 'delete_task',
|
|
240
|
-
title: 'Delete Task',
|
|
241
|
-
description: 'Delete a task by ID.',
|
|
242
|
-
zodSchema: z.object({
|
|
243
|
-
id: z.string().describe('The task ID to delete')
|
|
244
|
-
}),
|
|
245
|
-
annotations: { requiresConfirmation: true },
|
|
246
|
-
execute: async (args, target) => {
|
|
247
|
-
const success = await target.deleteTask(args.id);
|
|
248
|
-
return { success };
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
export const listDeliverablesTool = defineTool<{ projectId?: string }>({
|
|
253
|
-
name: 'list_deliverables',
|
|
254
|
-
title: 'List Deliverables',
|
|
255
|
-
description: 'List deliverables/milestones for a project.',
|
|
256
|
-
zodSchema: z.object({
|
|
257
|
-
projectId: z.string().optional().describe('Project ID')
|
|
258
|
-
}),
|
|
259
|
-
annotations: { readOnlyHint: true },
|
|
260
|
-
execute: async (args, target, ambientContext) => {
|
|
261
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
262
|
-
if (!projectId) throw new Error('projectId is required to list deliverables.');
|
|
263
|
-
if ('getDeliverables' in target && typeof (target as any).getDeliverables === 'function') {
|
|
264
|
-
return (target as any).getDeliverables(projectId);
|
|
265
|
-
}
|
|
266
|
-
return [];
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
export const createDeliverableTool = defineTool<{
|
|
271
|
-
projectId?: string;
|
|
272
|
-
title: string;
|
|
273
|
-
description?: string;
|
|
274
|
-
dueDate?: string;
|
|
275
|
-
taskIds?: string[];
|
|
276
|
-
}>({
|
|
277
|
-
name: 'create_deliverable',
|
|
278
|
-
title: 'Create Deliverable',
|
|
279
|
-
description: 'Create a milestone deliverable within a project.',
|
|
280
|
-
zodSchema: z.object({
|
|
281
|
-
projectId: z.string().optional(),
|
|
282
|
-
title: z.string(),
|
|
283
|
-
description: z.string().optional(),
|
|
284
|
-
dueDate: z.string().optional(),
|
|
285
|
-
taskIds: z.array(z.string()).optional()
|
|
286
|
-
}),
|
|
287
|
-
execute: async (args, target, ambientContext) => {
|
|
288
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
289
|
-
if (!projectId) throw new Error('projectId is required to create a deliverable.');
|
|
290
|
-
if ('createDeliverable' in target && typeof (target as any).createDeliverable === 'function') {
|
|
291
|
-
return (target as any).createDeliverable({
|
|
292
|
-
...args,
|
|
293
|
-
projectId
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
throw new Error('createDeliverable is not supported by this backend target.');
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
export const listCommentsTool = defineTool<{ taskId: string }>({
|
|
301
|
-
name: 'list_comments',
|
|
302
|
-
title: 'List Comments',
|
|
303
|
-
description: 'List comments associated with a task.',
|
|
304
|
-
zodSchema: z.object({
|
|
305
|
-
taskId: z.string().describe('The task ID')
|
|
306
|
-
}),
|
|
307
|
-
annotations: { readOnlyHint: true },
|
|
308
|
-
execute: async (args, target) => {
|
|
309
|
-
if ('getComments' in target && typeof (target as any).getComments === 'function') {
|
|
310
|
-
return (target as any).getComments(args.taskId);
|
|
311
|
-
}
|
|
312
|
-
return [];
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
export const addCommentTool = defineTool<{ taskId: string; content: string }>({
|
|
317
|
-
name: 'add_comment',
|
|
318
|
-
title: 'Add Comment',
|
|
319
|
-
description: 'Add a comment to a task. The comment is attributed to the identity this MCP server runs as.',
|
|
320
|
-
zodSchema: z.object({
|
|
321
|
-
taskId: z.string().describe('The task ID'),
|
|
322
|
-
content: z.string().describe('Comment body/markdown')
|
|
323
|
-
}),
|
|
324
|
-
execute: async (args, target) => {
|
|
325
|
-
return target.addComment({ taskId: args.taskId, content: args.content });
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
export const calculateCriticalPathTool = defineTool<{ projectId?: string }>({
|
|
330
|
-
name: 'calculate_critical_path',
|
|
331
|
-
title: 'Calculate Critical Path',
|
|
332
|
-
description: 'Calculate Critical Path Method (CPM) schedule, early/late start and finish, total slack, and critical bottlenecks for a project.',
|
|
333
|
-
zodSchema: z.object({
|
|
334
|
-
projectId: z.string().optional().describe('Project ID (falls back to ambient context if omitted)')
|
|
335
|
-
}),
|
|
336
|
-
annotations: { readOnlyHint: true },
|
|
337
|
-
execute: async (args, target, ambientContext) => {
|
|
338
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
339
|
-
if (!projectId) {
|
|
340
|
-
throw new Error('projectId is required to calculate critical path.');
|
|
341
|
-
}
|
|
342
|
-
return (target as any).calculateCriticalPath(projectId);
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
export const getTimelineLadderTool = defineTool<{
|
|
347
|
-
projectId?: string;
|
|
348
|
-
level?: 'macro' | 'standard' | 'concrete' | 'all';
|
|
349
|
-
containerId?: string;
|
|
350
|
-
iterationId?: string;
|
|
351
|
-
}>({
|
|
352
|
-
name: 'get_timeline_ladder',
|
|
353
|
-
title: 'Get Timeline Ladder of Abstraction',
|
|
354
|
-
description: 'Retrieve Ladder of Abstraction for a project timeline across macro phase envelopes, standard Gantt tasks & CPM, and concrete deliverables/time/attachments.',
|
|
355
|
-
zodSchema: z.object({
|
|
356
|
-
projectId: z.string().optional().describe('Project ID (falls back to ambient context if omitted)'),
|
|
357
|
-
level: z.enum(['macro', 'standard', 'concrete', 'all']).optional().describe('Abstraction level (macro, standard, concrete, or all)'),
|
|
358
|
-
containerId: z.string().optional().describe('Optional container ID filter'),
|
|
359
|
-
iterationId: z.string().optional().describe('Optional iteration/sprint ID filter')
|
|
360
|
-
}),
|
|
361
|
-
annotations: { readOnlyHint: true },
|
|
362
|
-
execute: async (args, target, ambientContext) => {
|
|
363
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
364
|
-
if (!projectId) {
|
|
365
|
-
throw new Error('projectId is required to get timeline ladder.');
|
|
366
|
-
}
|
|
367
|
-
return (target as any).getTimelineLadder(projectId, {
|
|
368
|
-
level: args.level,
|
|
369
|
-
containerId: args.containerId,
|
|
370
|
-
iterationId: args.iterationId
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
export const getTaskLadderTool = defineTool<{ taskId: string }>({
|
|
376
|
-
name: 'get_task_ladder',
|
|
377
|
-
title: 'Get Task Ladder View',
|
|
378
|
-
description: 'Retrieve multi-scale ladder view for a single task, connecting its macro phase, standard CPM timeline position, and concrete work evidence.',
|
|
379
|
-
zodSchema: z.object({
|
|
380
|
-
taskId: z.string().describe('The task ID')
|
|
381
|
-
}),
|
|
382
|
-
annotations: { readOnlyHint: true },
|
|
383
|
-
execute: async (args, target) => {
|
|
384
|
-
return (target as any).getTaskLadder(args.taskId);
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
export const getTaskMetricsTool = defineTool<{ taskId: string }>({
|
|
389
|
-
name: 'get_task_metrics',
|
|
390
|
-
title: 'Get Task Metrics',
|
|
391
|
-
description: 'Retrieve multi-dimensional task metrics including inferred actuals, active working duration, effort/duration/schedule variances, progress inference, and Earned Value Management (EVM) metrics.',
|
|
392
|
-
zodSchema: z.object({
|
|
393
|
-
taskId: z.string().describe('The task ID')
|
|
394
|
-
}),
|
|
395
|
-
annotations: { readOnlyHint: true },
|
|
396
|
-
execute: async (args, target) => {
|
|
397
|
-
return (target as any).getTaskMetrics(args.taskId);
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
export const getTaskProgressHistoryTool = defineTool<{ taskId: string }>({
|
|
402
|
-
name: 'get_task_progress_history',
|
|
403
|
-
title: 'Get Task Progress History',
|
|
404
|
-
description: 'Retrieve time-series progress data points and curve shape classification (linear, s_curve, early_surge, late_rush, stalled) for a task.',
|
|
405
|
-
zodSchema: z.object({
|
|
406
|
-
taskId: z.string().describe('The task ID')
|
|
407
|
-
}),
|
|
408
|
-
annotations: { readOnlyHint: true },
|
|
409
|
-
execute: async (args, target) => {
|
|
410
|
-
return (target as any).getTaskProgressHistory(args.taskId);
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
export const getWorkloadDistributionTool = defineTool<{
|
|
415
|
-
projectId?: string;
|
|
416
|
-
startDate?: string;
|
|
417
|
-
endDate?: string;
|
|
418
|
-
interval?: 'day' | 'week' | 'month';
|
|
419
|
-
groupBy?: 'assignee' | 'team' | 'taskType' | 'priority' | 'status';
|
|
420
|
-
metric?: 'scheduled' | 'logged' | 'remaining' | 'blended';
|
|
421
|
-
defaultWeeklyCapacityHours?: number;
|
|
422
|
-
}>({
|
|
423
|
-
name: 'get_workload_distribution',
|
|
424
|
-
title: 'Get Workload Distribution',
|
|
425
|
-
description: 'Retrieve time-series workload and capacity distribution suitable for streamgraphs, stacked charts, and team capacity planning.',
|
|
426
|
-
zodSchema: z.object({
|
|
427
|
-
projectId: z.string().optional().describe('Project ID (optional, defaults to workspace-wide or ambient project)'),
|
|
428
|
-
startDate: z.string().optional().describe('Start date ISO (YYYY-MM-DD)'),
|
|
429
|
-
endDate: z.string().optional().describe('End date ISO (YYYY-MM-DD)'),
|
|
430
|
-
interval: z.enum(['day', 'week', 'month']).optional().describe('Bucket interval (day, week, month)'),
|
|
431
|
-
groupBy: z.enum(['assignee', 'team', 'taskType', 'priority', 'status']).optional().describe('Dimension to segment by'),
|
|
432
|
-
metric: z.enum(['scheduled', 'logged', 'remaining', 'blended']).optional().describe('Effort metric mode'),
|
|
433
|
-
defaultWeeklyCapacityHours: z.number().optional().describe('Default weekly capacity hours per person (default 40)')
|
|
434
|
-
}),
|
|
435
|
-
annotations: { readOnlyHint: true },
|
|
436
|
-
execute: async (args, target, ambientContext) => {
|
|
437
|
-
const projectId = args.projectId || ambientContext?.projectId;
|
|
438
|
-
return (target as any).getWorkloadDistribution(projectId, {
|
|
439
|
-
startDate: args.startDate,
|
|
440
|
-
endDate: args.endDate,
|
|
441
|
-
interval: args.interval,
|
|
442
|
-
groupBy: args.groupBy,
|
|
443
|
-
metric: args.metric,
|
|
444
|
-
defaultWeeklyCapacityHours: args.defaultWeeklyCapacityHours
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
export const ALL_TOOLS: ToolDefinition[] = [
|
|
450
|
-
listProjectsTool,
|
|
451
|
-
getProjectTool,
|
|
452
|
-
createProjectTool,
|
|
453
|
-
listTasksTool,
|
|
454
|
-
getTaskTool,
|
|
455
|
-
createTaskTool,
|
|
456
|
-
updateTaskTool,
|
|
457
|
-
deleteTaskTool,
|
|
458
|
-
listDeliverablesTool,
|
|
459
|
-
createDeliverableTool,
|
|
460
|
-
listCommentsTool,
|
|
461
|
-
addCommentTool,
|
|
462
|
-
calculateCriticalPathTool,
|
|
463
|
-
getTimelineLadderTool,
|
|
464
|
-
getTaskLadderTool,
|
|
465
|
-
getTaskMetricsTool,
|
|
466
|
-
getTaskProgressHistoryTool,
|
|
467
|
-
getWorkloadDistributionTool
|
|
468
|
-
];
|
|
469
|
-
|
|
470
|
-
export const TOOL_MAP = new Map<string, ToolDefinition>(
|
|
471
|
-
ALL_TOOLS.map((tool) => [tool.name, tool])
|
|
472
|
-
);
|
package/src/web/index.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
|
-
import { ALL_TOOLS, parseToolArgs, type ToolDefinition } from '../tools/definitions.js';
|
|
3
|
-
|
|
4
|
-
export interface WebMcpToolRegistration {
|
|
5
|
-
name: string;
|
|
6
|
-
title?: string;
|
|
7
|
-
description: string;
|
|
8
|
-
inputSchema: Record<string, unknown>;
|
|
9
|
-
annotations?: {
|
|
10
|
-
readOnlyHint?: boolean;
|
|
11
|
-
};
|
|
12
|
-
execute: (input: any) => Promise<any>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ModelContextInterface {
|
|
16
|
-
registerTool: (tool: WebMcpToolRegistration, options?: { signal?: AbortSignal }) => Promise<void> | void;
|
|
17
|
-
unregisterTool?: (toolName: string) => void;
|
|
18
|
-
getTools?: () => Promise<WebMcpToolRegistration[]> | WebMcpToolRegistration[];
|
|
19
|
-
executeTool?: (name: string, input?: any) => Promise<any>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface RegisterWebMcpOptions {
|
|
23
|
-
client: CriticalPathClient;
|
|
24
|
-
projectId?: string;
|
|
25
|
-
tools?: string[];
|
|
26
|
-
signal?: AbortSignal;
|
|
27
|
-
document?: any;
|
|
28
|
-
navigator?: any;
|
|
29
|
-
window?: any;
|
|
30
|
-
onToolExecuted?: (toolName: string, input: any, result: any) => void;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface WebMcpRegistryHandle {
|
|
34
|
-
unregister: () => void;
|
|
35
|
-
getRegisteredTools: () => WebMcpToolRegistration[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Polyfill/shim a minimal ModelContextInterface onto the document/window if not natively present.
|
|
40
|
-
*/
|
|
41
|
-
export function ensureModelContextShim(doc: any = typeof document !== 'undefined' ? document : null): ModelContextInterface | null {
|
|
42
|
-
if (!doc) return null;
|
|
43
|
-
|
|
44
|
-
if (!doc.modelContext) {
|
|
45
|
-
const registeredTools = new Map<string, WebMcpToolRegistration>();
|
|
46
|
-
|
|
47
|
-
const shim: ModelContextInterface = {
|
|
48
|
-
registerTool(tool, options) {
|
|
49
|
-
registeredTools.set(tool.name, tool);
|
|
50
|
-
if (options?.signal) {
|
|
51
|
-
options.signal.addEventListener('abort', () => {
|
|
52
|
-
registeredTools.delete(tool.name);
|
|
53
|
-
}, { once: true });
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
unregisterTool(toolName) {
|
|
57
|
-
registeredTools.delete(toolName);
|
|
58
|
-
},
|
|
59
|
-
async getTools() {
|
|
60
|
-
return Array.from(registeredTools.values());
|
|
61
|
-
},
|
|
62
|
-
async executeTool(name, input) {
|
|
63
|
-
const tool = registeredTools.get(name);
|
|
64
|
-
if (!tool) {
|
|
65
|
-
throw new Error(`Tool "${name}" is not registered on modelContext.`);
|
|
66
|
-
}
|
|
67
|
-
return tool.execute(input || {});
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
doc.modelContext = shim;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return doc.modelContext;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Registers Critical Path tools with the browser's WebMCP modelContext.
|
|
79
|
-
*/
|
|
80
|
-
export function registerWebMcpTools(options: RegisterWebMcpOptions): WebMcpRegistryHandle {
|
|
81
|
-
const doc = options.document ?? (typeof document !== 'undefined' ? document : null);
|
|
82
|
-
const nav = options.navigator ?? (typeof navigator !== 'undefined' ? navigator : null);
|
|
83
|
-
const win = options.window ?? (typeof window !== 'undefined' ? window : null);
|
|
84
|
-
|
|
85
|
-
// Target modelContext: document.modelContext (W3C standard draft) -> navigator.modelContext -> document shim
|
|
86
|
-
let modelContext: ModelContextInterface | undefined;
|
|
87
|
-
if (doc?.modelContext) {
|
|
88
|
-
modelContext = doc.modelContext;
|
|
89
|
-
} else if (nav?.modelContext) {
|
|
90
|
-
modelContext = nav.modelContext;
|
|
91
|
-
} else if (doc) {
|
|
92
|
-
modelContext = ensureModelContextShim(doc) ?? undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const selectedTools: ToolDefinition[] = options.tools
|
|
96
|
-
? ALL_TOOLS.filter((t) => options.tools!.includes(t.name))
|
|
97
|
-
: ALL_TOOLS;
|
|
98
|
-
|
|
99
|
-
const registeredTools: WebMcpToolRegistration[] = [];
|
|
100
|
-
const abortController = new AbortController();
|
|
101
|
-
|
|
102
|
-
// Combine caller signal with our internal abort controller
|
|
103
|
-
if (options.signal) {
|
|
104
|
-
options.signal.addEventListener('abort', () => abortController.abort(), { once: true });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
for (const toolDef of selectedTools) {
|
|
108
|
-
const webTool: WebMcpToolRegistration = {
|
|
109
|
-
name: toolDef.name,
|
|
110
|
-
title: toolDef.title,
|
|
111
|
-
description: toolDef.description,
|
|
112
|
-
inputSchema: toolDef.inputSchema,
|
|
113
|
-
annotations: toolDef.annotations,
|
|
114
|
-
execute: async (input: any) => {
|
|
115
|
-
const ambientContext = options.projectId ? { projectId: options.projectId } : undefined;
|
|
116
|
-
const result = await toolDef.execute(parseToolArgs(toolDef, input), options.client, ambientContext);
|
|
117
|
-
options.onToolExecuted?.(toolDef.name, input, result);
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
registeredTools.push(webTool);
|
|
123
|
-
|
|
124
|
-
if (modelContext?.registerTool) {
|
|
125
|
-
try {
|
|
126
|
-
modelContext.registerTool(webTool, { signal: abortController.signal });
|
|
127
|
-
} catch (err) {
|
|
128
|
-
console.warn(`[Critical Path WebMCP] Failed to register tool "${webTool.name}":`, err);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Also publish to window fallback registry for browser extensions & DevTools
|
|
134
|
-
if (win) {
|
|
135
|
-
win.__CRITICAL_PATH_WEBMCP__ = {
|
|
136
|
-
projectId: options.projectId,
|
|
137
|
-
tools: registeredTools,
|
|
138
|
-
execute: async (name: string, input: any) => {
|
|
139
|
-
const tool = registeredTools.find((t) => t.name === name);
|
|
140
|
-
if (!tool) throw new Error(`WebMCP tool "${name}" not found in Critical Path registry.`);
|
|
141
|
-
return tool.execute(input);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const unregister = () => {
|
|
147
|
-
abortController.abort();
|
|
148
|
-
if (modelContext?.unregisterTool) {
|
|
149
|
-
for (const t of registeredTools) {
|
|
150
|
-
modelContext.unregisterTool(t.name);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (win && win.__CRITICAL_PATH_WEBMCP__?.tools === registeredTools) {
|
|
154
|
-
delete win.__CRITICAL_PATH_WEBMCP__;
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
unregister,
|
|
160
|
-
getRegisteredTools: () => registeredTools
|
|
161
|
-
};
|
|
162
|
-
}
|
package/tsconfig.json
DELETED
package/tsconfig.tsbuildinfo
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["./src/index.test.ts","./src/index.ts","./src/bin/args.test.ts","./src/bin/args.ts","./src/bin/cli.ts","./src/server/index.ts","./src/tools/definitions.test.ts","./src/tools/definitions.ts","./src/web/index.ts"],"version":"5.9.3"}
|