wolfpack-mcp 1.0.60 → 1.0.62
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 +27 -0
- package/dist/index.js +146 -27
- package/package.json +1 -1
- package/dist/imageProcessor.js +0 -21
package/dist/client.js
CHANGED
|
@@ -60,6 +60,17 @@ export class WolfpackClient {
|
|
|
60
60
|
const response = await this.api.get('/teams');
|
|
61
61
|
return response.teams;
|
|
62
62
|
}
|
|
63
|
+
// Search methods
|
|
64
|
+
async search(options) {
|
|
65
|
+
const params = new URLSearchParams({ q: options.query });
|
|
66
|
+
if (options.teamSlug)
|
|
67
|
+
params.append('teamSlug', options.teamSlug);
|
|
68
|
+
if (options.includeInactive)
|
|
69
|
+
params.append('includeInactive', 'true');
|
|
70
|
+
if (options.exactOnly)
|
|
71
|
+
params.append('exactOnly', 'true');
|
|
72
|
+
return this.api.get(`/search?${params.toString()}`);
|
|
73
|
+
}
|
|
63
74
|
// Team Member methods
|
|
64
75
|
async listTeamMembers(teamSlug) {
|
|
65
76
|
const params = new URLSearchParams();
|
|
@@ -469,6 +480,14 @@ export class WolfpackClient {
|
|
|
469
480
|
const query = params.toString();
|
|
470
481
|
return this.api.get(`/categories${query ? `?${query}` : ''}`);
|
|
471
482
|
}
|
|
483
|
+
// Tag methods
|
|
484
|
+
async listTags(teamSlug) {
|
|
485
|
+
const params = new URLSearchParams();
|
|
486
|
+
if (teamSlug)
|
|
487
|
+
params.append('teamSlug', teamSlug);
|
|
488
|
+
const query = params.toString();
|
|
489
|
+
return this.api.get(`/tags${query ? `?${query}` : ''}`);
|
|
490
|
+
}
|
|
472
491
|
/**
|
|
473
492
|
* Upload an image and get back a URL that can be used in markdown content.
|
|
474
493
|
*/
|
|
@@ -483,6 +502,14 @@ export class WolfpackClient {
|
|
|
483
502
|
const { buffer, contentType } = await this.api.getBuffer(`/images/${team}/${filename}`);
|
|
484
503
|
return { base64: buffer.toString('base64'), mimeType: contentType };
|
|
485
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Download a stored file (new /api/files/{fileId}/{filename} URL shape) and
|
|
507
|
+
* return raw base64 + mimeType.
|
|
508
|
+
*/
|
|
509
|
+
async downloadFile(fileId) {
|
|
510
|
+
const { buffer, contentType } = await this.api.getBuffer(`/files/${fileId}`);
|
|
511
|
+
return { base64: buffer.toString('base64'), mimeType: contentType };
|
|
512
|
+
}
|
|
486
513
|
/**
|
|
487
514
|
* Download an issue attachment image and return raw base64 + mimeType.
|
|
488
515
|
*/
|
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
|
-
|
|
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()
|
|
@@ -217,7 +220,14 @@ const CreateRadarItemSchema = z.object({
|
|
|
217
220
|
.optional()
|
|
218
221
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
219
222
|
title: z.string().describe('Title of the radar/initiative item'),
|
|
220
|
-
description: z
|
|
223
|
+
description: z
|
|
224
|
+
.string()
|
|
225
|
+
.optional()
|
|
226
|
+
.describe('Short summary shown on the roadmap card (1-2 sentences). Put extended detail in notes, not here.'),
|
|
227
|
+
notes: z
|
|
228
|
+
.string()
|
|
229
|
+
.optional()
|
|
230
|
+
.describe("Extended details shown on the initiative's Notes page (markdown). Use this for long-form content."),
|
|
221
231
|
stage: z
|
|
222
232
|
.enum(['pending', 'now', 'next', 'later', 'completed'])
|
|
223
233
|
.describe('Stage: "pending" (not started), "now" (current sprint), "next" (upcoming), "later" (future), "completed"'),
|
|
@@ -225,8 +235,11 @@ const CreateRadarItemSchema = z.object({
|
|
|
225
235
|
const UpdateRadarItemSchema = z.object({
|
|
226
236
|
item_id: z.string().describe('The refId (number) of the radar item to update'),
|
|
227
237
|
title: z.string().optional().describe('Updated title'),
|
|
228
|
-
description: z
|
|
229
|
-
|
|
238
|
+
description: z
|
|
239
|
+
.string()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe('Updated short summary (1-2 sentences; extended detail belongs in notes)'),
|
|
242
|
+
notes: z.string().optional().describe('Updated Notes page content (markdown)'),
|
|
230
243
|
stage: z
|
|
231
244
|
.enum(['pending', 'now', 'next', 'later', 'completed'])
|
|
232
245
|
.optional()
|
|
@@ -343,6 +356,22 @@ const UpdateIssueSchema = z.object({
|
|
|
343
356
|
.optional()
|
|
344
357
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
345
358
|
});
|
|
359
|
+
// Search schema
|
|
360
|
+
const SearchSchema = z.object({
|
|
361
|
+
query: z.string().describe('Search query (websearch syntax: quoted phrases, -exclusions)'),
|
|
362
|
+
project_slug: z
|
|
363
|
+
.string()
|
|
364
|
+
.optional()
|
|
365
|
+
.describe('Project slug; omit to search all accessible projects'),
|
|
366
|
+
include_inactive: z
|
|
367
|
+
.boolean()
|
|
368
|
+
.optional()
|
|
369
|
+
.describe('Include finished/archived items (default false)'),
|
|
370
|
+
exact_only: z
|
|
371
|
+
.boolean()
|
|
372
|
+
.optional()
|
|
373
|
+
.describe('Only exact full-text matches, skipping semantic results (default false)'),
|
|
374
|
+
});
|
|
346
375
|
// Wiki Page schemas
|
|
347
376
|
const ListWikiPagesSchema = z.object({
|
|
348
377
|
project_slug: z.string().optional().describe('Project slug to filter wiki pages'),
|
|
@@ -488,7 +517,7 @@ const UploadImageSchema = z.object({
|
|
|
488
517
|
const DownloadImageSchema = z.object({
|
|
489
518
|
image_url: z
|
|
490
519
|
.string()
|
|
491
|
-
.describe('The image URL path found in content fields (e.g. "/api/files/images/{team}/{filename}").'),
|
|
520
|
+
.describe('The image URL path found in content fields (e.g. "/api/files/{fileId}/{filename}" or legacy "/api/files/images/{team}/{filename}").'),
|
|
492
521
|
});
|
|
493
522
|
// Skill schemas
|
|
494
523
|
const GetSkillSchema = z.object({
|
|
@@ -505,6 +534,13 @@ const ListCategoriesSchema = z.object({
|
|
|
505
534
|
.optional()
|
|
506
535
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
507
536
|
});
|
|
537
|
+
// Tag schemas
|
|
538
|
+
const ListTagsSchema = z.object({
|
|
539
|
+
project_slug: z
|
|
540
|
+
.string()
|
|
541
|
+
.optional()
|
|
542
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
543
|
+
});
|
|
508
544
|
// Team member schemas
|
|
509
545
|
const ListTeamMembersSchema = z.object({
|
|
510
546
|
project_slug: z
|
|
@@ -671,6 +707,36 @@ class WolfpackMCPServer {
|
|
|
671
707
|
properties: {},
|
|
672
708
|
},
|
|
673
709
|
},
|
|
710
|
+
// Search tool
|
|
711
|
+
{
|
|
712
|
+
name: 'search',
|
|
713
|
+
description: 'Ranked full-text search across project content: wiki pages, work items, cases, journal entries and issues. ' +
|
|
714
|
+
'Title matches outrank body matches; results include a snippet, entity type, and refId/slug for follow-up calls ' +
|
|
715
|
+
'(get_work_item, get_issue, get_wiki_page, ...). ' +
|
|
716
|
+
'Use this to find existing content before creating new items, or when the user asks to "find" or "look up" something without saying where it lives.',
|
|
717
|
+
inputSchema: {
|
|
718
|
+
type: 'object',
|
|
719
|
+
properties: {
|
|
720
|
+
query: {
|
|
721
|
+
type: 'string',
|
|
722
|
+
description: 'Search query (websearch syntax: quoted phrases, -exclusions)',
|
|
723
|
+
},
|
|
724
|
+
project_slug: {
|
|
725
|
+
type: 'string',
|
|
726
|
+
description: 'Project slug; omit to search all accessible projects',
|
|
727
|
+
},
|
|
728
|
+
include_inactive: {
|
|
729
|
+
type: 'boolean',
|
|
730
|
+
description: 'Include finished/archived items (default false)',
|
|
731
|
+
},
|
|
732
|
+
exact_only: {
|
|
733
|
+
type: 'boolean',
|
|
734
|
+
description: 'Only exact full-text matches, skipping semantic results (default false)',
|
|
735
|
+
},
|
|
736
|
+
},
|
|
737
|
+
required: ['query'],
|
|
738
|
+
},
|
|
739
|
+
},
|
|
674
740
|
// Work Item tools
|
|
675
741
|
{
|
|
676
742
|
name: 'list_work_items',
|
|
@@ -748,7 +814,7 @@ class WolfpackMCPServer {
|
|
|
748
814
|
'(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
|
|
749
815
|
'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
816
|
'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. ``) can be viewed using the download_image tool.',
|
|
752
818
|
inputSchema: {
|
|
753
819
|
type: 'object',
|
|
754
820
|
properties: {
|
|
@@ -790,7 +856,7 @@ class WolfpackMCPServer {
|
|
|
790
856
|
name: 'update_work_item',
|
|
791
857
|
description: 'Update one or more fields on a work item. Only provide the fields you want to change. ' +
|
|
792
858
|
'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),
|
|
859
|
+
'radar_item_id (initiative), category_id, priority (0-4), size (S/M/L), tags, and closing_comment. ' +
|
|
794
860
|
'STATUS WORKFLOW: "pending" (backlog) → "new" (to do) → "doing" (in progress) → "review" (work done) → "ready" (awaiting deployment) → "completed" (deployed). ' +
|
|
795
861
|
'Use "blocked" when work cannot proceed. For "pending" items use pull_work_item first. ' +
|
|
796
862
|
'When moving to "review", add a completion comment. When moving to "blocked", add a comment explaining the blocker.',
|
|
@@ -857,10 +923,10 @@ class WolfpackMCPServer {
|
|
|
857
923
|
type: ['string', 'null'],
|
|
858
924
|
description: 'User ID for third assisting user, or null to remove',
|
|
859
925
|
},
|
|
860
|
-
|
|
926
|
+
tags: {
|
|
861
927
|
type: 'array',
|
|
862
928
|
items: { type: 'string' },
|
|
863
|
-
description: 'Tag
|
|
929
|
+
description: 'Tag names to apply (replaces existing tags). Use list_tags to see available tags.',
|
|
864
930
|
},
|
|
865
931
|
closing_comment: {
|
|
866
932
|
type: ['string', 'null'],
|
|
@@ -953,7 +1019,7 @@ class WolfpackMCPServer {
|
|
|
953
1019
|
{
|
|
954
1020
|
name: 'get_radar_item',
|
|
955
1021
|
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. ``) can be viewed using the download_image tool.',
|
|
957
1023
|
inputSchema: {
|
|
958
1024
|
type: 'object',
|
|
959
1025
|
properties: {
|
|
@@ -972,6 +1038,7 @@ class WolfpackMCPServer {
|
|
|
972
1038
|
{
|
|
973
1039
|
name: 'create_radar_item',
|
|
974
1040
|
description: 'Create a new radar/initiative item in your current project. Requires mcp:radar:create permission. ' +
|
|
1041
|
+
'Keep "description" to a short summary; put extended detail in "notes". ' +
|
|
975
1042
|
CONTENT_LINKING_HELP,
|
|
976
1043
|
inputSchema: {
|
|
977
1044
|
type: 'object',
|
|
@@ -983,7 +1050,11 @@ class WolfpackMCPServer {
|
|
|
983
1050
|
title: { type: 'string', description: 'Title of the radar/initiative item' },
|
|
984
1051
|
description: {
|
|
985
1052
|
type: 'string',
|
|
986
|
-
description: '
|
|
1053
|
+
description: 'Short summary shown on the roadmap card (1-2 sentences). Put extended detail in notes, not here.',
|
|
1054
|
+
},
|
|
1055
|
+
notes: {
|
|
1056
|
+
type: 'string',
|
|
1057
|
+
description: "Extended details shown on the initiative's Notes page (markdown). Use this for long-form content.",
|
|
987
1058
|
},
|
|
988
1059
|
stage: {
|
|
989
1060
|
type: 'string',
|
|
@@ -1006,8 +1077,11 @@ class WolfpackMCPServer {
|
|
|
1006
1077
|
description: 'The refId (number) of the radar item to update',
|
|
1007
1078
|
},
|
|
1008
1079
|
title: { type: 'string', description: 'Updated title' },
|
|
1009
|
-
description: {
|
|
1010
|
-
|
|
1080
|
+
description: {
|
|
1081
|
+
type: 'string',
|
|
1082
|
+
description: 'Updated short summary (1-2 sentences; extended detail belongs in notes)',
|
|
1083
|
+
},
|
|
1084
|
+
notes: { type: 'string', description: 'Updated Notes page content (markdown)' },
|
|
1011
1085
|
stage: {
|
|
1012
1086
|
type: 'string',
|
|
1013
1087
|
enum: ['pending', 'now', 'next', 'later', 'completed'],
|
|
@@ -1086,7 +1160,7 @@ class WolfpackMCPServer {
|
|
|
1086
1160
|
description: 'Get a specific issue by its PREFIXED reference #iN (e.g. #i5). ' +
|
|
1087
1161
|
'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
1162
|
'Returns full details including comment and attachment counts. ' +
|
|
1089
|
-
'IMAGES: Image references in the description (e.g. ``) can be viewed using the download_image tool.',
|
|
1090
1164
|
inputSchema: {
|
|
1091
1165
|
type: 'object',
|
|
1092
1166
|
properties: {
|
|
@@ -1271,7 +1345,7 @@ class WolfpackMCPServer {
|
|
|
1271
1345
|
{
|
|
1272
1346
|
name: 'get_wiki_page',
|
|
1273
1347
|
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. ``) can be viewed using the download_image tool.',
|
|
1275
1349
|
inputSchema: {
|
|
1276
1350
|
type: 'object',
|
|
1277
1351
|
properties: {
|
|
@@ -1323,7 +1397,7 @@ class WolfpackMCPServer {
|
|
|
1323
1397
|
tag_ids: {
|
|
1324
1398
|
type: 'array',
|
|
1325
1399
|
items: { type: 'string' },
|
|
1326
|
-
description: 'Tag IDs to apply to the page (replaces existing tags)
|
|
1400
|
+
description: 'Tag IDs to apply to the page (replaces existing tags)',
|
|
1327
1401
|
},
|
|
1328
1402
|
project_slug: {
|
|
1329
1403
|
type: 'string',
|
|
@@ -1364,7 +1438,7 @@ class WolfpackMCPServer {
|
|
|
1364
1438
|
{
|
|
1365
1439
|
name: 'get_journal_entry',
|
|
1366
1440
|
description: 'Get a specific journal/log entry by reference number. Returns full content. ' +
|
|
1367
|
-
'IMAGES: Image references in the content (e.g. ``) can be viewed using the download_image tool.',
|
|
1368
1442
|
inputSchema: {
|
|
1369
1443
|
type: 'object',
|
|
1370
1444
|
properties: {
|
|
@@ -1427,7 +1501,7 @@ class WolfpackMCPServer {
|
|
|
1427
1501
|
{
|
|
1428
1502
|
name: 'list_work_item_comments',
|
|
1429
1503
|
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. ``) can be viewed using the download_image tool.',
|
|
1431
1505
|
inputSchema: {
|
|
1432
1506
|
type: 'object',
|
|
1433
1507
|
properties: {
|
|
@@ -1443,7 +1517,7 @@ class WolfpackMCPServer {
|
|
|
1443
1517
|
{
|
|
1444
1518
|
name: 'list_issue_comments',
|
|
1445
1519
|
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. ``) can be viewed using the download_image tool.',
|
|
1447
1521
|
inputSchema: {
|
|
1448
1522
|
type: 'object',
|
|
1449
1523
|
properties: {
|
|
@@ -1563,7 +1637,7 @@ class WolfpackMCPServer {
|
|
|
1563
1637
|
{
|
|
1564
1638
|
name: 'download_image',
|
|
1565
1639
|
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 ``. ' +
|
|
1640
|
+
'Content from work items, issues, wiki pages, journal entries, and comments may contain image references like `` or the legacy ``. ' +
|
|
1567
1641
|
'Issues may also have attachment images with URLs like `/api/teams/{team}/issues/{refId}/attachments/{id}`. ' +
|
|
1568
1642
|
'Use this tool with that URL path to download and view the image. ' +
|
|
1569
1643
|
'Requires mcp:images:read permission.',
|
|
@@ -1572,7 +1646,7 @@ class WolfpackMCPServer {
|
|
|
1572
1646
|
properties: {
|
|
1573
1647
|
image_url: {
|
|
1574
1648
|
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}").',
|
|
1649
|
+
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
1650
|
},
|
|
1577
1651
|
},
|
|
1578
1652
|
required: ['image_url'],
|
|
@@ -1593,6 +1667,21 @@ class WolfpackMCPServer {
|
|
|
1593
1667
|
},
|
|
1594
1668
|
},
|
|
1595
1669
|
},
|
|
1670
|
+
// Tag tools
|
|
1671
|
+
{
|
|
1672
|
+
name: 'list_tags',
|
|
1673
|
+
description: 'List all tags available in a project. Returns tag names and colours. ' +
|
|
1674
|
+
'Work items are tagged by name via update_work_item.',
|
|
1675
|
+
inputSchema: {
|
|
1676
|
+
type: 'object',
|
|
1677
|
+
properties: {
|
|
1678
|
+
project_slug: {
|
|
1679
|
+
type: 'string',
|
|
1680
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1681
|
+
},
|
|
1682
|
+
},
|
|
1683
|
+
},
|
|
1684
|
+
},
|
|
1596
1685
|
// Team member tools
|
|
1597
1686
|
{
|
|
1598
1687
|
name: 'list_team_members',
|
|
@@ -1929,6 +2018,22 @@ class WolfpackMCPServer {
|
|
|
1929
2018
|
],
|
|
1930
2019
|
};
|
|
1931
2020
|
}
|
|
2021
|
+
// Search handler
|
|
2022
|
+
case 'search': {
|
|
2023
|
+
const parsed = SearchSchema.parse(args);
|
|
2024
|
+
const results = await this.client.search({
|
|
2025
|
+
query: parsed.query,
|
|
2026
|
+
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
2027
|
+
includeInactive: parsed.include_inactive,
|
|
2028
|
+
exactOnly: parsed.exact_only,
|
|
2029
|
+
});
|
|
2030
|
+
const text = results.length === 0
|
|
2031
|
+
? 'No results found.'
|
|
2032
|
+
: JSON.stringify(stripUuids(results), null, 2);
|
|
2033
|
+
return {
|
|
2034
|
+
content: [{ type: 'text', text }],
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
1932
2037
|
// Work Item handlers
|
|
1933
2038
|
case 'list_work_items': {
|
|
1934
2039
|
const parsed = ListWorkItemsSchema.parse(args);
|
|
@@ -2029,8 +2134,8 @@ class WolfpackMCPServer {
|
|
|
2029
2134
|
fields.assistingUser2Id = parsed.assisting_user2_id;
|
|
2030
2135
|
if (parsed.assisting_user3_id !== undefined)
|
|
2031
2136
|
fields.assistingUser3Id = parsed.assisting_user3_id;
|
|
2032
|
-
if (parsed.
|
|
2033
|
-
fields.
|
|
2137
|
+
if (parsed.tags !== undefined)
|
|
2138
|
+
fields.tags = parsed.tags;
|
|
2034
2139
|
if (parsed.closing_comment !== undefined)
|
|
2035
2140
|
fields.closingComment = parsed.closing_comment;
|
|
2036
2141
|
const workItem = await this.client.updateWorkItem(parsed.work_item_id, fields, teamSlug);
|
|
@@ -2077,7 +2182,7 @@ class WolfpackMCPServer {
|
|
|
2077
2182
|
changes.push(parsed.assisting_user3_id
|
|
2078
2183
|
? `assisting user 3 updated`
|
|
2079
2184
|
: 'assisting user 3 removed');
|
|
2080
|
-
if (parsed.
|
|
2185
|
+
if (parsed.tags !== undefined)
|
|
2081
2186
|
changes.push('tags updated');
|
|
2082
2187
|
if (parsed.closing_comment !== undefined)
|
|
2083
2188
|
changes.push('closing comment set');
|
|
@@ -2168,6 +2273,7 @@ class WolfpackMCPServer {
|
|
|
2168
2273
|
const radarItem = await this.client.createRadarItem({
|
|
2169
2274
|
title: parsed.title,
|
|
2170
2275
|
description: parsed.description,
|
|
2276
|
+
notes: parsed.notes,
|
|
2171
2277
|
stage: parsed.stage,
|
|
2172
2278
|
teamSlug: parsed.project_slug || this.client.getProjectSlug() || undefined,
|
|
2173
2279
|
});
|
|
@@ -2557,13 +2663,18 @@ class WolfpackMCPServer {
|
|
|
2557
2663
|
}
|
|
2558
2664
|
case 'download_image': {
|
|
2559
2665
|
const parsed = DownloadImageSchema.parse(args);
|
|
2560
|
-
// Try
|
|
2666
|
+
// Try stored-file pattern (#1439): /api/files/{fileId}/{filename}
|
|
2667
|
+
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);
|
|
2668
|
+
// Try legacy S3-stored image pattern: /api/files/images/{team}/{filename}
|
|
2561
2669
|
const s3Match = parsed.image_url.match(/\/api\/files\/images\/([^/]+)\/(.+)$/);
|
|
2562
2670
|
// Try issue attachment pattern: /api/teams/{team}/issues/{refId}/attachments/{id}
|
|
2563
2671
|
const attachmentMatch = parsed.image_url.match(/\/api\/teams\/([^/]+)\/issues\/(\d+)\/attachments\/([^/]+)$/);
|
|
2564
2672
|
let base64;
|
|
2565
2673
|
let mimeType;
|
|
2566
|
-
if (
|
|
2674
|
+
if (storedFileMatch) {
|
|
2675
|
+
({ base64, mimeType } = await this.client.downloadFile(storedFileMatch[1]));
|
|
2676
|
+
}
|
|
2677
|
+
else if (s3Match) {
|
|
2567
2678
|
const [, team, filename] = s3Match;
|
|
2568
2679
|
({ base64, mimeType } = await this.client.downloadImage(team, filename));
|
|
2569
2680
|
}
|
|
@@ -2572,7 +2683,7 @@ class WolfpackMCPServer {
|
|
|
2572
2683
|
({ base64, mimeType } = await this.client.downloadIssueAttachment(team, refId, attachmentId));
|
|
2573
2684
|
}
|
|
2574
2685
|
else {
|
|
2575
|
-
throw new Error('Invalid image URL. Expected format: /api/files/images/{team}/{filename} or /api/teams/{team}/issues/{refId}/attachments/{id}');
|
|
2686
|
+
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
2687
|
}
|
|
2577
2688
|
return {
|
|
2578
2689
|
content: [
|
|
@@ -2592,6 +2703,14 @@ class WolfpackMCPServer {
|
|
|
2592
2703
|
content: [{ type: 'text', text: JSON.stringify(categories, null, 2) }],
|
|
2593
2704
|
};
|
|
2594
2705
|
}
|
|
2706
|
+
// Tag handlers
|
|
2707
|
+
case 'list_tags': {
|
|
2708
|
+
const parsed = ListTagsSchema.parse(args);
|
|
2709
|
+
const tags = await this.client.listTags(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
2710
|
+
return {
|
|
2711
|
+
content: [{ type: 'text', text: JSON.stringify(tags, null, 2) }],
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2595
2714
|
// Team member handlers
|
|
2596
2715
|
case 'list_team_members': {
|
|
2597
2716
|
const parsed = ListTeamMembersSchema.parse(args);
|
package/package.json
CHANGED
package/dist/imageProcessor.js
DELETED
|
@@ -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, ``);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}
|