wolfpack-mcp 1.0.37 → 1.0.39

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/apiClient.js CHANGED
@@ -8,6 +8,16 @@ export class ApiError extends Error {
8
8
  this.name = 'ApiError';
9
9
  }
10
10
  }
11
+ function formatError(error) {
12
+ if (error instanceof Error) {
13
+ const code = error.code;
14
+ if (code)
15
+ return `${error.message} (${code})`;
16
+ if (error.message)
17
+ return error.message;
18
+ }
19
+ return String(error) || 'unknown error';
20
+ }
11
21
  export class ApiClient {
12
22
  headers = {
13
23
  Authorization: `Bearer ${config.apiKey}`,
@@ -30,7 +40,7 @@ export class ApiClient {
30
40
  if (error instanceof ApiError) {
31
41
  throw error;
32
42
  }
33
- throw new Error(`Failed to GET ${path}: ${error}`);
43
+ throw new Error(`Failed to GET ${path}: ${formatError(error)}`);
34
44
  }
35
45
  }
36
46
  async post(path, body) {
@@ -51,7 +61,7 @@ export class ApiClient {
51
61
  if (error instanceof ApiError) {
52
62
  throw error;
53
63
  }
54
- throw new Error(`Failed to POST ${path}: ${error}`);
64
+ throw new Error(`Failed to POST ${path}: ${formatError(error)}`);
55
65
  }
56
66
  }
57
67
  async put(path, body) {
@@ -72,7 +82,7 @@ export class ApiClient {
72
82
  if (error instanceof ApiError) {
73
83
  throw error;
74
84
  }
75
- throw new Error(`Failed to PUT ${path}: ${error}`);
85
+ throw new Error(`Failed to PUT ${path}: ${formatError(error)}`);
76
86
  }
77
87
  }
78
88
  async patch(path, body) {
@@ -93,7 +103,7 @@ export class ApiClient {
93
103
  if (error instanceof ApiError) {
94
104
  throw error;
95
105
  }
96
- throw new Error(`Failed to PATCH ${path}: ${error}`);
106
+ throw new Error(`Failed to PATCH ${path}: ${formatError(error)}`);
97
107
  }
98
108
  }
99
109
  async getBuffer(path) {
@@ -119,7 +129,7 @@ export class ApiClient {
119
129
  if (error instanceof ApiError) {
120
130
  throw error;
121
131
  }
122
- throw new Error(`Failed to GET buffer ${path}: ${error}`);
132
+ throw new Error(`Failed to GET buffer ${path}: ${formatError(error)}`);
123
133
  }
124
134
  }
125
135
  async postMultipart(path, buffer, filename, mimeType) {
@@ -166,7 +176,7 @@ export class ApiClient {
166
176
  if (error instanceof ApiError) {
167
177
  throw error;
168
178
  }
169
- throw new Error(`Failed to DELETE ${path}: ${error}`);
179
+ throw new Error(`Failed to DELETE ${path}: ${formatError(error)}`);
170
180
  }
171
181
  }
172
182
  }
