wolfpack-mcp 1.0.38 → 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/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,9 @@ 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
+ });
197
209
  }
198
210
  catch (error) {
199
211
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -204,7 +216,7 @@ export class WolfpackClient {
204
216
  }
205
217
  async updateWorkItemInitiative(workItemId, radarItemId) {
206
218
  try {
207
- return await this.api.put(`/work-items/${workItemId}/initiative`, { radarItemId });
219
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/initiative`), { radarItemId });
208
220
  }
209
221
  catch (error) {
210
222
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -215,7 +227,7 @@ export class WolfpackClient {
215
227
  }
216
228
  async pullWorkItem(workItemId, data) {
217
229
  try {
218
- return await this.api.post(`/work-items/${workItemId}/pull`, data || {});
230
+ return await this.api.post(this.withTeamSlug(`/work-items/${workItemId}/pull`), data || {});
219
231
  }
220
232
  catch (error) {
221
233
  if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
@@ -226,7 +238,7 @@ export class WolfpackClient {
226
238
  }
227
239
  async submitWorkItemForm(workItemId, formValues) {
228
240
  try {
229
- return await this.api.put(`/work-items/${workItemId}/form`, {
241
+ return await this.api.put(this.withTeamSlug(`/work-items/${workItemId}/form`), {
230
242
  formValues,
231
243
  });
232
244
  }
@@ -349,7 +361,7 @@ export class WolfpackClient {
349
361
  return this.api.post('/issues', { ...rest, teamSlug });
350
362
  }
351
363
  async updateIssue(issueId, data) {
352
- return this.api.patch(`/issues/${issueId}`, data);
364
+ return this.api.patch(this.withTeamSlug(`/issues/${issueId}`), data);
353
365
  }
354
366
  // Wiki Page methods
355
367
  async listWikiPages(options) {
@@ -398,7 +410,7 @@ export class WolfpackClient {
398
410
  return this.api.post('/wiki-pages', { ...rest, teamSlug });
399
411
  }
400
412
  async updateWikiPage(pageId, data) {
401
- return this.api.patch(`/wiki-pages/${pageId}`, data);
413
+ return this.api.patch(this.withTeamSlug(`/wiki-pages/${pageId}`), data);
402
414
  }
403
415
  // Journal Entry methods
404
416
  async listJournalEntries(options) {
@@ -447,20 +459,20 @@ export class WolfpackClient {
447
459
  return this.api.post('/journal-entries', { ...rest, teamSlug });
448
460
  }
449
461
  async updateJournalEntry(entryId, data) {
450
- return this.api.patch(`/journal-entries/${entryId}`, data);
462
+ return this.api.patch(this.withTeamSlug(`/journal-entries/${entryId}`), data);
451
463
  }
452
464
  // Comment methods
453
465
  async listWorkItemComments(workItemId) {
454
- return this.api.get(`/work-items/${workItemId}/comments`);
466
+ return this.api.get(this.withTeamSlug(`/work-items/${workItemId}/comments`));
455
467
  }
456
468
  async listIssueComments(issueId) {
457
- return this.api.get(`/issues/${issueId}/comments`);
469
+ return this.api.get(this.withTeamSlug(`/issues/${issueId}/comments`));
458
470
  }
459
471
  async createWorkItemComment(workItemId, data) {
460
- return this.api.post(`/work-items/${workItemId}/comments`, data);
472
+ return this.api.post(this.withTeamSlug(`/work-items/${workItemId}/comments`), data);
461
473
  }
462
474
  async createIssueComment(issueId, data) {
463
- return this.api.post(`/issues/${issueId}/comments`, data);
475
+ return this.api.post(this.withTeamSlug(`/issues/${issueId}/comments`), data);
464
476
  }
465
477
  /**
466
478
  * Upload an image and get back a URL that can be used in markdown content.
@@ -476,6 +488,32 @@ export class WolfpackClient {
476
488
  const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
477
489
  return { base64: buffer.toString('base64'), mimeType: contentType };
478
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
+ }
479
517
  close() {
480
518
  // No cleanup needed for API client
481
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({
@@ -147,7 +153,7 @@ const ListRadarItemsSchema = z.object({
147
153
  offset: z.number().optional().describe('Number of items to skip'),
148
154
  });
149
155
  const GetRadarItemSchema = z.object({
150
- 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'),
151
157
  project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
152
158
  });
153
159
  // Issue schemas
@@ -184,7 +190,7 @@ const ListIssuesSchema = z.object({
184
190
  offset: z.number().optional().describe('Number of items to skip'),
185
191
  });
186
192
  const GetIssueSchema = z.object({
187
- 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'),
188
194
  project_slug: z.string().optional().describe('Project slug (required when looking up by refId)'),
189
195
  });
190
196
  // Create schemas
@@ -229,7 +235,7 @@ const CreateIssueSchema = z.object({
229
235
  actual_behavior: z.string().optional().describe('Actual behavior observed'),
230
236
  });
231
237
  const UpdateIssueSchema = z.object({
232
- 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'),
233
239
  title: z.string().optional().describe('Updated title'),
234
240
  description: z.string().optional().describe('Updated description'),
235
241
  status: z
@@ -256,7 +262,7 @@ const ListWikiPagesSchema = z.object({
256
262
  offset: z.number().optional().describe('Number of pages to skip'),
257
263
  });
258
264
  const GetWikiPageSchema = z.object({
259
- page_id: z.string().describe('The page UUID or slug'),
265
+ page_id: z.string().describe('The page slug'),
260
266
  });
261
267
  const CreateWikiPageSchema = z.object({
262
268
  project_slug: z
@@ -275,7 +281,7 @@ const CreateWikiPageSchema = z.object({
275
281
  content: z.string().describe('Page content (markdown)'),
276
282
  });
277
283
  const UpdateWikiPageSchema = z.object({
278
- page_id: z.string().describe('The page UUID'),
284
+ page_id: z.string().describe('The page slug'),
279
285
  title: z.string().optional().describe('Updated title'),
280
286
  content: z.string().optional().describe('Updated content (markdown)'),
281
287
  });
@@ -295,8 +301,8 @@ const ListJournalEntriesSchema = z.object({
295
301
  offset: z.number().optional().describe('Number of entries to skip'),
296
302
  });
297
303
  const GetJournalEntrySchema = z.object({
298
- entry_id: z.string().describe('The entry UUID or refId'),
299
- 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)'),
300
306
  });
301
307
  const CreateJournalEntrySchema = z.object({
302
308
  project_slug: z
@@ -305,26 +311,25 @@ const CreateJournalEntrySchema = z.object({
305
311
  .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
306
312
  title: z.string().describe('Entry title'),
307
313
  content: z.string().describe('Entry content (markdown)'),
308
- date: z.string().optional().describe('Entry date (ISO format, defaults to now)'),
309
314
  });
310
315
  const UpdateJournalEntrySchema = z.object({
311
- entry_id: z.string().describe('The entry UUID'),
316
+ entry_id: z.string().describe('The entry refId (number)'),
312
317
  title: z.string().optional().describe('Updated title'),
313
318
  content: z.string().optional().describe('Updated content (markdown)'),
314
319
  });
315
320
  // Comment schemas
316
321
  const ListWorkItemCommentsSchema = z.object({
317
- work_item_id: z.string().describe('The work item UUID'),
322
+ work_item_id: z.string().describe('The work item refId (number)'),
318
323
  });
319
324
  const ListIssueCommentsSchema = z.object({
320
- issue_id: z.string().describe('The issue UUID'),
325
+ issue_id: z.string().describe('The issue refId (number)'),
321
326
  });
322
327
  const CreateWorkItemCommentSchema = z.object({
323
- work_item_id: z.string().describe('The work item UUID'),
328
+ work_item_id: z.string().describe('The work item refId (number)'),
324
329
  content: z.string().describe('Comment content (markdown)'),
325
330
  });
326
331
  const CreateIssueCommentSchema = z.object({
327
- issue_id: z.string().describe('The issue UUID'),
332
+ issue_id: z.string().describe('The issue refId (number)'),
328
333
  content: z.string().describe('Comment content (markdown)'),
329
334
  });
330
335
  // Image upload schema
@@ -343,6 +348,54 @@ const DownloadImageSchema = z.object({
343
348
  .string()
344
349
  .describe('The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").'),
345
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
+ }
346
399
  // Helper to detect if a work item description contains a plan
347
400
  function hasPlan(description) {
348
401
  if (!description)
@@ -458,7 +511,7 @@ class WolfpackMCPServer {
458
511
  },
459
512
  {
460
513
  name: 'get_work_item',
461
- 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). ' +
462
515
  'Call this before updating to see current content. ' +
463
516
  'WORKFLOW: When asked to work on an item, check its status and follow the required state transitions ' +
464
517
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
@@ -470,11 +523,11 @@ class WolfpackMCPServer {
470
523
  properties: {
471
524
  work_item_id: {
472
525
  type: 'string',
473
- description: 'The ID (UUID) or refId (number) of the work item',
526
+ description: 'The refId (number) of the work item',
474
527
  },
475
528
  project_slug: {
476
529
  type: 'string',
477
- description: 'Project slug (required when looking up by refId)',
530
+ description: 'Project slug (required for refId lookup)',
478
531
  },
479
532
  },
480
533
  required: ['work_item_id'],
@@ -484,7 +537,8 @@ class WolfpackMCPServer {
484
537
  name: 'update_work_progress',
485
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. ' +
486
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). ' +
487
- '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,
488
542
  inputSchema: {
489
543
  type: 'object',
490
544
  properties: {
@@ -662,18 +716,18 @@ class WolfpackMCPServer {
662
716
  },
663
717
  {
664
718
  name: 'get_radar_item',
665
- 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. ' +
666
720
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
667
721
  inputSchema: {
668
722
  type: 'object',
669
723
  properties: {
670
724
  item_id: {
671
725
  type: 'string',
672
- description: 'The ID (UUID) or refId (number) of the radar item',
726
+ description: 'The refId (number) of the radar item',
673
727
  },
674
728
  project_slug: {
675
729
  type: 'string',
676
- description: 'Project slug (required when looking up by refId)',
730
+ description: 'Project slug (required for refId lookup)',
677
731
  },
678
732
  },
679
733
  required: ['item_id'],
@@ -740,18 +794,18 @@ class WolfpackMCPServer {
740
794
  },
741
795
  {
742
796
  name: 'get_issue',
743
- 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. ' +
744
798
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
745
799
  inputSchema: {
746
800
  type: 'object',
747
801
  properties: {
748
802
  issue_id: {
749
803
  type: 'string',
750
- description: 'The ID (UUID) or refId (number) of the issue',
804
+ description: 'The refId (number) of the issue',
751
805
  },
752
806
  project_slug: {
753
807
  type: 'string',
754
- description: 'Project slug (required when looking up by refId)',
808
+ description: 'Project slug (required for refId lookup)',
755
809
  },
756
810
  },
757
811
  required: ['issue_id'],
@@ -760,7 +814,8 @@ class WolfpackMCPServer {
760
814
  // Create/Update tools
761
815
  {
762
816
  name: 'create_work_item',
763
- 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,
764
819
  inputSchema: {
765
820
  type: 'object',
766
821
  properties: {
@@ -815,7 +870,8 @@ class WolfpackMCPServer {
815
870
  },
816
871
  {
817
872
  name: 'create_issue',
818
- 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,
819
875
  inputSchema: {
820
876
  type: 'object',
821
877
  properties: {
@@ -848,11 +904,15 @@ class WolfpackMCPServer {
848
904
  },
849
905
  {
850
906
  name: 'update_issue',
851
- 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,
852
909
  inputSchema: {
853
910
  type: 'object',
854
911
  properties: {
855
- 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
+ },
856
916
  title: { type: 'string', description: 'Updated title' },
857
917
  description: { type: 'string', description: 'Updated description' },
858
918
  status: {
@@ -904,14 +964,14 @@ class WolfpackMCPServer {
904
964
  },
905
965
  {
906
966
  name: 'get_wiki_page',
907
- 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. ' +
908
968
  'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
909
969
  inputSchema: {
910
970
  type: 'object',
911
971
  properties: {
912
972
  page_id: {
913
973
  type: 'string',
914
- description: 'The page UUID or slug (URL path like "getting-started")',
974
+ description: 'The page slug (URL path like "getting-started")',
915
975
  },
916
976
  },
917
977
  required: ['page_id'],
@@ -919,7 +979,8 @@ class WolfpackMCPServer {
919
979
  },
920
980
  {
921
981
  name: 'create_wiki_page',
922
- 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,
923
984
  inputSchema: {
924
985
  type: 'object',
925
986
  properties: {
@@ -942,11 +1003,12 @@ class WolfpackMCPServer {
942
1003
  },
943
1004
  {
944
1005
  name: 'update_wiki_page',
945
- 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,
946
1008
  inputSchema: {
947
1009
  type: 'object',
948
1010
  properties: {
949
- page_id: { type: 'string', description: 'The page UUID' },
1011
+ page_id: { type: 'string', description: 'The page slug' },
950
1012
  title: { type: 'string', description: 'Updated title' },
951
1013
  content: {
952
1014
  type: 'string',
@@ -986,15 +1048,15 @@ class WolfpackMCPServer {
986
1048
  },
987
1049
  {
988
1050
  name: 'get_journal_entry',
989
- 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. ' +
990
1052
  'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
991
1053
  inputSchema: {
992
1054
  type: 'object',
993
1055
  properties: {
994
- entry_id: { type: 'string', description: 'The entry UUID or refId' },
1056
+ entry_id: { type: 'string', description: 'The entry refId (number)' },
995
1057
  project_slug: {
996
1058
  type: 'string',
997
- description: 'Project slug (required when looking up by refId)',
1059
+ description: 'Project slug (required for refId lookup)',
998
1060
  },
999
1061
  },
1000
1062
  required: ['entry_id'],
@@ -1002,7 +1064,8 @@ class WolfpackMCPServer {
1002
1064
  },
1003
1065
  {
1004
1066
  name: 'create_journal_entry',
1005
- 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,
1006
1069
  inputSchema: {
1007
1070
  type: 'object',
1008
1071
  properties: {
@@ -1015,18 +1078,18 @@ class WolfpackMCPServer {
1015
1078
  type: 'string',
1016
1079
  description: 'Entry content (markdown)',
1017
1080
  },
1018
- date: { type: 'string', description: 'Entry date (ISO format, defaults to now)' },
1019
1081
  },
1020
1082
  required: ['title', 'content'],
1021
1083
  },
1022
1084
  },
1023
1085
  {
1024
1086
  name: 'update_journal_entry',
1025
- 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,
1026
1089
  inputSchema: {
1027
1090
  type: 'object',
1028
1091
  properties: {
1029
- entry_id: { type: 'string', description: 'The entry UUID' },
1092
+ entry_id: { type: 'string', description: 'The entry refId (number)' },
1030
1093
  title: { type: 'string', description: 'Updated title' },
1031
1094
  content: {
1032
1095
  type: 'string',
@@ -1044,7 +1107,7 @@ class WolfpackMCPServer {
1044
1107
  inputSchema: {
1045
1108
  type: 'object',
1046
1109
  properties: {
1047
- work_item_id: { type: 'string', description: 'The work item UUID' },
1110
+ work_item_id: { type: 'string', description: 'The work item refId (number)' },
1048
1111
  },
1049
1112
  required: ['work_item_id'],
1050
1113
  },
@@ -1056,7 +1119,7 @@ class WolfpackMCPServer {
1056
1119
  inputSchema: {
1057
1120
  type: 'object',
1058
1121
  properties: {
1059
- issue_id: { type: 'string', description: 'The issue UUID' },
1122
+ issue_id: { type: 'string', description: 'The issue refId (number)' },
1060
1123
  },
1061
1124
  required: ['issue_id'],
1062
1125
  },
@@ -1068,11 +1131,12 @@ class WolfpackMCPServer {
1068
1131
  '2) Completion summaries when moving to "review" (what was done, files changed, testing notes). ' +
1069
1132
  '3) Important observations or decisions that should be visible in the activity history. ' +
1070
1133
  'USE DESCRIPTION (update_work_progress) FOR: Plans, checklists, and progress tracking that need to be updated over time. ' +
1071
- 'Comments are typically not used in personal projects.',
1134
+ 'Comments are typically not used in personal projects. ' +
1135
+ CONTENT_LINKING_HELP,
1072
1136
  inputSchema: {
1073
1137
  type: 'object',
1074
1138
  properties: {
1075
- work_item_id: { type: 'string', description: 'The work item UUID' },
1139
+ work_item_id: { type: 'string', description: 'The work item refId (number)' },
1076
1140
  content: {
1077
1141
  type: 'string',
1078
1142
  description: 'Comment content (markdown)',
@@ -1083,11 +1147,12 @@ class WolfpackMCPServer {
1083
1147
  },
1084
1148
  {
1085
1149
  name: 'create_issue_comment',
1086
- 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,
1087
1152
  inputSchema: {
1088
1153
  type: 'object',
1089
1154
  properties: {
1090
- issue_id: { type: 'string', description: 'The issue UUID' },
1155
+ issue_id: { type: 'string', description: 'The issue refId (number)' },
1091
1156
  content: {
1092
1157
  type: 'string',
1093
1158
  description: 'Comment content (markdown)',
@@ -1138,6 +1203,51 @@ class WolfpackMCPServer {
1138
1203
  required: ['image_url'],
1139
1204
  },
1140
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
+ },
1141
1251
  ],
1142
1252
  }));
1143
1253
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -1183,7 +1293,7 @@ class WolfpackMCPServer {
1183
1293
  limit: parsed.limit,
1184
1294
  offset: parsed.offset,
1185
1295
  });
1186
- let text = JSON.stringify(result.items, null, 2);
1296
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1187
1297
  if (result.truncated) {
1188
1298
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use filters or limit/offset for pagination.\n\n${text}`;
1189
1299
  }
@@ -1195,7 +1305,7 @@ class WolfpackMCPServer {
1195
1305
  const parsed = GetWorkItemSchema.parse(args);
1196
1306
  const workItem = await this.client.getWorkItem(parsed.work_item_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
1197
1307
  if (workItem) {
1198
- let text = JSON.stringify(workItem, null, 2);
1308
+ let text = JSON.stringify(stripUuids(workItem), null, 2);
1199
1309
  // Add hint if no plan detected in description
1200
1310
  if (!hasPlan(workItem.description)) {
1201
1311
  text =
@@ -1218,7 +1328,7 @@ class WolfpackMCPServer {
1218
1328
  content: [
1219
1329
  {
1220
1330
  type: 'text',
1221
- 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)}`,
1222
1332
  },
1223
1333
  ],
1224
1334
  };
@@ -1235,7 +1345,7 @@ class WolfpackMCPServer {
1235
1345
  content: [
1236
1346
  {
1237
1347
  type: 'text',
1238
- 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)}`,
1239
1349
  },
1240
1350
  ],
1241
1351
  };
@@ -1257,7 +1367,7 @@ class WolfpackMCPServer {
1257
1367
  content: [
1258
1368
  {
1259
1369
  type: 'text',
1260
- 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)}`,
1261
1371
  },
1262
1372
  ],
1263
1373
  };
@@ -1274,7 +1384,7 @@ class WolfpackMCPServer {
1274
1384
  content: [
1275
1385
  {
1276
1386
  type: 'text',
1277
- 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)}`,
1278
1388
  },
1279
1389
  ],
1280
1390
  };
@@ -1294,7 +1404,7 @@ class WolfpackMCPServer {
1294
1404
  content: [
1295
1405
  {
1296
1406
  type: 'text',
1297
- text: `Updated "${workItem.title}" - ${initiativeText}\n\n${JSON.stringify(workItem, null, 2)}`,
1407
+ text: `Updated "${workItem.title}" - ${initiativeText}\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1298
1408
  },
1299
1409
  ],
1300
1410
  };
@@ -1313,7 +1423,7 @@ class WolfpackMCPServer {
1313
1423
  content: [
1314
1424
  {
1315
1425
  type: 'text',
1316
- 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)}`,
1317
1427
  },
1318
1428
  ],
1319
1429
  };
@@ -1330,7 +1440,7 @@ class WolfpackMCPServer {
1330
1440
  content: [
1331
1441
  {
1332
1442
  type: 'text',
1333
- text: `Submitted form values for "${workItem.title}"\n\n${JSON.stringify(workItem, null, 2)}`,
1443
+ text: `Submitted form values for "${workItem.title}"\n\n${JSON.stringify(stripUuids(workItem), null, 2)}`,
1334
1444
  },
1335
1445
  ],
1336
1446
  };
@@ -1349,7 +1459,7 @@ class WolfpackMCPServer {
1349
1459
  limit: parsed.limit,
1350
1460
  offset: parsed.offset,
1351
1461
  });
1352
- let text = JSON.stringify(result.items, null, 2);
1462
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1353
1463
  if (result.truncated) {
1354
1464
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use stage filter or limit/offset for pagination.\n\n${text}`;
1355
1465
  }
@@ -1362,7 +1472,7 @@ class WolfpackMCPServer {
1362
1472
  const radarItem = await this.client.getRadarItem(parsed.item_id, parsed.project_slug);
1363
1473
  if (radarItem) {
1364
1474
  return {
1365
- content: [{ type: 'text', text: JSON.stringify(radarItem, null, 2) }],
1475
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(radarItem), null, 2) }],
1366
1476
  };
1367
1477
  }
1368
1478
  return {
@@ -1386,7 +1496,7 @@ class WolfpackMCPServer {
1386
1496
  limit: parsed.limit,
1387
1497
  offset: parsed.offset,
1388
1498
  });
1389
- let text = JSON.stringify(result.items, null, 2);
1499
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1390
1500
  if (result.truncated) {
1391
1501
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} items. Use filters or limit/offset for pagination.\n\n${text}`;
1392
1502
  }
@@ -1399,7 +1509,7 @@ class WolfpackMCPServer {
1399
1509
  const issue = await this.client.getIssue(parsed.issue_id, parsed.project_slug);
1400
1510
  if (issue) {
1401
1511
  return {
1402
- content: [{ type: 'text', text: JSON.stringify(issue, null, 2) }],
1512
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(issue), null, 2) }],
1403
1513
  };
