@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.
Files changed (3) hide show
  1. package/README.md +38 -6
  2. package/dist/index.js +76 -2
  3. 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": "damper",
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": "damper",
53
+ "command": "npx",
54
+ "args": ["@damper/mcp"],
53
55
  "env": { "DAMPER_API_KEY": "dmp_frontend_xxx" }
54
56
  },
55
57
  "damper-backend": {
56
- "command": "damper",
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.0',
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
- return `• ${t.id}: ${typeIcon} ${t.title} [${t.status}] ${p}${t.hasImplementationPlan ? ' 📋' : ''}`;
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',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {