@damper/mcp 0.1.1 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +151 -8
  2. package/package.json +10 -3
package/dist/index.js CHANGED
@@ -30,6 +30,48 @@ const server = new McpServer({
30
30
  name: 'damper',
31
31
  version: '0.1.0',
32
32
  });
33
+ // Output schemas
34
+ const TaskSummarySchema = z.object({
35
+ id: z.string(),
36
+ title: z.string(),
37
+ status: z.string(),
38
+ priority: z.string(),
39
+ feedbackCount: z.number(),
40
+ hasImplementationPlan: z.boolean(),
41
+ });
42
+ const TaskDetailSchema = z.object({
43
+ id: z.string(),
44
+ title: z.string(),
45
+ description: z.string().optional(),
46
+ implementationPlan: z.string().optional(),
47
+ status: z.string(),
48
+ voteScore: z.number(),
49
+ agentNotes: z.string().optional(),
50
+ feedback: z.array(z.object({
51
+ id: z.string(),
52
+ title: z.string(),
53
+ description: z.string(),
54
+ voterCount: z.number(),
55
+ })),
56
+ });
57
+ const FeedbackSummarySchema = z.object({
58
+ id: z.string(),
59
+ title: z.string(),
60
+ type: z.string(),
61
+ voterCount: z.number(),
62
+ linkedTaskId: z.string().optional(),
63
+ });
64
+ const FeedbackDetailSchema = z.object({
65
+ id: z.string(),
66
+ title: z.string(),
67
+ description: z.string(),
68
+ type: z.string(),
69
+ status: z.string(),
70
+ voteScore: z.number(),
71
+ linkedTaskId: z.string().optional(),
72
+ voters: z.array(z.object({ email: z.string(), plan: z.string() })),
73
+ comments: z.array(z.object({ author: z.string(), body: z.string() })),
74
+ });
33
75
  // Tool: List tasks