1404
1514
  }
1405
1515
  return {
@@ -1424,7 +1534,7 @@ class WolfpackMCPServer {
1424
1534
  content: [
1425
1535
  {
1426
1536
  type: 'text',
1427
- 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)}`,
1428
1538
  },
1429
1539
  ],
1430
1540
  };
@@ -1449,7 +1559,7 @@ class WolfpackMCPServer {
1449
1559
  content: [
1450
1560
  {
1451
1561
  type: 'text',
1452
- 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)}`,
1453
1563
  },
1454
1564
  ],
1455
1565
  };
@@ -1468,7 +1578,7 @@ class WolfpackMCPServer {
1468
1578
  content: [
1469
1579
  {
1470
1580
  type: 'text',
1471
- 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)}`,
1472
1582
  },
1473
1583
  ],
1474
1584
  };
@@ -1484,7 +1594,7 @@ class WolfpackMCPServer {
1484
1594
  limit: parsed.limit,
1485
1595
  offset: parsed.offset,
1486
1596
  });
1487
- let text = JSON.stringify(result.items, null, 2);
1597
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1488
1598
  if (result.truncated) {
1489
1599
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} pages. Use limit/offset for pagination.\n\n${text}`;
1490
1600
  }
@@ -1497,7 +1607,7 @@ class WolfpackMCPServer {
1497
1607
  const page = await this.client.getWikiPage(parsed.page_id);
1498
1608
  if (page) {
1499
1609
  return {
1500
- content: [{ type: 'text', text: JSON.stringify(page, null, 2) }],
1610
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(page), null, 2) }],
1501
1611
  };
