wolfpack-mcp 1.0.93 → 1.0.95
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 +45 -0
- package/dist/agentBuilderTools.js +57 -10
- package/dist/agentBuilderTools.test.js +48 -0
- package/dist/client.js +30 -4
- package/dist/index.js +211 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -355,6 +355,51 @@ Get a specific radar item.
|
|
|
355
355
|
- `item_id` (required): UUID or reference number
|
|
356
356
|
- `team_id` (optional): Required when using reference number
|
|
357
357
|
|
|
358
|
+
### Tags
|
|
359
|
+
|
|
360
|
+
Tags label work items, issues, wiki pages and journal entries, and are filed under nestable groups. Project admins define them; a key with `mcp:tags:manage` lets an admin's agent keep them in step with an external system (for example, one tag per CRM customer account keyed on `external_id`). There is no delete tool — archive instead (`update_tag` with `archived: true`); removing a tag outright is done in the browser.
|
|
361
|
+
|
|
362
|
+
#### `list_tags`
|
|
363
|
+
|
|
364
|
+
List a project's tags with id, name, colour, `externalId`, the group each is filed under and whether it is `archived`. Any key that can read a tagged module may list them.
|
|
365
|
+
|
|
366
|
+
- `project_slug` (optional): Project slug
|
|
367
|
+
|
|
368
|
+
#### `create_tag`
|
|
369
|
+
|
|
370
|
+
- `name` (required): Tag name, unique within the project
|
|
371
|
+
- `colour` (optional): Hex colour such as `#e879f9`
|
|
372
|
+
- `group` (optional): Tag group name or id
|
|
373
|
+
- `external_id` (optional): Id of this tag in the system that maintains it, unique within the project
|
|
374
|
+
- `project_slug` (optional): Project slug
|
|
375
|
+
|
|
376
|
+
#### `update_tag`
|
|
377
|
+
|
|
378
|
+
Only the fields given change; pass `null` for `colour`, `group` or `external_id` to clear it. `archived: true` is the soft delete: the tag stays on the items that carry it and keeps its page, but no picker offers it and it cannot be applied; `archived: false` restores it. A sync uses this for accounts the source system has dropped.
|
|
379
|
+
|
|
380
|
+
- `tag` (required): Tag id or current name
|
|
381
|
+
- `name`, `colour`, `group`, `external_id`, `archived` (optional)
|
|
382
|
+
- `project_slug` (optional): Project slug
|
|
383
|
+
|
|
384
|
+
#### `list_tag_groups`
|
|
385
|
+
|
|
386
|
+
List a project's tag groups with their parent and full path (e.g. `Customers › EMEA`).
|
|
387
|
+
|
|
388
|
+
- `project_slug` (optional): Project slug
|
|
389
|
+
|
|
390
|
+
#### `create_tag_group`
|
|
391
|
+
|
|
392
|
+
- `name` (required): Group name, unique within the project
|
|
393
|
+
- `parent` (optional): Parent group name or id
|
|
394
|
+
- `project_slug` (optional): Project slug
|
|
395
|
+
|
|
396
|
+
#### `update_tag_group`
|
|
397
|
+
|
|
398
|
+
- `group` (required): Group id or current name
|
|
399
|
+
- `name` (optional): New name
|
|
400
|
+
- `parent` (optional): Parent group name or id, or `null` for the top level
|
|
401
|
+
- `project_slug` (optional): Project slug
|
|
402
|
+
|
|
358
403
|
### Images
|
|
359
404
|
|
|
360
405
|
#### `upload_image`
|
|
@@ -40,12 +40,25 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
40
40
|
// ─── Group 1: Agent CRUD ─────────────────────────────────────────────────
|
|
41
41
|
{
|
|
42
42
|
name: 'list_agents',
|
|
43
|
-
description: 'List
|
|
44
|
-
|
|
43
|
+
description: 'List agents. Returns name, status, template, and assigned projects. ' +
|
|
44
|
+
'scope "org" (the default) lists the organisation\'s agents; scope "personal" lists your own ' +
|
|
45
|
+
'My Agents from My Space, which belong to no organisation. Call it twice to see both.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
scope: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
enum: ['org', 'personal'],
|
|
52
|
+
description: "Which agents to list: the organisation's (default) or your own personal ones.",
|
|
53
|
+
},
|
|
54
|
+
...ORG_SLUG_PROP,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
45
57
|
},
|
|
46
58
|
{
|
|
47
59
|
name: 'get_agent',
|
|
48
|
-
description: 'Get full details for an agent including config, instructions, LLM model, and linked skills.'
|
|
60
|
+
description: 'Get full details for an agent including config, instructions, LLM model, and linked skills. ' +
|
|
61
|
+
'Takes an organisation agent or one of your own personal agents.',
|
|
49
62
|
inputSchema: {
|
|
50
63
|
type: 'object',
|
|
51
64
|
properties: {
|
|
@@ -57,7 +70,10 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
57
70
|
},
|
|
58
71
|
{
|
|
59
72
|
name: 'create_agent',
|
|
60
|
-
description: 'Create a new agent from a container image. Use list_container_images to see available images.'
|
|
73
|
+
description: 'Create a new agent from a container image. Use list_container_images to see available images. ' +
|
|
74
|
+
'With personal=true, creates one of your own My Agents instead of an organisation agent: ' +
|
|
75
|
+
'it needs a handle, and only an image opened to personal use (list_container_images with ' +
|
|
76
|
+
'personal=true) qualifies.',
|
|
61
77
|
inputSchema: {
|
|
62
78
|
type: 'object',
|
|
63
79
|
properties: {
|
|
@@ -67,6 +83,14 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
67
83
|
},
|
|
68
84
|
name: { type: 'string', description: 'Display name for the agent' },
|
|
69
85
|
config: { type: 'object', description: 'Optional agent-specific configuration' },
|
|
86
|
+
personal: {
|
|
87
|
+
type: 'boolean',
|
|
88
|
+
description: 'Create one of your own personal agents (My Space > My Agents) rather than an organisation agent.',
|
|
89
|
+
},
|
|
90
|
+
handle: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Handle for a personal agent — it becomes "@<your username>/<handle>". Required with personal=true, ignored otherwise.',
|
|
93
|
+
},
|
|
70
94
|
...ORG_SLUG_PROP,
|
|
71
95
|
},
|
|
72
96
|
required: ['container_image_id', 'name'],
|
|
@@ -798,8 +822,19 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
798
822
|
// ─── Group 7: Discovery ───────────────────────────────────────────────────
|
|
799
823
|
{
|
|
800
824
|
name: 'list_container_images',
|
|
801
|
-
description: 'List agent-capable container images assigned to the organisation. Use image IDs when calling create_agent.'
|
|
802
|
-
|
|
825
|
+
description: 'List agent-capable container images assigned to the organisation. Use image IDs when calling create_agent. ' +
|
|
826
|
+
'With personal=true, lists the images a personal agent may run instead — the bring-your-own-token ' +
|
|
827
|
+
'images opened to personal use, which are not an organisation catalogue.',
|
|
828
|
+
inputSchema: {
|
|
829
|
+
type: 'object',
|
|
830
|
+
properties: {
|
|
831
|
+
personal: {
|
|
832
|
+
type: 'boolean',
|
|
833
|
+
description: 'List the images available to personal agents rather than the organisation catalogue.',
|
|
834
|
+
},
|
|
835
|
+
...ORG_SLUG_PROP,
|
|
836
|
+
},
|
|
837
|
+
},
|
|
803
838
|
},
|
|
804
839
|
{
|
|
805
840
|
name: 'list_llm_models',
|
|
@@ -837,8 +872,10 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
837
872
|
}
|
|
838
873
|
// ─── Agent CRUD ────────────────────────────────────────────────────────
|
|
839
874
|
case 'list_agents': {
|
|
840
|
-
const parsed = z
|
|
841
|
-
|
|
875
|
+
const parsed = z
|
|
876
|
+
.object({ scope: z.enum(['org', 'personal']).optional(), org_slug: orgSlugField })
|
|
877
|
+
.parse(args);
|
|
878
|
+
const agents = await client.listAgents(resolveOrg(parsed), parsed.scope);
|
|
842
879
|
return { content: [{ type: 'text', text: text(agents) }] };
|
|
843
880
|
}
|
|
844
881
|
case 'get_agent': {
|
|
@@ -854,13 +891,21 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
854
891
|
container_image_id: z.string(),
|
|
855
892
|
name: z.string(),
|
|
856
893
|
config: z.record(z.unknown()).optional(),
|
|
894
|
+
personal: z.boolean().optional(),
|
|
895
|
+
handle: z.string().optional(),
|
|
857
896
|
org_slug: orgSlugField,
|
|
897
|
+
})
|
|
898
|
+
.refine((v) => !v.personal || !!v.handle, {
|
|
899
|
+
message: 'handle is required with personal=true',
|
|
900
|
+
path: ['handle'],
|
|
858
901
|
})
|
|
859
902
|
.parse(args);
|
|
860
903
|
const agent = await client.createAgent({
|
|
861
904
|
containerImageId: parsed.container_image_id,
|
|
862
905
|
name: parsed.name,
|
|
863
906
|
config: parsed.config,
|
|
907
|
+
personal: parsed.personal,
|
|
908
|
+
handleName: parsed.handle,
|
|
864
909
|
}, resolveOrg(parsed));
|
|
865
910
|
return {
|
|
866
911
|
content: [
|
|
@@ -1427,8 +1472,10 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
1427
1472
|
}
|
|
1428
1473
|
// ─── Discovery ────────────────────────────────────────────────────────────
|
|
1429
1474
|
case 'list_container_images': {
|
|
1430
|
-
const parsed = z
|
|
1431
|
-
|
|
1475
|
+
const parsed = z
|
|
1476
|
+
.object({ personal: z.boolean().optional(), org_slug: orgSlugField })
|
|
1477
|
+
.parse(args);
|
|
1478
|
+
const images = await client.listContainerImages(resolveOrg(parsed), parsed.personal);
|
|
1432
1479
|
return { content: [{ type: 'text', text: text(images) }] };
|
|
1433
1480
|
}
|
|
1434
1481
|
case 'list_llm_models': {
|
|
@@ -144,3 +144,51 @@ describe('schedule pre-flight over MCP (#2083)', () => {
|
|
|
144
144
|
expect(Object.keys(properties)).not.toContain('scheduling_enabled');
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
|
+
// #2273 — My Agents reached over MCP. There is no second tool set: a personal
|
|
148
|
+
// agent is addressed by the same tools and the same agent_id as an org one, so
|
|
149
|
+
// what these cover is the three tools that had to learn the difference.
|
|
150
|
+
describe('personal agents over MCP (#2273)', () => {
|
|
151
|
+
function fake(method, result) {
|
|
152
|
+
const fn = vi.fn().mockResolvedValue(result);
|
|
153
|
+
return { client: { [method]: fn }, fn };
|
|
154
|
+
}
|
|
155
|
+
it('list_agents offers both scopes and defaults to neither being sent', async () => {
|
|
156
|
+
const scope = toolNamed('list_agents').inputSchema.properties.scope;
|
|
157
|
+
expect(scope.enum).toEqual(['org', 'personal']);
|
|
158
|
+
const { client, fn } = fake('listAgents', []);
|
|
159
|
+
await handleAgentBuilderTool('list_agents', {}, client);
|
|
160
|
+
expect(fn.mock.calls[0][1]).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
it('list_agents passes the personal scope through', async () => {
|
|
163
|
+
const { client, fn } = fake('listAgents', [{ id: 'agent-1' }]);
|
|
164
|
+
await handleAgentBuilderTool('list_agents', { scope: 'personal' }, client);
|
|
165
|
+
expect(fn.mock.calls[0][1]).toBe('personal');
|
|
166
|
+
});
|
|
167
|
+
it('create_agent sends the personal flag and the handle', async () => {
|
|
168
|
+
const { client, fn } = fake('createAgent', { userId: 'agent_1' });
|
|
169
|
+
await handleAgentBuilderTool('create_agent', {
|
|
170
|
+
container_image_id: 'image-1',
|
|
171
|
+
name: 'Raiven',
|
|
172
|
+
personal: true,
|
|
173
|
+
handle: 'raiven',
|
|
174
|
+
}, client);
|
|
175
|
+
expect(fn.mock.calls[0][0]).toMatchObject({ personal: true, handleName: 'raiven' });
|
|
176
|
+
});
|
|
177
|
+
// A personal agent's handle is required, so say so here rather than spending a
|
|
178
|
+
// round trip to learn it from the backend.
|
|
179
|
+
it('create_agent refuses personal without a handle', async () => {
|
|
180
|
+
const { client, fn } = fake('createAgent', { userId: 'agent_1' });
|
|
181
|
+
await expect(handleAgentBuilderTool('create_agent', { container_image_id: 'image-1', name: 'Raiven', personal: true }, client)).rejects.toThrow('handle is required with personal=true');
|
|
182
|
+
expect(fn).not.toHaveBeenCalled();
|
|
183
|
+
});
|
|
184
|
+
it('create_agent stays organisational when the flag is left off', async () => {
|
|
185
|
+
const { client, fn } = fake('createAgent', { userId: 'agent_1' });
|
|
186
|
+
await handleAgentBuilderTool('create_agent', { container_image_id: 'image-1', name: 'Scout' }, client);
|
|
187
|
+
expect(fn.mock.calls[0][0].personal).toBeUndefined();
|
|
188
|
+
});
|
|
189
|
+
it('list_container_images asks for the personal catalogue', async () => {
|
|
190
|
+
const { client, fn } = fake('listContainerImages', []);
|
|
191
|
+
await handleAgentBuilderTool('list_container_images', { personal: true }, client);
|
|
192
|
+
expect(fn.mock.calls[0][1]).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
});
|
package/dist/client.js
CHANGED
|
@@ -525,6 +525,28 @@ export class WolfpackClient {
|
|
|
525
525
|
const query = params.toString();
|
|
526
526
|
return this.api.get(`/tags${query ? `?${query}` : ''}`);
|
|
527
527
|
}
|
|
528
|
+
async createTag(input, teamSlug) {
|
|
529
|
+
return this.api.post('/tags', { ...input, teamSlug });
|
|
530
|
+
}
|
|
531
|
+
async updateTag(tag, input, teamSlug) {
|
|
532
|
+
return this.api.patch(`/tags/${encodeURIComponent(tag)}`, { ...input, teamSlug });
|
|
533
|
+
}
|
|
534
|
+
async listTagGroups(teamSlug) {
|
|
535
|
+
const params = new URLSearchParams();
|
|
536
|
+
if (teamSlug)
|
|
537
|
+
params.append('teamSlug', teamSlug);
|
|
538
|
+
const query = params.toString();
|
|
539
|
+
return this.api.get(`/tag-groups${query ? `?${query}` : ''}`);
|
|
540
|
+
}
|
|
541
|
+
async createTagGroup(input, teamSlug) {
|
|
542
|
+
return this.api.post('/tag-groups', { ...input, teamSlug });
|
|
543
|
+
}
|
|
544
|
+
async updateTagGroup(group, input, teamSlug) {
|
|
545
|
+
return this.api.patch(`/tag-groups/${encodeURIComponent(group)}`, {
|
|
546
|
+
...input,
|
|
547
|
+
teamSlug,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
528
550
|
/**
|
|
529
551
|
* Upload an image and get back a URL that can be used in markdown content.
|
|
530
552
|
*/
|
|
@@ -651,8 +673,9 @@ export class WolfpackClient {
|
|
|
651
673
|
return response.organisations;
|
|
652
674
|
}
|
|
653
675
|
// ─── Agent Builder: Agent CRUD ─────────────────────────────────────────────
|
|
654
|
-
async listAgents(orgSlug) {
|
|
655
|
-
|
|
676
|
+
async listAgents(orgSlug, scope) {
|
|
677
|
+
const path = scope === 'personal' ? '/agents?scope=personal' : '/agents';
|
|
678
|
+
return this.api.get(this.withOrgSlug(path, orgSlug));
|
|
656
679
|
}
|
|
657
680
|
async getAgent(agentId, orgSlug) {
|
|
658
681
|
try {
|
|
@@ -844,8 +867,11 @@ export class WolfpackClient {
|
|
|
844
867
|
}
|
|
845
868
|
}
|
|
846
869
|
// ─── Agent Builder: Discovery ──────────────────────────────────────────────
|
|
847
|
-
async listContainerImages(orgSlug) {
|
|
848
|
-
|
|
870
|
+
async listContainerImages(orgSlug, personal) {
|
|
871
|
+
const path = personal
|
|
872
|
+
? '/agent-builder/container-images?personal=true'
|
|
873
|
+
: '/agent-builder/container-images';
|
|
874
|
+
return this.api.get(this.withOrgSlug(path, orgSlug));
|
|
849
875
|
}
|
|
850
876
|
async listLlmModels(orgSlug) {
|
|
851
877
|
return this.api.get(this.withOrgSlug('/agent-builder/llm-models', orgSlug));
|
package/dist/index.js
CHANGED
|
@@ -600,6 +600,59 @@ const ListTagsSchema = z.object({
|
|
|
600
600
|
.optional()
|
|
601
601
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
602
602
|
});
|
|
603
|
+
const CreateTagSchema = z.object({
|
|
604
|
+
project_slug: z
|
|
605
|
+
.string()
|
|
606
|
+
.optional()
|
|
607
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
608
|
+
name: z.string().describe('Tag name, unique within the project'),
|
|
609
|
+
colour: z.string().optional().describe('Hex colour such as #e879f9'),
|
|
610
|
+
group: z.string().optional().describe('Tag group name or id to file the tag under'),
|
|
611
|
+
external_id: z
|
|
612
|
+
.string()
|
|
613
|
+
.optional()
|
|
614
|
+
.describe('Id of this tag in the system that maintains it, unique within the project'),
|
|
615
|
+
});
|
|
616
|
+
const UpdateTagSchema = z.object({
|
|
617
|
+
project_slug: z
|
|
618
|
+
.string()
|
|
619
|
+
.optional()
|
|
620
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
621
|
+
tag: z.string().describe('Tag id or current name'),
|
|
622
|
+
name: z.string().optional().describe('New name'),
|
|
623
|
+
colour: z.string().nullable().optional().describe('Hex colour, or null to clear'),
|
|
624
|
+
group: z
|
|
625
|
+
.string()
|
|
626
|
+
.nullable()
|
|
627
|
+
.optional()
|
|
628
|
+
.describe('Tag group name or id, or null to move the tag out of its group'),
|
|
629
|
+
external_id: z.string().nullable().optional().describe('External id, or null to clear'),
|
|
630
|
+
archived: z
|
|
631
|
+
.boolean()
|
|
632
|
+
.optional()
|
|
633
|
+
.describe('true archives the tag (soft delete), false restores it'),
|
|
634
|
+
});
|
|
635
|
+
const CreateTagGroupSchema = z.object({
|
|
636
|
+
project_slug: z
|
|
637
|
+
.string()
|
|
638
|
+
.optional()
|
|
639
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
640
|
+
name: z.string().describe('Group name, unique within the project'),
|
|
641
|
+
parent: z.string().optional().describe('Parent group name or id'),
|
|
642
|
+
});
|
|
643
|
+
const UpdateTagGroupSchema = z.object({
|
|
644
|
+
project_slug: z
|
|
645
|
+
.string()
|
|
646
|
+
.optional()
|
|
647
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
648
|
+
group: z.string().describe('Group id or current name'),
|
|
649
|
+
name: z.string().optional().describe('New name'),
|
|
650
|
+
parent: z
|
|
651
|
+
.string()
|
|
652
|
+
.nullable()
|
|
653
|
+
.optional()
|
|
654
|
+
.describe('Parent group name or id, or null for the top level'),
|
|
655
|
+
});
|
|
603
656
|
// Team member schemas
|
|
604
657
|
const ListTeamMembersSchema = z.object({
|
|
605
658
|
project_slug: z
|
|
@@ -814,6 +867,9 @@ class WolfpackMCPServer {
|
|
|
814
867
|
'assigned_to_id you pass; the response says so when this applies. ' +
|
|
815
868
|
'AGENTS: when more than one item is claimable, the response also states the order to take ' +
|
|
816
869
|
'them in (bug fixes first, then higher priority, then oldest) and which to pull next. ' +
|
|
870
|
+
'AGENTS: blockedBy on each item names the prerequisites of it that have not finished. An item ' +
|
|
871
|
+
'with a non-empty blockedBy is NOT claimable however approved it is — take the work it names ' +
|
|
872
|
+
'first; the response says so too. ' +
|
|
817
873
|
'TERMINOLOGY: "board" and "kanban" are synonymous - both refer to the Kanban board of work items. ' +
|
|
818
874
|
'The board has columns: "new" (to do), "doing" (in progress), "review" (pending review), "ready" (code done, awaiting deployment), "blocked", "completed" (deployed). ' +
|
|
819
875
|
'The "backlog" or "pending" status represents items not yet on the board. ' +
|
|
@@ -1937,8 +1993,23 @@ class WolfpackMCPServer {
|
|
|
1937
1993
|
// Tag tools
|
|
1938
1994
|
{
|
|
1939
1995
|
name: 'list_tags',
|
|
1940
|
-
description: 'List all tags
|
|
1941
|
-
'
|
|
1996
|
+
description: 'List all tags of a project: id, name, colour, external id, the group each is filed under, and whether it is archived. ' +
|
|
1997
|
+
'Items are tagged by name via update_work_item / update_issue; archived tags cannot be applied. ' +
|
|
1998
|
+
'A sync from an external system (e.g. a CRM) keys on externalId.',
|
|
1999
|
+
inputSchema: {
|
|
2000
|
+
type: 'object',
|
|
2001
|
+
properties: {
|
|
2002
|
+
project_slug: {
|
|
2003
|
+
type: 'string',
|
|
2004
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
2005
|
+
},
|
|
2006
|
+
},
|
|
2007
|
+
},
|
|
2008
|
+
},
|
|
2009
|
+
{
|
|
2010
|
+
name: 'create_tag',
|
|
2011
|
+
description: 'Create a tag in a project. Project admins only (mcp:tags:manage). ' +
|
|
2012
|
+
'Set external_id when the tag mirrors a record in another system, so a later sync can find it by id rather than name.',
|
|
1942
2013
|
inputSchema: {
|
|
1943
2014
|
type: 'object',
|
|
1944
2015
|
properties: {
|
|
@@ -1946,7 +2017,99 @@ class WolfpackMCPServer {
|
|
|
1946
2017
|
type: 'string',
|
|
1947
2018
|
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1948
2019
|
},
|
|
2020
|
+
name: { type: 'string', description: 'Tag name, unique within the project' },
|
|
2021
|
+
colour: { type: 'string', description: 'Hex colour such as #e879f9 (optional)' },
|
|
2022
|
+
group: {
|
|
2023
|
+
type: 'string',
|
|
2024
|
+
description: 'Tag group name or id to file the tag under (optional, see list_tag_groups)',
|
|
2025
|
+
},
|
|
2026
|
+
external_id: {
|
|
2027
|
+
type: 'string',
|
|
2028
|
+
description: 'Id of this tag in the system that maintains it, unique within the project (optional)',
|
|
2029
|
+
},
|
|
1949
2030
|
},
|
|
2031
|
+
required: ['name'],
|
|
2032
|
+
},
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
name: 'update_tag',
|
|
2036
|
+
description: 'Rename, recolour, regroup, re-key or archive a tag. Project admins only (mcp:tags:manage). ' +
|
|
2037
|
+
'Only the fields given change; pass null for colour, group or external_id to clear it. ' +
|
|
2038
|
+
'archived: true is the soft delete — the tag stays on the items that carry it but no picker offers it; archived: false restores it.',
|
|
2039
|
+
inputSchema: {
|
|
2040
|
+
type: 'object',
|
|
2041
|
+
properties: {
|
|
2042
|
+
project_slug: {
|
|
2043
|
+
type: 'string',
|
|
2044
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
2045
|
+
},
|
|
2046
|
+
tag: { type: 'string', description: 'Tag id or current name' },
|
|
2047
|
+
name: { type: 'string', description: 'New name' },
|
|
2048
|
+
colour: { type: ['string', 'null'], description: 'Hex colour, or null to clear' },
|
|
2049
|
+
group: {
|
|
2050
|
+
type: ['string', 'null'],
|
|
2051
|
+
description: 'Tag group name or id, or null to move the tag out of its group',
|
|
2052
|
+
},
|
|
2053
|
+
external_id: {
|
|
2054
|
+
type: ['string', 'null'],
|
|
2055
|
+
description: 'External id, or null to clear',
|
|
2056
|
+
},
|
|
2057
|
+
archived: {
|
|
2058
|
+
type: 'boolean',
|
|
2059
|
+
description: 'true archives the tag (soft delete), false restores it',
|
|
2060
|
+
},
|
|
2061
|
+
},
|
|
2062
|
+
required: ['tag'],
|
|
2063
|
+
},
|
|
2064
|
+
},
|
|
2065
|
+
{
|
|
2066
|
+
name: 'list_tag_groups',
|
|
2067
|
+
description: 'List the tag groups of a project with their parent and full path (groups nest, e.g. "Customers › EMEA").',
|
|
2068
|
+
inputSchema: {
|
|
2069
|
+
type: 'object',
|
|
2070
|
+
properties: {
|
|
2071
|
+
project_slug: {
|
|
2072
|
+
type: 'string',
|
|
2073
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
2074
|
+
},
|
|
2075
|
+
},
|
|
2076
|
+
},
|
|
2077
|
+
},
|
|
2078
|
+
{
|
|
2079
|
+
name: 'create_tag_group',
|
|
2080
|
+
description: 'Create a tag group, optionally inside a parent group. Project admins only (mcp:tags:manage).',
|
|
2081
|
+
inputSchema: {
|
|
2082
|
+
type: 'object',
|
|
2083
|
+
properties: {
|
|
2084
|
+
project_slug: {
|
|
2085
|
+
type: 'string',
|
|
2086
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
2087
|
+
},
|
|
2088
|
+
name: { type: 'string', description: 'Group name, unique within the project' },
|
|
2089
|
+
parent: { type: 'string', description: 'Parent group name or id (optional)' },
|
|
2090
|
+
},
|
|
2091
|
+
required: ['name'],
|
|
2092
|
+
},
|
|
2093
|
+
},
|
|
2094
|
+
{
|
|
2095
|
+
name: 'update_tag_group',
|
|
2096
|
+
description: 'Rename a tag group or move it under another parent. Project admins only (mcp:tags:manage). ' +
|
|
2097
|
+
'Pass parent: null for the top level.',
|
|
2098
|
+
inputSchema: {
|
|
2099
|
+
type: 'object',
|
|
2100
|
+
properties: {
|
|
2101
|
+
project_slug: {
|
|
2102
|
+
type: 'string',
|
|
2103
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
2104
|
+
},
|
|
2105
|
+
group: { type: 'string', description: 'Group id or current name' },
|
|
2106
|
+
name: { type: 'string', description: 'New name' },
|
|
2107
|
+
parent: {
|
|
2108
|
+
type: ['string', 'null'],
|
|
2109
|
+
description: 'Parent group name or id, or null for the top level',
|
|
2110
|
+
},
|
|
2111
|
+
},
|
|
2112
|
+
required: ['group'],
|
|
1950
2113
|
},
|
|
1951
2114
|
},
|
|
1952
2115
|
// Team member tools
|
|
@@ -3086,6 +3249,52 @@ class WolfpackMCPServer {
|
|
|
3086
3249
|
content: [{ type: 'text', text: JSON.stringify(tags, null, 2) }],
|
|
3087
3250
|
};
|
|
3088
3251
|
}
|
|
3252
|
+
case 'create_tag': {
|
|
3253
|
+
const parsed = CreateTagSchema.parse(args);
|
|
3254
|
+
const tag = await this.client.createTag({
|
|
3255
|
+
name: parsed.name,
|
|
3256
|
+
colour: parsed.colour,
|
|
3257
|
+
group: parsed.group,
|
|
3258
|
+
externalId: parsed.external_id,
|
|
3259
|
+
}, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3260
|
+
return {
|
|
3261
|
+
content: [{ type: 'text', text: JSON.stringify(tag, null, 2) }],
|
|
3262
|
+
};
|
|
3263
|
+
}
|
|
3264
|
+
case 'update_tag': {
|
|
3265
|
+
const parsed = UpdateTagSchema.parse(args);
|
|
3266
|
+
const tag = await this.client.updateTag(parsed.tag, {
|
|
3267
|
+
name: parsed.name,
|
|
3268
|
+
colour: parsed.colour,
|
|
3269
|
+
group: parsed.group,
|
|
3270
|
+
externalId: parsed.external_id,
|
|
3271
|
+
archived: parsed.archived,
|
|
3272
|
+
}, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3273
|
+
return {
|
|
3274
|
+
content: [{ type: 'text', text: JSON.stringify(tag, null, 2) }],
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
case 'list_tag_groups': {
|
|
3278
|
+
const parsed = ListTagsSchema.parse(args);
|
|
3279
|
+
const groups = await this.client.listTagGroups(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3280
|
+
return {
|
|
3281
|
+
content: [{ type: 'text', text: JSON.stringify(groups, null, 2) }],
|
|
3282
|
+
};
|
|
3283
|
+
}
|
|
3284
|
+
case 'create_tag_group': {
|
|
3285
|
+
const parsed = CreateTagGroupSchema.parse(args);
|
|
3286
|
+
const group = await this.client.createTagGroup({ name: parsed.name, parent: parsed.parent }, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3287
|
+
return {
|
|
3288
|
+
content: [{ type: 'text', text: JSON.stringify(group, null, 2) }],
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3291
|
+
case 'update_tag_group': {
|
|
3292
|
+
const parsed = UpdateTagGroupSchema.parse(args);
|
|
3293
|
+
const group = await this.client.updateTagGroup(parsed.group, { name: parsed.name, parent: parsed.parent }, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3294
|
+
return {
|
|
3295
|
+
content: [{ type: 'text', text: JSON.stringify(group, null, 2) }],
|
|
3296
|
+
};
|
|
3297
|
+
}
|
|
3089
3298
|
// Team member handlers
|
|
3090
3299
|
case 'list_team_members': {
|
|
3091
3300
|
const parsed = ListTeamMembersSchema.parse(args);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wolfpack-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.95",
|
|
4
4
|
"description": "MCP server for Wolfpack AI-enhanced software delivery tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"@eslint/js": "^9.17.0",
|
|
46
46
|
"@types/node": "^22.12.0",
|
|
47
47
|
"eslint": "^9.17.0",
|
|
48
|
-
"tsx": "^4.
|
|
48
|
+
"tsx": "^4.23.12",
|
|
49
49
|
"typescript": "^5.7.3",
|
|
50
|
-
"typescript-eslint": "^8.
|
|
51
|
-
"vitest": "^4.
|
|
50
|
+
"typescript-eslint": "^8.68.0",
|
|
51
|
+
"vitest": "^4.1.11"
|
|
52
52
|
}
|
|
53
53
|
}
|