wolfpack-mcp 1.0.31 → 1.0.33
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 +45 -41
- package/dist/index.js +127 -83
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -5,42 +5,38 @@ const MAX_ITEMS_THRESHOLD = 200;
|
|
|
5
5
|
const PAGE_SIZE = 50;
|
|
6
6
|
export class WolfpackClient {
|
|
7
7
|
api;
|
|
8
|
-
|
|
8
|
+
projectSlug = null;
|
|
9
9
|
constructor() {
|
|
10
10
|
this.api = new ApiClient();
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Fetch and cache the project
|
|
14
|
-
* Uses the MCP team endpoint to
|
|
13
|
+
* Fetch and cache the project slug by verifying it exists.
|
|
14
|
+
* Uses the MCP team endpoint to validate the slug.
|
|
15
15
|
*/
|
|
16
16
|
async resolveProjectSlug(projectSlug) {
|
|
17
17
|
try {
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
return
|
|
18
|
+
await this.api.get(`/team/${projectSlug}`);
|
|
19
|
+
this.projectSlug = projectSlug;
|
|
20
|
+
return projectSlug;
|
|
21
21
|
}
|
|
22
22
|
catch (error) {
|
|
23
23
|
throw new Error(`Failed to resolve project slug "${projectSlug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
return this.
|
|
26
|
+
getProjectSlug() {
|
|
27
|
+
return this.projectSlug;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
this.
|
|
29
|
+
setProjectSlug(slug) {
|
|
30
|
+
this.projectSlug = slug;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Resolve a project slug from
|
|
33
|
+
* Resolve a project slug from the provided slug or the cached project slug.
|
|
34
34
|
*/
|
|
35
|
-
async resolveSlug(
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
35
|
+
async resolveSlug(teamSlug) {
|
|
36
|
+
const slug = teamSlug || this.projectSlug;
|
|
37
|
+
if (!slug)
|
|
38
38
|
throw new Error('No project selected. Use list_projects first.');
|
|
39
|
-
|
|
40
|
-
const project = projects.find((t) => t.id === id);
|
|
41
|
-
if (!project)
|
|
42
|
-
throw new Error(`Project with ID ${id} not found`);
|
|
43
|
-
return project.slug;
|
|
39
|
+
return slug;
|
|
44
40
|
}
|
|
45
41
|
/**
|
|
46
42
|
* List all projects the authenticated user is a member of.
|
|
@@ -98,8 +94,8 @@ export class WolfpackClient {
|
|
|
98
94
|
// Work Item methods
|
|
99
95
|
async listWorkItems(options) {
|
|
100
96
|
const params = new URLSearchParams();
|
|
101
|
-
if (options?.
|
|
102
|
-
params.append('
|
|
97
|
+
if (options?.teamSlug)
|
|
98
|
+
params.append('teamSlug', options.teamSlug);
|
|
103
99
|
if (options?.status)
|
|
104
100
|
params.append('status', options.status);
|
|
105
101
|
if (options?.assignedToId)
|
|
@@ -145,11 +141,11 @@ export class WolfpackClient {
|
|
|
145
141
|
// Otherwise, fetch all pages automatically
|
|
146
142
|
return this.fetchAllPages('/work-items', params);
|
|
147
143
|
}
|
|
148
|
-
async getWorkItem(workItemId,
|
|
144
|
+
async getWorkItem(workItemId, teamSlug) {
|
|
149
145
|
try {
|
|
150
146
|
const params = new URLSearchParams();
|
|
151
|
-
if (
|
|
152
|
-
params.append('
|
|
147
|
+
if (teamSlug)
|
|
148
|
+
params.append('teamSlug', teamSlug);
|
|
153
149
|
const query = params.toString();
|
|
154
150
|
return await this.api.get(`/work-items/${workItemId}${query ? `?${query}` : ''}`);
|
|
155
151
|
}
|
|
@@ -209,8 +205,8 @@ export class WolfpackClient {
|
|
|
209
205
|
// Radar Item (Initiative/Roadmap) methods
|
|
210
206
|
async listRadarItems(options) {
|
|
211
207
|
const params = new URLSearchParams();
|
|
212
|
-
if (options?.
|
|
213
|
-
params.append('
|
|
208
|
+
if (options?.teamSlug)
|
|
209
|
+
params.append('teamSlug', options.teamSlug);
|
|
214
210
|
if (options?.stage)
|
|
215
211
|
params.append('stage', options.stage);
|
|
216
212
|
if (options?.search)
|
|
@@ -235,11 +231,11 @@ export class WolfpackClient {
|
|
|
235
231
|
}
|
|
236
232
|
return this.fetchAllPages('/radar-items', params);
|
|
237
233
|
}
|
|
238
|
-
async getRadarItem(itemId,
|
|
234
|
+
async getRadarItem(itemId, teamSlug) {
|
|
239
235
|
try {
|
|
240
236
|
const params = new URLSearchParams();
|
|
241
|
-
if (
|
|
242
|
-
params.append('
|
|
237
|
+
if (teamSlug)
|
|
238
|
+
params.append('teamSlug', teamSlug);
|
|
243
239
|
const query = params.toString();
|
|
244
240
|
return await this.api.get(`/radar-items/${itemId}${query ? `?${query}` : ''}`);
|
|
245
241
|
}
|
|
@@ -253,8 +249,8 @@ export class WolfpackClient {
|
|
|
253
249
|
// Issue methods
|
|
254
250
|
async listIssues(options) {
|
|
255
251
|
const params = new URLSearchParams();
|
|
256
|
-
if (options?.
|
|
257
|
-
params.append('
|
|
252
|
+
if (options?.teamSlug)
|
|
253
|
+
params.append('teamSlug', options.teamSlug);
|
|
258
254
|
if (options?.status)
|
|
259
255
|
params.append('status', options.status);
|
|
260
256
|
if (options?.severity)
|
|
@@ -293,11 +289,11 @@ export class WolfpackClient {
|
|
|
293
289
|
}
|
|
294
290
|
return this.fetchAllPages('/issues', params);
|
|
295
291
|
}
|
|
296
|
-
async getIssue(issueId,
|
|
292
|
+
async getIssue(issueId, teamSlug) {
|
|
297
293
|
try {
|
|
298
294
|
const params = new URLSearchParams();
|
|
299
|
-
if (
|
|
300
|
-
params.append('
|
|
295
|
+
if (teamSlug)
|
|
296
|
+
params.append('teamSlug', teamSlug);
|
|
301
297
|
const query = params.toString();
|
|
302
298
|
return await this.api.get(`/issues/${issueId}${query ? `?${query}` : ''}`);
|
|
303
299
|
}
|
|
@@ -310,10 +306,12 @@ export class WolfpackClient {
|
|
|
310
306
|
}
|
|
311
307
|
// Create methods
|
|
312
308
|
async createWorkItem(data) {
|
|
313
|
-
|
|
309
|
+
const { teamSlug, ...rest } = data;
|
|
310
|
+
return this.api.post('/work-items', { ...rest, teamSlug });
|
|
314
311
|
}
|
|
315
312
|
async createIssue(data) {
|
|
316
|
-
|
|
313
|
+
const { teamSlug, ...rest } = data;
|
|
314
|
+
return this.api.post('/issues', { ...rest, teamSlug });
|
|
317
315
|
}
|
|
318
316
|
async updateIssue(issueId, data) {
|
|
319
317
|
return this.api.patch(`/issues/${issueId}`, data);
|
|
@@ -321,6 +319,8 @@ export class WolfpackClient {
|
|
|
321
319
|
// Wiki Page methods
|
|
322
320
|
async listWikiPages(options) {
|
|
323
321
|
const params = new URLSearchParams();
|
|
322
|
+
if (options?.teamSlug)
|
|
323
|
+
params.append('teamSlug', options.teamSlug);
|
|
324
324
|
if (options?.search)
|
|
325
325
|
params.append('search', options.search);
|
|
326
326
|
if (options?.dateFrom)
|
|
@@ -359,7 +359,8 @@ export class WolfpackClient {
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
async createWikiPage(data) {
|
|
362
|
-
|
|
362
|
+
const { teamSlug, ...rest } = data;
|
|
363
|
+
return this.api.post('/wiki-pages', { ...rest, teamSlug });
|
|
363
364
|
}
|
|
364
365
|
async updateWikiPage(pageId, data) {
|
|
365
366
|
return this.api.patch(`/wiki-pages/${pageId}`, data);
|
|
@@ -367,6 +368,8 @@ export class WolfpackClient {
|
|
|
367
368
|
// Journal Entry methods
|
|
368
369
|
async listJournalEntries(options) {
|
|
369
370
|
const params = new URLSearchParams();
|
|
371
|
+
if (options?.teamSlug)
|
|
372
|
+
params.append('teamSlug', options.teamSlug);
|
|
370
373
|
if (options?.search)
|
|
371
374
|
params.append('search', options.search);
|
|
372
375
|
if (options?.dateFrom)
|
|
@@ -389,11 +392,11 @@ export class WolfpackClient {
|
|
|
389
392
|
}
|
|
390
393
|
return this.fetchAllPages('/journal-entries', params);
|
|
391
394
|
}
|
|
392
|
-
async getJournalEntry(entryId,
|
|
395
|
+
async getJournalEntry(entryId, teamSlug) {
|
|
393
396
|
try {
|
|
394
397
|
const params = new URLSearchParams();
|
|
395
|
-
if (
|
|
396
|
-
params.append('
|
|
398
|
+
if (teamSlug)
|
|
399
|
+
params.append('teamSlug', teamSlug);
|
|
397
400
|
const query = params.toString();
|
|
398
401
|
return await this.api.get(`/journal-entries/${entryId}${query ? `?${query}` : ''}`);
|
|
399
402
|
}
|
|
@@ -405,7 +408,8 @@ export class WolfpackClient {
|
|
|
405
408
|
}
|
|
406
409
|
}
|
|
407
410
|
async createJournalEntry(data) {
|
|
408
|
-
|
|
411
|
+
const { teamSlug, ...rest } = data;
|
|
412
|
+
return this.api.post('/journal-entries', { ...rest, teamSlug });
|
|
409
413
|
}
|
|
410
414
|
async updateJournalEntry(entryId, data) {
|
|
411
415
|
return this.api.patch(`/journal-entries/${entryId}`, data);
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ async function checkForUpdates() {
|
|
|
46
46
|
// Work Item schemas
|
|
47
47
|
// Use z.coerce.string() to handle any type coercion issues from MCP args
|
|
48
48
|
const ListWorkItemsSchema = z.object({
|
|
49
|
-
|
|
49
|
+
project_slug: z.string().optional().describe('Project slug to filter work items'),
|
|
50
50
|
status: z.coerce
|
|
51
51
|
.string()
|
|
52
52
|
.optional()
|
|
@@ -85,15 +85,24 @@ const ListWorkItemsSchema = z.object({
|
|
|
85
85
|
});
|
|
86
86
|
const GetWorkItemSchema = z.object({
|
|
87
87
|
work_item_id: z.string().describe('The ID (UUID) or refId (number) of the work item'),
|
|
88
|
-
|
|
88
|
+
project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
|
|
89
89
|
});
|
|
90
90
|
const UpdateWorkProgressSchema = z.object({
|
|
91
91
|
work_item_id: z.string().describe('The ID of the work item'),
|
|
92
92
|
description: z.string().describe('Updated description/notes for the work item'),
|
|
93
93
|
});
|
|
94
|
+
const VALID_STATUSES = [
|
|
95
|
+
'pending',
|
|
96
|
+
'new',
|
|
97
|
+
'doing',
|
|
98
|
+
'blocked',
|
|
99
|
+
'review',
|
|
100
|
+
'ready',
|
|
101
|
+
'completed',
|
|
102
|
+
];
|
|
94
103
|
const UpdateWorkItemStatusSchema = z.object({
|
|
95
104
|
work_item_id: z.string().describe('The ID of the work item'),
|
|
96
|
-
status: z.
|
|
105
|
+
status: z.enum(VALID_STATUSES).describe('New status'),
|
|
97
106
|
});
|
|
98
107
|
const UpdateWorkItemAssigneeSchema = z.object({
|
|
99
108
|
work_item_id: z.string().describe('The ID of the work item'),
|
|
@@ -111,7 +120,7 @@ const PullWorkItemSchema = z.object({
|
|
|
111
120
|
});
|
|
112
121
|
// Radar Item (Initiative/Roadmap) schemas
|
|
113
122
|
const ListRadarItemsSchema = z.object({
|
|
114
|
-
|
|
123
|
+
project_slug: z.string().optional().describe('Project slug to filter radar items'),
|
|
115
124
|
stage: z
|
|
116
125
|
.enum(['pending', 'now', 'next', 'later', 'completed'])
|
|
117
126
|
.optional()
|
|
@@ -122,11 +131,11 @@ const ListRadarItemsSchema = z.object({
|
|
|
122
131
|
});
|
|
123
132
|
const GetRadarItemSchema = z.object({
|
|
124
133
|
item_id: z.string().describe('The ID (UUID) or refId (number) of the radar item'),
|
|
125
|
-
|
|
134
|
+
project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
|
|
126
135
|
});
|
|
127
136
|
// Issue schemas
|
|
128
137
|
const ListIssuesSchema = z.object({
|
|
129
|
-
|
|
138
|
+
project_slug: z.string().optional().describe('Project slug to filter issues'),
|
|
130
139
|
status: z
|
|
131
140
|
.enum(['open', 'in-progress', 'resolved', 'closed'])
|
|
132
141
|
.optional()
|
|
@@ -159,17 +168,18 @@ const ListIssuesSchema = z.object({
|
|
|
159
168
|
});
|
|
160
169
|
const GetIssueSchema = z.object({
|
|
161
170
|
issue_id: z.string().describe('The ID (UUID) or refId (number) of the issue'),
|
|
162
|
-
|
|
171
|
+
project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
|
|
163
172
|
});
|
|
164
173
|
// Create schemas
|
|
165
174
|
const CreateWorkItemSchema = z.object({
|
|
166
|
-
|
|
167
|
-
description: z
|
|
175
|
+
project_slug: z
|
|
168
176
|
.string()
|
|
169
177
|
.optional()
|
|
170
|
-
.describe('
|
|
178
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
179
|
+
title: z.string().describe('Title of the work item'),
|
|
180
|
+
description: z.string().optional().describe('Description/notes for the work item (markdown)'),
|
|
171
181
|
status: z
|
|
172
|
-
.
|
|
182
|
+
.enum(VALID_STATUSES)
|
|
173
183
|
.optional()
|
|
174
184
|
.describe('Initial status: "pending" (backlog), "new" (to do), "doing", "review", "ready", "blocked", "completed". Defaults to "new".'),
|
|
175
185
|
priority: z.number().optional().describe('Priority level (0-4, higher is more important)'),
|
|
@@ -178,6 +188,10 @@ const CreateWorkItemSchema = z.object({
|
|
|
178
188
|
radar_item_id: z.string().optional().describe('Radar/initiative item ID to link to'),
|
|
179
189
|
});
|
|
180
190
|
const CreateIssueSchema = z.object({
|
|
191
|
+
project_slug: z
|
|
192
|
+
.string()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
181
195
|
title: z.string().describe('Title of the issue'),
|
|
182
196
|
description: z.string().optional().describe('Description of the issue'),
|
|
183
197
|
severity: z.enum(['low', 'medium', 'high', 'critical']).optional().describe('Severity level'),
|
|
@@ -207,6 +221,7 @@ const UpdateIssueSchema = z.object({
|
|
|
207
221
|
});
|
|
208
222
|
// Wiki Page schemas
|
|
209
223
|
const ListWikiPagesSchema = z.object({
|
|
224
|
+
project_slug: z.string().optional().describe('Project slug to filter wiki pages'),
|
|
210
225
|
search: z.coerce.string().optional().describe('Text search in title and content'),
|
|
211
226
|
date_from: z.coerce
|
|
212
227
|
.string()
|
|
@@ -223,6 +238,10 @@ const GetWikiPageSchema = z.object({
|
|
|
223
238
|
page_id: z.string().describe('The page UUID or slug'),
|
|
224
239
|
});
|
|
225
240
|
const CreateWikiPageSchema = z.object({
|
|
241
|
+
project_slug: z
|
|
242
|
+
.string()
|
|
243
|
+
.optional()
|
|
244
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
226
245
|
slug: z
|
|
227
246
|
.string()
|
|
228
247
|
.describe('URL slug for the page (without team prefix). The system automatically prepends the team and wiki path. For example, to create a page at "myteam/wiki/guides/onboarding", pass just "guides/onboarding". Do NOT include the team slug or "wiki/" prefix.')
|
|
@@ -232,20 +251,16 @@ const CreateWikiPageSchema = z.object({
|
|
|
232
251
|
return slug.replace(wikiPrefix, '');
|
|
233
252
|
}),
|
|
234
253
|
title: z.string().describe('Page title'),
|
|
235
|
-
content: z
|
|
236
|
-
.string()
|
|
237
|
-
.describe('Page content (markdown). Supports base64-encoded images (e.g., ) which will be auto-uploaded.'),
|
|
254
|
+
content: z.string().describe('Page content (markdown)'),
|
|
238
255
|
});
|
|
239
256
|
const UpdateWikiPageSchema = z.object({
|
|
240
257
|
page_id: z.string().describe('The page UUID'),
|
|
241
258
|
title: z.string().optional().describe('Updated title'),
|
|
242
|
-
content: z
|
|
243
|
-
.string()
|
|
244
|
-
.optional()
|
|
245
|
-
.describe('Updated content (markdown). Supports base64-encoded images which will be auto-uploaded.'),
|
|
259
|
+
content: z.string().optional().describe('Updated content (markdown)'),
|
|
246
260
|
});
|
|
247
261
|
// Journal Entry schemas
|
|
248
262
|
const ListJournalEntriesSchema = z.object({
|
|
263
|
+
project_slug: z.string().optional().describe('Project slug to filter journal entries'),
|
|
249
264
|
search: z.coerce.string().optional().describe('Text search in title and content'),
|
|
250
265
|
date_from: z.coerce
|
|
251
266
|
.string()
|
|
@@ -260,22 +275,21 @@ const ListJournalEntriesSchema = z.object({
|
|
|
260
275
|
});
|
|
261
276
|
const GetJournalEntrySchema = z.object({
|
|
262
277
|
entry_id: z.string().describe('The entry UUID or refId'),
|
|
263
|
-
|
|
278
|
+
project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
|
|
264
279
|
});
|
|
265
280
|
const CreateJournalEntrySchema = z.object({
|
|
266
|
-
|
|
267
|
-
content: z
|
|
281
|
+
project_slug: z
|
|
268
282
|
.string()
|
|
269
|
-
.
|
|
283
|
+
.optional()
|
|
284
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
285
|
+
title: z.string().describe('Entry title'),
|
|
286
|
+
content: z.string().describe('Entry content (markdown)'),
|
|
270
287
|
date: z.string().optional().describe('Entry date (ISO format, defaults to now)'),
|
|
271
288
|
});
|
|
272
289
|
const UpdateJournalEntrySchema = z.object({
|
|
273
290
|
entry_id: z.string().describe('The entry UUID'),
|
|
274
291
|
title: z.string().optional().describe('Updated title'),
|
|
275
|
-
content: z
|
|
276
|
-
.string()
|
|
277
|
-
.optional()
|
|
278
|
-
.describe('Updated content (markdown). Supports base64-encoded images which will be auto-uploaded.'),
|
|
292
|
+
content: z.string().optional().describe('Updated content (markdown)'),
|
|
279
293
|
});
|
|
280
294
|
// Comment schemas
|
|
281
295
|
const ListWorkItemCommentsSchema = z.object({
|
|
@@ -286,15 +300,11 @@ const ListIssueCommentsSchema = z.object({
|
|
|
286
300
|
});
|
|
287
301
|
const CreateWorkItemCommentSchema = z.object({
|
|
288
302
|
work_item_id: z.string().describe('The work item UUID'),
|
|
289
|
-
content: z
|
|
290
|
-
.string()
|
|
291
|
-
.describe('Comment content (markdown). Supports base64-encoded images which will be auto-uploaded.'),
|
|
303
|
+
content: z.string().describe('Comment content (markdown)'),
|
|
292
304
|
});
|
|
293
305
|
const CreateIssueCommentSchema = z.object({
|
|
294
306
|
issue_id: z.string().describe('The issue UUID'),
|
|
295
|
-
content: z
|
|
296
|
-
.string()
|
|
297
|
-
.describe('Comment content (markdown). Supports base64-encoded images which will be auto-uploaded.'),
|
|
307
|
+
content: z.string().describe('Comment content (markdown)'),
|
|
298
308
|
});
|
|
299
309
|
// Image upload schema
|
|
300
310
|
const UploadImageSchema = z.object({
|
|
@@ -302,10 +312,10 @@ const UploadImageSchema = z.object({
|
|
|
302
312
|
.string()
|
|
303
313
|
.describe('Absolute path to an image file on disk (e.g., "/tmp/screenshot.png"). ' +
|
|
304
314
|
'Supported formats: JPEG, PNG, GIF, WebP. Max 5MB.'),
|
|
305
|
-
|
|
306
|
-
.
|
|
315
|
+
project_slug: z
|
|
316
|
+
.string()
|
|
307
317
|
.optional()
|
|
308
|
-
.describe('Project
|
|
318
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
309
319
|
});
|
|
310
320
|
const DownloadImageSchema = z.object({
|
|
311
321
|
image_url: z
|
|
@@ -353,7 +363,7 @@ class WolfpackMCPServer {
|
|
|
353
363
|
'3) NEVER perform bulk actions across multiple projects - always work in one project at a time. ' +
|
|
354
364
|
'4) If the user mentions a specific project, use that for all subsequent operations. ' +
|
|
355
365
|
'5) If unclear which project to use, ASK the user before proceeding. ' +
|
|
356
|
-
'Returns project
|
|
366
|
+
'Returns project slugs, names, and types. Single-project users have their project auto-selected; multi-project users must specify project_slug in other tool calls.',
|
|
357
367
|
inputSchema: {
|
|
358
368
|
type: 'object',
|
|
359
369
|
properties: {},
|
|
@@ -374,9 +384,9 @@ class WolfpackMCPServer {
|
|
|
374
384
|
inputSchema: {
|
|
375
385
|
type: 'object',
|
|
376
386
|
properties: {
|
|
377
|
-
|
|
378
|
-
type: '
|
|
379
|
-
description: 'Project
|
|
387
|
+
project_slug: {
|
|
388
|
+
type: 'string',
|
|
389
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
380
390
|
},
|
|
381
391
|
status: {
|
|
382
392
|
type: 'string',
|
|
@@ -440,9 +450,9 @@ class WolfpackMCPServer {
|
|
|
440
450
|
type: 'string',
|
|
441
451
|
description: 'The ID (UUID) or refId (number) of the work item',
|
|
442
452
|
},
|
|
443
|
-
|
|
444
|
-
type: '
|
|
445
|
-
description: 'Project
|
|
453
|
+
project_slug: {
|
|
454
|
+
type: 'string',
|
|
455
|
+
description: 'Project slug (required when looking up by refId)',
|
|
446
456
|
},
|
|
447
457
|
},
|
|
448
458
|
required: ['work_item_id'],
|
|
@@ -485,6 +495,7 @@ class WolfpackMCPServer {
|
|
|
485
495
|
},
|
|
486
496
|
status: {
|
|
487
497
|
type: 'string',
|
|
498
|
+
enum: ['pending', 'new', 'doing', 'blocked', 'review', 'ready', 'completed'],
|
|
488
499
|
description: 'New status: "pending" (backlog), "new" (to do), "doing" (in progress), "review" (work done), "ready" (awaiting deployment), "blocked", "completed" (deployed)',
|
|
489
500
|
},
|
|
490
501
|
},
|
|
@@ -541,9 +552,9 @@ class WolfpackMCPServer {
|
|
|
541
552
|
inputSchema: {
|
|
542
553
|
type: 'object',
|
|
543
554
|
properties: {
|
|
544
|
-
|
|
545
|
-
type: '
|
|
546
|
-
description: 'Project
|
|
555
|
+
project_slug: {
|
|
556
|
+
type: 'string',
|
|
557
|
+
description: 'Project slug (use list_projects to get slugs)',
|
|
547
558
|
},
|
|
548
559
|
stage: {
|
|
549
560
|
type: 'string',
|
|
@@ -570,9 +581,9 @@ class WolfpackMCPServer {
|
|
|
570
581
|
type: 'string',
|
|
571
582
|
description: 'The ID (UUID) or refId (number) of the radar item',
|
|
572
583
|
},
|
|
573
|
-
|
|
574
|
-
type: '
|
|
575
|
-
description: 'Project
|
|
584
|
+
project_slug: {
|
|
585
|
+
type: 'string',
|
|
586
|
+
description: 'Project slug (required when looking up by refId)',
|
|
576
587
|
},
|
|
577
588
|
},
|
|
578
589
|
required: ['item_id'],
|
|
@@ -589,9 +600,9 @@ class WolfpackMCPServer {
|
|
|
589
600
|
inputSchema: {
|
|
590
601
|
type: 'object',
|
|
591
602
|
properties: {
|
|
592
|
-
|
|
593
|
-
type: '
|
|
594
|
-
description: 'Project
|
|
603
|
+
project_slug: {
|
|
604
|
+
type: 'string',
|
|
605
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
595
606
|
},
|
|
596
607
|
status: {
|
|
597
608
|
type: 'string',
|
|
@@ -648,9 +659,9 @@ class WolfpackMCPServer {
|
|
|
648
659
|
type: 'string',
|
|
649
660
|
description: 'The ID (UUID) or refId (number) of the issue',
|
|
650
661
|
},
|
|
651
|
-
|
|
652
|
-
type: '
|
|
653
|
-
description: 'Project
|
|
662
|
+
project_slug: {
|
|
663
|
+
type: 'string',
|
|
664
|
+
description: 'Project slug (required when looking up by refId)',
|
|
654
665
|
},
|
|
655
666
|
},
|
|
656
667
|
required: ['issue_id'],
|
|
@@ -663,13 +674,18 @@ class WolfpackMCPServer {
|
|
|
663
674
|
inputSchema: {
|
|
664
675
|
type: 'object',
|
|
665
676
|
properties: {
|
|
677
|
+
project_slug: {
|
|
678
|
+
type: 'string',
|
|
679
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
680
|
+
},
|
|
666
681
|
title: { type: 'string', description: 'Title of the work item' },
|
|
667
682
|
description: {
|
|
668
683
|
type: 'string',
|
|
669
|
-
description: 'Description/notes for the work item (markdown)
|
|
684
|
+
description: 'Description/notes for the work item (markdown)',
|
|
670
685
|
},
|
|
671
686
|
status: {
|
|
672
687
|
type: 'string',
|
|
688
|
+
enum: ['pending', 'new', 'doing', 'blocked', 'review', 'ready', 'completed'],
|
|
673
689
|
description: 'Initial status: "pending" (backlog), "new" (to do), "doing", "review", "ready", "blocked", "completed". Defaults to "new".',
|
|
674
690
|
},
|
|
675
691
|
priority: {
|
|
@@ -698,6 +714,10 @@ class WolfpackMCPServer {
|
|
|
698
714
|
inputSchema: {
|
|
699
715
|
type: 'object',
|
|
700
716
|
properties: {
|
|
717
|
+
project_slug: {
|
|
718
|
+
type: 'string',
|
|
719
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
720
|
+
},
|
|
701
721
|
title: { type: 'string', description: 'Title of the issue' },
|
|
702
722
|
description: { type: 'string', description: 'Description of the issue' },
|
|
703
723
|
severity: {
|
|
@@ -756,6 +776,10 @@ class WolfpackMCPServer {
|
|
|
756
776
|
inputSchema: {
|
|
757
777
|
type: 'object',
|
|
758
778
|
properties: {
|
|
779
|
+
project_slug: {
|
|
780
|
+
type: 'string',
|
|
781
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
782
|
+
},
|
|
759
783
|
search: {
|
|
760
784
|
type: 'string',
|
|
761
785
|
description: 'Text search in title and content',
|
|
@@ -794,6 +818,10 @@ class WolfpackMCPServer {
|
|
|
794
818
|
inputSchema: {
|
|
795
819
|
type: 'object',
|
|
796
820
|
properties: {
|
|
821
|
+
project_slug: {
|
|
822
|
+
type: 'string',
|
|
823
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
824
|
+
},
|
|
797
825
|
slug: {
|
|
798
826
|
type: 'string',
|
|
799
827
|
description: 'URL slug for the page (without team prefix). The system automatically prepends the team and wiki path. For example, to create a page at "myteam/wiki/guides/onboarding", pass just "guides/onboarding". Do NOT include the team slug or "wiki/" prefix.',
|
|
@@ -801,7 +829,7 @@ class WolfpackMCPServer {
|
|
|
801
829
|
title: { type: 'string', description: 'Page title' },
|
|
802
830
|
content: {
|
|
803
831
|
type: 'string',
|
|
804
|
-
description: 'Page content (markdown)
|
|
832
|
+
description: 'Page content (markdown)',
|
|
805
833
|
},
|
|
806
834
|
},
|
|
807
835
|
required: ['slug', 'title', 'content'],
|
|
@@ -817,7 +845,7 @@ class WolfpackMCPServer {
|
|
|
817
845
|
title: { type: 'string', description: 'Updated title' },
|
|
818
846
|
content: {
|
|
819
847
|
type: 'string',
|
|
820
|
-
description: 'Updated content (markdown)
|
|
848
|
+
description: 'Updated content (markdown)',
|
|
821
849
|
},
|
|
822
850
|
},
|
|
823
851
|
required: ['page_id'],
|
|
@@ -830,6 +858,10 @@ class WolfpackMCPServer {
|
|
|
830
858
|
inputSchema: {
|
|
831
859
|
type: 'object',
|
|
832
860
|
properties: {
|
|
861
|
+
project_slug: {
|
|
862
|
+
type: 'string',
|
|
863
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
864
|
+
},
|
|
833
865
|
search: {
|
|
834
866
|
type: 'string',
|
|
835
867
|
description: 'Text search in title and content',
|
|
@@ -855,9 +887,9 @@ class WolfpackMCPServer {
|
|
|
855
887
|
type: 'object',
|
|
856
888
|
properties: {
|
|
857
889
|
entry_id: { type: 'string', description: 'The entry UUID or refId' },
|
|
858
|
-
|
|
859
|
-
type: '
|
|
860
|
-
description: 'Project
|
|
890
|
+
project_slug: {
|
|
891
|
+
type: 'string',
|
|
892
|
+
description: 'Project slug (required when looking up by refId)',
|
|
861
893
|
},
|
|
862
894
|
},
|
|
863
895
|
required: ['entry_id'],
|
|
@@ -869,10 +901,14 @@ class WolfpackMCPServer {
|
|
|
869
901
|
inputSchema: {
|
|
870
902
|
type: 'object',
|
|
871
903
|
properties: {
|
|
904
|
+
project_slug: {
|
|
905
|
+
type: 'string',
|
|
906
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
907
|
+
},
|
|
872
908
|
title: { type: 'string', description: 'Entry title' },
|
|
873
909
|
content: {
|
|
874
910
|
type: 'string',
|
|
875
|
-
description: 'Entry content (markdown)
|
|
911
|
+
description: 'Entry content (markdown)',
|
|
876
912
|
},
|
|
877
913
|
date: { type: 'string', description: 'Entry date (ISO format, defaults to now)' },
|
|
878
914
|
},
|
|
@@ -889,7 +925,7 @@ class WolfpackMCPServer {
|
|
|
889
925
|
title: { type: 'string', description: 'Updated title' },
|
|
890
926
|
content: {
|
|
891
927
|
type: 'string',
|
|
892
|
-
description: 'Updated content (markdown)
|
|
928
|
+
description: 'Updated content (markdown)',
|
|
893
929
|
},
|
|
894
930
|
},
|
|
895
931
|
required: ['entry_id'],
|
|
@@ -934,7 +970,7 @@ class WolfpackMCPServer {
|
|
|
934
970
|
work_item_id: { type: 'string', description: 'The work item UUID' },
|
|
935
971
|
content: {
|
|
936
972
|
type: 'string',
|
|
937
|
-
description: 'Comment content (markdown)
|
|
973
|
+
description: 'Comment content (markdown)',
|
|
938
974
|
},
|
|
939
975
|
},
|
|
940
976
|
required: ['work_item_id', 'content'],
|
|
@@ -949,7 +985,7 @@ class WolfpackMCPServer {
|
|
|
949
985
|
issue_id: { type: 'string', description: 'The issue UUID' },
|
|
950
986
|
content: {
|
|
951
987
|
type: 'string',
|
|
952
|
-
description: 'Comment content (markdown)
|
|
988
|
+
description: 'Comment content (markdown)',
|
|
953
989
|
},
|
|
954
990
|
},
|
|
955
991
|
required: ['issue_id', 'content'],
|
|
@@ -959,8 +995,10 @@ class WolfpackMCPServer {
|
|
|
959
995
|
{
|
|
960
996
|
name: 'upload_image',
|
|
961
997
|
description: 'Upload an image file from disk and get back a permanent URL. ' +
|
|
962
|
-
'Reads the file directly from disk
|
|
998
|
+
'Reads the file directly from disk. ' +
|
|
963
999
|
'Returns a markdown image URL you can include in any content field. ' +
|
|
1000
|
+
'IMPORTANT: This tool requires direct filesystem access and may not work in sandboxed environments (e.g. Claude.ai, Claude Desktop). ' +
|
|
1001
|
+
'If the MCP server cannot access the file path, inform the user that image uploads are not supported in their environment. ' +
|
|
964
1002
|
'Requires mcp:images:upload permission.',
|
|
965
1003
|
inputSchema: {
|
|
966
1004
|
type: 'object',
|
|
@@ -970,9 +1008,9 @@ class WolfpackMCPServer {
|
|
|
970
1008
|
description: 'Absolute path to an image file on disk (e.g., "/tmp/screenshot.png"). ' +
|
|
971
1009
|
'Supported formats: JPEG, PNG, GIF, WebP. Max 5MB.',
|
|
972
1010
|
},
|
|
973
|
-
|
|
974
|
-
type: '
|
|
975
|
-
description: 'Project
|
|
1011
|
+
project_slug: {
|
|
1012
|
+
type: 'string',
|
|
1013
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
976
1014
|
},
|
|
977
1015
|
},
|
|
978
1016
|
required: ['file_path'],
|
|
@@ -1004,17 +1042,17 @@ class WolfpackMCPServer {
|
|
|
1004
1042
|
// Project handlers
|
|
1005
1043
|
case 'list_projects': {
|
|
1006
1044
|
const teams = await this.client.listProjects();
|
|
1007
|
-
const
|
|
1045
|
+
const currentProjectSlug = this.client.getProjectSlug();
|
|
1008
1046
|
return {
|
|
1009
1047
|
content: [
|
|
1010
1048
|
{
|
|
1011
1049
|
type: 'text',
|
|
1012
1050
|
text: JSON.stringify({
|
|
1013
1051
|
projects: teams,
|
|
1014
|
-
|
|
1052
|
+
currentProjectSlug,
|
|
1015
1053
|
hint: teams.length === 1
|
|
1016
1054
|
? 'Only one project available - it will be used automatically.'
|
|
1017
|
-
: 'Multiple projects available. Use
|
|
1055
|
+
: 'Multiple projects available. Use project_slug parameter in other tools to specify which project to use.',
|
|
1018
1056
|
}, null, 2),
|
|
1019
1057
|
},
|
|
1020
1058
|
],
|
|
@@ -1024,7 +1062,7 @@ class WolfpackMCPServer {
|
|
|
1024
1062
|
case 'list_work_items': {
|
|
1025
1063
|
const parsed = ListWorkItemsSchema.parse(args);
|
|
1026
1064
|
const result = await this.client.listWorkItems({
|
|
1027
|
-
|
|
1065
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1028
1066
|
status: parsed.status,
|
|
1029
1067
|
assignedToId: parsed.assigned_to_id,
|
|
1030
1068
|
search: parsed.search,
|
|
@@ -1050,7 +1088,7 @@ class WolfpackMCPServer {
|
|
|
1050
1088
|
}
|
|
1051
1089
|
case 'get_work_item': {
|
|
1052
1090
|
const parsed = GetWorkItemSchema.parse(args);
|
|
1053
|
-
const workItem = await this.client.getWorkItem(parsed.work_item_id, parsed.
|
|
1091
|
+
const workItem = await this.client.getWorkItem(parsed.work_item_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
1054
1092
|
if (workItem) {
|
|
1055
1093
|
let text = JSON.stringify(workItem, null, 2);
|
|
1056
1094
|
// Add hint if no plan detected in description
|
|
@@ -1146,7 +1184,7 @@ class WolfpackMCPServer {
|
|
|
1146
1184
|
case 'list_radar_items': {
|
|
1147
1185
|
const parsed = ListRadarItemsSchema.parse(args);
|
|
1148
1186
|
const result = await this.client.listRadarItems({
|
|
1149
|
-
|
|
1187
|
+
teamSlug: parsed.project_slug,
|
|
1150
1188
|
stage: parsed.stage,
|
|
1151
1189
|
search: parsed.search,
|
|
1152
1190
|
limit: parsed.limit,
|
|
@@ -1162,7 +1200,7 @@ class WolfpackMCPServer {
|
|
|
1162
1200
|
}
|
|
1163
1201
|
case 'get_radar_item': {
|
|
1164
1202
|
const parsed = GetRadarItemSchema.parse(args);
|
|
1165
|
-
const radarItem = await this.client.getRadarItem(parsed.item_id, parsed.
|
|
1203
|
+
const radarItem = await this.client.getRadarItem(parsed.item_id, parsed.project_slug);
|
|
1166
1204
|
if (radarItem) {
|
|
1167
1205
|
return {
|
|
1168
1206
|
content: [{ type: 'text', text: JSON.stringify(radarItem, null, 2) }],
|
|
@@ -1176,7 +1214,7 @@ class WolfpackMCPServer {
|
|
|
1176
1214
|
case 'list_issues': {
|
|
1177
1215
|
const parsed = ListIssuesSchema.parse(args);
|
|
1178
1216
|
const result = await this.client.listIssues({
|
|
1179
|
-
|
|
1217
|
+
teamSlug: parsed.project_slug,
|
|
1180
1218
|
status: parsed.status,
|
|
1181
1219
|
severity: parsed.severity,
|
|
1182
1220
|
type: parsed.type,
|
|
@@ -1199,7 +1237,7 @@ class WolfpackMCPServer {
|
|
|
1199
1237
|
}
|
|
1200
1238
|
case 'get_issue': {
|
|
1201
1239
|
const parsed = GetIssueSchema.parse(args);
|
|
1202
|
-
const issue = await this.client.getIssue(parsed.issue_id, parsed.
|
|
1240
|
+
const issue = await this.client.getIssue(parsed.issue_id, parsed.project_slug);
|
|
1203
1241
|
if (issue) {
|
|
1204
1242
|
return {
|
|
1205
1243
|
content: [{ type: 'text', text: JSON.stringify(issue, null, 2) }],
|
|
@@ -1220,6 +1258,7 @@ class WolfpackMCPServer {
|
|
|
1220
1258
|
leadingUserId: parsed.leading_user_id,
|
|
1221
1259
|
categoryId: parsed.category_id,
|
|
1222
1260
|
radarItemId: parsed.radar_item_id,
|
|
1261
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1223
1262
|
});
|
|
1224
1263
|
return {
|
|
1225
1264
|
content: [
|
|
@@ -1244,6 +1283,7 @@ class WolfpackMCPServer {
|
|
|
1244
1283
|
stepsToReproduce: parsed.steps_to_reproduce,
|
|
1245
1284
|
expectedBehavior: parsed.expected_behavior,
|
|
1246
1285
|
actualBehavior: parsed.actual_behavior,
|
|
1286
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1247
1287
|
});
|
|
1248
1288
|
return {
|
|
1249
1289
|
content: [
|
|
@@ -1277,6 +1317,7 @@ class WolfpackMCPServer {
|
|
|
1277
1317
|
case 'list_wiki_pages': {
|
|
1278
1318
|
const parsed = ListWikiPagesSchema.parse(args);
|
|
1279
1319
|
const result = await this.client.listWikiPages({
|
|
1320
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1280
1321
|
search: parsed.search,
|
|
1281
1322
|
dateFrom: parsed.date_from,
|
|
1282
1323
|
dateTo: parsed.date_to,
|
|
@@ -1309,6 +1350,7 @@ class WolfpackMCPServer {
|
|
|
1309
1350
|
slug: parsed.slug,
|
|
1310
1351
|
title: parsed.title,
|
|
1311
1352
|
content: parsed.content,
|
|
1353
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1312
1354
|
});
|
|
1313
1355
|
return {
|
|
1314
1356
|
content: [
|
|
@@ -1338,6 +1380,7 @@ class WolfpackMCPServer {
|
|
|
1338
1380
|
case 'list_journal_entries': {
|
|
1339
1381
|
const parsed = ListJournalEntriesSchema.parse(args);
|
|
1340
1382
|
const result = await this.client.listJournalEntries({
|
|
1383
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1341
1384
|
search: parsed.search,
|
|
1342
1385
|
dateFrom: parsed.date_from,
|
|
1343
1386
|
dateTo: parsed.date_to,
|
|
@@ -1354,7 +1397,7 @@ class WolfpackMCPServer {
|
|
|
1354
1397
|
}
|
|
1355
1398
|
case 'get_journal_entry': {
|
|
1356
1399
|
const parsed = GetJournalEntrySchema.parse(args);
|
|
1357
|
-
const entry = await this.client.getJournalEntry(parsed.entry_id, parsed.
|
|
1400
|
+
const entry = await this.client.getJournalEntry(parsed.entry_id, parsed.project_slug);
|
|
1358
1401
|
if (entry) {
|
|
1359
1402
|
return {
|
|
1360
1403
|
content: [{ type: 'text', text: JSON.stringify(entry, null, 2) }],
|
|
@@ -1370,6 +1413,7 @@ class WolfpackMCPServer {
|
|
|
1370
1413
|
title: parsed.title,
|
|
1371
1414
|
content: parsed.content,
|
|
1372
1415
|
date: parsed.date,
|
|
1416
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
1373
1417
|
});
|
|
1374
1418
|
return {
|
|
1375
1419
|
content: [
|
|
@@ -1440,7 +1484,7 @@ class WolfpackMCPServer {
|
|
|
1440
1484
|
}
|
|
1441
1485
|
case 'upload_image': {
|
|
1442
1486
|
const parsed = UploadImageSchema.parse(args);
|
|
1443
|
-
const teamSlug = await this.client.resolveSlug(parsed.
|
|
1487
|
+
const teamSlug = await this.client.resolveSlug(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
1444
1488
|
const filePath = resolve(parsed.file_path);
|
|
1445
1489
|
// Validate file extension
|
|
1446
1490
|
const ext = extname(filePath).toLowerCase();
|
|
@@ -1540,8 +1584,8 @@ class WolfpackMCPServer {
|
|
|
1540
1584
|
if (config.projectSlug) {
|
|
1541
1585
|
// Explicit project slug configured - use it
|
|
1542
1586
|
try {
|
|
1543
|
-
|
|
1544
|
-
console.error(`Resolved project "${config.projectSlug}"
|
|
1587
|
+
await this.client.resolveProjectSlug(config.projectSlug);
|
|
1588
|
+
console.error(`Resolved project: "${config.projectSlug}"`);
|
|
1545
1589
|
}
|
|
1546
1590
|
catch (error) {
|
|
1547
1591
|
console.error(`Failed to resolve project slug: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1554,14 +1598,14 @@ class WolfpackMCPServer {
|
|
|
1554
1598
|
const teams = await this.client.listProjects();
|
|
1555
1599
|
if (teams.length === 1) {
|
|
1556
1600
|
// Auto-select the only project
|
|
1557
|
-
this.client.
|
|
1601
|
+
this.client.setProjectSlug(teams[0].slug);
|
|
1558
1602
|
console.error(`Auto-selected project: ${teams[0].name} (${teams[0].slug})`);
|
|
1559
1603
|
}
|
|
1560
1604
|
else if (teams.length === 0) {
|
|
1561
1605
|
console.error('Warning: No projects found for this API key');
|
|
1562
1606
|
}
|
|
1563
1607
|
else {
|
|
1564
|
-
console.error(`Multiple projects available (${teams.length}). Use list_projects tool to see them, then specify
|
|
1608
|
+
console.error(`Multiple projects available (${teams.length}). Use list_projects tool to see them, then specify project_slug in tool calls.`);
|
|
1565
1609
|
}
|
|
1566
1610
|
}
|
|
1567
1611
|
catch (error) {
|