wolfpack-mcp 1.0.27 → 1.0.29

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/README.md CHANGED
@@ -77,24 +77,24 @@ After saving the configuration, restart Claude Desktop to connect.
77
77
  | **Journal** | "Log my standup notes" / "What did I work on last week?" |
78
78
  | **Radar** | "What initiatives are in progress?" / "Show the roadmap" |
79
79
 
80
- ## Multi-Team Users
80
+ ## Multiple Projects
81
81
 
82
- If you belong to multiple teams, Claude will ask which team you mean, or you can specify:
82
+ If you belong to multiple project teams, Claude will ask which team you mean, or you can specify:
83
83
 
84
84
  - "Show my work items for the Platform team"
85
85
  - Use `list_teams` to see all your teams
86
86
 
87
- To pre-select a default team, add to your config:
87
+ To pre-select a default team, add `WOLFPACK_TEAM_SLUG` to your config:
88
88
 
89
89
  ```json
90
- "env": {
91
- "WOLFPACK_API_KEY": "wfp_sk_your_api_key_here",
92
- "WOLFPACK_TEAM_SLUG": "your-team-slug"
90
+ {
91
+ "env": {
92
+ "WOLFPACK_API_KEY": "wfp_sk_your_api_key_here",
93
+ "WOLFPACK_TEAM_SLUG": "your-team-slug"
94
+ }
93
95
  }
94
96
  ```
95
97
 
96
- ## Project Focus
97
-
98
98
  The MCP server is designed to work within **one project at a time**:
99
99
 
100
100
  - The agent will identify which project you're working in before taking actions
@@ -102,53 +102,6 @@ The MCP server is designed to work within **one project at a time**:
102
102
  - The agent will not perform bulk actions across multiple projects
103
103
  - To switch projects, explicitly tell Claude (e.g., "switch to the Platform project")
104
104
 
