@krr2020/taskflow-mcp-server 0.1.0-beta.1 → 0.1.0-beta.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/src/index.ts CHANGED
@@ -1,261 +1,507 @@
1
- #!/usr/bin/env node
1
+ import process from "node:process";
2
+ // Import all commands from core package
3
+ import {
4
+ CheckCommand,
5
+ type CommandContext,
6
+ type CommandResult,
7
+ CommitCommand,
8
+ InitCommand,
9
+ NextCommand,
10
+ PrdCreateCommand,
11
+ PrdGenerateArchCommand,
12
+ ResumeCommand,
13
+ RetroAddCommand,
14
+ RetroListCommand,
15
+ SkipCommand,
16
+ StartCommand,
17
+ StatusCommand,
18
+ TasksGenerateCommand,
19
+ } from "@krr2020/taskflow-core";
2
20
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
21
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
22
  import {
5
- CallToolRequestSchema,
6
- ListToolsRequestSchema,
7
- ErrorCode,
8
- McpError,
23
+ CallToolRequestSchema,
24
+ type CallToolResult,
25
+ ErrorCode,
26
+ ListToolsRequestSchema,
27
+ McpError,
9
28
  } from "@modelcontextprotocol/sdk/types.js";
10
29
  import { z } from "zod";
11
- import { StateMachine, ConfigLoader, GitManager } from "@krr2020/taskflow-core";
12
30
 
13
- // Initialize Core Components
14
- const configLoader = new ConfigLoader();
15
- const gitManager = new GitManager();
16
- const stateMachine = new StateMachine(configLoader, gitManager);
31
+ // Create command context
32
+ const context: CommandContext = {
33
+ projectRoot: process.cwd(),
34
+ };
17
35
 
18
36
  // Initialize MCP Server
19
37
  const server = new Server(
20
- {
21
- name: "taskflow-mcp-server",
22
- version: "0.1.0",
23
- },
24
- {
25
- capabilities: {
26
- tools: {},
27
- },
28
- }
38
+ {
39
+ name: "taskflow-mcp-server",
40
+ version: "0.1.0",
41
+ },
42
+ {
43
+ capabilities: {
44
+ tools: {},
45
+ },
46
+ },
29
47
  );
30
48
 
31
49
  // Tool Definitions
