wolfpack-mcp 1.0.45 → 1.0.47

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/dist/client.js CHANGED
@@ -509,6 +509,65 @@ export class WolfpackClient {
509
509
  throw error;
510
510
  }
511
511
  }
512
+ // Notification methods
513
+ async listNotifications(options) {
514
+ const params = new URLSearchParams();
515
+ if (options?.unreadOnly)
516
+ params.append('unreadOnly', 'true');
517
+ if (options?.limit)
518
+ params.append('limit', options.limit.toString());
519
+ if (options?.offset)
520
+ params.append('offset', options.offset.toString());
521
+ const query = params.toString();
522
+ return this.api.get(`/notifications${query ? `?${query}` : ''}`);
523
+ }
524
+ async markNotificationRead(notificationId) {
525
+ return this.api.put(`/notifications/${notificationId}/read`, {});
526
+ }
527
+ async markAllNotificationsRead() {
528
+ return this.api.put('/notifications/read-all', {});
529
+ }
530
+ async deleteNotification(notificationId) {
531
+ await this.api.delete(`/notifications/${notificationId}`);
532
+ return { message: 'Notification deleted' };
533
+ }
534
+ // Subscription methods
535
+ async listSubscriptions(options) {
536
+ const params = new URLSearchParams();
537
+ if (options?.documentType)
538
+ params.append('documentType', options.documentType);
539
+ if (options?.isActive !== undefined)
540
+ params.append('isActive', options.isActive.toString());
541
+ const query = params.toString();
542
+ return this.api.get(`/subscriptions${query ? `?${query}` : ''}`);
543
+ }
544
+ async subscribe(data) {
545
+ return this.api.post('/subscriptions', data);
546
+ }
547
+ async unsubscribe(documentType, documentId) {
548
+ return this.api.post(`/subscriptions/${documentType}/${documentId}/unsubscribe`, {});
549
+ }
550
+ async muteSubscription(documentType, documentId, duration) {
551
+ return this.api.post(`/subscriptions/${documentType}/${documentId}/mute`, {
552
+ duration,
553
+ });
554
+ }
555
+ async unmuteSubscription(documentType, documentId) {
556
+ return this.api.post(`/subscriptions/${documentType}/${documentId}/unmute`, {});
557
+ }
558
+ // Discussion methods
559
+ async getDiscussions(documentType, documentId) {
560
+ return this.api.get(`/discussions/${documentType}/${documentId}`);
561
+ }
562
+ async getDiscussionByComment(commentId) {
563
+ return this.api.get(`/discussions/by-comment/${commentId}`);
564
+ }
565
+ async addDiscussionComment(discussionId, content, parentCommentId) {
566
+ return this.api.post(`/discussions/${discussionId}/comments`, {
567
+ content,
568
+ parentCommentId,
569
+ });
570
+ }
512
571
  close() {
513
572
  // No cleanup needed for API client
514
573
  }
package/dist/index.js CHANGED
@@ -469,6 +469,54 @@ const ListTeamMembersSchema = z.object({
469
469
  .optional()
470
470
  .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
471
471
  });
472
+ // Notification schemas
473
+ const ListNotificationsSchema = z.object({
474
+ unread_only: z.boolean().optional().describe('If true, only return unread notifications'),
475
+ limit: z.number().optional().describe('Maximum number of notifications to return (default 20)'),
476
+ offset: z.number().optional().describe('Number of notifications to skip for pagination'),
477
+ });
478
+ const MarkNotificationReadSchema = z.object({
479
+ notification_id: z.string().describe('The ID of the notification to mark as read'),
480
+ });
481
+ const DeleteNotificationSchema = z.object({
482
+ notification_id: z.string().describe('The ID of the notification to delete'),
483
+ });
484
+ // Subscription schemas
485
+ const VALID_DOCUMENT_TYPES = [
486
+ 'wiki_page',
487
+ 'work_item',
488
+ 'radar_item',
489
+ 'issue',
490
+ 'journal',
491
+ 'discussion',
492
+ ];
493
+ const ListSubscriptionsSchema = z.object({
494
+ document_type: z.enum(VALID_DOCUMENT_TYPES).optional().describe('Filter by document type'),
495
+ is_active: z.boolean().optional().describe('Filter by active status'),
496
+ });
497
+ const SubscribeSchema = z.object({
498
+ document_type: z.enum(VALID_DOCUMENT_TYPES).describe('Type of document to subscribe to'),
499
+ document_id: z.string().describe('The ID of the document to subscribe to'),
500
+ reason: z.string().optional().describe('Reason for subscribing (default: "watched")'),
501
+ notify_on_mentions: z.boolean().optional().describe('Notify when mentioned in this document'),
502
+ notify_on_edits: z.boolean().optional().describe('Notify when the document is edited'),
503
+ notify_on_comments: z.boolean().optional().describe('Notify on new comments'),
504
+ notify_on_status: z.boolean().optional().describe('Notify on status changes'),
505
+ cooldown_minutes: z.number().optional().describe('Minimum minutes between notifications'),
506
+ });
507
+ const UnsubscribeSchema = z.object({
508
+ document_type: z.enum(VALID_DOCUMENT_TYPES).describe('Type of document to unsubscribe from'),
509
+ document_id: z.string().describe('The ID of the document to unsubscribe from'),
510
+ });
511
+ const MuteSubscriptionSchema = z.object({
512
+ document_type: z.enum(VALID_DOCUMENT_TYPES).describe('Type of document'),
513
+ document_id: z.string().describe('The ID of the document'),
514
+ duration: z.number().optional().describe('Duration in minutes to mute (omit for indefinite)'),
515
+ });
516
+ const UnmuteSubscriptionSchema = z.object({
517
+ document_type: z.enum(VALID_DOCUMENT_TYPES).describe('Type of document'),
518
+ document_id: z.string().describe('The ID of the document'),
519
+ });
472
520
  // UUID v4 field names to remove from responses.
473
521
  // These are internal database IDs that agents should not use.
474
522
  // Agents should use refId (sequential int) or slug instead.
@@ -477,6 +525,24 @@ const UUID_FIELDS_TO_STRIP = new Set([
477
525
  'teamId', // Internal team UUID - noise for agents
478
526
  'workItemId', // Cross-reference UUID on Issues - noise
479
527
  ]);
528
+ // Discussion schemas
529
+ const GetDiscussionsSchema = z.object({
530
+ document_type: z.string().describe('Document type (e.g. "wiki", "work_item", "issue")'),
531
+ document_id: z.string().describe('The ID of the document'),
532
+ });
533
+ const GetDiscussionByCommentSchema = z.object({
534
+ comment_id: z
535
+ .string()
536
+ .describe('The ID of a discussion comment (e.g. from a notification sourceDocumentId)'),
537
+ });
538
+ const AddDiscussionCommentSchema = z.object({
539
+ discussion_id: z.string().describe('The ID of the discussion to comment on'),
540
+ content: z.string().describe('Comment content (supports markdown and @mentions)'),
541
+ parent_comment_id: z
542
+ .string()
543
+ .optional()
544
+ .describe('Parent comment ID for threaded replies (omit for top-level)'),
545
+ });
480
546
  // Fields containing user-defined data that should never be recursively processed.
481
547
  const PASSTHROUGH_FIELDS = new Set(['formDefinition', 'formValues']);
482
548
  // Strip UUID v4 fields from response objects so agents use refId/slug instead.
@@ -1497,6 +1563,254 @@ class WolfpackMCPServer {
1497
1563
  required: ['skill_name', 'resource_name'],
1498
1564
  },
1499
1565
  },
1566
+ // Notification tools
1567
+ {
1568
+ name: 'list_notifications',
1569
+ description: 'List your notifications. Returns notifications with type, title, message, read status, and linked items (work items, issues). ' +
1570
+ 'Notification types include: mention, assignment, comment, status_change, team_invite, page_update, nomination, reaction. ' +
1571
+ 'Use unread_only=true to see only unread notifications. Supports pagination with limit/offset.',
1572
+ inputSchema: {
1573
+ type: 'object',
1574
+ properties: {
1575
+ unread_only: {
1576
+ type: 'boolean',
1577
+ description: 'If true, only return unread notifications',
1578
+ },
1579
+ limit: {
1580
+ type: 'number',
1581
+ description: 'Maximum number of notifications to return (default 20)',
1582
+ },
1583
+ offset: {
1584
+ type: 'number',
1585
+ description: 'Number of notifications to skip for pagination',
1586
+ },
1587
+ },
1588
+ },
1589
+ },
1590
+ {
1591
+ name: 'mark_notification_read',
1592
+ description: 'Mark a specific notification as read. Use this after processing a notification to prevent re-processing.',
1593
+ inputSchema: {
1594
+ type: 'object',
1595
+ properties: {
1596
+ notification_id: {
1597
+ type: 'string',
1598
+ description: 'The ID of the notification to mark as read',
1599
+ },
1600
+ },
1601
+ required: ['notification_id'],
1602
+ },
1603
+ },
1604
+ {
1605
+ name: 'mark_all_notifications_read',
1606
+ description: 'Mark all of your unread notifications as read.',
1607
+ inputSchema: {
1608
+ type: 'object',
1609
+ properties: {},
1610
+ },
1611
+ },
1612
+ {
1613
+ name: 'delete_notification',
1614
+ description: 'Delete a specific notification permanently.',
1615
+ inputSchema: {
1616
+ type: 'object',
1617
+ properties: {
1618
+ notification_id: {
1619
+ type: 'string',
1620
+ description: 'The ID of the notification to delete',
1621
+ },
1622
+ },
1623
+ required: ['notification_id'],
1624
+ },
1625
+ },
1626
+ // Subscription tools
1627
+ {
1628
+ name: 'list_subscriptions',
1629
+ description: 'List your document subscriptions. Subscriptions control which documents you receive notifications for. ' +
1630
+ 'Each subscription shows the document type, notification preferences (mentions, edits, comments, status), mute status, and reason for subscribing. ' +
1631
+ 'Filter by document_type to see subscriptions for a specific type (e.g. "work_item", "issue", "wiki_page").',
1632
+ inputSchema: {
1633
+ type: 'object',
1634
+ properties: {
1635
+ document_type: {
1636
+ type: 'string',
1637
+ enum: ['wiki_page', 'work_item', 'radar_item', 'issue', 'journal', 'discussion'],
1638
+ description: 'Filter by document type',
1639
+ },
1640
+ is_active: {
1641
+ type: 'boolean',
1642
+ description: 'Filter by active status',
1643
+ },
1644
+ },
1645
+ },
1646
+ },
1647
+ {
1648
+ name: 'subscribe',
1649
+ description: 'Subscribe to a document to receive notifications about it. ' +
1650
+ 'You can configure which notification types to receive: mentions, edits, comments, and status changes. ' +
1651
+ 'Supported document types: wiki_page, work_item, radar_item, issue, journal, discussion.',
1652
+ inputSchema: {
1653
+ type: 'object',
1654
+ properties: {
1655
+ document_type: {
1656
+ type: 'string',
1657
+ enum: ['wiki_page', 'work_item', 'radar_item', 'issue', 'journal', 'discussion'],
1658
+ description: 'Type of document to subscribe to',
1659
+ },
1660
+ document_id: {
1661
+ type: 'string',
1662
+ description: 'The ID of the document to subscribe to',
1663
+ },
1664
+ reason: {
1665
+ type: 'string',
1666
+ description: 'Reason for subscribing (default: "watched")',
1667
+ },
1668
+ notify_on_mentions: {
1669
+ type: 'boolean',
1670
+ description: 'Notify when mentioned in this document',
1671
+ },
1672
+ notify_on_edits: {
1673
+ type: 'boolean',
1674
+ description: 'Notify when the document is edited',
1675
+ },
1676
+ notify_on_comments: {
1677
+ type: 'boolean',
1678
+ description: 'Notify on new comments',
1679
+ },
1680
+ notify_on_status: {
1681
+ type: 'boolean',
1682
+ description: 'Notify on status changes',
1683
+ },
1684
+ cooldown_minutes: {
1685
+ type: 'number',
1686
+ description: 'Minimum minutes between notifications',
1687
+ },
1688
+ },
1689
+ required: ['document_type', 'document_id'],
1690
+ },
1691
+ },
1692
+ {
1693
+ name: 'unsubscribe',
1694
+ description: 'Unsubscribe from a document (soft delete). Stops notifications but keeps the subscription record. ' +
1695
+ 'The subscription can be reactivated by subscribing again.',
1696
+ inputSchema: {
1697
+ type: 'object',
1698
+ properties: {
1699
+ document_type: {
1700
+ type: 'string',
1701
+ enum: ['wiki_page', 'work_item', 'radar_item', 'issue', 'journal', 'discussion'],
1702
+ description: 'Type of document to unsubscribe from',
1703
+ },
1704
+ document_id: {
1705
+ type: 'string',
1706
+ description: 'The ID of the document to unsubscribe from',
1707
+ },
1708
+ },
1709
+ required: ['document_type', 'document_id'],
1710
+ },
1711
+ },
1712
+ {
1713
+ name: 'mute_subscription',
1714
+ description: 'Temporarily mute notifications from a subscription. The subscription remains active but notifications are silenced. ' +
1715
+ 'Specify duration in minutes, or omit for indefinite mute. Use unmute_subscription to resume.',
1716
+ inputSchema: {
1717
+ type: 'object',
1718
+ properties: {
1719
+ document_type: {
1720
+ type: 'string',
1721
+ enum: ['wiki_page', 'work_item', 'radar_item', 'issue', 'journal', 'discussion'],
1722
+ description: 'Type of document',
1723
+ },
1724
+ document_id: {
1725
+ type: 'string',
1726
+ description: 'The ID of the document',
1727
+ },
1728
+ duration: {
1729
+ type: 'number',
1730
+ description: 'Duration in minutes to mute (omit for indefinite)',
1731
+ },
1732
+ },
1733
+ required: ['document_type', 'document_id'],
1734
+ },
1735
+ },
1736
+ {
1737
+ name: 'unmute_subscription',
1738
+ description: 'Unmute a subscription to resume receiving notifications.',
1739
+ inputSchema: {
1740
+ type: 'object',
1741
+ properties: {
1742
+ document_type: {
1743
+ type: 'string',
1744
+ enum: ['wiki_page', 'work_item', 'radar_item', 'issue', 'journal', 'discussion'],
1745
+ description: 'Type of document',
1746
+ },
1747
+ document_id: {
1748
+ type: 'string',
1749
+ description: 'The ID of the document',
1750
+ },
1751
+ },
1752
+ required: ['document_type', 'document_id'],
1753
+ },
1754
+ },
1755
+ // Discussion tools
1756
+ {
1757
+ name: 'get_discussions',
1758
+ description: 'Get all discussion threads on a document (wiki page, work item, issue, etc.). ' +
1759
+ 'Returns discussions with their full comment threads including replies.',
1760
+ inputSchema: {
1761
+ type: 'object',
1762
+ properties: {
1763
+ document_type: {
1764
+ type: 'string',
1765
+ description: 'Document type (e.g. "wiki", "work_item", "issue")',
1766
+ },
1767
+ document_id: {
1768
+ type: 'string',
1769
+ description: 'The ID of the document',
1770
+ },
1771
+ },
1772
+ required: ['document_type', 'document_id'],
1773
+ },
1774
+ },
1775
+ {
1776
+ name: 'get_discussion_by_comment',
1777
+ description: 'Find the full discussion thread containing a specific comment. ' +
1778
+ 'Use this when you have a comment ID from a notification (sourceDocumentType: "discussion_comment") ' +
1779
+ 'and need to see the full discussion context.',
1780
+ inputSchema: {
1781
+ type: 'object',
1782
+ properties: {
1783
+ comment_id: {
1784
+ type: 'string',
1785
+ description: 'The comment ID (e.g. from a notification sourceDocumentId)',
1786
+ },
1787
+ },
1788
+ required: ['comment_id'],
1789
+ },
1790
+ },
1791
+ {
1792
+ name: 'create_discussion_comment',
1793
+ description: 'Add a comment to a discussion thread. Supports threaded replies via parent_comment_id. ' +
1794
+ 'Use this to respond to wiki page discussions, work item discussions, or any document discussion.',
1795
+ inputSchema: {
1796
+ type: 'object',
1797
+ properties: {
1798
+ discussion_id: {
1799
+ type: 'string',
1800
+ description: 'The ID of the discussion to comment on',
1801
+ },
1802
+ content: {
1803
+ type: 'string',
1804
+ description: 'Comment content (supports markdown and @mentions)',
1805
+ },
1806
+ parent_comment_id: {
1807
+ type: 'string',
1808
+ description: 'Parent comment ID for threaded replies (omit for top-level)',
1809
+ },
1810
+ },
1811
+ required: ['discussion_id', 'content'],
1812
+ },
1813
+ },
1500
1814
  ],