105
- ## API Key Permissions
106
-
107
- When creating your API key, select the permissions you need:
108
-
109
- | Permission | What It Enables |
110
- | ----------------------- | ------------------------------- |
111
- | `mcp:work_items:read` | View your tasks |
112
- | `mcp:work_items:create` | Create new tasks |
113
- | `mcp:work_items:update` | Update task status and notes |
114
- | `mcp:issues:read` | View issues |
115
- | `mcp:issues:create` | File new issues |
116
- | `mcp:issues:update` | Update issue status and details |
117
- | `mcp:wiki:read` | Read documentation |
118
- | `mcp:wiki:create` | Create new pages |
119
- | `mcp:wiki:update` | Edit existing pages |
120
- | `mcp:journal:read` | View journal entries |
121
- | `mcp:journal:create` | Create journal entries |
122
- | `mcp:journal:update` | Edit journal entries |
123
- | `mcp:comments:create` | Add comments to items |
124
- | `mcp:radar:read` | View initiatives and roadmap |
125
-
126
- ## Troubleshooting
127
-
128
- **"WOLFPACK_API_KEY environment variable is required"**
129
- Check that your Claude Desktop config has the API key set correctly.
130
-
131
- **"Invalid API key format"**
132
- API keys must start with `wfp_sk_` (user keys) or `wfp_ak_` (org-managed agent keys).
133
-
134
- **"Invalid API key"**
135
- Your key may be incorrect or revoked. Generate a new one from Account Settings.
136
-
137
- **"API key does not have permission: mcp:..."**
138
- Create a new key with the required permission enabled.
139
-
140
- **Connection errors**
141
- Verify [wolfpacks.work](https://wolfpacks.work) is accessible from your network.
142
-
143
- ## Security
144
-
145
- - API keys are scoped to your account and team memberships
146
- - Permissions are configurable per key—grant only what you need
147
- - Revoke keys anytime from Account Settings
148
-
149
- For additional security, you can **restrict API keys to specific projects** when creating them in Account Settings. This
150
- ensures the key can only access the projects you select, regardless of your team memberships.
151
-
152
105
  ## Available Tools Reference
153
106
 
154
107
  <details>
@@ -167,10 +120,18 @@ List all teams you have access to.
167
120
 
168
121
  #### `list_work_items`
169
122
 
170
- Lists work items assigned to you (excludes completed by default).
123
+ Lists work items on the Kanban board or backlog (excludes completed/closed by default).
171
124
 
172
125
  - `team_id` (optional): Filter by team
173
- - `status` (optional): Filter by status (new, doing, review, completed, blocked)
126
+ - `status` (optional): Filter by status (new, doing, review, ready, blocked, completed, pending/backlog, all)
127
+ - `assigned_to_id` (optional): Filter by assignee ("all", "me", "unassigned", or a user ID)
128
+ - `search` (optional): Text search in title and description
129
+ - `category_id` (optional): Filter by category ID, or "none" for uncategorized
130
+ - `priority` (optional): Filter by priority level (0-4)
131
+ - `radar_item_id` (optional): Filter by linked radar/initiative item
132
+ - `date_from`, `date_to` (optional): Filter by creation date (ISO format, e.g. "2025-01-01")
133
+ - `sort_by` (optional): Sort field (dateUpdated, dateCreated, priority, title)
134
+ - `sort_order` (optional): Sort direction (desc, asc)
174
135
  - `limit`, `offset` (optional): Pagination
175
136
 
176
137
  #### `get_work_item`
@@ -201,6 +162,20 @@ Change work item status.
201
162
  - `work_item_id` (required): The work item ID
202
163
  - `status` (required): New status
203
164
 
165
+ #### `update_work_item_assignee`
166
+
167
+ Change the assignee on a work item.
168
+
169
+ - `work_item_id` (required): The work item ID
170
+ - `leading_user_id` (required): User ID to assign, or null to unassign
171
+
172
+ #### `pull_work_item`
173
+
174
+ Pull a work item from the backlog to the board (sets status to "new" and assigns to you).
175
+
176
+ - `work_item_id` (required): The work item ID
177
+ - `leading_user_id` (optional): User ID to assign (defaults to API key owner)
178
+
204
179
  ### Issues
205
180
 
206
181
  #### `list_issues`
@@ -208,6 +183,10 @@ Change work item status.
208
183
  List issues (excludes closed by default).
209
184
 
210
185
  - `team_id`, `status`, `severity`, `type`, `assigned_to_id` (optional): Filters
186
+ - `search` (optional): Text search in title and description
187
+ - `date_from`, `date_to` (optional): Filter by creation date (ISO format, e.g. "2025-01-01")
188
+ - `sort_by` (optional): Sort field (dateCreated, dateUpdated, severity, title)
189
+ - `sort_order` (optional): Sort direction (desc, asc)
211
190
  - `limit`, `offset` (optional): Pagination
212
191
 
213
192
  #### `get_issue`
@@ -238,6 +217,8 @@ Update an existing issue.
238
217
 
239
218
  List wiki pages.
240
219
 
220
+ - `search` (optional): Text search in title and content
221
+ - `date_from`, `date_to` (optional): Filter by last updated date (ISO format, e.g. "2025-01-01")
241
222
  - `limit`, `offset` (optional): Pagination
242
223
 
243
224
  #### `get_wiki_page`
@@ -267,6 +248,8 @@ Update an existing wiki page.
267
248
 
268
249
  List journal entries.
269
250
 
251
+ - `search` (optional): Text search in title and content
252
+ - `date_from`, `date_to` (optional): Filter by entry date (ISO format, e.g. "2025-01-01")
270
253
  - `limit`, `offset` (optional): Pagination
271
254
 
272
255
  #### `get_journal_entry`
@@ -293,6 +276,18 @@ Update an existing journal entry.
293
276
 
294
277
  ### Comments
295
278
 
279
+ #### `list_work_item_comments`
280
+
281
+ List all comments on a work item.
282
+
283
+ - `work_item_id` (required): The work item UUID
284
+
285
+ #### `list_issue_comments`
286
+
287
+ List all comments on an issue.
288
+
289
+ - `issue_id` (required): The issue UUID
290
+
296
291
  #### `create_work_item_comment`
297
292
 
298
293
  Add a comment to a work item.
@@ -315,6 +310,7 @@ List radar items/initiatives (excludes completed by default).
315
310
 
316
311
  - `team_id` (optional): Filter by team
317
312
  - `stage` (optional): Filter by stage (pending, now, next, later, completed)
313
+ - `search` (optional): Text search in title and description
318
314
  - `limit`, `offset` (optional): Pagination
319
315
 
320
316
  #### `get_radar_item`
@@ -324,4 +320,19 @@ Get a specific radar item.
324
320
  - `item_id` (required): UUID or reference number
325
321
  - `team_id` (optional): Required when using reference number
326
322
 
323
+ ### Images
324
+
325
+ #### `upload_image`
326
+
327
+ Upload an image file from disk and get back a permanent URL for use in markdown content.
328
+
329
+ - `file_path` (required): Absolute path to an image file (JPEG, PNG, GIF, WebP; max 5MB)
330
+ - `team_id` (optional): Team ID (required for multi-team users)
331
+
332
+ #### `download_image`
333
+
334
+ Download and view an image referenced in content fields. Content from work items, issues, wiki pages, journal entries, and comments may contain image references like `![alt](/api/files/images/...)`. Use this tool with that URL path to view the image.
335
+
336
+ - `image_url` (required): The image URL path (e.g. `/api/files/images/{team}/{filename}`)
337
+
327
338
  </details>
package/dist/apiClient.js CHANGED
@@ -96,6 +96,32 @@ export class ApiClient {
96
96
  throw new Error(`Failed to PATCH ${path}: ${error}`);
97
97
  }
98
98
  }
