@damper/mcp 0.3.10 → 0.3.12

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 +225 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -644,6 +644,7 @@ server.registerTool('get_agent_instructions', {
644
644
  outputSchema: z.object({
645
645
  format: z.enum(['markdown', 'section']),
646
646
  content: z.string(),
647
+ lastModified: z.string().describe('ISO date when instructions were last updated'),
647
648
  }),
648
649
  annotations: {
649
650
  readOnlyHint: true,
@@ -652,8 +653,11 @@ server.registerTool('get_agent_instructions', {
652
653
  openWorldHint: false,
653
654
  },
654
655
  }, async ({ format = 'section' }) => {
656
+ const lastModified = '2025-02-04';
655
657
  const section = `## Task Management with Damper MCP
656
658
 
659
+ > Last updated: ${lastModified}
660
+
657
661
  This project uses Damper MCP for task tracking. **You MUST follow this workflow.**
658
662
 
659
663
  ### At Session Start (MANDATORY)
@@ -668,6 +672,13 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
668
672
  - \`update_subtask\` to mark subtask progress
669
673
  - **Follow patterns from project context** - Don't reinvent; use existing conventions
670
674
 
675
+ ### Feedback & Changelog Integration
676
+ - \`link_feedback_to_task\` - Link user feedback IDs to your task (helps track what customer requests led to the feature)
677
+ - When completing a **public** task, it auto-adds to the project's draft changelog
678
+ - \`list_changelogs\` - View existing changelogs and drafts
679
+ - \`create_changelog\` / \`update_changelog\` - Create or edit changelog entries
680
+ - \`add_to_changelog\` - Manually add completed tasks to a changelog
681
+
671
682
  ### At Session End (MANDATORY)
672
683
  - ALWAYS call \`add_note\` with session summary before stopping
673
684
  - ALWAYS call \`complete_task\` (if done) or \`abandon_task\` (if stopping early)
@@ -678,16 +689,17 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
678
689
  - **Project context prevents mistakes** - Contains architecture decisions, gotchas, and patterns
679
690
  - Locked tasks block other agents from working on them
680
691
  - Commits and notes help the next agent continue the work
681
- - Updating context saves future agents from re-analyzing the codebase`;
692
+ - Updating context saves future agents from re-analyzing the codebase
693
+ - Linking feedback connects customer requests to shipped features`;
682
694
  if (format === 'markdown') {
683
695
  return {
684
696
  content: [{ type: 'text', text: `# CLAUDE.md\n\n${section}` }],
685
- structuredContent: { format: 'markdown', content: `# CLAUDE.md\n\n${section}` },
697
+ structuredContent: { format: 'markdown', content: `# CLAUDE.md\n\n${section}`, lastModified },
686
698
  };
687
699
  }
688
700
  return {
689
701
  content: [{ type: 'text', text: section }],
690
- structuredContent: { format: 'section', content: section },
702
+ structuredContent: { format: 'section', content: section, lastModified },
691
703
  };
692
704
  });
693
705
  // ==================== Context Tools ====================