1502
1612
  }
1503
1613
  return {
@@ -1516,7 +1626,7 @@ class WolfpackMCPServer {
1516
1626
  content: [
1517
1627
  {
1518
1628
  type: 'text',
1519
- 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)}`,
1520
1630
  },
1521
1631
  ],
1522
1632
  };
@@ -1531,7 +1641,7 @@ class WolfpackMCPServer {
1531
1641
  content: [
1532
1642
  {
1533
1643
  type: 'text',
1534
- 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)}`,
1535
1645
  },
1536
1646
  ],
1537
1647
  };
@@ -1547,7 +1657,7 @@ class WolfpackMCPServer {
1547
1657
  limit: parsed.limit,
1548
1658
  offset: parsed.offset,
1549
1659
  });
1550
- let text = JSON.stringify(result.items, null, 2);
1660
+ let text = JSON.stringify(stripUuids(result.items), null, 2);
1551
1661
  if (result.truncated) {
1552
1662
  text = `Note: Results truncated. Showing ${result.items.length} of ${result.total} entries. Use limit/offset for pagination.\n\n${text}`;
1553
1663
  }
@@ -1560,7 +1670,7 @@ class WolfpackMCPServer {
1560
1670
  const entry = await this.client.getJournalEntry(parsed.entry_id, parsed.project_slug);
1561
1671
  if (entry) {
1562
1672
  return {
1563
- content: [{ type: 'text', text: JSON.stringify(entry, null, 2) }],
1673
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(entry), null, 2) }],
1564
1674
  };