99
+ async getBuffer(path) {
100
+ const url = `${config.apiUrl}${path}`;
101
+ try {
102
+ const response = await fetch(url, {
103
+ method: 'GET',
104
+ headers: {
105
+ Authorization: `Bearer ${config.apiKey}`,
106
+ },
107
+ });
108
+ if (!response.ok) {
109
+ const errorText = await response.text();
110
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
111
+ }
112
+ const arrayBuffer = await response.arrayBuffer();
113
+ return {
114
+ buffer: Buffer.from(arrayBuffer),
115
+ contentType: response.headers.get('content-type') || 'application/octet-stream',
116
+ };
117
+ }
118
+ catch (error) {
119
+ if (error instanceof ApiError) {
120
+ throw error;
121
+ }
122
+ throw new Error(`Failed to GET buffer ${path}: ${error}`);
123
+ }
124
+ }
99
125
  async postMultipart(path, buffer, filename, mimeType) {
100
126
  const url = `${config.apiUrl}${path}`;
101
127
  const boundary = `----FormBoundary${Date.now()}`;
package/dist/client.js CHANGED
@@ -411,6 +411,12 @@ export class WolfpackClient {
411
411
  return this.api.patch(`/journal-entries/${entryId}`, data);
412
412
  }
413
413
  // Comment methods
414
+ async listWorkItemComments(workItemId) {
415
+ return this.api.get(`/work-items/${workItemId}/comments`);
416
+ }
417
+ async listIssueComments(issueId) {
418
+ return this.api.get(`/issues/${issueId}/comments`);
419
+ }
414
420
  async createWorkItemComment(workItemId, data) {
415
421
  return this.api.post(`/work-items/${workItemId}/comments`, data);
416
422
  }
@@ -424,6 +430,13 @@ export class WolfpackClient {
424
430
  const buffer = Buffer.from(base64Data, 'base64');
425
431
  return this.api.postMultipart(`/teams/${teamSlug}/upload-image`, buffer, filename, mimeType);
426
432
  }
433
+ /**
434
+ * Download an image from the MCP images endpoint and return raw base64 + mimeType.
435
+ */
436
+ async downloadImage(team, filename) {
437
+ const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
438
+ return { base64: buffer.toString('base64'), mimeType: contentType };
439
+ }
427
440
  close() {
428
441
  // No cleanup needed for API client
429
442
  }
@@ -0,0 +1,21 @@
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
+ }
package/dist/index.js CHANGED
@@ -271,6 +271,12 @@ const UpdateJournalEntrySchema = z.object({
271
271
  .describe('Updated content (markdown). Supports base64-encoded images which will be auto-uploaded.'),
272
272
  });