1501
1815
  }));
1502
1816
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -2190,6 +2504,120 @@ class WolfpackMCPServer {
2190
2504
  ],
2191
2505
  };
2192
2506
  }
2507
+ // Notification handlers
2508
+ case 'list_notifications': {
2509
+ const parsed = ListNotificationsSchema.parse(args);
2510
+ const result = await this.client.listNotifications({
2511
+ unreadOnly: parsed.unread_only,
2512
+ limit: parsed.limit,
2513
+ offset: parsed.offset,
2514
+ });
2515
+ // Don't strip UUIDs — agents need notification IDs to mark as read/delete
2516
+ return {
2517
+ content: [
2518
+ {
2519
+ type: 'text',
2520
+ text: JSON.stringify(result, null, 2),
2521
+ },
2522
+ ],
2523
+ };
2524
+ }
2525
+ case 'mark_notification_read': {
2526
+ const parsed = MarkNotificationReadSchema.parse(args);
2527
+ const result = await this.client.markNotificationRead(parsed.notification_id);
2528
+ return {
2529
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2530
+ };
2531
+ }
2532
+ case 'mark_all_notifications_read': {
2533
+ const result = await this.client.markAllNotificationsRead();
2534
+ return {
2535
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2536
+ };
2537
+ }
2538
+ case 'delete_notification': {
2539
+ const parsed = DeleteNotificationSchema.parse(args);
2540
+ const result = await this.client.deleteNotification(parsed.notification_id);
2541
+ return {
2542
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2543
+ };
2544
+ }
2545
+ // Subscription handlers
2546
+ case 'list_subscriptions': {
2547
+ const parsed = ListSubscriptionsSchema.parse(args);
2548
+ const result = await this.client.listSubscriptions({
2549
+ documentType: parsed.document_type,
2550
+ isActive: parsed.is_active,
2551
+ });
2552
+ // Don't strip UUIDs — agents need subscription IDs
2553
+ return {
2554
+ content: [
2555
+ {
2556
+ type: 'text',
2557
+ text: JSON.stringify(result, null, 2),
2558
+ },
2559
+ ],
2560
+ };
2561
+ }
2562
+ case 'subscribe': {
2563
+ const parsed = SubscribeSchema.parse(args);
2564
+ const result = await this.client.subscribe({
2565
+ documentType: parsed.document_type,
2566
+ documentId: parsed.document_id,
2567
+ reason: parsed.reason,
2568
+ notifyOnMentions: parsed.notify_on_mentions,
2569
+ notifyOnEdits: parsed.notify_on_edits,
2570
+ notifyOnComments: parsed.notify_on_comments,
2571
+ notifyOnStatus: parsed.notify_on_status,
2572
+ cooldownMinutes: parsed.cooldown_minutes,
2573
+ });
2574
+ return {
2575
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2576
+ };
2577
+ }
2578
+ case 'unsubscribe': {
2579
+ const parsed = UnsubscribeSchema.parse(args);
2580
+ const result = await this.client.unsubscribe(parsed.document_type, parsed.document_id);
2581
+ return {
2582
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2583
+ };
2584
+ }
2585
+ case 'mute_subscription': {
2586
+ const parsed = MuteSubscriptionSchema.parse(args);
2587
+ const result = await this.client.muteSubscription(parsed.document_type, parsed.document_id, parsed.duration);
2588
+ return {
2589
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2590
+ };
2591
+ }
2592
+ case 'unmute_subscription': {
2593
+ const parsed = UnmuteSubscriptionSchema.parse(args);
2594
+ const result = await this.client.unmuteSubscription(parsed.document_type, parsed.document_id);
2595
+ return {
2596
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2597
+ };
2598
+ }
2599
+ // Discussion handlers
2600
+ case 'get_discussions': {
2601
+ const parsed = GetDiscussionsSchema.parse(args);
2602
+ const result = await this.client.getDiscussions(parsed.document_type, parsed.document_id);
2603
+ return {
2604
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2605
+ };
2606
+ }
2607
+ case 'get_discussion_by_comment': {
2608
+ const parsed = GetDiscussionByCommentSchema.parse(args);
2609
+ const result = await this.client.getDiscussionByComment(parsed.comment_id);
2610
+ return {
2611
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2612
+ };
2613
+ }
2614
+ case 'create_discussion_comment': {
2615
+ const parsed = AddDiscussionCommentSchema.parse(args);
2616
+ const result = await this.client.addDiscussionComment(parsed.discussion_id, parsed.content, parsed.parent_comment_id);
2617
+ return {
2618
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
2619
+ };
2620
+ }
2193
2621
  default:
2194
2622
  throw new Error(`Unknown tool: ${name}`);
2195
2623
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.45",
3
+ "version": "1.0.47",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",