@@ -767,9 +779,12 @@ server.registerTool('get_context_section', {
767
779
  openWorldHint: false,
768
780
  },
769
781
  }, async ({ section }) => {
770
- // Encode section for URL path - encodeURIComponent doesn't encode * which can cause
771
- // issues with some proxies/CDNs that interpret * as a wildcard
772
- const encodedSection = encodeURIComponent(section).replace(/\*/g, '%2A');
782
+ // Encode each path segment individually but preserve slashes for hierarchical sections
783
+ // Also encode * which can cause issues with some proxies/CDNs that interpret * as a wildcard
784
+ const encodedSection = section
785
+ .split('/')
786
+ .map(part => encodeURIComponent(part).replace(/\*/g, '%2A'))
787
+ .join('/');
773
788
  const data = await api('GET', `/api/agent/context/${encodedSection}`);
774
789
  // Handle glob pattern response (multiple sections)
775
790
  if (data.pattern && data.sections) {
@@ -859,7 +874,11 @@ server.registerTool('delete_context_section', {
859
874
  openWorldHint: false,
860
875
  },
861
876
  }, async ({ section }) => {
862
- const encodedSection = encodeURIComponent(section).replace(/\*/g, '%2A');
877
+ // Encode each path segment individually but preserve slashes
878
+ const encodedSection = section
879
+ .split('/')
880
+ .map(part => encodeURIComponent(part).replace(/\*/g, '%2A'))
881
+ .join('/');
863
882
  const result = await api('DELETE', `/api/agent/context/${encodedSection}`);
864
883
  return {
865
884
  content: [{ type: 'text', text: `🗑️ Deleted context section: ${result.section}` }],
@@ -1366,6 +1385,205 @@ server.registerTool('sync_modules', {
1366
1385
  structuredContent: result,
1367
1386
  };
1368
1387
  });
1388
+ // ==================== Changelog Tools ====================
1389
+ // Tool: Link feedback to task
1390
+ server.registerTool('link_feedback_to_task', {
1391
+ title: 'Link Feedback to Task',
1392
+ description: 'Link feedback items to a roadmap task. Links the specified feedback IDs to the task.\n\n' +
1393
+ '**When to use:**\n' +
1394
+ '- After seeing relevant feedback in `list_feedback`\n' +
1395
+ '- When user mentions feedback that should be tracked with a task',
1396
+ inputSchema: z.object({
1397
+ taskId: z.string().describe('Task ID to link feedback to'),
1398
+ feedbackIds: z.array(z.string()).describe('Feedback IDs to link'),
1399
+ }),
1400
+ outputSchema: z.object({
1401
+ taskId: z.string(),
1402
+ linkedFeedbackIds: z.array(z.string()),
1403
+ totalLinkedFeedback: z.number(),
1404
+ feedbackTitles: z.array(z.string()),
1405
+ }),
1406
+ annotations: {
1407
+ readOnlyHint: false,
1408
+ destructiveHint: false,
1409
+ idempotentHint: true,
1410
+ openWorldHint: false,
1411
+ },
1412
+ }, async ({ taskId, feedbackIds }) => {
1413
+ const result = await api('POST', `/api/agent/tasks/${taskId}/feedback`, { feedbackIds });
1414
+ const linkedCount = result.linkedFeedbackIds.length;
1415
+ if (linkedCount === 0) {
1416
+ return {
1417
+ content: [{ type: 'text', text: `No new feedback linked (already linked or not found)` }],
1418
+ structuredContent: result,
1419
+ };
1420
+ }
1421
+ return {
1422
+ content: [{ type: 'text', text: `🔗 Linked ${linkedCount} feedback to task: ${result.feedbackTitles.join(', ')}` }],
1423
+ structuredContent: result,
1424
+ };
1425
+ });
1426
+ // Tool: List changelogs
1427
+ server.registerTool('list_changelogs', {
1428
+ title: 'List Changelogs',
1429
+ description: 'List changelogs for the project. Filter by status (draft, published).\n\n' +
1430
+ '**Draft changelogs:** Automatically created when completing public roadmap items. ' +
1431
+ 'Review and publish them to announce releases.',
1432
+ inputSchema: z.object({
1433
+ status: z.enum(['draft', 'published']).optional().describe('Filter by status'),
1434
+ limit: z.number().optional(),
1435
+ }),
1436
+ outputSchema: z.object({
1437
+ changelogs: z.array(z.object({
1438
+ id: z.string(),
1439
+ title: z.string(),
1440
+ version: z.string().nullable().optional(),
1441
+ status: z.string(),
1442
+ publishedAt: z.string().nullable().optional(),
1443
+ roadmapItemCount: z.number(),
1444
+ contentPreview: z.string(),
1445
+ })),
1446
+ }),
1447
+ annotations: {
1448
+ readOnlyHint: true,
1449
+ destructiveHint: false,
1450
+ idempotentHint: true,
1451
+ openWorldHint: false,
1452
+ },
1453
+ }, async ({ status, limit }) => {
1454
+ const params = new URLSearchParams();
1455
+ if (status)
1456
+ params.set('status', status);
1457
+ if (limit)
1458
+ params.set('limit', String(limit));
1459
+ const query = params.toString();
1460
+ const data = await api('GET', `/api/agent/changelogs${query ? `?${query}` : ''}`);
1461
+ if (!data.changelogs.length) {
1462
+ return {
1463
+ content: [{ type: 'text', text: 'No changelogs found' }],
1464
+ structuredContent: { changelogs: [] },
1465
+ };
1466
+ }
1467
+ const lines = data.changelogs.map((c) => {
1468
+ const status = c.status === 'draft' ? '📝' : '✅';
1469
+ const version = c.version ? ` v${c.version}` : '';
1470
+ const items = c.roadmapItemCount > 0 ? ` (${c.roadmapItemCount} items)` : '';
1471
+ return `• ${c.id}: ${status} ${c.title}${version}${items}`;
1472
+ });
1473
+ return {
1474
+ content: [{ type: 'text', text: `Changelogs:\n${lines.join('\n')}` }],
1475
+ structuredContent: data,
1476
+ };
1477
+ });
1478
+ // Tool: Create changelog
1479
+ server.registerTool('create_changelog', {
1480
+ title: 'Create Changelog',
1481
+ description: 'Create a new changelog entry. Usually starts as draft.\n\n' +
1482
+ '**Note:** Draft changelogs are auto-created when completing public roadmap items. ' +
1483
+ 'Use this to create additional changelogs if needed.',
1484
+ inputSchema: z.object({
1485
+ title: z.string().describe('Changelog title (e.g., "v2.1.0" or "January 2025 Release")'),
1486
+ content: z.string().optional().describe('Initial changelog content (markdown)'),
1487
+ version: z.string().optional().describe('Version number'),
1488
+ status: z.enum(['draft', 'published']).optional().describe('Status (default: draft)'),
1489
+ }),
1490
+ outputSchema: z.object({
1491
+ id: z.string(),
1492
+ title: z.string(),
1493
+ version: z.string().nullable().optional(),
1494
+ status: z.string(),
1495
+ }),
1496
+ annotations: {
1497
+ readOnlyHint: false,
1498
+ destructiveHint: false,
1499
+ idempotentHint: false,
1500
+ openWorldHint: false,
1501
+ },
1502
+ }, async (args) => {
1503
+ const result = await api('POST', '/api/agent/changelogs', args);
1504
+ const status = result.status === 'draft' ? '📝' : '✅';
1505
+ return {
1506
+ content: [{ type: 'text', text: `${status} Created changelog: ${result.id} "${result.title}"` }],
1507
+ structuredContent: result,
1508
+ };
1509
+ });
1510
+ // Tool: Update changelog
1511
+ server.registerTool('update_changelog', {
1512
+ title: 'Update Changelog',
1513
+ description: 'Update a changelog entry. Can update title, content, version, or status.\n\n' +
1514
+ '**Publishing:** Set status to "published" to make the changelog public.',
1515
+ inputSchema: z.object({
1516
+ changelogId: z.string().describe('Changelog ID'),
1517
+ title: z.string().optional().describe('New title'),
1518
+ content: z.string().optional().describe('New content (markdown)'),
1519
+ version: z.string().optional().describe('Version number'),
1520
+ status: z.enum(['draft', 'published']).optional().describe('Status'),
1521
+ }),
1522
+ outputSchema: z.object({
1523
+ id: z.string(),
1524
+ title: z.string(),
1525
+ version: z.string().nullable().optional(),
1526
+ status: z.string(),
1527
+ publishedAt: z.string().nullable().optional(),
1528
+ }),
1529
+ annotations: {
1530
+ readOnlyHint: false,
1531
+ destructiveHint: false,
1532
+ idempotentHint: true,
1533
+ openWorldHint: false,
1534
+ },
1535
+ }, async ({ changelogId, title, content, version, status }) => {
1536
+ const body = {};
1537
+ if (title !== undefined)
1538
+ body.title = title;
1539
+ if (content !== undefined)
1540
+ body.content = content;
1541
+ if (version !== undefined)
1542
+ body.version = version;
1543
+ if (status !== undefined)
1544
+ body.status = status;
1545
+ const result = await api('PATCH', `/api/agent/changelogs/${changelogId}`, body);
1546
+ const statusIcon = result.status === 'published' ? '✅' : '📝';
1547
+ const published = result.status === 'published' && result.publishedAt ? ' (just published)' : '';
1548
+ return {
1549
+ content: [{ type: 'text', text: `${statusIcon} Updated changelog: "${result.title}"${published}` }],
1550
+ structuredContent: result,
1551
+ };
1552
+ });
1553
+ // Tool: Add roadmap items to changelog
1554
+ server.registerTool('add_to_changelog', {
1555
+ title: 'Add to Changelog',
1556
+ description: 'Add completed roadmap items to a changelog. Links the items and appends formatted entries to content.\n\n' +
1557
+ '**When to use:**\n' +
1558
+ '- After completing multiple items that should be in one release\n' +
1559
+ '- To manually add items to a draft changelog',
1560
+ inputSchema: z.object({
1561
+ changelogId: z.string().describe('Changelog ID'),
1562
+ roadmapItemIds: z.array(z.string()).describe('Roadmap item IDs to add'),
1563
+ }),
1564
+ outputSchema: z.object({
1565
+ id: z.string(),
1566
+ title: z.string(),
1567
+ roadmapItemCount: z.number(),
1568
+ addedItems: z.array(z.object({
1569
+ id: z.string(),
1570
+ title: z.string(),
1571
+ })),
1572
+ }),
1573
+ annotations: {
1574
+ readOnlyHint: false,
1575
+ destructiveHint: false,
1576
+ idempotentHint: true,
1577
+ openWorldHint: false,
1578
+ },
1579
+ }, async ({ changelogId, roadmapItemIds }) => {
1580
+ const result = await api('POST', `/api/agent/changelogs/${changelogId}/items`, { roadmapItemIds });
1581
+ const addedTitles = result.addedItems.map((i) => i.title).join(', ');
1582
+ return {
1583
+ content: [{ type: 'text', text: `📋 Added ${result.addedItems.length} items to "${result.title}": ${addedTitles}` }],
1584
+ structuredContent: result,
1585
+ };
1586
+ });
1369
1587
  // Start
1370
1588
  async function main() {
1371
1589
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {