@damper/mcp 0.3.18 → 0.3.20

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 +65 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -117,10 +117,12 @@ server.registerTool('list_tasks', {
117
117
  type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Filter by task type'),
118
118
  quarter: z.string().optional().describe('Filter by quarter (e.g., "Q1 2025") or "none" for unscheduled'),
119
119
  sort: z.enum(['importance', 'newest', 'votes']).optional().describe('Sort order: importance (priority+votes, default), newest, or votes'),
120
- limit: z.number().optional(),
120
+ limit: z.number().optional().describe('Max tasks to return (default: 20)'),
121
+ offset: z.number().optional().describe('Skip first N tasks for pagination (default: 0)'),
121
122
  }),
122
123
  outputSchema: z.object({
123
124
  project: z.string(),
125
+ total: z.number(),
124
126
  tasks: z.array(TaskSummarySchema),
125
127
  }),
126
128
  annotations: {
@@ -129,7 +131,7 @@ server.registerTool('list_tasks', {
129
131
  idempotentHint: true,
130
132
  openWorldHint: false,
131
133
  },
132
- }, async ({ status, type, quarter, sort, limit }) => {
134
+ }, async ({ status, type, quarter, sort, limit, offset }) => {
133
135
  const params = new URLSearchParams();
134
136
  if (status)
135
137
  params.set('status', status);
@@ -141,13 +143,15 @@ server.registerTool('list_tasks', {
141
143
  params.set('sort', sort);
142
144
  if (limit)
143
145
  params.set('limit', String(limit));
146
+ if (offset)
147
+ params.set('offset', String(offset));
144
148
  const query = params.toString();
145
149
  const data = await api('GET', `/api/agent/tasks${query ? `?${query}` : ''}`);
146
150
  if (!data.tasks.length) {
147
151
  const filters = [type && `type: ${type}`, quarter && `quarter: ${quarter}`].filter(Boolean).join(', ');
148
152
  return {
149
153
  content: [{ type: 'text', text: `No tasks in "${data.project.name}"${filters ? ` (${filters})` : ''}` }],
150
- structuredContent: { project: data.project.name, tasks: [] },
154
+ structuredContent: { project: data.project.name, total: 0, tasks: [] },
151
155
  };
152
156
  }
153
157
  const lines = data.tasks.map((t) => {
@@ -157,15 +161,20 @@ server.registerTool('list_tasks', {
157
161
  const quarterInfo = t.quarter ? ` šŸ“…${t.quarter}` : '';
158
162
  return `• ${t.id}: ${typeIcon} ${t.title} [${t.status}] ${p}${quarterInfo}${t.hasImplementationPlan ? ' šŸ“‹' : ''}${subtaskInfo}`;
159
163
  });
164
+ const currentOffset = offset || 0;
165
+ const paginationInfo = data.total > currentOffset + data.tasks.length
166
+ ? `\nšŸ“„ Showing ${currentOffset + 1}–${currentOffset + data.tasks.length} of ${data.total}. Use offset=${currentOffset + data.tasks.length} to see more.`
167
+ : '';
160
168
  const output = [
161
- `Tasks in "${data.project.name}":`,
169
+ `Tasks in "${data.project.name}" (${data.total} total):`,
162
170
  lines.join('\n'),
171
+ paginationInfo,
163
172
  '',
164
173
  'šŸ’” **Tip:** Run `get_project_context` first to understand codebase patterns before starting work.',
165
174
  ].join('\n');
166
175
  return {
167
176
  content: [{ type: 'text', text: output }],
168
- structuredContent: { project: data.project.name, tasks: data.tasks },
177
+ structuredContent: { project: data.project.name, total: data.total, tasks: data.tasks },
169
178
  };
170
179
  });
171
180
  // Tool: Get task
@@ -244,6 +253,7 @@ server.registerTool('update_task', {
244
253
  'Useful for refining task details as you learn more about the work.',
245
254
  inputSchema: z.object({
246
255
  taskId: z.string().describe('Task ID'),
256
+ title: z.string().optional().describe('Task title'),
247
257
  description: z.string().optional().describe('Task description'),
248
258
  implementationPlan: z.string().optional().describe('Implementation plan (markdown)'),
249
259
  priority: z.enum(['high', 'medium', 'low']).nullable().optional().describe('Task priority'),
@@ -269,8 +279,10 @@ server.registerTool('update_task', {
269
279
  idempotentHint: true,
270
280
  openWorldHint: false,
271
281
  },
272
- }, async ({ taskId, description, implementationPlan, priority, effort, quarter, labels, isPublic }) => {
282
+ }, async ({ taskId, title, description, implementationPlan, priority, effort, quarter, labels, isPublic }) => {
273
283
  const body = {};
284
+ if (title !== undefined)
285
+ body.title = title;
274
286
  if (description !== undefined)
275
287
  body.description = description;
276
288
  if (implementationPlan !== undefined)
@@ -287,6 +299,8 @@ server.registerTool('update_task', {
287
299
  body.isPublic = isPublic;
288
300
  const result = await api('PATCH', `/api/agent/tasks/${taskId}`, body);
289
301
  const updates = [];
302
+ if (title !== undefined)
303
+ updates.push(`title="${title}"`);
290
304
  if (description !== undefined)
291
305
  updates.push('description');
292
306
  if (implementationPlan !== undefined)
@@ -321,10 +335,12 @@ server.registerTool('create_task', {
321
335
  title: 'Create Task',
322
336
  description: 'Create a new roadmap task. Use for importing from TODO files or creating work items.',
323
337
  inputSchema: z.object({
324
- title: z.string(),
338
+ title: z.string().describe('Task title. Use verb prefix matching the type: ' +
339
+ 'bug → "Fix …", feature → "Add …", improvement → "Improve …", task → "Set up …" / "Update …"'),
325
340
  description: z.string().optional(),
326
341
  type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Task type (default: feature)'),
327
- status: z.enum(['planned', 'in_progress']).optional(),
342
+ status: z.enum(['planned', 'in_progress', 'done']).optional(),
343
+ priority: z.enum(['high', 'medium', 'low']).optional().describe('Task priority'),
328
344
  implementationPlan: z.string().optional(),
329
345
  isPublic: z.boolean().optional().describe('Whether task is visible on public roadmap (default: true)'),
330
346
  }),
@@ -1160,6 +1176,40 @@ server.registerTool('get_feedback', {
1160
1176
  structuredContent: f,
1161
1177
  };
1162
1178
  });
1179
+ // Tool: Update feedback
1180
+ server.registerTool('update_feedback', {
1181
+ title: 'Update Feedback',
1182
+ description: 'Update feedback status. Use to triage, close, or mark feedback as done.',
1183
+ inputSchema: z.object({
1184
+ feedbackId: z.string().describe('Feedback ID'),
1185
+ status: z
1186
+ .enum(['new', 'under_review', 'planned', 'in_progress', 'done', 'closed'])
1187
+ .describe('New status'),
1188
+ }),
1189
+ outputSchema: z.object({
1190
+ id: z.string(),
1191
+ title: z.string(),
1192
+ status: z.string(),
1193
+ type: z.string(),
1194
+ }),
1195
+ annotations: {
1196
+ readOnlyHint: false,
1197
+ destructiveHint: false,
1198
+ idempotentHint: true,
1199
+ openWorldHint: false,
1200
+ },
1201
+ }, async ({ feedbackId, status }) => {
1202
+ const result = await api('PATCH', `/api/agent/feedback/${feedbackId}`, { status });
1203
+ return {
1204
+ content: [
1205
+ {
1206
+ type: 'text',
1207
+ text: `Updated feedback "${result.title}" → ${result.status}`,
1208
+ },
1209
+ ],
1210
+ structuredContent: result,
1211
+ };
1212
+ });
1163
1213
  // ==================== Issue Reporting ====================
1164
1214
  // Tool: Report issue
1165
1215
  server.registerTool('report_issue', {
@@ -1658,16 +1708,16 @@ server.registerTool('update_changelog', {
1658
1708
  structuredContent: result,
1659
1709
  };
1660
1710
  });
1661
- // Tool: Add roadmap items to changelog
1711
+ // Tool: Add tasks to changelog
1662
1712
  server.registerTool('add_to_changelog', {
1663
1713
  title: 'Add to Changelog',
1664
- description: 'Add completed roadmap items to a changelog. Links the items and appends formatted entries to content.\n\n' +
1714
+ description: 'Add completed tasks to a changelog. Links the tasks and appends formatted entries to content.\n\n' +
1665
1715
  '**When to use:**\n' +
1666
- '- After completing multiple items that should be in one release\n' +
1667
- '- To manually add items to a draft changelog',
1716
+ '- After completing multiple tasks that should be in one release\n' +
1717
+ '- To manually add tasks to a draft changelog',
1668
1718
  inputSchema: z.object({
1669
1719
  changelogId: z.string().describe('Changelog ID'),
1670
- roadmapItemIds: z.array(z.string()).describe('Roadmap item IDs to add'),
1720
+ taskIds: z.array(z.string()).describe('Task IDs to add'),
1671
1721
  }),
1672
1722
  outputSchema: z.object({
1673
1723
  id: z.string(),
@@ -1684,8 +1734,8 @@ server.registerTool('add_to_changelog', {
1684
1734
  idempotentHint: true,
1685
1735
  openWorldHint: false,
1686
1736
  },
1687
- }, async ({ changelogId, roadmapItemIds }) => {
1688
- const result = await api('POST', `/api/agent/changelogs/${changelogId}/items`, { roadmapItemIds });
1737
+ }, async ({ changelogId, taskIds }) => {
1738
+ const result = await api('POST', `/api/agent/changelogs/${changelogId}/items`, { roadmapItemIds: taskIds });
1689
1739
  const addedTitles = result.addedItems.map((i) => i.title).join(', ');
1690
1740
  return {
1691
1741
  content: [{ type: 'text', text: `šŸ“‹ Added ${result.addedItems.length} items to "${result.title}": ${addedTitles}` }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.3.18",
3
+ "version": "0.3.20",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {