@damper/mcp 0.1.4 → 0.1.6
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 +38 -6
- package/dist/index.js +76 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,12 +15,13 @@ Damper → Settings → API Keys → Generate
|
|
|
15
15
|
|
|
16
16
|
### 2. Configure Your AI Agent
|
|
17
17
|
|
|
18
|
-
**Claude Code** (`~/.claude.json`):
|
|
18
|
+
**Claude Code** (`~/.claude.json` or `~/.config/claude/claude.json`):
|
|
19
19
|
```json
|
|
20
20
|
{
|
|
21
21
|
"mcpServers": {
|
|
22
22
|
"damper": {
|
|
23
|
-
"command": "
|
|
23
|
+
"command": "npx",
|
|
24
|
+
"args": ["@damper/mcp"],
|
|
24
25
|
"env": { "DAMPER_API_KEY": "dmp_..." }
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -44,16 +45,18 @@ Damper → Settings → API Keys → Generate
|
|
|
44
45
|
|
|
45
46
|
Each API key is tied to one project. For multiple projects, configure separate server entries:
|
|
46
47
|
|
|
47
|
-
**Claude Code** (`~/.claude.json`):
|
|
48
|
+
**Claude Code** (`~/.claude.json` or `~/.config/claude/claude.json`):
|
|
48
49
|
```json
|
|
49
50
|
{
|
|
50
51
|
"mcpServers": {
|
|
51
52
|
"damper-frontend": {
|
|
52
|
-
"command": "
|
|
53
|
+
"command": "npx",
|
|
54
|
+
"args": ["@damper/mcp"],
|
|
53
55
|
"env": { "DAMPER_API_KEY": "dmp_frontend_xxx" }
|
|
54
56
|
},
|
|
55
57
|
"damper-backend": {
|
|
56
|
-
"command": "
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["@damper/mcp"],
|
|
57
60
|
"env": { "DAMPER_API_KEY": "dmp_backend_xxx" }
|
|
58
61
|
}
|
|
59
62
|
}
|
|
@@ -69,10 +72,11 @@ The AI will see tools from both servers and can distinguish between them:
|
|
|
69
72
|
| Tool | Description |
|
|
70
73
|
|------|-------------|
|
|
71
74
|
| `list_tasks` | Get roadmap tasks (filter by `status`, `type`) |
|
|
72
|
-
| `get_task` | Task details + linked feedback |
|
|
75
|
+
| `get_task` | Task details + subtasks + linked feedback |
|
|
73
76
|
| `create_task` | Create task with type (bug, feature, improvement, task) |
|
|
74
77
|
| `start_task` | Lock and start task (use `force` to take over) |
|
|
75
78
|
| `add_note` | Add progress note |
|
|
79
|
+
| `update_subtask` | Mark subtask done/undone |
|
|
76
80
|
| `complete_task` | Mark done, release lock |
|
|
77
81
|
| `abandon_task` | Release lock, return to planned |
|
|
78
82
|
| `list_feedback` | Browse user feedback |
|
|
@@ -90,6 +94,32 @@ Filter tasks by type to prioritize work:
|
|
|
90
94
|
|
|
91
95
|
Types: `bug` 🐛, `feature` ✨, `improvement` 💡, `task` 📌
|
|
92
96
|
|
|
97
|
+
### Task Metadata
|
|
98
|
+
|
|
99
|
+
Tasks include project management fields visible in `list_tasks` and `get_task`:
|
|
100
|
+
|
|
101
|
+
- **Priority**: high 🔴, medium 🟡, low ⚪
|
|
102
|
+
- **Effort**: xs, s, m, l, xl
|
|
103
|
+
- **Labels**: Custom tags
|
|
104
|
+
- **Due date**: Target completion date
|
|
105
|
+
|
|
106
|
+
### Subtasks
|
|
107
|
+
|
|
108
|
+
Tasks can have subtasks for tracking incremental progress. Use `get_task` to see subtasks with their IDs:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
## Subtasks (2/5)
|
|
112
|
+
- [x] Setup database schema (id: abc123)
|
|
113
|
+
- [ ] Implement API endpoints (id: def456)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Mark subtasks complete as you work:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
> Mark the database schema subtask as done
|
|
120
|
+
> Update subtask def456 to done
|
|
121
|
+
```
|
|
122
|
+
|
|
93
123
|
### Task Locking
|
|
94
124
|
|
|
95
125
|
When you start a task, it's locked to prevent other agents from working on it simultaneously:
|
|
@@ -105,6 +135,8 @@ When you start a task, it's locked to prevent other agents from working on it si
|
|
|
105
135
|
> List bugs I can fix
|
|
106
136
|
> Import my TODO.md into Damper
|
|
107
137
|
> Work on the dark mode feature
|
|
138
|
+
> Show me the subtasks for this task
|
|
139
|
+
> Mark the first subtask as done
|
|
108
140
|
> I'm done with the auth task - tests pass
|
|
109
141
|
> Abandon the current task, I'm blocked
|
|
110
142
|
```
|
package/dist/index.js
CHANGED
|
@@ -34,17 +34,30 @@ 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.6',
|
|
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(),
|
|
@@ -53,7 +66,12 @@ const TaskDetailSchema = z.object({
|
|
|
53
66
|
type: z.string(),
|
|
54
67
|
implementationPlan: z.string().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(),
|
|
74
|
+
subtasks: z.array(SubtaskSchema).optional(),
|
|
57
75
|
agentNotes: z.string().optional(),
|
|
58
76
|
feedback: z.array(z.object({
|
|
59
77
|
id: 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,43 @@ server.registerTool('add_note', {
|
|
|
273
310
|
structuredContent: { taskId, success: true },
|
|
274
311
|
};
|
|
275
312
|
});
|
|
313
|
+
// Tool: Update subtask
|
|
314
|
+
server.registerTool('update_subtask', {
|
|
315
|
+
title: 'Update Subtask',
|
|
316
|
+
description: 'Mark a subtask as done or not done. Use get_task to see subtask IDs.',
|
|
317
|
+
inputSchema: z.object({
|
|
318
|
+
taskId: z.string().describe('Task ID'),
|
|
319
|
+
subtaskId: z.string().describe('Subtask ID'),
|
|
320
|
+
done: z.boolean().describe('Whether the subtask is done'),
|
|
321
|
+
}),
|
|
322
|
+
outputSchema: z.object({
|
|
323
|
+
taskId: z.string(),
|
|
324
|
+
subtaskId: z.string(),
|
|
325
|
+
done: z.boolean(),
|
|
326
|
+
progress: z.object({
|
|
327
|
+
done: z.number(),
|
|
328
|
+
total: z.number(),
|
|
329
|
+
}),
|
|
330
|
+
}),
|
|
331
|
+
annotations: {
|
|
332
|
+
readOnlyHint: false,
|
|
333
|
+
destructiveHint: false,
|
|
334
|
+
idempotentHint: true,
|
|
335
|
+
openWorldHint: false,
|
|
336
|
+
},
|
|
337
|
+
}, async ({ taskId, subtaskId, done }) => {
|
|
338
|
+
const result = await api('PATCH', `/api/agent/tasks/${taskId}/subtasks/${subtaskId}`, { done });
|
|
339
|
+
const status = done ? '✅' : '⬜';
|
|
340
|
+
return {
|
|
341
|
+
content: [{ type: 'text', text: `${status} Subtask updated (${result.progress.done}/${result.progress.total} done)` }],
|
|
342
|
+
structuredContent: {
|
|
343
|
+
taskId,
|
|
344
|
+
subtaskId,
|
|
345
|
+
done: result.done,
|
|
346
|
+
progress: result.progress,
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
});
|
|
276
350
|
// Tool: Complete task
|
|
277
351
|
server.registerTool('complete_task', {
|
|
278
352
|
title: 'Complete Task',
|