wolfpack-mcp 1.0.60 → 1.0.61

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
@@ -469,6 +469,14 @@ export class WolfpackClient {
469
469
  const query = params.toString();
470
470
  return this.api.get(`/categories${query ? `?${query}` : ''}`);
471
471
  }
472
+ // Tag methods
473
+ async listTags(teamSlug) {
474
+ const params = new URLSearchParams();
475
+ if (teamSlug)
476
+ params.append('teamSlug', teamSlug);
477
+ const query = params.toString();
478
+ return this.api.get(`/tags${query ? `?${query}` : ''}`);
479
+ }
472
480
  /**
473
481
  * Upload an image and get back a URL that can be used in markdown content.
474
482
  */
@@ -483,6 +491,14 @@ export class WolfpackClient {
483
491
  const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
484
492
  return { base64: buffer.toString('base64'), mimeType: contentType };
485
493
  }
494
+ /**
495
+ * Download a stored file (new /api/files/{fileId}/{filename} URL shape) and
496
+ * return raw base64 + mimeType.
497
+ */
498
+ async downloadFile(fileId) {
499
+ const { buffer, contentType } = await this.api.getBuffer(`/files/${fileId}`);
500
+ return { base64: buffer.toString('base64'), mimeType: contentType };
501
+ }
486
502
  /**
487
503
  * Download an issue attachment image and return raw base64 + mimeType.
488
504
  */
