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 +68 -57
- package/dist/apiClient.js +26 -0
- package/dist/client.js +13 -0
- package/dist/imageProcessor.js +21 -0
- package/dist/index.js +93 -5
- package/package.json +1 -1
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
|
-
##
|
|
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
|
-
|
|
91
|
-
"
|
|
92
|
-
"
|
|
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
|
|
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,
|
|
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 ``. 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, ``);
|
|
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. ``) 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. ``) 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. ``) 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. ``) 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. ``) 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. ``) 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. ``) 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 ``. ' +
|
|
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
|
}
|