@programinglive/dev-workflow-mcp-server 1.0.1 ā 1.0.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 +13 -0
- package/README.md +15 -0
- package/index.js +130 -52
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.0.2](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.1...v1.0.2) (2025-10-19)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### š Bug Fixes
|
|
9
|
+
|
|
10
|
+
* guard run_tests arguments ([2004c59](https://github.com/programinglive/dev-workflow-mcp-server/commit/2004c590fabe359d068122cf240a731382f81ca0))
|
|
11
|
+
* normalize tool call arguments ([44d5a3d](https://github.com/programinglive/dev-workflow-mcp-server/commit/44d5a3d35f191012445fa02cee6254afbc993c98))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### š Documentation
|
|
15
|
+
|
|
16
|
+
* clarify tool argument requirements ([4528614](https://github.com/programinglive/dev-workflow-mcp-server/commit/45286146661ad850eccb04849c11819e91ddd580))
|
|
17
|
+
|
|
5
18
|
### [1.0.1](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.0.0...v1.0.1) (2025-10-18)
|
|
6
19
|
|
|
7
20
|
|
package/README.md
CHANGED
|
@@ -57,6 +57,21 @@ After adding the configuration, restart the application to load the MCP server.
|
|
|
57
57
|
|
|
58
58
|
## š ļø Available Tools
|
|
59
59
|
|
|
60
|
+
### Tool Argument Requirements
|
|
61
|
+
|
|
62
|
+
All tool invocations validate their `arguments` payload before running:
|
|
63
|
+
- Strings are parsed as JSON and must resolve to an object (key/value pairs).
|
|
64
|
+
- Passing non-object data (numbers, arrays, plain text) triggers a guidance error.
|
|
65
|
+
- Missing or malformed arguments safely default to empty input so the tool can respond with actionable reminders.
|
|
66
|
+
|
|
67
|
+
Example (stringified JSON object):
|
|
68
|
+
```
|
|
69
|
+
{
|
|
70
|
+
"name": "start_task",
|
|
71
|
+
"arguments": "{\"description\":\"Add reporting endpoint\",\"type\":\"feature\"}"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
60
75
|
### `start_task`
|
|
61
76
|
Start a new coding task. This is your first step - be conscious about what you're coding.
|
|
62
77
|
|
package/index.js
CHANGED
|
@@ -70,6 +70,42 @@ await workflowState.load();
|
|
|
70
70
|
|
|
71
71
|
const exec = promisify(execCallback);
|
|
72
72
|
|
|
73
|
+
function normalizeRequestArgs(rawArgs) {
|
|
74
|
+
if (rawArgs === undefined || rawArgs === null) {
|
|
75
|
+
return { args: {}, error: null };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof rawArgs === "string") {
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(rawArgs);
|
|
81
|
+
if (parsed && typeof parsed === "object") {
|
|
82
|
+
return { args: parsed, error: null };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
args: {},
|
|
87
|
+
error:
|
|
88
|
+
"ā ļø Tool arguments must be a JSON object. Please provide key/value pairs.",
|
|
89
|
+
};
|
|
90
|
+
} catch (parseError) {
|
|
91
|
+
return {
|
|
92
|
+
args: {},
|
|
93
|
+
error:
|
|
94
|
+
"ā ļø Unable to parse tool arguments. Please provide valid JSON-formatted data.",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (typeof rawArgs === "object") {
|
|
100
|
+
return { args: rawArgs, error: null };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
args: {},
|
|
105
|
+
error: "ā ļø Unsupported tool arguments format. Expected a JSON object.",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
73
109
|
async function hasStagedChanges() {
|
|
74
110
|
try {
|
|
75
111
|
const { stdout } = await exec("git status --porcelain");
|
|
@@ -232,96 +268,127 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
232
268
|
|
|
233
269
|
// Handle tool calls
|
|
234
270
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
workflowState.state.currentPhase = "coding";
|
|
241
|
-
workflowState.state.taskDescription = args.description;
|
|
242
|
-
workflowState.state.taskType = args.type;
|
|
243
|
-
await workflowState.save();
|
|
271
|
+
try {
|
|
272
|
+
const { name } = request.params;
|
|
273
|
+
const { args, error: argumentsError } = normalizeRequestArgs(
|
|
274
|
+
request.params.arguments
|
|
275
|
+
);
|
|
244
276
|
|
|
277
|
+
if (argumentsError) {
|
|
245
278
|
return {
|
|
246
279
|
content: [
|
|
247
280
|
{
|
|
248
281
|
type: "text",
|
|
249
|
-
text:
|
|
282
|
+
text: argumentsError,
|
|
250
283
|
},
|
|
251
284
|
],
|
|
252
285
|
};
|
|
253
286
|
}
|
|
254
287
|
|
|
255
|
-
|
|
256
|
-
|
|
288
|
+
switch (name) {
|
|
289
|
+
case "start_task": {
|
|
290
|
+
workflowState.reset();
|
|
291
|
+
workflowState.state.currentPhase = "coding";
|
|
292
|
+
workflowState.state.taskDescription = args.description;
|
|
293
|
+
workflowState.state.taskType = args.type;
|
|
294
|
+
await workflowState.save();
|
|
295
|
+
|
|
257
296
|
return {
|
|
258
297
|
content: [
|
|
259
298
|
{
|
|
260
299
|
type: "text",
|
|
261
|
-
text:
|
|
300
|
+
text: `ā
Task Started: ${args.description}\n\nšÆ Be conscious about what you're coding!\n\nWorkflow Steps:\n1. ā Start task (current)\n2. ā³ Fix/implement the feature\n3. ā³ Create tests\n4. ā³ Run tests (must pass!)\n5. ā³ Create documentation\n6. ā³ Commit & push\n\nReminder: Focus on writing clean, maintainable code!`,
|
|
262
301
|
},
|
|
263
302
|
],
|
|
264
303
|
};
|
|
265
304
|
}
|
|
266
305
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
306
|
+
case "mark_bug_fixed": {
|
|
307
|
+
if (workflowState.state.currentPhase === "idle") {
|
|
308
|
+
return {
|
|
309
|
+
content: [
|
|
310
|
+
{
|
|
311
|
+
type: "text",
|
|
312
|
+
text: "ā ļø Please start a task first using 'start_task'!",
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
workflowState.state.bugFixed = true;
|
|
319
|
+
workflowState.state.currentPhase = "testing";
|
|
320
|
+
workflowState.state.fixSummary = args.summary;
|
|
321
|
+
await workflowState.save();
|
|
281
322
|
|
|
282
|
-
case "run_tests": {
|
|
283
|
-
if (!workflowState.state.bugFixed) {
|
|
284
323
|
return {
|
|
285
324
|
content: [
|
|
286
325
|
{
|
|
287
326
|
type: "text",
|
|
288
|
-
text:
|
|
327
|
+
text: `ā
Feature/Bug marked as fixed!\n\nā ļø CRITICAL REMINDER: You MUST create tests now!\n\nNext Steps:\n1. ā Fix/implement feature\n2. ā³ Create tests for: ${args.summary}\n3. ā³ Run tests (must be green!)\n4. ā³ Create documentation\n5. ā³ Commit & push\n\nš« DO NOT SKIP TESTING!`,
|
|
289
328
|
},
|
|
290
329
|
],
|
|
291
330
|
};
|
|
292
331
|
}
|
|
293
332
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
333
|
+
case "run_tests": {
|
|
334
|
+
if (!workflowState.state.bugFixed) {
|
|
335
|
+
return {
|
|
336
|
+
content: [
|
|
337
|
+
{
|
|
338
|
+
type: "text",
|
|
339
|
+
text: "ā ļø Please mark your feature/bug as fixed first using 'mark_bug_fixed'!",
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (
|
|
346
|
+
typeof args.passed !== "boolean" ||
|
|
347
|
+
typeof args.testCommand !== "string" ||
|
|
348
|
+
args.testCommand.trim() === ""
|
|
349
|
+
) {
|
|
350
|
+
return {
|
|
351
|
+
content: [
|
|
352
|
+
{
|
|
353
|
+
type: "text",
|
|
354
|
+
text: "ā ļø Please provide both 'passed' (boolean) and 'testCommand' (non-empty string) when recording test results.",
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
workflowState.state.testsPassed = args.passed;
|
|
361
|
+
workflowState.state.testCommand = args.testCommand;
|
|
362
|
+
workflowState.state.testDetails =
|
|
363
|
+
typeof args.details === "string" ? args.details : "";
|
|
364
|
+
|
|
365
|
+
if (!args.passed) {
|
|
366
|
+
workflowState.state.currentPhase = "testing";
|
|
367
|
+
await workflowState.save();
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
content: [
|
|
371
|
+
{
|
|
372
|
+
type: "text",
|
|
373
|
+
text: `ā TESTS FAILED!\n\nš« STOP! DO NOT COMMIT OR PUSH!\n\nYou must:\n1. Fix the failing tests\n2. Run tests again until they pass\n\nTest command: ${args.testCommand}\n\nNever skip or ignore failing tests!`,
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
workflowState.state.currentPhase = "documentation";
|
|
300
380
|
await workflowState.save();
|
|
301
381
|
|
|
302
382
|
return {
|
|
303
383
|
content: [
|
|
304
384
|
{
|
|
305
385
|
type: "text",
|
|
306
|
-
text:
|
|
386
|
+
text: `ā
All tests passed! š\n\nTest command: ${args.testCommand}\n\nNext Steps:\n1. ā Fix/implement feature\n2. ā Create tests\n3. ā Run tests (GREEN!)\n4. ā³ Create/update documentation\n5. ā³ Commit & push\n\nReminder: Document what you did before committing!`,
|
|
307
387
|
},
|
|
308
388
|
],
|
|
309
389
|
};
|
|
310
390
|
}
|
|
311
391
|
|
|
312
|
-
workflowState.state.currentPhase = "documentation";
|
|
313
|
-
await workflowState.save();
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
content: [
|
|
317
|
-
{
|
|
318
|
-
type: "text",
|
|
319
|
-
text: `ā
All tests passed! š\n\nTest command: ${args.testCommand}\n\nNext Steps:\n1. ā Fix/implement feature\n2. ā Create tests\n3. ā Run tests (GREEN!)\n4. ā³ Create/update documentation\n5. ā³ Commit & push\n\nReminder: Document what you did before committing!`,
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
392
|
case "create_documentation": {
|
|
326
393
|
if (!workflowState.state.testsPassed) {
|
|
327
394
|
return {
|
|
@@ -496,8 +563,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
496
563
|
};
|
|
497
564
|
}
|
|
498
565
|
|
|
499
|
-
|
|
500
|
-
|
|
566
|
+
default:
|
|
567
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
568
|
+
}
|
|
569
|
+
} catch (error) {
|
|
570
|
+
console.error("Tool handler error:", error);
|
|
571
|
+
return {
|
|
572
|
+
content: [
|
|
573
|
+
{
|
|
574
|
+
type: "text",
|
|
575
|
+
text: "ā ļø Internal server error while processing the tool request. Please try again.",
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
};
|
|
501
579
|
}
|
|
502
580
|
});
|
|
503
581
|
|