32
50
  server.setRequestHandler(ListToolsRequestSchema, async () => {
33
- return {
34
- tools: [
35
- {
36
- name: "start_task",
37
- description: "Start a new task, checking out the correct story branch and entering PLANNING mode.",
38
- inputSchema: {
39
- type: "object",
40
- properties: {
41
- taskId: {
42
- type: "string",
43
- description: "The ID of the task to start (e.g., '1.2.3')",
44
- },
45
- storyId: {
46
- type: "string",
47
- description: "The Story ID this task belongs to (e.g., '15')",
48
- },
49
- slug: {
50
- type: "string",
51
- description: "Short slug for the story (e.g., 'user-auth')",
52
- },
53
- },
54
- required: ["taskId", "storyId", "slug"],
55
- },
56
- },
57
- {
58
- name: "approve_plan",
59
- description: "Approve the implementation plan and switch to EXECUTION mode.",
60
- inputSchema: {
61
- type: "object",
62
- properties: {},
63
- },
64
- },
65
- {
66
- name: "get_status",
67
- description: "Get the current state machine status and active task.",
68
- inputSchema: {
69
- type: "object",
70
- properties: {},
71
- },
72
- },
73
- {
74
- name: "generate_prd",
75
- description: "Generate a PRD template based on project context.",
76
- inputSchema: {
77
- type: "object",
78
- properties: {
79
- requirements: { type: "string" }
80
- },
81
- },
82
- },
83
- {
84
- name: "generate_tasks",
85
- description: "Generate tasks from a PRD.",
86
- inputSchema: {
87
- type: "object",
88
- properties: {
89
- prdContent: { type: "string" }
90
- },
91
- },
92
- },
93
- {
94
- name: "run_checks",
95
- description: "Run project validations and enter VERIFICATION state.",
96
- inputSchema: {
97
- type: "object",
98
- properties: {},
99
- },
100
- },
101
- {
102
- name: "submit_task",
103
- description: "Submit the current task and complete the workflow.",
104
- inputSchema: {
105
- type: "object",
106
- properties: {},
107
- },
108
- },
109
- ],
110
- };
51
+ return {
52
+ tools: [
53
+ // Initialization
54
+ {
55
+ name: "init",
56
+ description:
57
+ "Initialize Taskflow in the current project. Creates taskflow.config.json and .taskflow directory structure with template files.",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ projectName: {
62
+ type: "string",
63
+ description:
64
+ "Project name (optional, defaults to directory name)",
65
+ },
66
+ },
67
+ },
68
+ },
69
+
70
+ // Status & Navigation
71
+ {
72
+ name: "get_status",
73
+ description:
74
+ "Get project status, feature status, or story status. Shows progress, tasks, and active task information.",
75
+ inputSchema: {
76
+ type: "object",
77
+ properties: {
78
+ id: {
79
+ type: "string",
80
+ description:
81
+ "Optional: Feature ID (N) or Story ID (N.M) to get specific status",
82
+ },
83
+ },
84
+ },
85
+ },
86
+ {
87
+ name: "find_next_task",
88
+ description:
89
+ "Find the next available task that can be worked on. Checks dependencies and returns task details.",
90
+ inputSchema: {
91
+ type: "object",
92
+ properties: {},
93
+ },
94
+ },
95
+
96
+ // PRD Generation
97
+ {
98
+ name: "prd_create",
99
+ description:
100
+ "Create a new PRD (Product Requirements Document) template. Generates a structured markdown template for defining features.",
101
+ inputSchema: {
102
+ type: "object",
103
+ properties: {
104
+ featureName: {
105
+ type: "string",
106
+ description: "Name of the feature (e.g., 'user-authentication')",
107
+ },
108
+ },
109
+ required: ["featureName"],
110
+ },
111
+ },
112
+ {
113
+ name: "prd_generate_arch",
114
+ description:
115
+ "Generate coding-standards.md and ARCHITECTURE-RULES.md from a PRD. Analyzes codebase and PRD to create project-specific standards.",
116
+ inputSchema: {
117
+ type: "object",
118
+ properties: {
119
+ prdFile: {
120
+ type: "string",
121
+ description: "PRD filename (e.g., '2024-01-15-user-auth.md')",
122
+ },
123
+ },
124
+ required: ["prdFile"],
125
+ },
126
+ },
127
+
128
+ // Task Generation
129
+ {
130
+ name: "tasks_generate",
131
+ description:
132
+ "Generate complete task breakdown from a PRD. Creates features, stories, and tasks with dependencies.",
133
+ inputSchema: {
134
+ type: "object",
135
+ properties: {
136
+ prdFile: {
137
+ type: "string",
138
+ description: "PRD filename to generate tasks from",
139
+ },
140
+ },
141
+ required: ["prdFile"],
142
+ },
143
+ },
144
+
145
+ // Task Workflow
146
+ {
147
+ name: "start_task",
148
+ description:
149
+ "Start working on a task. Switches to story branch, loads requirements, sets status to SETUP. Provides comprehensive AI guidance.",
150
+ inputSchema: {
151
+ type: "object",
152
+ properties: {
153
+ taskId: {
154
+ type: "string",
155
+ description: "Task ID in format N.M.K (e.g., '1.1.0')",
156
+ },
157
+ },
158
+ required: ["taskId"],
159
+ },
160
+ },
161
+ {
162
+ name: "check_task",
163
+ description:
164
+ "Validate current task and advance to next status. Behavior depends on current status (SETUP→PLANNING→IMPLEMENTING→VERIFYING→VALIDATING→COMMITTING).",
165
+ inputSchema: {
166
+ type: "object",
167
+ properties: {},
168
+ },
169
+ },
170
+ {
171
+ name: "commit_task",
172
+ description:
173
+ "Commit changes and complete the task. Requires bullet points describing changes. Runs git add, commit, push and marks task as completed.",
174
+ inputSchema: {
175
+ type: "object",
176
+ properties: {
177
+ message: {
178
+ type: "string",
179
+ description:
180
+ 'Bullet points describing changes (e.g., "- Added feature X\\n- Fixed bug Y")',
181
+ },
182
+ },
183
+ required: ["message"],
184
+ },
185
+ },
186
+ {
187
+ name: "resume_task",
188
+ description:
189
+ "Resume a blocked or on-hold task. Restores task to active status and provides guidance on continuing work.",
190
+ inputSchema: {
191
+ type: "object",
192
+ properties: {
193
+ status: {
194
+ type: "string",
195
+ description:
196
+ "Status to resume to (setup, implementing, verifying, validating)",
197
+ enum: ["setup", "implementing", "verifying", "validating"],
198
+ },
199
+ },
200
+ },
201
+ },
202
+ {
203
+ name: "block_task",
204
+ description:
205
+ "Mark current task as blocked with a reason. Saves current status and finds next available task.",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ reason: {
210
+ type: "string",
211
+ description: "Reason for blocking the task",
212
+ },
213
+ },
214
+ required: ["reason"],
215
+ },
216
+ },
217
+
218
+ // Retrospective
219
+ {
220
+ name: "add_retrospective",
221
+ description:
222
+ "Add a new error pattern to the retrospective. Helps prevent repeated mistakes by documenting solutions.",
223
+ inputSchema: {
224
+ type: "object",
225
+ properties: {
226
+ category: {
227
+ type: "string",
228
+ description:
229
+ "Error category (type_error, lint, runtime, build, test, etc.)",
230
+ },
231
+ pattern: {
232
+ type: "string",
233
+ description: "Error pattern to match in validation output",
234
+ },
235
+ solution: {
236
+ type: "string",
237
+ description: "Solution to the error",
238
+ },
239
+ criticality: {
240
+ type: "string",
241
+ description: "Criticality level (low, medium, high)",
242
+ enum: ["low", "medium", "high"],
243
+ },
244
+ },
245
+ required: ["category", "pattern", "solution"],
246
+ },
247
+ },
248
+ {
249
+ name: "list_retrospectives",
250
+ description:
251
+ "List all retrospective entries. Can filter by category. Shows error patterns, solutions, and counts.",
252
+ inputSchema: {
253
+ type: "object",
254
+ properties: {
255
+ category: {
256
+ type: "string",
257
+ description: "Optional: Filter by category",
258
+ },
259
+ },
260
+ },
261
+ },
262
+ ],
263
+ };
111
264
  });
