@damper/mcp 0.1.5 → 0.1.7
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/README.md +33 -1
- package/dist/index.js +113 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,10 +72,12 @@ The AI will see tools from both servers and can distinguish between them:
|
|
|
72
72
|
| Tool | Description |
|
|
73
73
|
|------|-------------|
|
|
74
74
|
| `list_tasks` | Get roadmap tasks (filter by `status`, `type`) |
|
|
75
|
-
| `get_task` | Task details + linked feedback |
|
|
75
|
+
| `get_task` | Task details + subtasks + linked feedback |
|
|
76
76
|
| `create_task` | Create task with type (bug, feature, improvement, task) |
|
|
77
77
|
| `start_task` | Lock and start task (use `force` to take over) |
|
|
78
78
|
| `add_note` | Add progress note |
|
|
79
|
+
| `create_subtask` | Add subtask to a task |
|
|
80
|
+
| `update_subtask` | Mark subtask done/undone |
|
|
79
81
|
| `complete_task` | Mark done, release lock |
|
|
80
82
|
| `abandon_task` | Release lock, return to planned |
|
|
81
83
|
| `list_feedback` | Browse user feedback |
|
|
@@ -93,6 +95,34 @@ Filter tasks by type to prioritize work:
|
|
|
93
95
|
|
|
94
96
|
Types: `bug` 🐛, `feature` ✨, `improvement` 💡, `task` 📌
|
|
95
97
|
|
|
98
|
+
### Task Metadata
|
|
99
|
+
|
|
100
|
+
Tasks include project management fields visible in `list_tasks` and `get_task`:
|
|
101
|
+
|
|
102
|
+
- **Priority**: high 🔴, medium 🟡, low ⚪
|
|
103
|
+
- **Effort**: xs, s, m, l, xl
|
|
104
|
+
- **Labels**: Custom tags
|
|
105
|
+
- **Due date**: Target completion date
|
|
106
|
+
|
|
107
|
+
### Subtasks
|
|
108
|
+
|
|
109
|
+
Tasks can have subtasks for tracking incremental progress. Use `get_task` to see subtasks with their IDs:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
## Subtasks (2/5)
|
|
113
|
+
- [x] Setup database schema (id: abc123)
|
|
114
|
+
- [ ] Implement API endpoints (id: def456)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Create and update subtasks as you work:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
> Add a subtask "Write unit tests" to this task
|
|
121
|
+
> Create subtask for database migrations
|
|
122
|
+
> Mark the database schema subtask as done
|
|
123
|
+
> Update subtask def456 to done
|
|
124
|
+
```
|
|
125
|
+
|
|
96
126
|
### Task Locking
|
|
97
127
|
|
|
98
128
|
When you start a task, it's locked to prevent other agents from working on it simultaneously:
|
|
@@ -108,6 +138,8 @@ When you start a task, it's locked to prevent other agents from working on it si
|
|
|
108
138
|
> List bugs I can fix
|
|
109
139
|
> Import my TODO.md into Damper
|
|
110
140
|
> Work on the dark mode feature
|
|
141
|
+
> Show me the subtasks for this task
|
|
142
|
+
> Mark the first subtask as done
|
|
111
143
|
> I'm done with the auth task - tests pass
|
|
112
144
|
> Abandon the current task, I'm blocked
|
|
113
145
|
```
|
package/dist/index.js
CHANGED
|
@@ -34,27 +34,45 @@ async function api(method, path, body) {
|
|
|
34
34
|
// Server
|
|
35
35
|
const server = new McpServer({
|
|
36
36
|
name: 'damper',
|
|
37
|
-
version: '0.1.
|
|
37
|
+
version: '0.1.7',
|
|
38
38
|
});
|
|
39
39
|
// Output schemas
|
|
40
|
+
const SubtaskProgressSchema = z.object({
|
|
41
|
+
done: z.number(),
|
|
42
|
+
total: z.number(),
|
|
43
|
+
}).nullable();
|
|
40
44
|
const TaskSummarySchema = z.object({
|
|
41
45
|
id: z.string(),
|
|
42
46
|
title: z.string(),
|
|
43
47
|
type: z.string(),
|
|
44
48
|
status: z.string(),
|
|
45
49
|
priority: z.string(),
|
|
50
|
+
effort: z.string().nullable().optional(),
|
|
51
|
+
labels: z.array(z.string()).optional(),
|
|
52
|
+
dueDate: z.string().nullable().optional(),
|
|
46
53
|
feedbackCount: z.number(),
|
|
47
54
|
hasImplementationPlan: z.boolean(),
|
|
55
|
+
subtaskProgress: SubtaskProgressSchema.optional(),
|
|
56
|
+
});
|
|
57
|
+
const SubtaskSchema = z.object({
|
|
58
|
+
id: z.string(),
|
|
59
|
+
title: z.string(),
|
|
60
|
+
done: z.boolean(),
|
|
48
61
|
});
|
|
49
62
|
const TaskDetailSchema = z.object({
|
|
50
63
|
id: z.string(),
|
|
51
64
|
title: z.string(),
|
|
52
|
-
description: z.string().optional(),
|
|
65
|
+
description: z.string().nullable().optional(),
|
|
53
66
|
type: z.string(),
|
|
54
|
-
implementationPlan: z.string().optional(),
|
|
67
|
+
implementationPlan: z.string().nullable().optional(),
|
|
55
68
|
status: z.string(),
|
|
69
|
+
priority: z.string().nullable().optional(),
|
|
70
|
+
effort: z.string().nullable().optional(),
|
|
71
|
+
labels: z.array(z.string()).optional(),
|
|
72
|
+
dueDate: z.string().nullable().optional(),
|
|
56
73
|
voteScore: z.number(),
|
|
57
|
-
|
|
74
|
+
subtasks: z.array(SubtaskSchema).optional(),
|
|
75
|
+
agentNotes: z.string().nullable().optional(),
|
|
58
76
|
feedback: z.array(z.object({
|
|
59
77
|
id: z.string(),
|
|
60
78
|
title: z.string(),
|
|
@@ -119,7 +137,8 @@ server.registerTool('list_tasks', {
|
|
|
119
137
|
const lines = data.tasks.map((t) => {
|
|
120
138
|
const p = t.priority === 'high' ? '🔴' : t.priority === 'medium' ? '🟡' : '⚪';
|
|
121
139
|
const typeIcon = t.type === 'bug' ? '🐛' : t.type === 'feature' ? '✨' : t.type === 'improvement' ? '💡' : '📌';
|
|
122
|
-
|
|
140
|
+
const subtaskInfo = t.subtaskProgress ? ` [${t.subtaskProgress.done}/${t.subtaskProgress.total}]` : '';
|
|
141
|
+
return `• ${t.id}: ${typeIcon} ${t.title} [${t.status}] ${p}${t.hasImplementationPlan ? ' 📋' : ''}${subtaskInfo}`;
|
|
123
142
|
});
|
|
124
143
|
return {
|
|
125
144
|
content: [{ type: 'text', text: `Tasks in "${data.project.name}":\n${lines.join('\n')}` }],
|
|
@@ -147,10 +166,28 @@ server.registerTool('get_task', {
|
|
|
147
166
|
`# ${typeIcon} ${t.title}`,
|
|
148
167
|
`Type: ${t.type} | Status: ${t.status} | Score: ${t.voteScore}`,
|
|
149
168
|
];
|
|
169
|
+
// Add priority/effort/labels if present
|
|
170
|
+
const meta = [];
|
|
171
|
+
if (t.priority)
|
|
172
|
+
meta.push(`Priority: ${t.priority}`);
|
|
173
|
+
if (t.effort)
|
|
174
|
+
meta.push(`Effort: ${t.effort}`);
|
|
175
|
+
if (t.dueDate)
|
|
176
|
+
meta.push(`Due: ${t.dueDate}`);
|
|
177
|
+
if (t.labels && t.labels.length)
|
|
178
|
+
meta.push(`Labels: ${t.labels.join(', ')}`);
|
|
179
|
+
if (meta.length)
|
|
180
|
+
parts.push(meta.join(' | '));
|
|
150
181
|
if (t.description)
|
|
151
182
|
parts.push(`\n## Description\n${t.description}`);
|
|
152
183
|
if (t.implementationPlan)
|
|
153
184
|
parts.push(`\n## Plan\n${t.implementationPlan}`);
|
|
185
|
+
// Show subtasks
|
|
186
|
+
if (t.subtasks && t.subtasks.length) {
|
|
187
|
+
const done = t.subtasks.filter(s => s.done).length;
|
|
188
|
+
parts.push(`\n## Subtasks (${done}/${t.subtasks.length})`);
|
|
189
|
+
t.subtasks.forEach((s) => parts.push(`- [${s.done ? 'x' : ' '}] ${s.title} (id: ${s.id})`));
|
|
190
|
+
}
|
|
154
191
|
if (t.agentNotes)
|
|
155
192
|
parts.push(`\n## Notes\n${t.agentNotes}`);
|
|
156
193
|
if (t.feedback.length) {
|
|
@@ -273,6 +310,77 @@ server.registerTool('add_note', {
|
|
|
273
310
|
structuredContent: { taskId, success: true },
|
|
274
311
|
};
|
|
275
312
|
});
|
|
313
|
+
// Tool: Create subtask
|
|
314
|
+
server.registerTool('create_subtask', {
|
|
315
|
+
title: 'Create Subtask',
|
|
316
|
+
description: 'Add a new subtask to a task. Useful for breaking down work into smaller steps.',
|
|
317
|
+
inputSchema: z.object({
|
|
318
|
+
taskId: z.string().describe('Task ID'),
|
|
319
|
+
title: z.string().describe('Subtask title'),
|
|
320
|
+
}),
|
|
321
|
+
outputSchema: z.object({
|
|
322
|
+
taskId: z.string(),
|
|
323
|
+
subtask: z.object({
|
|
324
|
+
id: z.string(),
|
|
325
|
+
title: z.string(),
|
|
326
|
+
done: z.boolean(),
|
|
327
|
+
}),
|
|
328
|
+
totalSubtasks: z.number(),
|
|
329
|
+
}),
|
|
330
|
+
annotations: {
|
|
331
|
+
readOnlyHint: false,
|
|
332
|
+
destructiveHint: false,
|
|
333
|
+
idempotentHint: false,
|
|
334
|
+
openWorldHint: false,
|
|
335
|
+
},
|
|
336
|
+
}, async ({ taskId, title }) => {
|
|
337
|
+
const result = await api('POST', `/api/agent/tasks/${taskId}/subtasks`, { title });
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: 'text', text: `➕ Created subtask: "${result.subtask.title}" (${result.totalSubtasks} total)` }],
|
|
340
|
+
structuredContent: {
|
|
341
|
+
taskId,
|
|
342
|
+
subtask: result.subtask,
|
|
343
|
+
totalSubtasks: result.totalSubtasks,
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
});
|
|
347
|
+
// Tool: Update subtask
|
|
348
|
+
server.registerTool('update_subtask', {
|
|
349
|
+
title: 'Update Subtask',
|
|
350
|
+
description: 'Mark a subtask as done or not done. Use get_task to see subtask IDs.',
|
|
351
|
+
inputSchema: z.object({
|
|
352
|
+
taskId: z.string().describe('Task ID'),
|
|
353
|
+
subtaskId: z.string().describe('Subtask ID'),
|
|
354
|
+
done: z.boolean().describe('Whether the subtask is done'),
|
|
355
|
+
}),
|
|
356
|
+
outputSchema: z.object({
|
|
357
|
+
taskId: z.string(),
|
|
358
|
+
subtaskId: z.string(),
|
|
359
|
+
done: z.boolean(),
|
|
360
|
+
progress: z.object({
|
|
361
|
+
done: z.number(),
|
|
362
|
+
total: z.number(),
|
|
363
|
+
}),
|
|
364
|
+
}),
|
|
365
|
+
annotations: {
|
|
366
|
+
readOnlyHint: false,
|
|
367
|
+
destructiveHint: false,
|
|
368
|
+
idempotentHint: true,
|
|
369
|
+
openWorldHint: false,
|
|
370
|
+
},
|
|
371
|
+
}, async ({ taskId, subtaskId, done }) => {
|
|
372
|
+
const result = await api('PATCH', `/api/agent/tasks/${taskId}/subtasks/${subtaskId}`, { done });
|
|
373
|
+
const status = done ? '✅' : '⬜';
|
|
374
|
+
return {
|
|
375
|
+
content: [{ type: 'text', text: `${status} Subtask updated (${result.progress.done}/${result.progress.total} done)` }],
|
|
376
|
+
structuredContent: {
|
|
377
|
+
taskId,
|
|
378
|
+
subtaskId,
|
|
379
|
+
done: result.done,
|
|
380
|
+
progress: result.progress,
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
});
|
|
276
384
|
// Tool: Complete task
|
|
277
385
|
server.registerTool('complete_task', {
|
|
278
386
|
title: 'Complete Task',
|