34
76
  server.registerTool('list_tasks', {
35
77
  title: 'List Tasks',
@@ -38,6 +80,16 @@ server.registerTool('list_tasks', {
38
80
  status: z.enum(['planned', 'in_progress', 'done', 'all']).optional(),
39
81
  limit: z.number().optional(),
40
82
  }),
83
+ outputSchema: z.object({
84
+ project: z.string(),
85
+ tasks: z.array(TaskSummarySchema),
86
+ }),
87
+ annotations: {
88
+ readOnlyHint: true,
89
+ destructiveHint: false,
90
+ idempotentHint: true,
91
+ openWorldHint: false,
92
+ },
41
93
  }, async ({ status, limit }) => {
42
94
  const params = new URLSearchParams();
43
95
  if (status)
@@ -47,7 +99,10 @@ server.registerTool('list_tasks', {
47
99
  const query = params.toString();
48
100
  const data = await api('GET', `/api/agent/tasks${query ? `?${query}` : ''}`);
49
101
  if (!data.tasks.length) {
50
- return { content: [{ type: 'text', text: `No tasks in "${data.project.name}"` }] };
102
+ return {
103
+ content: [{ type: 'text', text: `No tasks in "${data.project.name}"` }],
104
+ structuredContent: { project: data.project.name, tasks: [] },
105
+ };
51
106
  }
52
107
  const lines = data.tasks.map((t) => {
53
108
  const p = t.priority === 'high' ? '🔴' : t.priority === 'medium' ? '🟡' : '⚪';
@@ -55,6 +110,7 @@ server.registerTool('list_tasks', {
55
110
  });
56
111
  return {
57
112
  content: [{ type: 'text', text: `Tasks in "${data.project.name}":\n${lines.join('\n')}` }],
113
+ structuredContent: { project: data.project.name, tasks: data.tasks },
58
114
  };
59
115
  });
60
116
  // Tool: Get task
@@ -64,6 +120,13 @@ server.registerTool('get_task', {
64
120
  inputSchema: z.object({
65
121
  taskId: z.string().describe('Task ID'),
66
122
  }),
123
+ outputSchema: TaskDetailSchema,
124
+ annotations: {
125
+ readOnlyHint: true,
126
+ destructiveHint: false,
127
+ idempotentHint: true,
128
+ openWorldHint: false,
129
+ },
67
130
  }, async ({ taskId }) => {
68
131
  const t = await api('GET', `/api/agent/tasks/${taskId}`);
69
132
  const parts = [
@@ -80,7 +143,10 @@ server.registerTool('get_task', {
80
143
  parts.push(`\n## Feedback (${t.feedback.length})`);
81
144
  t.feedback.forEach((f) => parts.push(`- ${f.title} (${f.voterCount} votes)`));
82
145
  }
83
- return { content: [{ type: 'text', text: parts.join('\n') }] };
146
+ return {
147
+ content: [{ type: 'text', text: parts.join('\n') }],
148
+ structuredContent: t,
149
+ };
84
150
  });
85
151
  // Tool: Create task
86
152
  server.registerTool('create_task', {
@@ -92,10 +158,22 @@ server.registerTool('create_task', {
92
158
  status: z.enum(['planned', 'in_progress']).optional(),
93
159
  implementationPlan: z.string().optional(),
94
160
  }),
161
+ outputSchema: z.object({
162
+ id: z.string(),
163
+ title: z.string(),
164
+ status: z.string(),
165
+ }),
166
+ annotations: {
167
+ readOnlyHint: false,
168
+ destructiveHint: false,
169
+ idempotentHint: false,
170
+ openWorldHint: false,
171
+ },
95
172
  }, async (args) => {
96
173
  const result = await api('POST', '/api/agent/tasks', args);
97
174
  return {
98
175
  content: [{ type: 'text', text: `Created: ${result.id} "${result.title}" [${result.status}]` }],
176
+ structuredContent: result,
99
177
  };
100
178
  });
101
179
  // Tool: Start task
@@ -105,9 +183,23 @@ server.registerTool('start_task', {
105
183
  inputSchema: z.object({
106
184
  taskId: z.string(),
107
185
  }),
186
+ outputSchema: z.object({
187
+ id: z.string(),
188
+ status: z.string(),
189
+ message: z.string(),
190
+ }),
191
+ annotations: {
192
+ readOnlyHint: false,
193
+ destructiveHint: false,
194
+ idempotentHint: true,
195
+ openWorldHint: false,
196
+ },
108
197
  }, async ({ taskId }) => {
109
198
  const result = await api('POST', `/api/agent/tasks/${taskId}/start`);
110
- return { content: [{ type: 'text', text: `Started ${result.id}: ${result.message}` }] };
199
+ return {
200
+ content: [{ type: 'text', text: `Started ${result.id}: ${result.message}` }],
201
+ structuredContent: result,
202
+ };
111
203
  });
112
204
  // Tool: Add note
113
205
  server.registerTool('add_note', {
@@ -117,9 +209,22 @@ server.registerTool('add_note', {
117
209
  taskId: z.string(),
118
210
  note: z.string(),
119
211
  }),
212
+ outputSchema: z.object({
213
+ taskId: z.string(),
214
+ success: z.boolean(),
215
+ }),
216
+ annotations: {
217
+ readOnlyHint: false,
218
+ destructiveHint: false,
219
+ idempotentHint: false,
220
+ openWorldHint: false,
221
+ },
120
222
  }, async ({ taskId, note }) => {
121
223
  await api('POST', `/api/agent/tasks/${taskId}/notes`, { note });
122
- return { content: [{ type: 'text', text: `Note added to ${taskId}` }] };
224
+ return {
225
+ content: [{ type: 'text', text: `Note added to ${taskId}` }],
226
+ structuredContent: { taskId, success: true },
227
+ };
123
228
  });
124
229
  // Tool: Complete task
125
230
  server.registerTool('complete_task', {
@@ -129,9 +234,22 @@ server.registerTool('complete_task', {
129
234
  taskId: z.string(),
130
235
  summary: z.string().describe('What was implemented'),
131
236
  }),
237
+ outputSchema: z.object({
238
+ id: z.string(),
239
+ status: z.string(),
240
+ }),
241
+ annotations: {
242
+ readOnlyHint: false,
243
+ destructiveHint: false,
244
+ idempotentHint: true,
245
+ openWorldHint: false,
246
+ },
132
247
  }, async ({ taskId, summary }) => {
133
248
  const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary });
134
- return { content: [{ type: 'text', text: `Completed ${result.id}` }] };
249
+ return {
250
+ content: [{ type: 'text', text: `Completed ${result.id}` }],
251
+ structuredContent: result,
252
+ };
135
253
  });
136
254
  // Tool: List feedback
137
255
  server.registerTool('list_feedback', {
@@ -141,6 +259,15 @@ server.registerTool('list_feedback', {
141
259
  status: z.enum(['new', 'under_review', 'planned', 'in_progress', 'done', 'closed']).optional(),
142
260
  limit: z.number().optional(),
143
261
  }),
262
+ outputSchema: z.object({
263
+ feedback: z.array(FeedbackSummarySchema),
264
+ }),
265
+ annotations: {
266
+ readOnlyHint: true,
267
+ destructiveHint: false,
268
+ idempotentHint: true,
269
+ openWorldHint: false,
270
+ },
144
271
  }, async ({ status, limit }) => {
145
272
  const params = new URLSearchParams();
146
273
  if (status)
@@ -150,13 +277,19 @@ server.registerTool('list_feedback', {
150
277
  const query = params.toString();
151
278
  const data = await api('GET', `/api/agent/feedback${query ? `?${query}` : ''}`);
152
279
  if (!data.feedback.length) {
153
- return { content: [{ type: 'text', text: 'No feedback found' }] };
280
+ return {
281
+ content: [{ type: 'text', text: 'No feedback found' }],
282
+ structuredContent: { feedback: [] },
283
+ };
154
284
  }
155
285
  const lines = data.feedback.map((f) => {
156
286
  const link = f.linkedTaskId ? ` → ${f.linkedTaskId}` : '';
157
287
  return `• ${f.id}: ${f.title} [${f.type}] (${f.voterCount} votes)${link}`;
158
288
  });
159
- return { content: [{ type: 'text', text: `Feedback:\n${lines.join('\n')}` }] };
289
+ return {
290
+ content: [{ type: 'text', text: `Feedback:\n${lines.join('\n')}` }],
291
+ structuredContent: { feedback: data.feedback },
292
+ };
160
293
  });
161
294
  // Tool: Get feedback
162
295
  server.registerTool('get_feedback', {
@@ -165,6 +298,13 @@ server.registerTool('get_feedback', {
165
298
  inputSchema: z.object({
166
299
  feedbackId: z.string(),
167
300
  }),
301
+ outputSchema: FeedbackDetailSchema,
302
+ annotations: {
303
+ readOnlyHint: true,
304
+ destructiveHint: false,
305
+ idempotentHint: true,
306
+ openWorldHint: false,
307
+ },
168
308
  }, async ({ feedbackId }) => {
169
309
  const f = await api('GET', `/api/agent/feedback/${feedbackId}`);
170
310
  const parts = [
@@ -185,7 +325,10 @@ server.registerTool('get_feedback', {
185
325
  if (f.comments.length > 3)
186
326
  parts.push(`... and ${f.comments.length - 3} more`);
187
327
  }
188
- return { content: [{ type: 'text', text: parts.join('\n') }] };
328
+ return {
329
+ content: [{ type: 'text', text: parts.join('\n') }],
330
+ structuredContent: f,
331
+ };
189
332
  });
190
333
  // Start
191
334
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {
@@ -15,7 +15,9 @@
15
15
  },
16
16
  "main": "./dist/index.js",
17
17
  "types": "./dist/index.d.ts",
18
- "files": ["dist"],
18
+ "files": [
19
+ "dist"
20
+ ],
19
21
  "scripts": {
20
22
  "build": "tsc",
21
23
  "dev": "tsx src/index.ts",
@@ -33,6 +35,11 @@
33
35
  "engines": {
34
36
  "node": ">=18"
35
37
  },
36
- "keywords": ["mcp", "damper", "ai", "task-management"],
38
+ "keywords": [
39
+ "mcp",
40
+ "damper",
41
+ "ai",
42
+ "task-management"
43
+ ],
37
44
  "license": "MIT"
38
45
  }