112
265
 
266
+ // Helper function to format command result for MCP
267
+ function formatCommandResult(result: CommandResult): CallToolResult {
268
+ const parts: string[] = [];
269
+
270
+ // Add output
271
+ if (result.output) {
272
+ parts.push(result.output);
273
+ }
274
+
275
+ // Add next steps
276
+ if (result.nextSteps) {
277
+ parts.push("\n\nNEXT STEPS:");
278
+ parts.push("─".repeat(60));
279
+ parts.push(result.nextSteps);
280
+ }
281
+
282
+ // Add AI guidance
283
+ if (result.aiGuidance) {
284
+ parts.push("\n\nAI GUIDANCE:");
285
+ parts.push("─".repeat(60));
286
+ parts.push(result.aiGuidance);
287
+ }
288
+
289
+ // Add context files
290
+ if (result.contextFiles && result.contextFiles.length > 0) {
291
+ parts.push("\n\nCONTEXT FILES:");
292
+ parts.push("─".repeat(60));
293
+ for (const file of result.contextFiles) {
294
+ parts.push(` ${file}`);
295
+ }
296
+ }
297
+
298
+ // Add warnings
299
+ if (result.warnings && result.warnings.length > 0) {
300
+ parts.push("\n\n⚠️ WARNINGS:");
301
+ parts.push("─".repeat(60));
302
+ for (const warning of result.warnings) {
303
+ parts.push(` ${warning}`);
304
+ }
305
+ }
306
+
307
+ // Add errors if failure
308
+ if (result.errors && result.errors.length > 0) {
309
+ parts.push("\n\n✗ ERRORS:");
310
+ parts.push("─".repeat(60));
311
+ for (const error of result.errors) {
312
+ parts.push(` ${error}`);
313
+ }
314
+ }
315
+
316
+ return {
317
+ content: [
318
+ {
319
+ type: "text",
320
+ text: parts.join("\n"),
321
+ },
322
+ ],
323
+ isError: result.success === false,
324
+ };
325
+ }
326
+
113
327
  // Tool Execution