273
273
  // Comment schemas
274
+ const ListWorkItemCommentsSchema = z.object({
275
+ work_item_id: z.string().describe('The work item UUID'),
276
+ });
277
+ const ListIssueCommentsSchema = z.object({
278
+ issue_id: z.string().describe('The issue UUID'),
279
+ });
274
280
  const CreateWorkItemCommentSchema = z.object({
275
281
  work_item_id: z.string().describe('The work item UUID'),
276
282
  content: z
@@ -294,6 +300,11 @@ const UploadImageSchema = z.object({
294
300
  .optional()
295
301
  .describe('Team ID (required for multi-team users, use list_teams to get IDs)'),
296
302
  });
303
+ const DownloadImageSchema = z.object({
304
+ image_url: z
305
+ .string()
306
+ .describe('The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").'),
307
+ });
297
308
  // Helper to detect if a work item description contains a plan
298
309
  function hasPlan(description) {
299
310
  if (!description)
@@ -414,7 +425,8 @@ class WolfpackMCPServer {
414
425
  'Call this before updating to see current content. ' +
415
426
  'WORKFLOW: When asked to work on an item, check its status and follow the required state transitions ' +
416
427
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
417
- '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.',
428
+ '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. ' +
429
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
418
430
  inputSchema: {
419
431
  type: 'object',
420
432
  properties: {
@@ -538,7 +550,8 @@ class WolfpackMCPServer {
538
550
  },
539
551
  {
540
552
  name: 'get_radar_item',
541
- description: 'Get a specific radar item (initiative) by ID or refId, including its work items and participants.',
553
+ description: 'Get a specific radar item (initiative) by ID or refId, including its work items and participants. ' +
554
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
542
555
  inputSchema: {
543
556
  type: 'object',
544
557
  properties: {
@@ -615,7 +628,8 @@ class WolfpackMCPServer {
615
628
  },
616
629
  {
617
630
  name: 'get_issue',
618
- description: 'Get a specific issue by ID or refId, including comment and attachment counts.',
631
+ description: 'Get a specific issue by ID or refId, including comment and attachment counts. ' +
632
+ 'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
619
633
  inputSchema: {
620
634
  type: 'object',
621
635
  properties: {
@@ -750,7 +764,8 @@ class WolfpackMCPServer {
750
764
  },
751
765
  {
752
766
  name: 'get_wiki_page',
753
- description: 'Get a specific wiki/documentation page by ID or slug (URL path). Returns full content in markdown.',
767
+ description: 'Get a specific wiki/documentation page by ID or slug (URL path). Returns full content in markdown. ' +
768
+ 'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
754
769
  inputSchema: {
755
770
  type: 'object',
756
771
  properties: {
@@ -820,7 +835,8 @@ class WolfpackMCPServer {
820
835
  },
821
836
  {
822
837
  name: 'get_journal_entry',
823
- description: 'Get a specific journal/log entry by ID or reference number. Returns full content.',
838
+ description: 'Get a specific journal/log entry by ID or reference number. Returns full content. ' +
839
+ 'IMAGES: Image references in the content (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
824
840
  inputSchema: {
825
841
  type: 'object',
826
842
  properties: {
@@ -866,6 +882,30 @@ class WolfpackMCPServer {
866
882
  },
867
883
  },
868
884
  // Comment tools
885
+ {
886
+ name: 'list_work_item_comments',
887
+ description: 'List all comments on a work item. Returns comments in chronological order. Requires mcp:comments:read permission. ' +
888
+ 'IMAGES: Image references in comments (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
889
+ inputSchema: {
890
+ type: 'object',
891
+ properties: {
892
+ work_item_id: { type: 'string', description: 'The work item UUID' },
893
+ },
894
+ required: ['work_item_id'],
895
+ },
896
+ },
897
+ {
898
+ name: 'list_issue_comments',
899
+ description: 'List all comments on an issue. Returns comments in chronological order. Requires mcp:comments:read permission. ' +
900
+ 'IMAGES: Image references in comments (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
901
+ inputSchema: {
902
+ type: 'object',
903
+ properties: {
904
+ issue_id: { type: 'string', description: 'The issue UUID' },
905
+ },
906
+ required: ['issue_id'],
907
+ },
908
+ },
869
909
  {
870
910
  name: 'create_work_item_comment',
871
911
  description: 'Add a comment to a work item. Requires mcp:comments:create permission. ' +
@@ -923,6 +963,22 @@ class WolfpackMCPServer {
923
963
  required: ['file_path'],
924
964
  },
925
965
  },
966
+ {
967
+ name: 'download_image',
968
+ description: 'Download and view an image referenced in content fields. ' +
969
+ 'Content from work items, issues, wiki pages, journal entries, and comments may contain image references like `![alt](/api/files/images/...)`. ' +
970
+ 'Use this tool with that URL path to download and view the image.',
971
+ inputSchema: {
972
+ type: 'object',
973
+ properties: {
974
+ image_url: {
975
+ type: 'string',
976
+ description: 'The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").',
977
+ },
978
+ },
979
+ required: ['image_url'],
980
+ },
981
+ },
926
982
  ],
927
983
  }));
928
984
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -1324,6 +1380,20 @@ class WolfpackMCPServer {
1324
1380
  };
1325
1381
  }
1326
1382
  // Comment handlers
1383
+ case 'list_work_item_comments': {
1384
+ const parsed = ListWorkItemCommentsSchema.parse(args);
1385
+ const comments = await this.client.listWorkItemComments(parsed.work_item_id);
1386
+ return {
1387
+ content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1388
+ };
1389
+ }
1390
+ case 'list_issue_comments': {
1391
+ const parsed = ListIssueCommentsSchema.parse(args);
1392
+ const comments = await this.client.listIssueComments(parsed.issue_id);
1393
+ return {
1394
+ content: [{ type: 'text', text: JSON.stringify(comments, null, 2) }],
1395
+ };
1396
+ }
1327
1397
  case 'create_work_item_comment': {
1328
1398
  const parsed = CreateWorkItemCommentSchema.parse(args);
1329
1399
  const comment = await this.client.createWorkItemComment(parsed.work_item_id, {
@@ -1391,6 +1461,24 @@ class WolfpackMCPServer {
1391
1461
  ],
1392
1462
  };
1393
1463
  }
1464
+ case 'download_image': {
1465
+ const parsed = DownloadImageSchema.parse(args);
1466
+ const match = parsed.image_url.match(/\/api\/files\/images\/([^/]+)\/(.+)$/);
1467
+ if (!match) {
1468
+ throw new Error('Invalid image URL. Expected format: /api/files/images/{team}/{filename}');
1469
+ }
1470
+ const [, team, filename] = match;
1471
+ const { base64, mimeType } = await this.client.downloadImage(team, filename);
1472
+ return {
1473
+ content: [
1474
+ {
1475
+ type: 'image',
1476
+ data: base64,
1477
+ mimeType,
1478
+ },
1479
+ ],
1480
+ };
1481
+ }
1394
1482
  default:
1395
1483
  throw new Error(`Unknown tool: ${name}`);
1396
1484
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",