1565
1675
  }
1566
1676
  return {
@@ -1572,14 +1682,13 @@ class WolfpackMCPServer {
1572
1682
  const entry = await this.client.createJournalEntry({
1573
1683
  title: parsed.title,
1574
1684
  content: parsed.content,
1575
- date: parsed.date,
1576
1685
  teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
1577
1686
  });
1578
1687
  return {
1579
1688
  content: [
1580
1689
  {
1581
1690
  type: 'text',
1582
- 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)}`,
1583
1692
  },
1584
1693
  ],
1585
1694
  };
@@ -1594,7 +1703,7 @@ class WolfpackMCPServer {
1594
1703
  content: [
1595
1704
  {
1596
1705
  type: 'text',
1597
- 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)}`,
1598
1707
  },
1599
1708
  ],
1600
1709
  };
@@ -1604,14 +1713,14 @@ class WolfpackMCPServer {
1604
1713
  const parsed = ListWorkItemCommentsSchema.parse(args);
1605
1714
  const comments = await this.client.listWorkItemComments(parsed.work_item_id);
1606
1715
  return {
1607
- content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1716
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(comments), null, 2) }],
1608
1717
  };
1609
1718
  }
1610
1719
  case 'list_issue_comments': {
1611
1720
  const parsed = ListIssueCommentsSchema.parse(args);
1612
1721
  const comments = await this.client.listIssueComments(parsed.issue_id);
1613
1722
  return {
1614
- content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1723
+ content: [{ type: 'text', text: JSON.stringify(stripUuids(comments), null, 2) }],
1615
1724
  };
1616
1725
  }
1617
1726
  case 'create_work_item_comment': {
@@ -1623,7 +1732,7 @@ class WolfpackMCPServer {
1623
1732
  content: [
1624
1733
  {
1625
1734
  type: 'text',
1626
- 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)}`,
1627
1736
  },
1628
1737
  ],
1629
1738
  };
@@ -1637,7 +1746,7 @@ class WolfpackMCPServer {
1637
1746
  content: [
1638
1747
  {
1639
1748
  type: 'text',
1640
- 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)}`,
1641
1750
  },
1642
1751
  ],
1643
1752
  };
@@ -1699,6 +1808,47 @@ class WolfpackMCPServer {
1699
1808
  ],
1700
1809
  };
1701
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
+ }
1702
1852
  default:
1703
1853
  throw new Error(`Unknown tool: ${name}`);
1704
1854
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.38",
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",