114
328
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
115
- const { name, arguments: args } = request.params;
116
-
117
- try {
118
- switch (name) {
119
- case "start_task": {
120
- const schema = z.object({
121
- taskId: z.string(),
122
- storyId: z.string(),
123
- slug: z.string(),
124
- });
125
- const { taskId, storyId, slug } = schema.parse(args);
126
-
127
- await stateMachine.startTask(taskId, storyId, slug);
128
-
129
- return {
130
- content: [
131
- {
132
- type: "text",
133
- text: `Task ${taskId} started on branch story/S${storyId}-${slug}. State is now PLANNING.`,
134
- },
135
- ],
136
- };
137
- }
138
-
139
- case "approve_plan": {
140
- stateMachine.approvePlan();
141
- return {
142
- content: [
143
- {
144
- type: "text",
145
- text: "Plan approved. State is now EXECUTION. You may now write code.",
146
- },
147
- ],
148
- };
149
- }
150
-
151
- case "get_status": {
152
- return {
153
- content: [
154
- {
155
- type: "text",
156
- text: JSON.stringify({
157
- state: stateMachine.getState(),
158
- activeTask: stateMachine.getActiveTask(),
159
- }, null, 2),
160
- },
161
- ],
162
- };
163
- }
164
-
165
- case "generate_prd": {
166
- const template = `# Project Requirements Document
167
- ## 1. Objective
168
- [Describe the goal]
169
-
170
- ## 2. Scope
171
- - [ ] In Scope
172
- - [ ] Out of Scope
173
-
174
- ## 3. Technical Requirements
175
- - Language: [e.g., TypeScript]
176
- - Framework: [e.g., React]
177
-
178
- ## 4. User Stories
179
- - Story 1: [Description]
180
- `;
181
- return {
182
- content: [
183
- {
184
- type: "text",
185
- text: template,
186
- },
187
- ],
188
- };
189
- }
190
-
191
- case "generate_tasks": {
192
- // In a real implementation, this would parse the PRD.
193
- // For prototype, we return the schema structure.
194
- return {
195
- content: [
196
- {
197
- type: "text",
198
- text: "Please provide the tasks in the following JSON format matching the TaskSchema:\n" +
199
- JSON.stringify({
200
- id: "1.0",
201
- title: "Example Task",
202
- status: "todo",
203
- subtasks: [{ id: "1.1", title: "Subtask 1" }]
204
- }, null, 2)
205
- },
206
- ],
207
- };
208
- }
209
-
210
- case "run_checks": {
211
- stateMachine.startVerification();
212
- // TODO: Actually run the validation commands from config
213
- return {
214
- content: [{ type: "text", text: "Verification phase started. Running checks... [MOCK PASSED]" }],
215
- };
216
- }
217
-
218
- case "submit_task": {
219
- stateMachine.completeTask();
220
- return {
221
- content: [{ type: "text", text: "Task submitted and completed. State is now IDLE." }],
222
- };
223
- }
224
-
225
- default:
226
- throw new McpError(
227
- ErrorCode.MethodNotFound,
228
- `Unknown tool: ${name}`
229
- );
230
- }
231
- } catch (error) {
232
- if (error instanceof z.ZodError) {
233
- throw new McpError(
234
- ErrorCode.InvalidParams,
235
- `Invalid arguments: ${error.message}`
236
- );
237
- }
238
- const errorMessage = error instanceof Error ? error.message : String(error);
239
- return {
240
- content: [
241
- {
242
- type: "text",
243
- text: `Error executing ${name}: ${errorMessage}`,
244
- },
245
- ],
246
- isError: true,
247
- };
248
- }
329
+ const { name, arguments: args } = request.params;
330
+
331
+ try {
332
+ switch (name) {
333
+ case "init": {
334
+ const schema = z.object({
335
+ projectName: z.string().optional(),
336
+ });
337
+ const { projectName } = schema.parse(args || {});
338
+
339
+ const cmd = new InitCommand(context);
340
+ const result = await cmd.execute(projectName);
341
+ return formatCommandResult(result);
342
+ }
343
+
344
+ case "get_status": {
345
+ const schema = z.object({
346
+ id: z.string().optional(),
347
+ });
348
+ const { id } = schema.parse(args || {});
349
+
350
+ const cmd = new StatusCommand(context);
351
+ const result = await cmd.execute(id);
352
+ return formatCommandResult(result);
353
+ }
354
+
355
+ case "find_next_task": {
356
+ const cmd = new NextCommand(context);
357
+ const result = await cmd.execute();
358
+ return formatCommandResult(result);
359
+ }
360
+
361
+ case "prd_create": {
362
+ const schema = z.object({
363
+ featureName: z.string(),
364
+ });
365
+ const { featureName } = schema.parse(args);
366
+
367
+ const cmd = new PrdCreateCommand(context);
368
+ const result = await cmd.execute(featureName);
369
+ return formatCommandResult(result);
370
+ }
371
+
372
+ case "prd_generate_arch": {
373
+ const schema = z.object({
374
+ prdFile: z.string(),
375
+ });
376
+ const { prdFile } = schema.parse(args);
377
+
378
+ const cmd = new PrdGenerateArchCommand(context);
379
+ const result = await cmd.execute(prdFile);
380
+ return formatCommandResult(result);
381
+ }
382
+
383
+ case "tasks_generate": {
384
+ const schema = z.object({
385
+ prdFile: z.string(),
386
+ });
387
+ const { prdFile } = schema.parse(args);
388
+
389
+ const cmd = new TasksGenerateCommand(context);
390
+ const result = await cmd.execute(prdFile);
391
+ return formatCommandResult(result);
392
+ }
393
+
394
+ case "start_task": {
395
+ const schema = z.object({
396
+ taskId: z.string(),
397
+ });
398
+ const { taskId } = schema.parse(args);
399
+
400
+ const cmd = new StartCommand(context);
401
+ const result = await cmd.execute(taskId);
402
+ return formatCommandResult(result);
403
+ }
404
+
405
+ case "check_task": {
406
+ const cmd = new CheckCommand(context);
407
+ const result = await cmd.execute();
408
+ return formatCommandResult(result);
409
+ }
410
+
411
+ case "commit_task": {
412
+ const schema = z.object({
413
+ message: z.string(),
414
+ });
415
+ const { message } = schema.parse(args);
416
+
417
+ const cmd = new CommitCommand(context);
418
+ const result = await cmd.execute(message);
419
+ return formatCommandResult(result);
420
+ }
421
+
422
+ case "resume_task": {
423
+ const schema = z.object({
424
+ status: z.string().optional(),
425
+ });
426
+ const { status } = schema.parse(args || {});
427
+
428
+ const cmd = new ResumeCommand(context);
429
+ const result = await cmd.execute(status);
430
+ return formatCommandResult(result);
431
+ }
432
+
433
+ case "block_task": {
434
+ const schema = z.object({
435
+ reason: z.string(),
436
+ });
437
+ const { reason } = schema.parse(args);
438
+
439
+ const cmd = new SkipCommand(context);
440
+ const result = await cmd.execute(reason);
441
+ return formatCommandResult(result);
442
+ }
443
+
444
+ case "add_retrospective": {
445
+ const schema = z.object({
446
+ category: z.string(),
447
+ pattern: z.string(),
448
+ solution: z.string(),
449
+ criticality: z.string().optional().default("medium"),
450
+ });
451
+ const { category, pattern, solution, criticality } = schema.parse(args);
452
+
453
+ const cmd = new RetroAddCommand(context);
454
+ const result = await cmd.execute(
455
+ category,
456
+ pattern,
457
+ solution,
458
+ criticality,
459
+ );
460
+ return formatCommandResult(result);
461
+ }
462
+
463
+ case "list_retrospectives": {
464
+ const schema = z.object({
465
+ category: z.string().optional(),
466
+ });
467
+ const { category } = schema.parse(args || {});
468
+
469
+ const cmd = new RetroListCommand(context);
470
+ const result = await cmd.execute(category);
471
+ return formatCommandResult(result);
472
+ }
473
+
474
+ default:
475
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
476
+ }
477
+ } catch (error) {
478
+ if (error instanceof z.ZodError) {
479
+ throw new McpError(
480
+ ErrorCode.InvalidParams,
481
+ `Invalid arguments: ${error.message}`,
482
+ );
483
+ }
484
+ const errorMessage = error instanceof Error ? error.message : String(error);
485
+ return {
486
+ content: [
487
+ {
488
+ type: "text",
489
+ text: `Error executing ${name}: ${errorMessage}`,
490
+ },
491
+ ],
492
+ isError: true,
493
+ };
494
+ }
249
495
  });
250
496
 
251
497
  // Start Server
252
498
  async function main() {
253
- const transport = new StdioServerTransport();
254
- await server.connect(transport);
255
- console.error("Taskflow MCP Server running on stdio");
499
+ const transport = new StdioServerTransport();
500
+ await server.connect(transport);
501
+ console.error("Taskflow MCP Server running on stdio");
256
502
  }
257
503
 
258
504
  main().catch((error) => {
259
- console.error("Fatal error in main():", error);
260
- process.exit(1);
505
+ console.error("Fatal error in main():", error);
506
+ process.exit(1);
261
507
  });