wolfpack-mcp 1.0.42 → 1.0.44
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 +38 -35
- package/dist/index.js +383 -168
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -53,6 +53,14 @@ export class WolfpackClient {
|
|
|
53
53
|
const response = await this.api.get('/teams');
|
|
54
54
|
return response.teams;
|
|
55
55
|
}
|
|
56
|
+
// Team Member methods
|
|
57
|
+
async listTeamMembers(teamSlug) {
|
|
58
|
+
const params = new URLSearchParams();
|
|
59
|
+
if (teamSlug)
|
|
60
|
+
params.append('teamSlug', teamSlug);
|
|
61
|
+
const query = params.toString();
|
|
62
|
+
return this.api.get(`/team-members${query ? `?${query}` : ''}`);
|
|
63
|
+
}
|
|
56
64
|
// Helper to fetch all pages of a paginated endpoint
|
|
57
65
|
async fetchAllPages(endpoint, baseParams) {
|
|
58
66
|
// First request to get total count
|
|
@@ -175,42 +183,9 @@ export class WolfpackClient {
|
|
|
175
183
|
throw error;
|
|
176
184
|
}
|
|
177
185
|
}
|
|
178
|
-
async
|
|
179
|
-
try {
|
|
180
|
-
return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/status`, teamSlug), { status });
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
throw error;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
async updateWorkItemAssignee(workItemId, data, teamSlug) {
|
|
190
|
-
try {
|
|
191
|
-
return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/assignee`, teamSlug), data);
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
195
|
-
return null;
|
|
196
|
-
}
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
async updateWorkItemTitle(workItemId, title, teamSlug) {
|
|
186
|
+
async updateWorkItem(workItemId, fields, teamSlug) {
|
|
201
187
|
try {
|
|
202
|
-
return await this.api.
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
throw error;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
async updateWorkItemInitiative(workItemId, radarItemId, teamSlug) {
|
|
212
|
-
try {
|
|
213
|
-
return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/initiative`, teamSlug), { radarItemId });
|
|
188
|
+
return await this.api.patch(this.withTeamSlug(`/work-items/${workItemId}`, teamSlug), fields);
|
|
214
189
|
}
|
|
215
190
|
catch (error) {
|
|
216
191
|
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
@@ -285,6 +260,13 @@ export class WolfpackClient {
|
|
|
285
260
|
throw error;
|
|
286
261
|
}
|
|
287
262
|
}
|
|
263
|
+
async createRadarItem(data) {
|
|
264
|
+
const { teamSlug, ...rest } = data;
|
|
265
|
+
return this.api.post('/radar-items', { ...rest, teamSlug });
|
|
266
|
+
}
|
|
267
|
+
async updateRadarItem(itemId, data, teamSlug) {
|
|
268
|
+
return this.api.patch(this.withTeamSlug(`/radar-items/${itemId}`, teamSlug), data);
|
|
269
|
+
}
|
|
288
270
|
// Issue methods
|
|
289
271
|
async listIssues(options) {
|
|
290
272
|
const params = new URLSearchParams();
|
|
@@ -466,6 +448,20 @@ export class WolfpackClient {
|
|
|
466
448
|
async createIssueComment(issueId, data, teamSlug) {
|
|
467
449
|
return this.api.post(this.withTeamSlug(`/issues/${issueId}/comments`, teamSlug), data);
|
|
468
450
|
}
|
|
451
|
+
async deleteWorkItemComment(workItemId, commentId, teamSlug) {
|
|
452
|
+
return this.api.delete(this.withTeamSlug(`/work-items/${workItemId}/comments/${commentId}`, teamSlug));
|
|
453
|
+
}
|
|
454
|
+
async deleteIssueComment(issueId, commentId, teamSlug) {
|
|
455
|
+
return this.api.delete(this.withTeamSlug(`/issues/${issueId}/comments/${commentId}`, teamSlug));
|
|
456
|
+
}
|
|
457
|
+
// Category methods
|
|
458
|
+
async listCategories(teamSlug) {
|
|
459
|
+
const params = new URLSearchParams();
|
|
460
|
+
if (teamSlug)
|
|
461
|
+
params.append('teamSlug', teamSlug);
|
|
462
|
+
const query = params.toString();
|
|
463
|
+
return this.api.get(`/categories${query ? `?${query}` : ''}`);
|
|
464
|
+
}
|
|
469
465
|
/**
|
|
470
466
|
* Upload an image and get back a URL that can be used in markdown content.
|
|
471
467
|
*/
|
|
@@ -480,6 +476,13 @@ export class WolfpackClient {
|
|
|
480
476
|
const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
|
|
481
477
|
return { base64: buffer.toString('base64'), mimeType: contentType };
|
|
482
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Download an issue attachment image and return raw base64 + mimeType.
|
|
481
|
+
*/
|
|
482
|
+
async downloadIssueAttachment(team, refId, attachmentId) {
|
|
483
|
+
const { buffer, contentType } = await this.api.getBuffer(`/issues/${team}/${refId}/attachments/${attachmentId}`);
|
|
484
|
+
return { base64: buffer.toString('base64'), mimeType: contentType };
|
|
485
|
+
}
|
|
483
486
|
// Skill methods (progressive disclosure)
|
|
484
487
|
async listSkills() {
|
|
485
488
|
return this.api.get('/skills');
|
package/dist/index.js
CHANGED
|
@@ -112,39 +112,31 @@ const VALID_STATUSES = [
|
|
|
112
112
|
'closed',
|
|
113
113
|
'archived',
|
|
114
114
|
];
|
|
115
|
-
const
|
|
116
|
-
work_item_id: z.string().describe('The ID of the work item'),
|
|
117
|
-
status: z.enum(VALID_STATUSES).describe('New status'),
|
|
118
|
-
project_slug: z
|
|
119
|
-
.string()
|
|
120
|
-
.optional()
|
|
121
|
-
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
122
|
-
});
|
|
123
|
-
const UpdateWorkItemAssigneeSchema = z.object({
|
|
115
|
+
const UpdateWorkItemSchema = z.object({
|
|
124
116
|
work_item_id: z.string().describe('The ID of the work item'),
|
|
117
|
+
title: z.string().optional().describe('New title for the work item'),
|
|
118
|
+
status: z.enum(VALID_STATUSES).optional().describe('New status'),
|
|
125
119
|
leading_user_id: z
|
|
126
120
|
.string()
|
|
127
121
|
.nullable()
|
|
122
|
+
.optional()
|
|
128
123
|
.describe('User ID to assign as leading user, or null to unassign'),
|
|
129
|
-
|
|
124
|
+
radar_item_id: z
|
|
130
125
|
.string()
|
|
126
|
+
.nullable()
|
|
131
127
|
.optional()
|
|
132
|
-
.describe('
|
|
133
|
-
|
|
134
|
-
const UpdateWorkItemTitleSchema = z.object({
|
|
135
|
-
work_item_id: z.string().describe('The ID of the work item'),
|
|
136
|
-
title: z.string().describe('New title for the work item'),
|
|
137
|
-
project_slug: z
|
|
128
|
+
.describe('Radar/initiative item ID to link to, or null to unlink'),
|
|
129
|
+
category_id: z
|
|
138
130
|
.string()
|
|
131
|
+
.nullable()
|
|
139
132
|
.optional()
|
|
140
|
-
.describe('
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
radar_item_id: z
|
|
145
|
-
.string()
|
|
133
|
+
.describe('Category ID to set, or null to remove the category'),
|
|
134
|
+
priority: z.coerce.number().optional().describe('Priority level (0-4, higher is more important)'),
|
|
135
|
+
size: z
|
|
136
|
+
.enum(['S', 'M', 'L'])
|
|
146
137
|
.nullable()
|
|
147
|
-
.
|
|
138
|
+
.optional()
|
|
139
|
+
.describe('Size estimate: "S" (small), "M" (medium), "L" (large), or null to remove'),
|
|
148
140
|
project_slug: z
|
|
149
141
|
.string()
|
|
150
142
|
.optional()
|
|
@@ -184,6 +176,31 @@ const GetRadarItemSchema = z.object({
|
|
|
184
176
|
item_id: z.string().describe('The refId (number) of the radar item'),
|
|
185
177
|
project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
|
|
186
178
|
});
|
|
179
|
+
const CreateRadarItemSchema = z.object({
|
|
180
|
+
project_slug: z
|
|
181
|
+
.string()
|
|
182
|
+
.optional()
|
|
183
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
184
|
+
title: z.string().describe('Title of the radar/initiative item'),
|
|
185
|
+
description: z.string().optional().describe('Description of the initiative (markdown)'),
|
|
186
|
+
stage: z
|
|
187
|
+
.enum(['pending', 'now', 'next', 'later', 'completed'])
|
|
188
|
+
.describe('Stage: "pending" (not started), "now" (current sprint), "next" (upcoming), "later" (future), "completed"'),
|
|
189
|
+
});
|
|
190
|
+
const UpdateRadarItemSchema = z.object({
|
|
191
|
+
item_id: z.string().describe('The refId (number) of the radar item to update'),
|
|
192
|
+
title: z.string().optional().describe('Updated title'),
|
|
193
|
+
description: z.string().optional().describe('Updated description (markdown)'),
|
|
194
|
+
notes: z.string().optional().describe('Updated internal notes (markdown)'),
|
|
195
|
+
stage: z
|
|
196
|
+
.enum(['pending', 'now', 'next', 'later', 'completed'])
|
|
197
|
+
.optional()
|
|
198
|
+
.describe('Updated stage'),
|
|
199
|
+
project_slug: z
|
|
200
|
+
.string()
|
|
201
|
+
.optional()
|
|
202
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
203
|
+
});
|
|
187
204
|
// Issue schemas
|
|
188
205
|
const ListIssuesSchema = z.object({
|
|
189
206
|
project_slug: z.string().optional().describe('Project slug to filter issues'),
|
|
@@ -271,8 +288,18 @@ const UpdateIssueSchema = z.object({
|
|
|
271
288
|
.optional()
|
|
272
289
|
.describe('Updated status'),
|
|
273
290
|
severity: z.enum(['low', 'medium', 'high', 'critical']).optional().describe('Updated severity'),
|
|
291
|
+
type: z
|
|
292
|
+
.enum(['bug', 'feature-request', 'task', 'improvement', 'question'])
|
|
293
|
+
.optional()
|
|
294
|
+
.describe('Updated type'),
|
|
274
295
|
assigned_to_id: z.string().optional().describe('Updated assignee'),
|
|
275
296
|
closing_note: z.string().optional().describe('Closing note (when closing the issue)'),
|
|
297
|
+
environment: z.string().optional().describe('Environment where the issue occurred'),
|
|
298
|
+
affected_version: z.string().optional().describe('Affected version'),
|
|
299
|
+
reproducible: z.boolean().optional().describe('Whether reproducible'),
|
|
300
|
+
steps_to_reproduce: z.string().optional().describe('Steps to reproduce'),
|
|
301
|
+
expected_behavior: z.string().optional().describe('Expected behavior'),
|
|
302
|
+
actual_behavior: z.string().optional().describe('Actual behavior'),
|
|
276
303
|
project_slug: z
|
|
277
304
|
.string()
|
|
278
305
|
.optional()
|
|
@@ -388,6 +415,22 @@ const CreateIssueCommentSchema = z.object({
|
|
|
388
415
|
.optional()
|
|
389
416
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
390
417
|
});
|
|
418
|
+
const DeleteWorkItemCommentSchema = z.object({
|
|
419
|
+
work_item_id: z.string().describe('The work item refId (number)'),
|
|
420
|
+
comment_id: z.string().describe('The comment ID to delete'),
|
|
421
|
+
project_slug: z
|
|
422
|
+
.string()
|
|
423
|
+
.optional()
|
|
424
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
425
|
+
});
|
|
426
|
+
const DeleteIssueCommentSchema = z.object({
|
|
427
|
+
issue_id: z.string().describe('The issue refId (number)'),
|
|
428
|
+
comment_id: z.string().describe('The comment ID to delete'),
|
|
429
|
+
project_slug: z
|
|
430
|
+
.string()
|
|
431
|
+
.optional()
|
|
432
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
433
|
+
});
|
|
391
434
|
// Image upload schema
|
|
392
435
|
const UploadImageSchema = z.object({
|
|
393
436
|
file_path: z
|
|
@@ -412,6 +455,20 @@ const GetSkillResourceSchema = z.object({
|
|
|
412
455
|
skill_name: z.string().describe('The name of the skill'),
|
|
413
456
|
resource_name: z.string().describe('The name of the resource file'),
|
|
414
457
|
});
|
|
458
|
+
// Category schemas
|
|
459
|
+
const ListCategoriesSchema = z.object({
|
|
460
|
+
project_slug: z
|
|
461
|
+
.string()
|
|
462
|
+
.optional()
|
|
463
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
464
|
+
});
|
|
465
|
+
// Team member schemas
|
|
466
|
+
const ListTeamMembersSchema = z.object({
|
|
467
|
+
project_slug: z
|
|
468
|
+
.string()
|
|
469
|
+
.optional()
|
|
470
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
471
|
+
});
|
|
415
472
|
// UUID v4 field names to remove from responses.
|
|
416
473
|
// These are internal database IDs that agents should not use.
|
|
417
474
|
// Agents should use refId (sequential int) or slug instead.
|
|
@@ -612,16 +669,13 @@ class WolfpackMCPServer {
|
|
|
612
669
|
},
|
|
613
670
|
},
|
|
614
671
|
{
|
|
615
|
-
name: '
|
|
616
|
-
description: '
|
|
617
|
-
'
|
|
618
|
-
'
|
|
619
|
-
'
|
|
620
|
-
'
|
|
621
|
-
'
|
|
622
|
-
'5) If work cannot be done: move to "blocked" and add a detailed comment explaining the blocker, what was attempted, and what is needed to unblock. ' +
|
|
623
|
-
'Statuses: "pending" (backlog), "new" (to do), "doing" (in progress), "review" (work done, pending review), ' +
|
|
624
|
-
'"ready" (reviewed, awaiting deployment), "blocked", "completed" (deployed).',
|
|
672
|
+
name: 'update_work_item',
|
|
673
|
+
description: 'Update one or more fields on a work item. Only provide the fields you want to change. ' +
|
|
674
|
+
'Supports: title, status, leading_user_id (assignee), radar_item_id (initiative), ' +
|
|
675
|
+
'category_id, priority (0-4), and size (S/M/L). ' +
|
|
676
|
+
'STATUS WORKFLOW: "pending" (backlog) → "new" (to do) → "doing" (in progress) → "review" (work done) → "ready" (awaiting deployment) → "completed" (deployed). ' +
|
|
677
|
+
'Use "blocked" when work cannot proceed. For "pending" items use pull_work_item first. ' +
|
|
678
|
+
'When moving to "review", add a completion comment. When moving to "blocked", add a comment explaining the blocker.',
|
|
625
679
|
inputSchema: {
|
|
626
680
|
type: 'object',
|
|
627
681
|
properties: {
|
|
@@ -629,6 +683,10 @@ class WolfpackMCPServer {
|
|
|
629
683
|
type: 'string',
|
|
630
684
|
description: 'The ID of the work item',
|
|
631
685
|
},
|
|
686
|
+
title: {
|
|
687
|
+
type: 'string',
|
|
688
|
+
description: 'New title for the work item',
|
|
689
|
+
},
|
|
632
690
|
status: {
|
|
633
691
|
type: 'string',
|
|
634
692
|
enum: [
|
|
@@ -642,84 +700,35 @@ class WolfpackMCPServer {
|
|
|
642
700
|
'closed',
|
|
643
701
|
'archived',
|
|
644
702
|
],
|
|
645
|
-
description: 'New status
|
|
646
|
-
},
|
|
647
|
-
project_slug: {
|
|
648
|
-
type: 'string',
|
|
649
|
-
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
650
|
-
},
|
|
651
|
-
},
|
|
652
|
-
required: ['work_item_id', 'status'],
|
|
653
|
-
},
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
name: 'update_work_item_assignee',
|
|
657
|
-
description: 'Change the assignee (leading user) on a work item. ' +
|
|
658
|
-
'Use this to assign work to yourself or another project member, or to unassign by passing null. ' +
|
|
659
|
-
'Not applicable for personal projects (single user).',
|
|
660
|
-
inputSchema: {
|
|
661
|
-
type: 'object',
|
|
662
|
-
properties: {
|
|
663
|
-
work_item_id: {
|
|
664
|
-
type: 'string',
|
|
665
|
-
description: 'The ID of the work item',
|
|
703
|
+
description: 'New status',
|
|
666
704
|
},
|
|
667
705
|
leading_user_id: {
|
|
668
706
|
type: ['string', 'null'],
|
|
669
707
|
description: 'User ID to assign as leading user, or null to unassign',
|
|
670
708
|
},
|
|
671
|
-
|
|
672
|
-
type: 'string',
|
|
673
|
-
description: '
|
|
674
|
-
},
|
|
675
|
-
},
|
|
676
|
-
required: ['work_item_id', 'leading_user_id'],
|
|
677
|
-
},
|
|
678
|
-
},
|
|
679
|
-
{
|
|
680
|
-
name: 'update_work_item_title',
|
|
681
|
-
description: 'Change the title of a work item. ' +
|
|
682
|
-
'Use this to rename or update the title of an existing work item.',
|
|
683
|
-
inputSchema: {
|
|
684
|
-
type: 'object',
|
|
685
|
-
properties: {
|
|
686
|
-
work_item_id: {
|
|
687
|
-
type: 'string',
|
|
688
|
-
description: 'The ID of the work item',
|
|
689
|
-
},
|
|
690
|
-
title: {
|
|
691
|
-
type: 'string',
|
|
692
|
-
description: 'New title for the work item',
|
|
709
|
+
radar_item_id: {
|
|
710
|
+
type: ['string', 'null'],
|
|
711
|
+
description: 'Radar/initiative item ID to link to, or null to unlink',
|
|
693
712
|
},
|
|
694
|
-
|
|
695
|
-
type: 'string',
|
|
696
|
-
description: '
|
|
713
|
+
category_id: {
|
|
714
|
+
type: ['string', 'null'],
|
|
715
|
+
description: 'Category ID to set, or null to remove the category',
|
|
697
716
|
},
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
},
|
|
702
|
-
{
|
|
703
|
-
name: 'update_work_item_initiative',
|
|
704
|
-
description: 'Link or unlink a work item to/from a radar item (initiative). ' +
|
|
705
|
-
'Pass a radar_item_id to link, or null to remove the initiative link.',
|
|
706
|
-
inputSchema: {
|
|
707
|
-
type: 'object',
|
|
708
|
-
properties: {
|
|
709
|
-
work_item_id: {
|
|
710
|
-
type: 'string',
|
|
711
|
-
description: 'The ID of the work item',
|
|
717
|
+
priority: {
|
|
718
|
+
type: 'number',
|
|
719
|
+
description: 'Priority level: 0 (None), 1 (Low), 2 (Medium), 3 (High), 4 (Urgent)',
|
|
712
720
|
},
|
|
713
|
-
|
|
721
|
+
size: {
|
|
714
722
|
type: ['string', 'null'],
|
|
715
|
-
|
|
723
|
+
enum: ['S', 'M', 'L', null],
|
|
724
|
+
description: 'Size estimate: "S" (small), "M" (medium), "L" (large), or null to remove',
|
|
716
725
|
},
|
|
717
726
|
project_slug: {
|
|
718
727
|
type: 'string',
|
|
719
728
|
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
720
729
|
},
|
|
721
730
|
},
|
|
722
|
-
required: ['work_item_id'
|
|
731
|
+
required: ['work_item_id'],
|
|
723
732
|
},
|
|
724
733
|
},
|
|
725
734
|
{
|
|
@@ -817,6 +826,58 @@ class WolfpackMCPServer {
|
|
|
817
826
|
required: ['item_id'],
|
|
818
827
|
},
|
|
819
828
|
},
|
|
829
|
+
{
|
|
830
|
+
name: 'create_radar_item',
|
|
831
|
+
description: 'Create a new radar/initiative item in your current project. Requires mcp:radar:create permission. ' +
|
|
832
|
+
CONTENT_LINKING_HELP,
|
|
833
|
+
inputSchema: {
|
|
834
|
+
type: 'object',
|
|
835
|
+
properties: {
|
|
836
|
+
project_slug: {
|
|
837
|
+
type: 'string',
|
|
838
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
839
|
+
},
|
|
840
|
+
title: { type: 'string', description: 'Title of the radar/initiative item' },
|
|
841
|
+
description: {
|
|
842
|
+
type: 'string',
|
|
843
|
+
description: 'Description of the initiative (markdown)',
|
|
844
|
+
},
|
|
845
|
+
stage: {
|
|
846
|
+
type: 'string',
|
|
847
|
+
enum: ['pending', 'now', 'next', 'later', 'completed'],
|
|
848
|
+
description: 'Stage: "pending" (not started), "now" (current sprint), "next" (upcoming), "later" (future), "completed"',
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
required: ['title', 'stage'],
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
name: 'update_radar_item',
|
|
856
|
+
description: 'Update an existing radar/initiative item. Requires mcp:radar:update permission. ' +
|
|
857
|
+
CONTENT_LINKING_HELP,
|
|
858
|
+
inputSchema: {
|
|
859
|
+
type: 'object',
|
|
860
|
+
properties: {
|
|
861
|
+
item_id: {
|
|
862
|
+
type: 'string',
|
|
863
|
+
description: 'The refId (number) of the radar item to update',
|
|
864
|
+
},
|
|
865
|
+
title: { type: 'string', description: 'Updated title' },
|
|
866
|
+
description: { type: 'string', description: 'Updated description (markdown)' },
|
|
867
|
+
notes: { type: 'string', description: 'Updated internal notes (markdown)' },
|
|
868
|
+
stage: {
|
|
869
|
+
type: 'string',
|
|
870
|
+
enum: ['pending', 'now', 'next', 'later', 'completed'],
|
|
871
|
+
description: 'Updated stage',
|
|
872
|
+
},
|
|
873
|
+
project_slug: {
|
|
874
|
+
type: 'string',
|
|
875
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
876
|
+
},
|
|
877
|
+
},
|
|
878
|
+
required: ['item_id'],
|
|
879
|
+
},
|
|
880
|
+
},
|
|
820
881
|
// Issue tools
|
|
821
882
|
{
|
|
822
883
|
name: 'list_issues',
|
|
@@ -1009,11 +1070,22 @@ class WolfpackMCPServer {
|
|
|
1009
1070
|
enum: ['low', 'medium', 'high', 'critical'],
|
|
1010
1071
|
description: 'Updated severity',
|
|
1011
1072
|
},
|
|
1073
|
+
type: {
|
|
1074
|
+
type: 'string',
|
|
1075
|
+
enum: ['bug', 'feature-request', 'task', 'improvement', 'question'],
|
|
1076
|
+
description: 'Updated type',
|
|
1077
|
+
},
|
|
1012
1078
|
assigned_to_id: { type: 'string', description: 'Updated assignee' },
|
|
1013
1079
|
closing_note: {
|
|
1014
1080
|
type: 'string',
|
|
1015
1081
|
description: 'Closing note (when closing the issue)',
|
|
1016
1082
|
},
|
|
1083
|
+
environment: { type: 'string', description: 'Environment where the issue occurred' },
|
|
1084
|
+
affected_version: { type: 'string', description: 'Affected version' },
|
|
1085
|
+
reproducible: { type: 'boolean', description: 'Whether reproducible' },
|
|
1086
|
+
steps_to_reproduce: { type: 'string', description: 'Steps to reproduce' },
|
|
1087
|
+
expected_behavior: { type: 'string', description: 'Expected behavior' },
|
|
1088
|
+
actual_behavior: { type: 'string', description: 'Actual behavior' },
|
|
1017
1089
|
project_slug: {
|
|
1018
1090
|
type: 'string',
|
|
1019
1091
|
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
@@ -1273,6 +1345,40 @@ class WolfpackMCPServer {
|
|
|
1273
1345
|
required: ['issue_id', 'content'],
|
|
1274
1346
|
},
|
|
1275
1347
|
},
|
|
1348
|
+
{
|
|
1349
|
+
name: 'delete_work_item_comment',
|
|
1350
|
+
description: 'Delete a comment from a work item. Only the comment author can delete their own comments. ' +
|
|
1351
|
+
'Requires mcp:comments:delete permission. Use list_work_item_comments to get comment IDs.',
|
|
1352
|
+
inputSchema: {
|
|
1353
|
+
type: 'object',
|
|
1354
|
+
properties: {
|
|
1355
|
+
work_item_id: { type: 'string', description: 'The work item refId (number)' },
|
|
1356
|
+
comment_id: { type: 'string', description: 'The comment ID to delete' },
|
|
1357
|
+
project_slug: {
|
|
1358
|
+
type: 'string',
|
|
1359
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1360
|
+
},
|
|
1361
|
+
},
|
|
1362
|
+
required: ['work_item_id', 'comment_id'],
|
|
1363
|
+
},
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
name: 'delete_issue_comment',
|
|
1367
|
+
description: 'Delete a comment from an issue. Only the comment author can delete their own comments. ' +
|
|
1368
|
+
'Requires mcp:comments:delete permission. Use list_issue_comments to get comment IDs.',
|
|
1369
|
+
inputSchema: {
|
|
1370
|
+
type: 'object',
|
|
1371
|
+
properties: {
|
|
1372
|
+
issue_id: { type: 'string', description: 'The issue refId (number)' },
|
|
1373
|
+
comment_id: { type: 'string', description: 'The comment ID to delete' },
|
|
1374
|
+
project_slug: {
|
|
1375
|
+
type: 'string',
|
|
1376
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
required: ['issue_id', 'comment_id'],
|
|
1380
|
+
},
|
|
1381
|
+
},
|
|
1276
1382
|
// Image tools
|
|
1277
1383
|
{
|
|
1278
1384
|
name: 'upload_image',
|
|
@@ -1302,6 +1408,7 @@ class WolfpackMCPServer {
|
|
|
1302
1408
|
name: 'download_image',
|
|
1303
1409
|
description: 'Download and view an image referenced in content fields. ' +
|
|
1304
1410
|
'Content from work items, issues, wiki pages, journal entries, and comments may contain image references like ``. ' +
|
|
1411
|
+
'Issues may also have attachment images with URLs like `/api/teams/{team}/issues/{refId}/attachments/{id}`. ' +
|
|
1305
1412
|
'Use this tool with that URL path to download and view the image. ' +
|
|
1306
1413
|
'Requires mcp:images:read permission.',
|
|
1307
1414
|
inputSchema: {
|
|
@@ -1309,12 +1416,42 @@ class WolfpackMCPServer {
|
|
|
1309
1416
|
properties: {
|
|
1310
1417
|
image_url: {
|
|
1311
1418
|
type: 'string',
|
|
1312
|
-
description: 'The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").',
|
|
1419
|
+
description: 'The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}" or "/api/teams/{team}/issues/{refId}/attachments/{id}").',
|
|
1313
1420
|
},
|
|
1314
1421
|
},
|
|
1315
1422
|
required: ['image_url'],
|
|
1316
1423
|
},
|
|
1317
1424
|
},
|
|
1425
|
+
// Category tools
|
|
1426
|
+
{
|
|
1427
|
+
name: 'list_categories',
|
|
1428
|
+
description: 'List all categories available in a project. Returns category IDs, names, and descriptions. ' +
|
|
1429
|
+
'Use this to look up category IDs by name when creating or updating work items.',
|
|
1430
|
+
inputSchema: {
|
|
1431
|
+
type: 'object',
|
|
1432
|
+
properties: {
|
|
1433
|
+
project_slug: {
|
|
1434
|
+
type: 'string',
|
|
1435
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1436
|
+
},
|
|
1437
|
+
},
|
|
1438
|
+
},
|
|
1439
|
+
},
|
|
1440
|
+
// Team member tools
|
|
1441
|
+
{
|
|
1442
|
+
name: 'list_team_members',
|
|
1443
|
+
description: 'List all members in a project/team. Returns user IDs, names, usernames, roles, and whether the member is an agent. ' +
|
|
1444
|
+
'Use this to look up user IDs when assigning work items or issues.',
|
|
1445
|
+
inputSchema: {
|
|
1446
|
+
type: 'object',
|
|
1447
|
+
properties: {
|
|
1448
|
+
project_slug: {
|
|
1449
|
+
type: 'string',
|
|
1450
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1451
|
+
},
|
|
1452
|
+
},
|
|
1453
|
+
},
|
|
1454
|
+
},
|
|
1318
1455
|
// Skill tools (progressive disclosure)
|
|
1319
1456
|
{
|
|
1320
1457
|
name: 'list_skills',
|
|
@@ -1450,78 +1587,61 @@ class WolfpackMCPServer {
|
|
|
1450
1587
|
content: [{ type: 'text', text: 'Work item not found or not assigned to you' }],
|
|
1451
1588
|
};
|
|
1452
1589
|
}
|
|
1453
|
-
case '
|
|
1454
|
-
const parsed =
|
|
1455
|
-
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
1456
|
-
const workItem = await this.client.updateWorkItemStatus(parsed.work_item_id, parsed.status, teamSlug);
|
|
1457
|
-
if (workItem) {
|
|
1458
|
-
return {
|
|
1459
|
-
content: [
|
|
1460
|
-
{
|
|
1461
|
-
type: 'text',
|
|
1462
|
-
text: `Updated status of "${workItem.title}" to ${parsed.status}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
|
|
1463
|
-
},
|
|
1464
|
-
],
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
return {
|
|
1468
|
-
content: [{ type: 'text', text: 'Work item not found or not assigned to you' }],
|
|
1469
|
-
};
|
|
1470
|
-
}
|
|
1471
|
-
case 'update_work_item_assignee': {
|
|
1472
|
-
const parsed = UpdateWorkItemAssigneeSchema.parse(args);
|
|
1473
|
-
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
1474
|
-
const workItem = await this.client.updateWorkItemAssignee(parsed.work_item_id, {
|
|
1475
|
-
leadingUserId: parsed.leading_user_id,
|
|
1476
|
-
}, teamSlug);
|
|
1477
|
-
if (workItem) {
|
|
1478
|
-
const assigneeText = parsed.leading_user_id
|
|
1479
|
-
? `assigned to ${parsed.leading_user_id}`
|
|
1480
|
-
: 'unassigned';
|
|
1481
|
-
return {
|
|
1482
|
-
content: [
|
|
1483
|
-
{
|
|
1484
|
-
type: 'text',
|
|
1485
|
-
text: `Updated "${workItem.title}" - now ${assigneeText}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
|
|
1486
|
-
},
|
|
1487
|
-
],
|
|
1488
|
-
};
|
|
1489
|
-
}
|
|
1490
|
-
return {
|
|
1491
|
-
content: [{ type: 'text', text: 'Work item not found' }],
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
case 'update_work_item_title': {
|
|
1495
|
-
const parsed = UpdateWorkItemTitleSchema.parse(args);
|
|
1496
|
-
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
1497
|
-
const workItem = await this.client.updateWorkItemTitle(parsed.work_item_id, parsed.title, teamSlug);
|
|
1498
|
-
if (workItem) {
|
|
1499
|
-
return {
|
|
1500
|
-
content: [
|
|
1501
|
-
{
|
|
1502
|
-
type: 'text',
|
|
1503
|
-
text: `Updated title to "${workItem.title}"\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
|
|
1504
|
-
},
|
|
1505
|
-
],
|
|
1506
|
-
};
|
|
1507
|
-
}
|
|
1508
|
-
return {
|
|
1509
|
-
content: [{ type: 'text', text: 'Work item not found' }],
|
|
1510
|
-
};
|
|
1511
|
-
}
|
|
1512
|
-
case 'update_work_item_initiative': {
|
|
1513
|
-
const parsed = UpdateWorkItemInitiativeSchema.parse(args);
|
|
1590
|
+
case 'update_work_item': {
|
|
1591
|
+
const parsed = UpdateWorkItemSchema.parse(args);
|
|
1514
1592
|
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
1515
|
-
|
|
1593
|
+
// Build the fields object with only provided values
|
|
1594
|
+
const fields = {};
|
|
1595
|
+
if (parsed.title !== undefined)
|
|
1596
|
+
fields.title = parsed.title;
|
|
1597
|
+
if (parsed.status !== undefined)
|
|
1598
|
+
fields.status = parsed.status;
|
|
1599
|
+
if (parsed.leading_user_id !== undefined)
|
|
1600
|
+
fields.leadingUserId = parsed.leading_user_id;
|
|
1601
|
+
if (parsed.radar_item_id !== undefined)
|
|
1602
|
+
fields.radarItemId = parsed.radar_item_id;
|
|
1603
|
+
if (parsed.category_id !== undefined)
|
|
1604
|
+
fields.categoryId = parsed.category_id;
|
|
1605
|
+
if (parsed.priority !== undefined)
|
|
1606
|
+
fields.priority = parsed.priority;
|
|
1607
|
+
if (parsed.size !== undefined)
|
|
1608
|
+
fields.size = parsed.size;
|
|
1609
|
+
const workItem = await this.client.updateWorkItem(parsed.work_item_id, fields, teamSlug);
|
|
1516
1610
|
if (workItem) {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1611
|
+
// Build a summary of what changed
|
|
1612
|
+
const changes = [];
|
|
1613
|
+
if (parsed.status !== undefined)
|
|
1614
|
+
changes.push(`status → ${parsed.status}`);
|
|
1615
|
+
if (parsed.title !== undefined)
|
|
1616
|
+
changes.push(`title → "${parsed.title}"`);
|
|
1617
|
+
if (parsed.leading_user_id !== undefined)
|
|
1618
|
+
changes.push(parsed.leading_user_id
|
|
1619
|
+
? `assigned to ${workItem.leadingUser?.name || parsed.leading_user_id}`
|
|
1620
|
+
: 'unassigned');
|
|
1621
|
+
if (parsed.radar_item_id !== undefined)
|
|
1622
|
+
changes.push(parsed.radar_item_id ? `linked to initiative` : 'unlinked from initiative');
|
|
1623
|
+
if (parsed.category_id !== undefined)
|
|
1624
|
+
changes.push(parsed.category_id
|
|
1625
|
+
? `category → ${workItem.category?.name || parsed.category_id}`
|
|
1626
|
+
: 'category removed');
|
|
1627
|
+
if (parsed.priority !== undefined) {
|
|
1628
|
+
const labels = {
|
|
1629
|
+
0: 'None',
|
|
1630
|
+
1: 'Low',
|
|
1631
|
+
2: 'Medium',
|
|
1632
|
+
3: 'High',
|
|
1633
|
+
4: 'Urgent',
|
|
1634
|
+
};
|
|
1635
|
+
changes.push(`priority → ${labels[parsed.priority] || parsed.priority}`);
|
|
1636
|
+
}
|
|
1637
|
+
if (parsed.size !== undefined)
|
|
1638
|
+
changes.push(parsed.size ? `size → ${parsed.size}` : 'size removed');
|
|
1639
|
+
const summary = changes.length > 0 ? changes.join(', ') : 'no changes';
|
|
1520
1640
|
return {
|
|
1521
1641
|
content: [
|
|
1522
1642
|
{
|
|
1523
1643
|
type: 'text',
|
|
1524
|
-
text: `Updated "${workItem.title}"
|
|
1644
|
+
text: `Updated "${workItem.title}" (${summary})\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
|
|
1525
1645
|
},
|
|
1526
1646
|
],
|
|
1527
1647
|
};
|
|
@@ -1598,6 +1718,41 @@ class WolfpackMCPServer {
|
|
|
1598
1718
|
content: [{ type: 'text', text: 'Radar item not found' }],
|
|
1599
1719
|
};
|
|
1600
1720
|
}
|
|
1721
|
+
case 'create_radar_item': {
|
|
1722
|
+
const parsed = CreateRadarItemSchema.parse(args);
|
|
1723
|
+
const radarItem = await this.client.createRadarItem({
|
|
1724
|
+
title: parsed.title,
|
|
1725
|
+
description: parsed.description,
|
|
1726
|
+
stage: parsed.stage,
|
|
1727
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1728
|
+
});
|
|
1729
|
+
return {
|
|
1730
|
+
content: [
|
|
1731
|
+
{
|
|
1732
|
+
type: 'text',
|
|
1733
|
+
text: `Created radar item #${radarItem.refId}: ${radarItem.title}\n\n${JSON.stringify(stripUuids(radarItem), null, 2)}`,
|
|
1734
|
+
},
|
|
1735
|
+
],
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
case 'update_radar_item': {
|
|
1739
|
+
const parsed = UpdateRadarItemSchema.parse(args);
|
|
1740
|
+
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
1741
|
+
const radarItem = await this.client.updateRadarItem(parsed.item_id, {
|
|
1742
|
+
title: parsed.title,
|
|
1743
|
+
description: parsed.description,
|
|
1744
|
+
notes: parsed.notes,
|
|
1745
|
+
stage: parsed.stage,
|
|
1746
|
+
}, teamSlug);
|
|
1747
|
+
return {
|
|
1748
|
+
content: [
|
|
1749
|
+
{
|
|
1750
|
+
type: 'text',
|
|
1751
|
+
text: `Updated radar item #${radarItem.refId}: ${radarItem.title}\n\n${JSON.stringify(stripUuids(radarItem), null, 2)}`,
|
|
1752
|
+
},
|
|
1753
|
+
],
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1601
1756
|
// Issue handlers
|
|
1602
1757
|
case 'list_issues': {
|
|
1603
1758
|
const parsed = ListIssuesSchema.parse(args);
|
|
@@ -1691,8 +1846,15 @@ class WolfpackMCPServer {
|
|
|
1691
1846
|
description: parsed.description,
|
|
1692
1847
|
status: parsed.status,
|
|
1693
1848
|
severity: parsed.severity,
|
|
1849
|
+
type: parsed.type,
|
|
1694
1850
|
assignedToId: parsed.assigned_to_id,
|
|
1695
1851
|
closingNote: parsed.closing_note,
|
|
1852
|
+
environment: parsed.environment,
|
|
1853
|
+
affectedVersion: parsed.affected_version,
|
|
1854
|
+
reproducible: parsed.reproducible,
|
|
1855
|
+
stepsToReproduce: parsed.steps_to_reproduce,
|
|
1856
|
+
expectedBehavior: parsed.expected_behavior,
|
|
1857
|
+
actualBehavior: parsed.actual_behavior,
|
|
1696
1858
|
}, teamSlug);
|
|
1697
1859
|
return {
|
|
1698
1860
|
content: [
|
|
@@ -1877,6 +2039,32 @@ class WolfpackMCPServer {
|
|
|
1877
2039
|
],
|
|
1878
2040
|
};
|
|
1879
2041
|
}
|
|
2042
|
+
case 'delete_work_item_comment': {
|
|
2043
|
+
const parsed = DeleteWorkItemCommentSchema.parse(args);
|
|
2044
|
+
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
2045
|
+
await this.client.deleteWorkItemComment(parsed.work_item_id, parsed.comment_id, teamSlug);
|
|
2046
|
+
return {
|
|
2047
|
+
content: [
|
|
2048
|
+
{
|
|
2049
|
+
type: 'text',
|
|
2050
|
+
text: 'Comment deleted successfully',
|
|
2051
|
+
},
|
|
2052
|
+
],
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
case 'delete_issue_comment': {
|
|
2056
|
+
const parsed = DeleteIssueCommentSchema.parse(args);
|
|
2057
|
+
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
2058
|
+
await this.client.deleteIssueComment(parsed.issue_id, parsed.comment_id, teamSlug);
|
|
2059
|
+
return {
|
|
2060
|
+
content: [
|
|
2061
|
+
{
|
|
2062
|
+
type: 'text',
|
|
2063
|
+
text: 'Comment deleted successfully',
|
|
2064
|
+
},
|
|
2065
|
+
],
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
1880
2068
|
case 'upload_image': {
|
|
1881
2069
|
const parsed = UploadImageSchema.parse(args);
|
|
1882
2070
|
const teamSlug = await this.client.resolveSlug(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
@@ -1918,12 +2106,23 @@ class WolfpackMCPServer {
|
|
|
1918
2106
|
}
|
|
1919
2107
|
case 'download_image': {
|
|
1920
2108
|
const parsed = DownloadImageSchema.parse(args);
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2109
|
+
// Try S3-stored image pattern: /api/files/images/{team}/{filename}
|
|
2110
|
+
const s3Match = parsed.image_url.match(/\/api\/files\/images\/([^/]+)\/(.+)$/);
|
|
2111
|
+
// Try issue attachment pattern: /api/teams/{team}/issues/{refId}/attachments/{id}
|
|
2112
|
+
const attachmentMatch = parsed.image_url.match(/\/api\/teams\/([^/]+)\/issues\/(\d+)\/attachments\/([^/]+)$/);
|
|
2113
|
+
let base64;
|
|
2114
|
+
let mimeType;
|
|
2115
|
+
if (s3Match) {
|
|
2116
|
+
const [, team, filename] = s3Match;
|
|
2117
|
+
({ base64, mimeType } = await this.client.downloadImage(team, filename));
|
|
2118
|
+
}
|
|
2119
|
+
else if (attachmentMatch) {
|
|
2120
|
+
const [, team, refId, attachmentId] = attachmentMatch;
|
|
2121
|
+
({ base64, mimeType } = await this.client.downloadIssueAttachment(team, refId, attachmentId));
|
|
2122
|
+
}
|
|
2123
|
+
else {
|
|
2124
|
+
throw new Error('Invalid image URL. Expected format: /api/files/images/{team}/{filename} or /api/teams/{team}/issues/{refId}/attachments/{id}');
|
|
1924
2125
|
}
|
|
1925
|
-
const [, team, filename] = match;
|
|
1926
|
-
const { base64, mimeType } = await this.client.downloadImage(team, filename);
|
|
1927
2126
|
return {
|
|
1928
2127
|
content: [
|
|
1929
2128
|
{
|
|
@@ -1934,6 +2133,22 @@ class WolfpackMCPServer {
|
|
|
1934
2133
|
],
|
|
1935
2134
|
};
|
|
1936
2135
|
}
|
|
2136
|
+
// Category handlers
|
|
2137
|
+
case 'list_categories': {
|
|
2138
|
+
const parsed = ListCategoriesSchema.parse(args);
|
|
2139
|
+
const categories = await this.client.listCategories(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
2140
|
+
return {
|
|
2141
|
+
content: [{ type: 'text', text: JSON.stringify(categories, null, 2) }],
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
// Team member handlers
|
|
2145
|
+
case 'list_team_members': {
|
|
2146
|
+
const parsed = ListTeamMembersSchema.parse(args);
|
|
2147
|
+
const members = await this.client.listTeamMembers(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
2148
|
+
return {
|
|
2149
|
+
content: [{ type: 'text', text: JSON.stringify(members, null, 2) }],
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
1937
2152
|
// Skill handlers
|
|
1938
2153
|
case 'list_skills': {
|
|
1939
2154
|
const skills = await this.client.listSkills();
|