package/dist/client.js CHANGED
@@ -9,6 +9,14 @@ export class WolfpackClient {
9
9
  constructor() {
10
10
  this.api = new ApiClient();
11
11
  }
12
+ /** Build a URL path with optional teamSlug query parameter. */
13
+ withTeamSlug(path, teamSlug) {
14
+ const slug = teamSlug || this.projectSlug;
15
+ if (!slug)
16
+ return path;
17
+ const sep = path.includes('?') ? '&' : '?';
18
+ return `${path}${sep}teamSlug=${encodeURIComponent(slug)}`;
19
+ }
12
20
  /**
13
21
  * Fetch and cache the project slug by verifying it exists.
14
22
  * Uses the MCP team endpoint to validate the slug.
@@ -158,7 +166,7 @@ export class WolfpackClient {
158
166
  }
159
167
  async updateWorkProgress(workItemId, description) {
160
168
  try {
161
- return await this.api.put(`/work-items/${workItemId}/progress`, {
169
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/progress`), {
162
170
  description,
163
171
  });
164
172
  }
@@ -171,7 +179,9 @@ export class WolfpackClient {
171
179
  }
172
180
  async updateWorkItemStatus(workItemId, status) {
173
181
  try {
174
- return await this.api.put(`/work-items/${workItemId}/status`, { status });
182
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/status`), {
183
+ status,
184
+ });
175
185
  }
176
186
  catch (error) {
177
187
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -182,7 +192,7 @@ export class WolfpackClient {
182
192
  }
183
193
  async updateWorkItemAssignee(workItemId, data) {
184
194
  try {
185
- return await this.api.put(`/work-items/${workItemId}/assignee`, data);
195
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/assignee`), data);
186
196
  }
187
197
  catch (error) {
188
198
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -193,7 +203,20 @@ export class WolfpackClient {
193
203
  }
194
204
  async updateWorkItemTitle(workItemId, title) {
195
205
  try {
196
- return await this.api.put(`/work-items/${workItemId}/title`, { title });
206
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/title`), {
207
+ title,
208
+ });
209
+ }
210
+ catch (error) {
211
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
212
+ return null;
213
+ }
214
+ throw error;
215
+ }
216
+ }
217
+ async updateWorkItemInitiative(workItemId, radarItemId) {
218
+ try {
219
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/initiative`), { radarItemId });
197
220
  }
198
221
  catch (error) {
199
222
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -204,7 +227,20 @@ export class WolfpackClient {
204
227
  }
205
228
  async pullWorkItem(workItemId, data) {
206
229
  try {
207
- return await this.api.post(`/work-items/${workItemId}/pull`, data || {});
230
+ return await this.api.post(this.withTeamSlug(`/work-items/${workItemId}/pull`), data || {});
231
+ }
232
+ catch (error) {
233
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
234
+ return null;
235
+ }
236
+ throw error;
237
+ }
238
+ }
239
+ async submitWorkItemForm(workItemId, formValues) {
240
+ try {
241
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/form`), {
242
+ formValues,
243
+ });
208
244
  }
209
245
  catch (error) {
210
246
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -325,7 +361,7 @@ export class WolfpackClient {
325
361
  return this.api.post('/issues', { ...rest, teamSlug });
326
362
  }
327
363
  async updateIssue(issueId, data) {
328
- return this.api.patch(`/issues/${issueId}`, data);
364
+ return this.api.patch(this.withTeamSlug(`/issues/${issueId}`), data);
329
365
  }
330
366
  // Wiki Page methods
331
367
  async listWikiPages(options) {
@@ -374,7 +410,7 @@ export class WolfpackClient {
374
410
  return this.api.post('/wiki-pages', { ...rest, teamSlug });
375
411
  }
376
412
  async updateWikiPage(pageId, data) {
377
- return this.api.patch(`/wiki-pages/${pageId}`, data);
413
+ return this.api.patch(this.withTeamSlug(`/wiki-pages/${pageId}`), data);
378
414
  }
379
415
  // Journal Entry methods
380
416
  async listJournalEntries(options) {
@@ -423,20 +459,20 @@ export class WolfpackClient {
423
459
  return this.api.post('/journal-entries', { ...rest, teamSlug });
424
460
  }
425
461
  async updateJournalEntry(entryId, data) {
426
- return this.api.patch(`/journal-entries/${entryId}`, data);
462
+ return this.api.patch(this.withTeamSlug(`/journal-entries/${entryId}`), data);
427
463
  }
428
464
  // Comment methods
429
465
  async listWorkItemComments(workItemId) {
430
- return this.api.get(`/work-items/${workItemId}/comments`);
466
+ return this.api.get(this.withTeamSlug(`/work-items/${workItemId}/comments`));
431
467
  }
432
468
  async listIssueComments(issueId) {
433
- return this.api.get(`/issues/${issueId}/comments`);
469
+ return this.api.get(this.withTeamSlug(`/issues/${issueId}/comments`));
434
470
  }
435
471
  async createWorkItemComment(workItemId, data) {
436
- return this.api.post(`/work-items/${workItemId}/comments`, data);
472
+ return this.api.post(this.withTeamSlug(`/work-items/${workItemId}/comments`), data);
437
473
  }
438
474
  async createIssueComment(issueId, data) {
439
- return this.api.post(`/issues/${issueId}/comments`, data);
475
+ return this.api.post(this.withTeamSlug(`/issues/${issueId}/comments`), data);
440
476
  }
441
477
  /**
442
478
  * Upload an image and get back a URL that can be used in markdown content.
@@ -452,6 +488,32 @@ export class WolfpackClient {
452
488
  const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
453
489
  return { base64: buffer.toString('base64'), mimeType: contentType };
454
490
  }
491
+ // Skill methods (progressive disclosure)
492
+ async listSkills() {
493
+ return this.api.get('/skills');
494
+ }
495
+ async getSkill(name) {
496
+ try {
497
+ return await this.api.get(`/skills/${encodeURIComponent(name)}`);
498
+ }
499
+ catch (error) {
500
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
501
+ return null;
502
+ }
503
+ throw error;
504
+ }
505
+ }
506
+ async getSkillResource(skillName, resourceName) {
507
+ try {
508
+ return await this.api.get(`/skills/${encodeURIComponent(skillName)}/resources/${encodeURIComponent(resourceName)}`);
509
+ }
510
+ catch (error) {
511
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
512
+ return null;
513
+ }
514
+ throw error;
515
+ }
516
+ }
455
517
  close() {
456
518
  // No cleanup needed for API client
457
519
  }
package/dist/index.js CHANGED
@@ -43,6 +43,12 @@ async function checkForUpdates() {
43
43
  }
44
44
  return null;
45
45
  }
46
+ // Cross-reference syntax for linking between content items in markdown fields
47
+ const CONTENT_LINKING_HELP = 'CROSS-REFERENCES: In any markdown content, you can link to other items using these patterns: ' +
48
+ '#123 or #w123 for work items, #i123 for issues, #r123 for initiatives/roadmap, ' +
49
+ '#j123 for journal entries, #c123 for cases, #p123 for procedures. ' +
50
+ 'Use @username to mention team members (triggers notifications). ' +
51
+ 'Standard markdown links also work: [link text](/project/{slug}/work-items/123).';
46
52
  // Work Item schemas
47
53
  // Use z.coerce.string() to handle any type coercion issues from MCP args
48
54
  const ListWorkItemsSchema = z.object({
@@ -84,7 +90,7 @@ const ListWorkItemsSchema = z.object({
84
90
  offset: z.number().optional().describe('Number of items to skip'),
85
91
  });
86
92
  const GetWorkItemSchema = z.object({
87
- work_item_id: z.string().describe('The ID (UUID) or refId (number) of the work item'),
93
+ work_item_id: z.string().describe('The refId (number) of the work item'),
88
94
  project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
89
95
  });
90
96
  const UpdateWorkProgressSchema = z.object({
@@ -117,6 +123,13 @@ const UpdateWorkItemTitleSchema = z.object({
117
123
  work_item_id: z.string().describe('The ID of the work item'),
118
124
  title: z.string().describe('New title for the work item'),
119
125
  });
126
+ const UpdateWorkItemInitiativeSchema = z.object({
127
+ work_item_id: z.string().describe('The ID of the work item'),
128
+ radar_item_id: z
129
+ .string()
130
+ .nullable()
131
+ .describe('Radar/initiative item ID to link to, or null to unlink'),
132
+ });
120
133
  const PullWorkItemSchema = z.object({
121
134
  work_item_id: z.string().describe('The ID of the work item to pull from backlog'),
122
135
  leading_user_id: z
@@ -124,6 +137,10 @@ const PullWorkItemSchema = z.object({
124
137
  .optional()
125
138
  .describe('User ID to assign as leading user (defaults to API key owner)'),
126
139
  });
140
+ const SubmitWorkItemFormSchema = z.object({
141
+ work_item_id: z.string().describe('The ID of the work item'),
142
+ form_values: z.record(z.any()).describe('Key-value pairs matching formDefinition field names'),
143
+ });
127
144
  // Radar Item (Initiative/Roadmap) schemas
128
145
  const ListRadarItemsSchema = z.object({
129
146
  project_slug: z.string().optional().describe('Project slug to filter radar items'),
@@ -136,7 +153,7 @@ const ListRadarItemsSchema = z.object({
136
153
  offset: z.number().optional().describe('Number of items to skip'),
137
154
  });
138
155
  const GetRadarItemSchema = z.object({
139
- item_id: z.string().describe('The ID (UUID) or refId (number) of the radar item'),
156
+ item_id: z.string().describe('The refId (number) of the radar item'),
140
157
  project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
141
158
  });
142
159
  // Issue schemas
@@ -173,7 +190,7 @@ const ListIssuesSchema = z.object({
173
190
  offset: z.number().optional().describe('Number of items to skip'),
174
191
  });
175
192
  const GetIssueSchema = z.object({
176
- issue_id: z.string().describe('The ID (UUID) or refId (number) of the issue'),
193
+ issue_id: z.string().describe('The refId (number) of the issue'),
177
194
  project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
178
195
  });
179
196
  // Create schemas
@@ -189,6 +206,10 @@ const CreateWorkItemSchema = z.object({
189
206
  .optional()
190
207
  .describe('Initial status: "pending" (backlog), "new" (to do), "doing", "review", "ready", "blocked", "completed". Defaults to "new".'),
191
208
  priority: z.number().optional().describe('Priority level (0-4, higher is more important)'),
209
+ size: z
210
+ .enum(['S', 'M', 'L'])
211
+ .optional()
212
+ .describe('Size estimate: "S" (small), "M" (medium), "L" (large)'),
192
213
  leading_user_id: z.string().optional().describe('User ID to assign as leading user'),
193
214
  category_id: z.string().optional().describe('Category ID to organize the work item'),
194
215
  radar_item_id: z.string().optional().describe('Radar/initiative item ID to link to'),
@@ -214,7 +235,7 @@ const CreateIssueSchema = z.object({
214
235
  actual_behavior: z.string().optional().describe('Actual behavior observed'),
215
236
  });
216
237
  const UpdateIssueSchema = z.object({
217
- issue_id: z.string().describe('The ID (UUID) of the issue to update'),
238
+ issue_id: z.string().describe('The refId (number) of the issue to update'),
218
239
  title: z.string().optional().describe('Updated title'),
219
240
  description: z.string().optional().describe('Updated description'),
220
241
  status: z
@@ -241,7 +262,7 @@ const ListWikiPagesSchema = z.object({
241
262
  offset: z.number().optional().describe('Number of pages to skip'),
242
263
  });
243
264
  const GetWikiPageSchema = z.object({
244
- page_id: z.string().describe('The page UUID or slug'),
265
+ page_id: z.string().describe('The page slug'),
245
266
  });
246
267
  const CreateWikiPageSchema = z.object({
247
268
  project_slug: z
@@ -260,7 +281,7 @@ const CreateWikiPageSchema = z.object({
260
281
  content: z.string().describe('Page content (markdown)'),
261
282
  });
262
283
  const UpdateWikiPageSchema = z.object({
263
- page_id: z.string().describe('The page UUID'),
284
+ page_id: z.string().describe('The page slug'),
264
285
  title: z.string().optional().describe('Updated title'),
265
286
  content: z.string().optional().describe('Updated content (markdown)'),
266
287
  });
@@ -280,8 +301,8 @@ const ListJournalEntriesSchema = z.object({
280
301
  offset: z.number().optional().describe('Number of entries to skip'),
281
302
  });
282
303
  const GetJournalEntrySchema = z.object({
283
- entry_id: z.string().describe('The entry UUID or refId'),
284
- project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
304
+ entry_id: z.string().describe('The entry refId (number)'),
305
+ project_slug: z.string().optional().describe('Project slug (required for refId lookup)'),
285
306
  });
286
307
  const CreateJournalEntrySchema = z.object({
287
308
  project_slug: z
@@ -290,26 +311,25 @@ const CreateJournalEntrySchema = z.object({
290
311
  .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
291
312
  title: z.string().describe('Entry title'),
292
313
  content: z.string().describe('Entry content (markdown)'),
293
- date: z.string().optional().describe('Entry date (ISO format, defaults to now)'),
294
314
  });
295
315
  const UpdateJournalEntrySchema = z.object({
296
- entry_id: z.string().describe('The entry UUID'),
316
+ entry_id: z.string().describe('The entry refId (number)'),
297
317
  title: z.string().optional().describe('Updated title'),
298
318
  content: z.string().optional().describe('Updated content (markdown)'),
299
319
  });
300
320
  // Comment schemas
301
321
  const ListWorkItemCommentsSchema = z.object({
302
- work_item_id: z.string().describe('The work item UUID'),
322
+ work_item_id: z.string().describe('The work item refId (number)'),
303
323
  });
304
324
  const ListIssueCommentsSchema = z.object({
305
- issue_id: z.string().describe('The issue UUID'),
325
+ issue_id: z.string().describe('The issue refId (number)'),
306
326
  });
307
327
  const CreateWorkItemCommentSchema = z.object({
308
- work_item_id: z.string().describe('The work item UUID'),
328
+ work_item_id: z.string().describe('The work item refId (number)'),
309
329
  content: z.string().describe('Comment content (markdown)'),
310
330
  });
311
331
  const CreateIssueCommentSchema = z.object({
312
- issue_id: z.string().describe('The issue UUID'),
332
+ issue_id: z.string().describe('The issue refId (number)'),
313
333
  content: z.string().describe('Comment content (markdown)'),
314
334
  });
315
335
  // Image upload schema
@@ -328,6 +348,54 @@ const DownloadImageSchema = z.object({
328
348
  .string()
329
349
  .describe('The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").'),
330
350
  });
351
+ // Skill schemas
352
+ const GetSkillSchema = z.object({
353
+ skill_name: z.string().describe('The name of the skill to load (e.g. "deploy-app")'),
354
+ });
355
+ const GetSkillResourceSchema = z.object({
356
+ skill_name: z.string().describe('The name of the skill'),
357
+ resource_name: z.string().describe('The name of the resource file'),
358
+ });
359
+ // UUID v4 field names to remove from responses.
360
+ // These are internal database IDs that agents should not use.
361
+ // Agents should use refId (sequential int) or slug instead.
362
+ const UUID_FIELDS_TO_STRIP = new Set([
363
+ 'id', // Main entity UUID - replaced by refId or slug
364
+ 'teamId', // Internal team UUID - noise for agents
365
+ 'workItemId', // Cross-reference UUID on Issues - noise
366
+ ]);
367
+ // Fields containing user-defined data that should never be recursively processed.
368
+ const PASSTHROUGH_FIELDS = new Set(['formDefinition', 'formValues']);
369
+ // Strip UUID v4 fields from response objects so agents use refId/slug instead.
370
+ // Preserves Clerk user IDs (user_xxx format) and operational fields (categoryId, radarItemId).
371
+ function stripUuids(obj) {
372
+ if (obj === null || obj === undefined)
373
+ return obj;
374
+ if (Array.isArray(obj))
375
+ return obj.map(stripUuids);
376
+ if (typeof obj !== 'object')
377
+ return obj;
378
+ const record = obj;
379
+ const result = {};
380
+ for (const [key, value] of Object.entries(record)) {
381
+ // Skip UUID fields
382
+ if (UUID_FIELDS_TO_STRIP.has(key))
383
+ continue;
384
+ // Preserve user-defined data fields as-is (no recursive stripping)
385
+ if (PASSTHROUGH_FIELDS.has(key)) {
386
+ result[key] = value;
387
+ continue;
388
+ }
389
+ // Recurse into nested objects/arrays
390
+ if (typeof value === 'object' && value !== null) {
391
+ result[key] = stripUuids(value);
392
+ }
393
+ else {
394
+ result[key] = value;
395
+ }
396
+ }
397
+ return result;
398
+ }
331
399
  // Helper to detect if a work item description contains a plan
332
400
  function hasPlan(description) {
333
401
  if (!description)
@@ -443,22 +511,23 @@ class WolfpackMCPServer {
443
511
  },
444
512
  {
445
513
  name: 'get_work_item',
446
- description: 'Get a specific work item/task by ID or reference number. Returns full details including description (markdown notes). ' +
514
+ description: 'Get a specific work item/task by reference number. Returns full details including description (markdown notes). ' +
447
515
  'Call this before updating to see current content. ' +
448
516
  'WORKFLOW: When asked to work on an item, check its status and follow the required state transitions ' +
449
517
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
450
518
  'PLANNING: Check if the description contains a plan (markdown checklist). If not, APPEND one using update_work_progress - preserve all original description text and add your plan below a "---" separator. ' +
519
+ 'FORMS: Procedure-created work items may include formDefinition (field definitions with name, label, type, required, options) and formValues (current values). Use submit_work_item_form to fill in form values. ' +
451
520
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
452
521
  inputSchema: {
453
522
  type: 'object',
454
523
  properties: {
455
524
  work_item_id: {
456
525
  type: 'string',
457
- description: 'The ID (UUID) or refId (number) of the work item',
526
+ description: 'The refId (number) of the work item',
458
527
  },
459
528
  project_slug: {
460
529
  type: 'string',
461
- description: 'Project slug (required when looking up by refId)',
530
+ description: 'Project slug (required for refId lookup)',
462
531
  },
463
532
  },
464
533
  required: ['work_item_id'],
@@ -468,7 +537,8 @@ class WolfpackMCPServer {
468
537
  name: 'update_work_progress',
469
538
  description: 'Update work item description/notes with your progress. WORKFLOW: 1) get_work_item to read current notes 2) Modify the markdown description with new findings/progress 3) Call this with the complete updated description. The full description replaces the existing one. ' +
470
539
  'CRITICAL: NEVER overwrite or remove the original description text. Preserve all existing content exactly as-is. Append your plan below a "---" separator. You may only modify content you previously added (your plan section). ' +
471
- 'BEST PRACTICE: Append a plan with markdown checkboxes (- [ ] task). Check off completed tasks (- [x] task) as you progress. Include sections for: Plan (checklist), Approach (strategy), and Notes (discoveries/decisions).',
540
+ 'BEST PRACTICE: Append a plan with markdown checkboxes (- [ ] task). Check off completed tasks (- [x] task) as you progress. Include sections for: Plan (checklist), Approach (strategy), and Notes (discoveries/decisions). ' +
541
+ CONTENT_LINKING_HELP,
472
542
  inputSchema: {
473
543
  type: 'object',
474
544
  properties: {
@@ -557,6 +627,25 @@ class WolfpackMCPServer {
557
627
  required: ['work_item_id', 'title'],
558
628
  },
559
629
  },
630
+ {
631
+ name: 'update_work_item_initiative',
632
+ description: 'Link or unlink a work item to/from a radar item (initiative). ' +
633
+ 'Pass a radar_item_id to link, or null to remove the initiative link.',
634
+ inputSchema: {
635
+ type: 'object',
636
+ properties: {
637
+ work_item_id: {
638
+ type: 'string',
639
+ description: 'The ID of the work item',
640
+ },
641
+ radar_item_id: {
642
+ type: ['string', 'null'],
643
+ description: 'Radar/initiative item ID to link to, or null to unlink',
644
+ },
645
+ },
646
+ required: ['work_item_id', 'radar_item_id'],
647
+ },
648
+ },
560
649
  {
561
650
  name: 'pull_work_item',
562
651
  description: 'Pull a specific work item from the backlog to the board. ' +
@@ -580,6 +669,26 @@ class WolfpackMCPServer {
580
669
  required: ['work_item_id'],
581
670
  },
582
671
  },
672
+ {
673
+ name: 'submit_work_item_form',
674
+ description: 'Submit form values for a procedure-created work item. ' +
675
+ 'Use get_work_item first to see formDefinition (field names, types, required) and current formValues. ' +
676
+ 'Then call this with form_values mapping field names to values.',
677
+ inputSchema: {
678
+ type: 'object',
679
+ properties: {
680
+ work_item_id: {
681
+ type: 'string',
682
+ description: 'The ID of the work item',
683
+ },
684
+ form_values: {
685
+ type: 'object',
686
+ description: 'Key-value pairs matching formDefinition field names',
687
+ },
688
+ },
689
+ required: ['work_item_id', 'form_values'],
690
+ },
691
+ },
583
692
  // Radar Item (Initiative/Roadmap) tools
584
693
  {
585
694
  name: 'list_radar_items',
@@ -607,18 +716,18 @@ class WolfpackMCPServer {
607
716
  },
608
717
  {
609
718
  name: 'get_radar_item',
610
- description: 'Get a specific radar item (initiative) by ID or refId, including its work items and participants. ' +
719
+ description: 'Get a specific radar item (initiative) by reference number, including its work items and participants. ' +
611
720
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
612
721
  inputSchema: {
613
722
  type: 'object',
614
723
  properties: {
615
724
  item_id: {
616
725
  type: 'string',
617
- description: 'The ID (UUID) or refId (number) of the radar item',
726
+ description: 'The refId (number) of the radar item',
618
727
  },
619
728
  project_slug: {
620
729
  type: 'string',
621
- description: 'Project slug (required when looking up by refId)',
730
+ description: 'Project slug (required for refId lookup)',
622
731
  },
623
732
  },
624
733
  required: ['item_id'],
@@ -685,18 +794,18 @@ class WolfpackMCPServer {
685
794
  },
686
795
  {
687
796
  name: 'get_issue',
688
- description: 'Get a specific issue by ID or refId, including comment and attachment counts. ' +
797
+ description: 'Get a specific issue by reference number, including comment and attachment counts. ' +
689
798
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
690
799
  inputSchema: {
691
800
  type: 'object',
692
801
  properties: {
693
802
  issue_id: {
694
803
  type: 'string',
695
- description: 'The ID (UUID) or refId (number) of the issue',
804
+ description: 'The refId (number) of the issue',
696
805
  },
697
806
  project_slug: {
698
807
  type: 'string',
699
- description: 'Project slug (required when looking up by refId)',
808
+ description: 'Project slug (required for refId lookup)',
700
809
  },
701
810
  },
702
811
  required: ['issue_id'],
@@ -705,7 +814,8 @@ class WolfpackMCPServer {
705
814
  // Create/Update tools
706
815
  {
707
816
  name: 'create_work_item',
708
- description: 'Create a new work item in your current project (auto-selected for single-project users, or use list_projects first for multi-project). Requires mcp:work_items:create permission.',
817
+ description: 'Create a new work item in your current project (auto-selected for single-project users, or use list_projects first for multi-project). Requires mcp:work_items:create permission. ' +
818
+ CONTENT_LINKING_HELP,
709
819
  inputSchema: {
710
820
  type: 'object',
711
821
  properties: {
@@ -737,6 +847,11 @@ class WolfpackMCPServer {
737
847
  type: 'number',
738
848
  description: 'Priority level (0-4, higher is more important)',
739
849
  },
850
+ size: {
851
+ type: 'string',
852
+ enum: ['S', 'M', 'L'],
853
+ description: 'Size estimate: "S" (small), "M" (medium), "L" (large)',
854
+ },
740
855
  leading_user_id: {
741
856
  type: 'string',
742
857
  description: 'User ID to assign as leading user',
@@ -755,7 +870,8 @@ class WolfpackMCPServer {
755
870
  },
756
871
  {
757
872
  name: 'create_issue',
758
- description: 'Create a new issue in your current project (auto-selected for single-project users, or use list_projects first for multi-project). Requires mcp:issues:create permission.',
873
+ description: 'Create a new issue in your current project (auto-selected for single-project users, or use list_projects first for multi-project). Requires mcp:issues:create permission. ' +
874
+ CONTENT_LINKING_HELP,
759
875
  inputSchema: {
760
876
  type: 'object',
761
877
  properties: {
@@ -788,11 +904,15 @@ class WolfpackMCPServer {
788
904
  },
789
905
  {
790
906
  name: 'update_issue',
791
- description: 'Update an existing issue. Requires mcp:issues:update permission.',
907
+ description: 'Update an existing issue. Requires mcp:issues:update permission. ' +
908
+ CONTENT_LINKING_HELP,
792
909
  inputSchema: {
793
910
  type: 'object',
794
911
  properties: {
795
- issue_id: { type: 'string', description: 'The ID (UUID) of the issue to update' },
912
+ issue_id: {
913
+ type: 'string',
914
+ description: 'The refId (number) of the issue to update',
915
+ },
796
916
  title: { type: 'string', description: 'Updated title' },
797
917
  description: { type: 'string', description: 'Updated description' },
798
918
  status: {
@@ -844,14 +964,14 @@ class WolfpackMCPServer {
844
964
  },
845
965
  {
846
966
  name: 'get_wiki_page',
847
- description: 'Get a specific wiki/documentation page by ID or slug (URL path). Returns full content in markdown. ' +
967
+ description: 'Get a specific wiki/documentation page by slug (URL path). Returns full content in markdown. ' +
848
968
  'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
849
969
  inputSchema: {
850
970
  type: 'object',
851
971
  properties: {
852
972
  page_id: {
853
973
  type: 'string',
854
- description: 'The page UUID or slug (URL path like "getting-started")',
974
+ description: 'The page slug (URL path like "getting-started")',
855
975
  },
856
976
  },
857
977
  required: ['page_id'],
@@ -859,7 +979,8 @@ class WolfpackMCPServer {
859
979
  },
860
980
  {
861
981
  name: 'create_wiki_page',
862
- description: 'Create a new wiki/documentation page. Use when user wants to "add docs", "create documentation", or "write a guide".',
982
+ description: 'Create a new wiki/documentation page. Use when user wants to "add docs", "create documentation", or "write a guide". ' +
983
+ CONTENT_LINKING_HELP,
863
984
  inputSchema: {
864
985
  type: 'object',
865
986
  properties: {
@@ -882,11 +1003,12 @@ class WolfpackMCPServer {
882
1003
  },
883
1004
  {
884
1005
  name: 'update_wiki_page',
885
- description: 'Update an existing wiki page. Requires mcp:wiki:update permission.',
1006
+ description: 'Update an existing wiki page. Requires mcp:wiki:update permission. ' +
1007
+ CONTENT_LINKING_HELP,
886
1008
  inputSchema: {
887
1009
  type: 'object',
888
1010
  properties: {
889
- page_id: { type: 'string', description: 'The page UUID' },
1011
+ page_id: { type: 'string', description: 'The page slug' },
890
1012
  title: { type: 'string', description: 'Updated title' },
891
1013
  content: {
892
1014
  type: 'string',
@@ -926,15 +1048,15 @@ class WolfpackMCPServer {
926
1048
  },
927
1049
  {
928
1050
  name: 'get_journal_entry',
929
- description: 'Get a specific journal/log entry by ID or reference number. Returns full content. ' +
1051
+ description: 'Get a specific journal/log entry by reference number. Returns full content. ' +
930
1052
  'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
931
1053
  inputSchema: {
932
1054
  type: 'object',
933
1055
  properties: {
934
- entry_id: { type: 'string', description: 'The entry UUID or refId' },
1056
+ entry_id: { type: 'string', description: 'The entry refId (number)' },
935
1057
  project_slug: {
936
1058
  type: 'string',
937
- description: 'Project slug (required when looking up by refId)',
1059
+ description: 'Project slug (required for refId lookup)',
938
1060
  },
939
1061
  },
940
1062
  required: ['entry_id'],
@@ -942,7 +1064,8 @@ class WolfpackMCPServer {
942
1064
  },
943
1065
  {
944
1066
  name: 'create_journal_entry',
945
- description: 'Create a new journal entry (daily log, standup note, progress update). Use when user wants to "log progress", "write a standup", "add a journal entry", or "record what I did".',
1067
+ description: 'Create a new journal entry (daily log, standup note, progress update). Use when user wants to "log progress", "write a standup", "add a journal entry", or "record what I did". ' +
1068
+ CONTENT_LINKING_HELP,
946
1069
  inputSchema: {
947
1070
  type: 'object',
948
1071
  properties: {
@@ -955,18 +1078,18 @@ class WolfpackMCPServer {
955
1078
  type: 'string',
956
1079
  description: 'Entry content (markdown)',
957
1080
  },
958
- date: { type: 'string', description: 'Entry date (ISO format, defaults to now)' },
959
1081
  },
960
1082
  required: ['title', 'content'],
961
1083
  },
962
1084
  },
963
1085
  {
964
1086
  name: 'update_journal_entry',
965
- description: 'Update an existing journal entry. Requires mcp:journal:update permission.',
1087
+ description: 'Update an existing journal entry. Requires mcp:journal:update permission. ' +
1088
+ CONTENT_LINKING_HELP,
966
1089
  inputSchema: {
967
1090
  type: 'object',
968
1091
  properties: {
969
- entry_id: { type: 'string', description: 'The entry UUID' },
1092
+ entry_id: { type: 'string', description: 'The entry refId (number)' },
970
1093
  title: { type: 'string', description: 'Updated title' },
971
1094
  content: {
972
1095
  type: 'string',
@@ -984,7 +1107,7 @@ class WolfpackMCPServer {
984
1107
  inputSchema: {
985
1108
  type: 'object',
986
1109
  properties: {
987
- work_item_id: { type: 'string', description: 'The work item UUID' },
1110
+ work_item_id: { type: 'string', description: 'The work item refId (number)' },
988
1111
  },
989
1112
  required: ['work_item_id'],
990
1113
  },
@@ -996,7 +1119,7 @@ class WolfpackMCPServer {
996
1119
  inputSchema: {
997
1120
  type: 'object',
998
1121
  properties: {
999
- issue_id: { type: 'string', description: 'The issue UUID' },
1122
+ issue_id: { type: 'string', description: 'The issue refId (number)' },
1000
1123
  },
1001
1124
  required: ['issue_id'],
1002
1125
  },
@@ -1008,11 +1131,12 @@ class WolfpackMCPServer {
1008
1131
  '2) Completion summaries when moving to "review" (what was done, files changed, testing notes). ' +
1009
1132
  '3) Important observations or decisions that should be visible in the activity history. ' +
1010
1133
  'USE DESCRIPTION (update_work_progress) FOR: Plans, checklists, and progress tracking that need to be updated over time. ' +
1011
- 'Comments are typically not used in personal projects.',
1134
+ 'Comments are typically not used in personal projects. ' +
1135
+ CONTENT_LINKING_HELP,
1012
1136
  inputSchema: {
1013
1137
  type: 'object',
1014
1138
  properties: {
1015
- work_item_id: { type: 'string', description: 'The work item UUID' },
1139
+ work_item_id: { type: 'string', description: 'The work item refId (number)' },
1016
1140
  content: {
1017
1141
  type: 'string',
1018
1142
  description: 'Comment content (markdown)',
@@ -1023,11 +1147,12 @@ class WolfpackMCPServer {
1023
1147
  },
1024
1148
  {
1025
1149
  name: 'create_issue_comment',
1026
- description: 'Add a comment to an issue. Requires mcp:comments:create permission.',
1150
+ description: 'Add a comment to an issue. Requires mcp:comments:create permission. ' +
1151
+ CONTENT_LINKING_HELP,
1027
1152
  inputSchema: {
1028
1153
  type: 'object',
1029
1154
  properties: {
1030
- issue_id: { type: 'string', description: 'The issue UUID' },
1155
+ issue_id: { type: 'string', description: 'The issue refId (number)' },
1031
1156
  content: {
1032
1157
  type: 'string',
1033
1158
  description: 'Comment content (markdown)',
@@ -1078,6 +1203,51 @@ class WolfpackMCPServer {
1078
1203
  required: ['image_url'],
1079
1204
  },
1080
1205
  },
1206
+ // Skill tools (progressive disclosure)
1207
+ {
1208
+ name: 'list_skills',
1209
+ description: 'List all skills available to the current agent. Returns lean metadata (name + description) for each skill. ' +
1210
+ 'Use get_skill to load the full instructions for a specific skill when needed.',
1211
+ inputSchema: {
1212
+ type: 'object',
1213
+ properties: {},
1214
+ },
1215
+ },
1216
+ {
1217
+ name: 'get_skill',
1218
+ description: 'Load the full instruction content for a specific skill by name. ' +
1219
+ "Call this when a task matches a skill's description to get detailed instructions before proceeding. " +
1220
+ 'Also returns a list of available resources (scripts, references, assets).',
1221
+ inputSchema: {
1222
+ type: 'object',
1223
+ properties: {
1224
+ skill_name: {
1225
+ type: 'string',
1226
+ description: 'The name of the skill to load (e.g. "deploy-app")',
1227
+ },
1228
+ },
1229
+ required: ['skill_name'],
1230
+ },
1231
+ },
1232
+ {
1233
+ name: 'get_skill_resource',
1234
+ description: 'Get a specific resource file attached to a skill. ' +
1235
+ 'Resources can be scripts, reference documents, or assets that supplement the skill instructions.',
1236
+ inputSchema: {
1237
+ type: 'object',
1238
+ properties: {
1239
+ skill_name: {
1240
+ type: 'string',
1241
+ description: 'The name of the skill',
1242
+ },
1243
+ resource_name: {
1244
+ type: 'string',
1245
+ description: 'The name of the resource file',
1246
+ },
1247
+ },
1248
+ required: ['skill_name', 'resource_name'],
1249
+ },
1250
+ },
1081
1251
  ],
1082
1252
  }));
1083
1253
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -1123,7 +1293,7 @@ class WolfpackMCPServer {
1123
1293
  limit: parsed.limit,
1124
1294
  offset: parsed.offset,
1125
1295
  });
1126
- let text = JSON.stringify(result.items, null, 2);
1296
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1127
1297
  if (result.truncated) {
1128
1298
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use filters or limit/offset for pagination.\n\n${text}`;
1129
1299
  }
@@ -1135,7 +1305,7 @@ class WolfpackMCPServer {
1135
1305
  const parsed = GetWorkItemSchema.parse(args);
1136
1306
  const workItem = await this.client.getWorkItem(parsed.work_item_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
1137
1307
  if (workItem) {
1138
- let text = JSON.stringify(workItem, null, 2);
1308
+ let text = JSON.stringify(stripUuids(workItem), null, 2);
1139
1309
  // Add hint if no plan detected in description
1140
1310
  if (!hasPlan(workItem.description)) {
1141
1311
  text =
@@ -1158,7 +1328,7 @@ class WolfpackMCPServer {
1158
1328
  content: [
1159
1329
  {
1160
1330
  type: 'text',
1161
- text: `Updated description on: ${workItem.title}\n\n${JSON.stringify(workItem, null, 2)}`,
1331
+ text: `Updated description on: ${workItem.title}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1162
1332
  },
1163
1333
  ],
1164
1334
  };
@@ -1175,7 +1345,7 @@ class WolfpackMCPServer {
1175
1345
  content: [
1176
1346
  {
1177
1347
  type: 'text',
1178
- text: `Updated status of "${workItem.title}" to ${parsed.status}\n\n${JSON.stringify(workItem, null, 2)}`,
1348
+ text: `Updated status of "${workItem.title}" to ${parsed.status}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1179
1349
  },
1180
1350
  ],
1181
1351
  };
@@ -1197,7 +1367,7 @@ class WolfpackMCPServer {
1197
1367
  content: [
1198
1368
  {
1199
1369
  type: 'text',
1200
- text: `Updated "${workItem.title}" - now ${assigneeText}\n\n${JSON.stringify(workItem, null, 2)}`,
1370
+ text: `Updated "${workItem.title}" - now ${assigneeText}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1201
1371
  },
1202
1372
  ],
1203
1373
  };
@@ -1214,7 +1384,27 @@ class WolfpackMCPServer {
1214
1384
  content: [
1215
1385
  {
1216
1386
  type: 'text',
1217
- text: `Updated title to "${workItem.title}"\n\n${JSON.stringify(workItem, null, 2)}`,
1387
+ text: `Updated title to "${workItem.title}"\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1388
+ },
1389
+ ],
1390
+ };
1391
+ }
1392
+ return {
1393
+ content: [{ type: 'text', text: 'Work item not found' }],
1394
+ };
1395
+ }
1396
+ case 'update_work_item_initiative': {
1397
+ const parsed = UpdateWorkItemInitiativeSchema.parse(args);
1398
+ const workItem = await this.client.updateWorkItemInitiative(parsed.work_item_id, parsed.radar_item_id);
1399
+ if (workItem) {
1400
+ const initiativeText = parsed.radar_item_id
1401
+ ? `linked to initiative ${parsed.radar_item_id}`
1402
+ : 'unlinked from initiative';
1403
+ return {
1404
+ content: [
1405
+ {
1406
+ type: 'text',
1407
+ text: `Updated "${workItem.title}" - ${initiativeText}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1218
1408
  },
1219
1409
  ],
1220
1410
  };
@@ -1233,7 +1423,24 @@ class WolfpackMCPServer {
1233
1423
  content: [
1234
1424
  {
1235
1425
  type: 'text',
1236
- text: `Pulled "${workItem.title}" from backlog to board (status: new)\n\n${JSON.stringify(workItem, null, 2)}`,
1426
+ text: `Pulled "${workItem.title}" from backlog to board (status: new)\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1427
+ },
1428
+ ],
1429
+ };
1430
+ }
1431
+ return {
1432
+ content: [{ type: 'text', text: 'Work item not found' }],
1433
+ };
1434
+ }
1435
+ case 'submit_work_item_form': {
1436
+ const parsed = SubmitWorkItemFormSchema.parse(args);
1437
+ const workItem = await this.client.submitWorkItemForm(parsed.work_item_id, parsed.form_values);
1438
+ if (workItem) {
1439
+ return {
1440
+ content: [
1441
+ {
1442
+ type: 'text',
1443
+ text: `Submitted form values for "${workItem.title}"\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1237
1444
  },
1238
1445
  ],
1239
1446
  };
@@ -1252,7 +1459,7 @@ class WolfpackMCPServer {
1252
1459
  limit: parsed.limit,
1253
1460
  offset: parsed.offset,
1254
1461
  });
1255
- let text = JSON.stringify(result.items, null, 2);
1462
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1256
1463
  if (result.truncated) {
1257
1464
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use stage filter or limit/offset for pagination.\n\n${text}`;
1258
1465
  }
@@ -1265,7 +1472,7 @@ class WolfpackMCPServer {
1265
1472
  const radarItem = await this.client.getRadarItem(parsed.item_id, parsed.project_slug);
1266
1473
  if (radarItem) {
1267
1474
  return {
1268
- content: [{ type: 'text', text: JSON.stringify(radarItem, null, 2) }],
1475
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(radarItem), null, 2) }],
1269
1476
  };
1270
1477
  }
1271
1478
  return {
@@ -1289,7 +1496,7 @@ class WolfpackMCPServer {
1289
1496
  limit: parsed.limit,
1290
1497
  offset: parsed.offset,
1291
1498
  });
1292
- let text = JSON.stringify(result.items, null, 2);
1499
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1293
1500
  if (result.truncated) {
1294
1501
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use filters or limit/offset for pagination.\n\n${text}`;
1295
1502
  }
@@ -1302,7 +1509,7 @@ class WolfpackMCPServer {
1302
1509
  const issue = await this.client.getIssue(parsed.issue_id, parsed.project_slug);
1303
1510
  if (issue) {
1304
1511
  return {
1305
- content: [{ type: 'text', text: JSON.stringify(issue, null, 2) }],
1512
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(issue), null, 2) }],
1306
1513
  };
1307
1514
  }
1308
1515
  return {
@@ -1317,6 +1524,7 @@ class WolfpackMCPServer {
1317
1524
  description: parsed.description,
1318
1525
  status: parsed.status,
1319
1526
  priority: parsed.priority,
1527
+ size: parsed.size,
1320
1528
  leadingUserId: parsed.leading_user_id,
1321
1529
  categoryId: parsed.category_id,
1322
1530
  radarItemId: parsed.radar_item_id,
@@ -1326,7 +1534,7 @@ class WolfpackMCPServer {
1326
1534
  content: [
1327
1535
  {
1328
1536
  type: 'text',
1329
- text: `Created work item #${workItem.refId}: ${workItem.title}\n\n${JSON.stringify(workItem, null, 2)}`,
1537
+ text: `Created work item #${workItem.refId}: ${workItem.title}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1330
1538
  },
1331
1539
  ],
1332
1540
  };
@@ -1351,7 +1559,7 @@ class WolfpackMCPServer {
1351
1559
  content: [
1352
1560
  {
1353
1561
  type: 'text',
1354
- text: `Created issue #${issue.refId}: ${issue.title}\n\n${JSON.stringify(issue, null, 2)}`,
1562
+ text: `Created issue #${issue.refId}: ${issue.title}\n\n${JSON.stringify(stripUuids(issue), null, 2)}`,
1355
1563
  },
1356
1564
  ],
1357
1565
  };
@@ -1370,7 +1578,7 @@ class WolfpackMCPServer {
1370
1578
  content: [
1371
1579
  {
1372
1580
  type: 'text',
1373
- text: `Updated issue #${issue.refId}: ${issue.title}\n\n${JSON.stringify(issue, null, 2)}`,
1581
+ text: `Updated issue #${issue.refId}: ${issue.title}\n\n${JSON.stringify(stripUuids(issue), null, 2)}`,
1374
1582
  },
1375
1583
  ],
1376
1584
  };
@@ -1386,7 +1594,7 @@ class WolfpackMCPServer {
1386
1594
  limit: parsed.limit,
1387
1595
  offset: parsed.offset,
1388
1596
  });
1389
- let text = JSON.stringify(result.items, null, 2);
1597
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1390
1598
  if (result.truncated) {
1391
1599
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} pages. Use limit/offset for pagination.\n\n${text}`;
1392
1600
  }
@@ -1399,7 +1607,7 @@ class WolfpackMCPServer {
1399
1607
  const page = await this.client.getWikiPage(parsed.page_id);
1400
1608
  if (page) {
1401
1609
  return {
1402
- content: [{ type: 'text', text: JSON.stringify(page, null, 2) }],
1610
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(page), null, 2) }],
1403
1611
  };
1404
1612
  }
1405
1613
  return {
@@ -1418,7 +1626,7 @@ class WolfpackMCPServer {
1418
1626
  content: [
1419
1627
  {
1420
1628
  type: 'text',
1421
- text: `Created wiki page: ${page.title}\n\n${JSON.stringify(page, null, 2)}`,
1629
+ text: `Created wiki page: ${page.title}\n\n${JSON.stringify(stripUuids(page), null, 2)}`,
1422
1630
  },
1423
1631
  ],
1424
1632
  };
@@ -1433,7 +1641,7 @@ class WolfpackMCPServer {
1433
1641
  content: [
1434
1642
  {
1435
1643
  type: 'text',
1436
- text: `Updated wiki page: ${page.title}\n\n${JSON.stringify(page, null, 2)}`,
1644
+ text: `Updated wiki page: ${page.title}\n\n${JSON.stringify(stripUuids(page), null, 2)}`,
1437
1645
  },
1438
1646
  ],
1439
1647
  };
@@ -1449,7 +1657,7 @@ class WolfpackMCPServer {
1449
1657
  limit: parsed.limit,
1450
1658
  offset: parsed.offset,
1451
1659
  });
1452
- let text = JSON.stringify(result.items, null, 2);
1660
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1453
1661
  if (result.truncated) {
1454
1662
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} entries. Use limit/offset for pagination.\n\n${text}`;
1455
1663
  }
@@ -1462,7 +1670,7 @@ class WolfpackMCPServer {
1462
1670
  const entry = await this.client.getJournalEntry(parsed.entry_id, parsed.project_slug);
1463
1671
  if (entry) {
1464
1672
  return {
1465
- content: [{ type: 'text', text: JSON.stringify(entry, null, 2) }],
1673
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(entry), null, 2) }],
1466
1674
  };
1467
1675
  }
1468
1676
  return {
@@ -1474,14 +1682,13 @@ class WolfpackMCPServer {
1474
1682
  const entry = await this.client.createJournalEntry({
1475
1683
  title: parsed.title,
1476
1684
  content: parsed.content,
1477
- date: parsed.date,
1478
1685
  teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
1479
1686
  });
1480
1687
  return {
1481
1688
  content: [
1482
1689
  {
1483
1690
  type: 'text',
1484
- text: `Created journal entry #${entry.refId}: ${entry.title}\n\n${JSON.stringify(entry, null, 2)}`,
1691
+ text: `Created journal entry #${entry.refId}: ${entry.title}\n\n${JSON.stringify(stripUuids(entry), null, 2)}`,
1485
1692
  },
1486
1693
  ],
1487
1694
  };
@@ -1496,7 +1703,7 @@ class WolfpackMCPServer {
1496
1703
  content: [
1497
1704
  {
1498
1705
  type: 'text',
1499
- text: `Updated journal entry #${entry.refId}: ${entry.title}\n\n${JSON.stringify(entry, null, 2)}`,
1706
+ text: `Updated journal entry #${entry.refId}: ${entry.title}\n\n${JSON.stringify(stripUuids(entry), null, 2)}`,
1500
1707
  },
1501
1708
  ],
1502
1709
  };
@@ -1506,14 +1713,14 @@ class WolfpackMCPServer {
1506
1713
  const parsed = ListWorkItemCommentsSchema.parse(args);
1507
1714
  const comments = await this.client.listWorkItemComments(parsed.work_item_id);
1508
1715
  return {
1509
- content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1716
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(comments), null, 2) }],
1510
1717
  };
1511
1718
  }
1512
1719
  case 'list_issue_comments': {
1513
1720
  const parsed = ListIssueCommentsSchema.parse(args);
1514
1721
  const comments = await this.client.listIssueComments(parsed.issue_id);
1515
1722
  return {
1516
- content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1723
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(comments), null, 2) }],
1517
1724
  };
1518
1725
  }
1519
1726
  case 'create_work_item_comment': {
@@ -1525,7 +1732,7 @@ class WolfpackMCPServer {
1525
1732
  content: [
1526
1733
  {
1527
1734
  type: 'text',
1528
- text: `Added comment to work item\n\n${JSON.stringify(comment, null, 2)}`,
1735
+ text: `Added comment to work item\n\n${JSON.stringify(stripUuids(comment), null, 2)}`,
1529
1736
  },
1530
1737
  ],
1531
1738
  };
@@ -1539,7 +1746,7 @@ class WolfpackMCPServer {
1539
1746
  content: [
1540
1747
  {
1541
1748
  type: 'text',
1542
- text: `Added comment to issue\n\n${JSON.stringify(comment, null, 2)}`,
1749
+ text: `Added comment to issue\n\n${JSON.stringify(stripUuids(comment), null, 2)}`,
1543
1750
  },
1544
1751
  ],
1545
1752
  };
@@ -1601,6 +1808,47 @@ class WolfpackMCPServer {
1601
1808
  ],
1602
1809
  };
1603
1810
  }
1811
+ // Skill handlers
1812
+ case 'list_skills': {
1813
+ const skills = await this.client.listSkills();
1814
+ return {
1815
+ content: [{ type: 'text', text: JSON.stringify(skills, null, 2) }],
1816
+ };
1817
+ }
1818
+ case 'get_skill': {
1819
+ const parsed = GetSkillSchema.parse(args);
1820
+ const skill = await this.client.getSkill(parsed.skill_name);
1821
+ if (skill) {
1822
+ return {
1823
+ content: [{ type: 'text', text: JSON.stringify(skill, null, 2) }],
1824
+ };
1825
+ }
1826
+ return {
1827
+ content: [
1828
+ {
1829
+ type: 'text',
1830
+ text: `Skill '${parsed.skill_name}' not found. Use list_skills to see available skills.`,
1831
+ },
1832
+ ],
1833
+ };
1834
+ }
1835
+ case 'get_skill_resource': {
1836
+ const parsed = GetSkillResourceSchema.parse(args);
1837
+ const resource = await this.client.getSkillResource(parsed.skill_name, parsed.resource_name);
1838
+ if (resource) {
1839
+ return {
1840
+ content: [{ type: 'text', text: JSON.stringify(resource, null, 2) }],
1841
+ };
1842
+ }
1843
+ return {
1844
+ content: [
1845
+ {
1846
+ type: 'text',
1847
+ text: `Resource '${parsed.resource_name}' not found in skill '${parsed.skill_name}'.`,
1848
+ },
1849
+ ],
1850
+ };
1851
+ }
1604
1852
  default:
1605
1853
  throw new Error(`Unknown tool: ${name}`);
1606
1854
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",