package/dist/index.js CHANGED
@@ -166,7 +166,10 @@ const UpdateWorkItemSchema = z.object({
166
166
  .nullable()
167
167
  .optional()
168
168
  .describe('User ID for third assisting user, or null to remove'),
169
- tag_ids: z.array(z.string()).optional().describe('Tag IDs to apply (replaces existing tags)'),
169
+ tags: z
170
+ .array(z.string())
171
+ .optional()
172
+ .describe('Tag names to apply (replaces existing tags). Use list_tags to see available tags.'),
170
173
  closing_comment: z
171
174
  .string()
172
175
  .nullable()
@@ -488,7 +491,7 @@ const UploadImageSchema = z.object({
488
491
  const DownloadImageSchema = z.object({
489
492
  image_url: z
490
493
  .string()
491
- .describe('The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").'),
494
+ .describe('The image URL path found in content fields (e.g. "/api/files/{fileId}/{filename}" or legacy "/api/files/images/{team}/{filename}").'),
492
495
  });
493
496
  // Skill schemas
494
497
  const GetSkillSchema = z.object({
@@ -505,6 +508,13 @@ const ListCategoriesSchema = z.object({
505
508
  .optional()
506
509
  .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
507
510
  });
511
+ // Tag schemas
512
+ const ListTagsSchema = z.object({
513
+ project_slug: z
514
+ .string()
515
+ .optional()
516
+ .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
517
+ });
508
518
  // Team member schemas
509
519
  const ListTeamMembersSchema = z.object({
510
520
  project_slug: z
@@ -748,7 +758,7 @@ class WolfpackMCPServer {
748
758
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
749
759
  '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. ' +
750
760
  '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. ' +
751
- 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
761
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
752
762
  inputSchema: {
753
763
  type: 'object',
754
764
  properties: {
@@ -790,7 +800,7 @@ class WolfpackMCPServer {
790
800
  name: 'update_work_item',
791
801
  description: 'Update one or more fields on a work item. Only provide the fields you want to change. ' +
792
802
  'Supports: title, description, status, leading_user_id (assignee), assisting_user1/2/3_id, ' +
793
- 'radar_item_id (initiative), category_id, priority (0-4), size (S/M/L), tag_ids, and closing_comment. ' +
803
+ 'radar_item_id (initiative), category_id, priority (0-4), size (S/M/L), tags, and closing_comment. ' +
794
804
  'STATUS WORKFLOW: "pending" (backlog) → "new" (to do) → "doing" (in progress) → "review" (work done) → "ready" (awaiting deployment) → "completed" (deployed). ' +
795
805
  'Use "blocked" when work cannot proceed. For "pending" items use pull_work_item first. ' +
796
806
  'When moving to "review", add a completion comment. When moving to "blocked", add a comment explaining the blocker.',
@@ -857,10 +867,10 @@ class WolfpackMCPServer {
857
867
  type: ['string', 'null'],
858
868
  description: 'User ID for third assisting user, or null to remove',
859
869
  },
860
- tag_ids: {
870
+ tags: {
861
871
  type: 'array',
862
872
  items: { type: 'string' },
863
- description: 'Tag IDs to apply (replaces existing tags)',
873
+ description: 'Tag names to apply (replaces existing tags). Use list_tags to see available tags.',
864
874
  },
865
875
  closing_comment: {
866
876
  type: ['string', 'null'],
@@ -953,7 +963,7 @@ class WolfpackMCPServer {
953
963
  {
954
964
  name: 'get_radar_item',
955
965
  description: 'Get a specific radar item (initiative) by reference number, including its work items and participants. ' +
956
- 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
966
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
957
967
  inputSchema: {
958
968
  type: 'object',
959
969
  properties: {
@@ -1086,7 +1096,7 @@ class WolfpackMCPServer {
1086
1096
  description: 'Get a specific issue by its PREFIXED reference #iN (e.g. #i5). ' +
1087
1097
  'IMPORTANT: A bare #N (without prefix) is ALWAYS a work item, NOT an issue. Only use this tool when the user explicitly says "issue" or uses the #i prefix. ' +
1088
1098
  'Returns full details including comment and attachment counts. ' +
1089
- 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1099
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
1090
1100
  inputSchema: {
1091
1101
  type: 'object',
1092
1102
  properties: {
@@ -1271,7 +1281,7 @@ class WolfpackMCPServer {
1271
1281
  {
1272
1282
  name: 'get_wiki_page',
1273
1283
  description: 'Get a specific wiki/documentation page by slug (URL path). Returns full content in markdown. ' +
1274
- 'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1284
+ 'IMAGES: Image references in the content (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
1275
1285
  inputSchema: {
1276
1286
  type: 'object',
1277
1287
  properties: {
@@ -1323,7 +1333,7 @@ class WolfpackMCPServer {
1323
1333
  tag_ids: {
1324
1334
  type: 'array',
1325
1335
  items: { type: 'string' },
1326
- description: 'Tag IDs to apply to the page (replaces existing tags). Use list tags endpoint to get available tag IDs.',
1336
+ description: 'Tag IDs to apply to the page (replaces existing tags)',
1327
1337
  },
1328
1338
  project_slug: {
1329
1339
  type: 'string',
@@ -1364,7 +1374,7 @@ class WolfpackMCPServer {
1364
1374
  {
1365
1375
  name: 'get_journal_entry',
1366
1376
  description: 'Get a specific journal/log entry by reference number. Returns full content. ' +
1367
- 'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1377
+ 'IMAGES: Image references in the content (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
1368
1378
  inputSchema: {
1369
1379
  type: 'object',
1370
1380
  properties: {
@@ -1427,7 +1437,7 @@ class WolfpackMCPServer {
1427
1437
  {
1428
1438
  name: 'list_work_item_comments',
1429
1439
  description: 'List all comments on a work item. Returns comments in chronological order. Requires mcp:comments:read permission. ' +
1430
- 'IMAGES: Image references in comments (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1440
+ 'IMAGES: Image references in comments (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
1431
1441
  inputSchema: {
1432
1442
  type: 'object',
1433
1443
  properties: {
@@ -1443,7 +1453,7 @@ class WolfpackMCPServer {
1443
1453
  {
1444
1454
  name: 'list_issue_comments',
1445
1455
  description: 'List all comments on an issue. Returns comments in chronological order. Requires mcp:comments:read permission. ' +
1446
- 'IMAGES: Image references in comments (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
1456
+ 'IMAGES: Image references in comments (e.g. `![alt](/api/files/...)`) can be viewed using the download_image tool.',
1447
1457
  inputSchema: {
1448
1458
  type: 'object',
1449
1459
  properties: {
@@ -1563,7 +1573,7 @@ class WolfpackMCPServer {
1563
1573
  {
1564
1574
  name: 'download_image',
1565
1575
  description: 'Download and view an image referenced in content fields. ' +
1566
- 'Content from work items, issues, wiki pages, journal entries, and comments may contain image references like `![alt](/api/files/images/...)`. ' +
1576
+ 'Content from work items, issues, wiki pages, journal entries, and comments may contain image references like `![alt](/api/files/{fileId}/...)` or the legacy `![alt](/api/files/images/...)`. ' +
1567
1577
  'Issues may also have attachment images with URLs like `/api/teams/{team}/issues/{refId}/attachments/{id}`. ' +
1568
1578
  'Use this tool with that URL path to download and view the image. ' +
1569
1579
  'Requires mcp:images:read permission.',
@@ -1572,7 +1582,7 @@ class WolfpackMCPServer {
1572
1582
  properties: {
1573
1583
  image_url: {
1574
1584
  type: 'string',
1575
- description: 'The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}" or "/api/teams/{team}/issues/{refId}/attachments/{id}").',
1585
+ description: 'The image URL path found in content fields (e.g. "/api/files/{fileId}/{filename}", legacy "/api/files/images/{team}/{filename}", or "/api/teams/{team}/issues/{refId}/attachments/{id}").',
1576
1586
  },
1577
1587
  },
1578
1588
  required: ['image_url'],
@@ -1593,6 +1603,21 @@ class WolfpackMCPServer {
1593
1603
  },
1594
1604
  },
1595
1605
  },
1606
+ // Tag tools
1607
+ {
1608
+ name: 'list_tags',
1609
+ description: 'List all tags available in a project. Returns tag names and colours. ' +
1610
+ 'Work items are tagged by name via update_work_item.',
1611
+ inputSchema: {
1612
+ type: 'object',
1613
+ properties: {
1614
+ project_slug: {
1615
+ type: 'string',
1616
+ description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1617
+ },
1618
+ },
1619
+ },
1620
+ },
1596
1621
  // Team member tools
1597
1622
  {
1598
1623
  name: 'list_team_members',
@@ -2029,8 +2054,8 @@ class WolfpackMCPServer {
2029
2054
  fields.assistingUser2Id = parsed.assisting_user2_id;
2030
2055
  if (parsed.assisting_user3_id !== undefined)
2031
2056
  fields.assistingUser3Id = parsed.assisting_user3_id;
2032
- if (parsed.tag_ids !== undefined)
2033
- fields.tagIds = parsed.tag_ids;
2057
+ if (parsed.tags !== undefined)
2058
+ fields.tags = parsed.tags;
2034
2059
  if (parsed.closing_comment !== undefined)
2035
2060
  fields.closingComment = parsed.closing_comment;
2036
2061
  const workItem = await this.client.updateWorkItem(parsed.work_item_id, fields, teamSlug);
@@ -2077,7 +2102,7 @@ class WolfpackMCPServer {
2077
2102
  changes.push(parsed.assisting_user3_id
2078
2103
  ? `assisting user 3 updated`
2079
2104
  : 'assisting user 3 removed');
2080
- if (parsed.tag_ids !== undefined)
2105
+ if (parsed.tags !== undefined)
2081
2106
  changes.push('tags updated');
2082
2107
  if (parsed.closing_comment !== undefined)
2083
2108
  changes.push('closing comment set');
@@ -2557,13 +2582,18 @@ class WolfpackMCPServer {
2557
2582
  }
2558
2583
  case 'download_image': {
2559
2584
  const parsed = DownloadImageSchema.parse(args);
2560
- // Try S3-stored image pattern: /api/files/images/{team}/{filename}
2585
+ // Try stored-file pattern (#1439): /api/files/{fileId}/{filename}
2586
+ const storedFileMatch = parsed.image_url.match(/\/api\/files\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\/|$)/i);
2587
+ // Try legacy S3-stored image pattern: /api/files/images/{team}/{filename}
2561
2588
  const s3Match = parsed.image_url.match(/\/api\/files\/images\/([^/]+)\/(.+)$/);
2562
2589
  // Try issue attachment pattern: /api/teams/{team}/issues/{refId}/attachments/{id}
2563
2590
  const attachmentMatch = parsed.image_url.match(/\/api\/teams\/([^/]+)\/issues\/(\d+)\/attachments\/([^/]+)$/);
2564
2591
  let base64;
2565
2592
  let mimeType;
2566
- if (s3Match) {
2593
+ if (storedFileMatch) {
2594
+ ({ base64, mimeType } = await this.client.downloadFile(storedFileMatch[1]));
2595
+ }
2596
+ else if (s3Match) {
2567
2597
  const [, team, filename] = s3Match;
2568
2598
  ({ base64, mimeType } = await this.client.downloadImage(team, filename));
2569
2599
  }
@@ -2572,7 +2602,7 @@ class WolfpackMCPServer {
2572
2602
  ({ base64, mimeType } = await this.client.downloadIssueAttachment(team, refId, attachmentId));
2573
2603
  }
2574
2604
  else {
2575
- throw new Error('Invalid image URL. Expected format: /api/files/images/{team}/{filename} or /api/teams/{team}/issues/{refId}/attachments/{id}');
2605
+ throw new Error('Invalid image URL. Expected format: /api/files/{fileId}/{filename}, /api/files/images/{team}/{filename} or /api/teams/{team}/issues/{refId}/attachments/{id}');
2576
2606
  }
2577
2607
  return {
2578
2608
  content: [
@@ -2592,6 +2622,14 @@ class WolfpackMCPServer {
2592
2622
  content: [{ type: 'text', text: JSON.stringify(categories, null, 2) }],
2593
2623
  };
2594
2624
  }
2625
+ // Tag handlers
2626
+ case 'list_tags': {
2627
+ const parsed = ListTagsSchema.parse(args);
2628
+ const tags = await this.client.listTags(parsed.project_slug || this.client.getProjectSlug() || undefined);
2629
+ return {
2630
+ content: [{ type: 'text', text: JSON.stringify(tags, null, 2) }],
2631
+ };
2632
+ }
2595
2633
  // Team member handlers
2596
2634
  case 'list_team_members': {
2597
2635
  const parsed = ListTeamMembersSchema.parse(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,21 +0,0 @@
1
- const IMAGE_URL_REGEX = /!\[([^\]]*)\]\(\/api\/files\/images\/([^/]+)\/([^)]+)\)/g;
2
- /**
3
- * Processes markdown content to replace image URLs with base64 data URIs.
4
- * Failed fetches or oversized images leave the original URL intact.
5
- */
6
- export async function processContentImages(content, client) {
7
- if (!content)
8
- return content;
9
- const matches = [...content.matchAll(IMAGE_URL_REGEX)];
10
- if (matches.length === 0)
11
- return content;
12
- let result = content;
13
- for (const match of matches) {
14
- const [fullMatch, alt, team, filename] = match;
15
- const dataUri = await client.fetchImageAsBase64(team, filename);
16
- if (dataUri) {
17
- result = result.replace(fullMatch, `![${alt}](${dataUri})`);
18
- }
19
- }
20
- return result;
21
- }