wolfpack-mcp 1.0.90 → 1.0.92

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.
@@ -113,6 +113,10 @@ export const AGENT_BUILDER_TOOLS = [
113
113
  items: { type: 'string' },
114
114
  description: 'Replace the full set of MCP permissions granted to the agent\'s session API key (e.g. ["mcp:work_items:read", "mcp:comments:create"]). Grant only what the agent\'s tasks need. An empty array falls back to a read-only default.',
115
115
  },
116
+ scheduling_enabled: {
117
+ type: 'boolean',
118
+ description: "The agent-level scheduling switch. No schedule fires while it is off, whatever the schedule's own enabled flag says.",
119
+ },
116
120
  ...ORG_SLUG_PROP,
117
121
  },
118
122
  required: ['agent_id'],
@@ -532,6 +536,23 @@ export const AGENT_BUILDER_TOOLS = [
532
536
  description: 'When true, tasks run once with access to all assigned projects. ' +
533
537
  'When false, tasks run once per project.',
534
538
  },
539
+ preflight_check: {
540
+ type: 'string',
541
+ enum: ['claimable-work', 'claimable-check'],
542
+ description: 'LLM-free condition evaluated when the schedule fires; a false result skips the fire with no session and no cost. ' +
543
+ '"claimable-work": an approved, unclaimed item is assigned to the agent or sits in one of its work pools. ' +
544
+ '"claimable-check": a pending, unclaimed review check sits on an item in one of its pools. Null to clear.',
545
+ },
546
+ check_kinds: {
547
+ type: 'array',
548
+ items: { type: 'string' },
549
+ description: 'With "claimable-check": only checks of these kinds wake the schedule (e.g. ["security-review"]), so reviewers ' +
550
+ 'sharing a pool each answer their own kind. Empty for every kind.',
551
+ },
552
+ skip_while_active: {
553
+ type: 'boolean',
554
+ description: 'Skip a fire entirely while the agent still has a queued or running task, or leads an item awaiting review.',
555
+ },
535
556
  task_ids: {
536
557
  type: 'array',
537
558
  items: { type: 'string' },
@@ -575,6 +596,23 @@ export const AGENT_BUILDER_TOOLS = [
575
596
  type: 'boolean',
576
597
  description: 'Run once across all projects (true) or once per project (false)',
577
598
  },
599
+ preflight_check: {
600
+ type: 'string',
601
+ enum: ['claimable-work', 'claimable-check'],
602
+ description: 'LLM-free condition evaluated when the schedule fires; a false result skips the fire with no session and no cost. ' +
603
+ '"claimable-work": an approved, unclaimed item is assigned to the agent or sits in one of its work pools. ' +
604
+ '"claimable-check": a pending, unclaimed review check sits on an item in one of its pools. Null to clear.',
605
+ },
606
+ check_kinds: {
607
+ type: 'array',
608
+ items: { type: 'string' },
609
+ description: 'With "claimable-check": only checks of these kinds wake the schedule (e.g. ["security-review"]), so reviewers ' +
610
+ 'sharing a pool each answer their own kind. Empty for every kind.',
611
+ },
612
+ skip_while_active: {
613
+ type: 'boolean',
614
+ description: 'Skip a fire entirely while the agent still has a queued or running task, or leads an item awaiting review.',
615
+ },
578
616
  task_ids: {
579
617
  type: 'array',
580
618
  items: { type: 'string' },
@@ -798,6 +836,19 @@ const AgentTaskSchema = z.object({
798
836
  org_slug: orgSlugField,
799
837
  });
800
838
  const SkillIdSchema = z.object({ skill_id: z.string(), org_slug: orgSlugField });
839
+ /**
840
+ * A schedule enabled on an agent whose own scheduling switch is off never
841
+ * fires (#2083) — say so in the result rather than letting the caller find
842
+ * out from a schedule that stays silent.
843
+ */
844
+ async function schedulingOffWarning(client, agentId, scheduleEnabled, orgSlug) {
845
+ if (!scheduleEnabled)
846
+ return '';
847
+ const agent = await client.getAgent(agentId, orgSlug);
848
+ return !agent || agent.schedulingEnabled
849
+ ? ''
850
+ : "\n\nWARNING: this agent's scheduling is switched off, so the schedule will not fire until update_agent sets scheduling_enabled: true.";
851
+ }
801
852
  export async function handleAgentBuilderTool(name, args, client) {
802
853
  const text = (t) => JSON.stringify(t, null, 2);
803
854
  switch (name) {
@@ -855,6 +906,7 @@ export async function handleAgentBuilderTool(name, args, client) {
855
906
  llm_model: z.string().nullable().optional(),
856
907
  llm_family: z.string().nullable().optional(),
857
908
  api_key_permissions: z.array(z.string()).optional(),
909
+ scheduling_enabled: z.boolean().optional(),
858
910
  org_slug: orgSlugField,
859
911
  })
860
912
  .parse(args);
@@ -878,6 +930,8 @@ export async function handleAgentBuilderTool(name, args, client) {
878
930
  fields.llmFamily = rest.llm_family;
879
931
  if (rest.api_key_permissions !== undefined)
880
932
  fields.apiKeyPermissions = rest.api_key_permissions;
933
+ if (rest.scheduling_enabled !== undefined)
934
+ fields.schedulingEnabled = rest.scheduling_enabled;
881
935
  const agent = await client.updateAgent(agent_id, fields, resolveOrg(parsed));
882
936
  return { content: [{ type: 'text', text: `Updated agent\n\n${text(agent)}` }] };
883
937
  }
@@ -1166,6 +1220,9 @@ export async function handleAgentBuilderTool(name, args, client) {
1166
1220
  timezone: z.string().optional(),
1167
1221
  dst_aware: z.boolean().optional(),
1168
1222
  multi_project: z.boolean().optional(),
1223
+ preflight_check: z.enum(['claimable-work', 'claimable-check']).nullable().optional(),
1224
+ check_kinds: z.array(z.string()).optional(),
1225
+ skip_while_active: z.boolean().optional(),
1169
1226
  task_ids: z.array(z.string()).optional(),
1170
1227
  org_slug: orgSlugField,
1171
1228
  })
@@ -1190,12 +1247,22 @@ export async function handleAgentBuilderTool(name, args, client) {
1190
1247
  body.dstAware = rest.dst_aware;
1191
1248
  if (rest.multi_project !== undefined)
1192
1249
  body.multiProject = rest.multi_project;
1250
+ if (rest.preflight_check !== undefined)
1251
+ body.preflightCheck = rest.preflight_check;
1252
+ if (rest.check_kinds !== undefined)
1253
+ body.checkKinds = rest.check_kinds;
1254
+ if (rest.skip_while_active !== undefined)
1255
+ body.skipWhileActive = rest.skip_while_active;
1193
1256
  if (rest.task_ids !== undefined)
1194
1257
  body.taskIds = rest.task_ids;
1195
1258
  const schedule = await client.createAgentSchedule(agent_id, body, resolveOrg(parsed));
1259
+ const warning = await schedulingOffWarning(client, agent_id, schedule.enabled, resolveOrg(parsed));
1196
1260
  return {
1197
1261
  content: [
1198
- { type: 'text', text: `Created schedule "${schedule.name}"\n\n${text(schedule)}` },
1262
+ {
1263
+ type: 'text',
1264
+ text: `Created schedule "${schedule.name}"${warning}\n\n${text(schedule)}`,
1265
+ },
1199
1266
  ],
1200
1267
  };
1201
1268
  }
@@ -1213,6 +1280,9 @@ export async function handleAgentBuilderTool(name, args, client) {
1213
1280
  timezone: z.string().optional(),
1214
1281
  dst_aware: z.boolean().optional(),
1215
1282
  multi_project: z.boolean().optional(),
1283
+ preflight_check: z.enum(['claimable-work', 'claimable-check']).nullable().optional(),
1284
+ check_kinds: z.array(z.string()).optional(),
1285
+ skip_while_active: z.boolean().optional(),
1216
1286
  task_ids: z.array(z.string()).optional(),
1217
1287
  org_slug: orgSlugField,
1218
1288
  })
@@ -1237,10 +1307,19 @@ export async function handleAgentBuilderTool(name, args, client) {
1237
1307
  body.dstAware = rest.dst_aware;
1238
1308
  if (rest.multi_project !== undefined)
1239
1309
  body.multiProject = rest.multi_project;
1310
+ if (rest.preflight_check !== undefined)
1311
+ body.preflightCheck = rest.preflight_check;
1312
+ if (rest.check_kinds !== undefined)
1313
+ body.checkKinds = rest.check_kinds;
1314
+ if (rest.skip_while_active !== undefined)
1315
+ body.skipWhileActive = rest.skip_while_active;
1240
1316
  if (rest.task_ids !== undefined)
1241
1317
  body.taskIds = rest.task_ids;
1242
1318
  const schedule = await client.updateAgentSchedule(agent_id, schedule_id, body, resolveOrg(parsed));
1243
- return { content: [{ type: 'text', text: `Updated schedule\n\n${text(schedule)}` }] };
1319
+ const warning = await schedulingOffWarning(client, agent_id, schedule.enabled, resolveOrg(parsed));
1320
+ return {
1321
+ content: [{ type: 'text', text: `Updated schedule${warning}\n\n${text(schedule)}` }],
1322
+ };
1244
1323
  }
1245
1324
  // ─── Skills ─────────────────────────────────────────────────────────────
1246
1325
  case 'create_skill': {
@@ -98,3 +98,68 @@ describe('extra instructions on a task run over MCP (#2048)', () => {
98
98
  expect(runAgentTask.mock.calls[0][6]).toBeUndefined();
99
99
  });
100
100
  });
101
+ // #2083: everything the schedule editor can set is settable over MCP, and a
102
+ // schedule enabled on an agent whose scheduling switch is off says so.
103
+ describe('schedule pre-flight and scheduling switch over MCP (#2083)', () => {
104
+ const SCHEDULE_FIELDS = ['preflight_check', 'check_kinds', 'skip_while_active'];
105
+ it.each(['create_agent_schedule', 'update_agent_schedule'])('%s advertises the pre-flight fields', (name) => {
106
+ const properties = toolNamed(name).inputSchema.properties;
107
+ expect(Object.keys(properties)).toEqual(expect.arrayContaining(SCHEDULE_FIELDS));
108
+ });
109
+ it('update_agent advertises the scheduling switch', () => {
110
+ const properties = toolNamed('update_agent').inputSchema.properties;
111
+ expect(Object.keys(properties)).toContain('scheduling_enabled');
112
+ });
113
+ function scheduleClient(schedulingEnabled) {
114
+ const schedule = { id: 'sched-1', name: 'Reviews', enabled: true };
115
+ const createAgentSchedule = vi.fn().mockResolvedValue(schedule);
116
+ const updateAgentSchedule = vi.fn().mockResolvedValue(schedule);
117
+ const updateAgent = vi.fn().mockResolvedValue({ id: 'agent-1', schedulingEnabled });
118
+ const getAgent = vi.fn().mockResolvedValue({ id: 'agent-1', schedulingEnabled });
119
+ return {
120
+ client: {
121
+ createAgentSchedule,
122
+ updateAgentSchedule,
123
+ updateAgent,
124
+ getAgent,
125
+ },
126
+ createAgentSchedule,
127
+ updateAgentSchedule,
128
+ updateAgent,
129
+ };
130
+ }
131
+ it('sends the pre-flight, kinds and skip-while-active when creating a schedule', async () => {
132
+ const { client, createAgentSchedule } = scheduleClient(true);
133
+ await handleAgentBuilderTool('create_agent_schedule', {
134
+ agent_id: 'agent-1',
135
+ preflight_check: 'claimable-check',
136
+ check_kinds: ['security-review'],
137
+ skip_while_active: true,
138
+ }, client);
139
+ expect(createAgentSchedule.mock.calls[0][1]).toMatchObject({
140
+ preflightCheck: 'claimable-check',
141
+ checkKinds: ['security-review'],
142
+ skipWhileActive: true,
143
+ });
144
+ });
145
+ it('sends the same fields when updating a schedule', async () => {
146
+ const { client, updateAgentSchedule } = scheduleClient(true);
147
+ await handleAgentBuilderTool('update_agent_schedule', { agent_id: 'agent-1', schedule_id: 'sched-1', preflight_check: null, check_kinds: [] }, client);
148
+ expect(updateAgentSchedule.mock.calls[0][2]).toEqual({ preflightCheck: null, checkKinds: [] });
149
+ });
150
+ it('sends the scheduling switch when updating an agent', async () => {
151
+ const { client, updateAgent } = scheduleClient(true);
152
+ await handleAgentBuilderTool('update_agent', { agent_id: 'agent-1', scheduling_enabled: true }, client);
153
+ expect(updateAgent.mock.calls[0][1]).toEqual({ schedulingEnabled: true });
154
+ });
155
+ it('warns when an enabled schedule lands on an agent whose scheduling is off', async () => {
156
+ const { client } = scheduleClient(false);
157
+ const result = await handleAgentBuilderTool('create_agent_schedule', { agent_id: 'agent-1', enabled: true }, client);
158
+ expect(result.content[0].text).toContain('scheduling is switched off');
159
+ });
160
+ it('stays quiet when the agent is scheduling', async () => {
161
+ const { client } = scheduleClient(true);
162
+ const result = await handleAgentBuilderTool('create_agent_schedule', { agent_id: 'agent-1', enabled: true }, client);
163
+ expect(result.content[0].text).not.toContain('WARNING');
164
+ });
165
+ });
package/dist/client.js CHANGED
@@ -247,9 +247,14 @@ export class WolfpackClient {
247
247
  params.set('workItemId', filter.workItemId);
248
248
  if (filter.status)
249
249
  params.set('status', filter.status);
250
+ if (filter.kind)
251
+ params.set('kind', filter.kind);
250
252
  const query = params.toString();
251
253
  return this.api.get(this.withTeamSlug(`/work-item-checks${query ? `?${query}` : ''}`, teamSlug));
252
254
  }
255
+ async addWorkItemCheck(workItemId, body, teamSlug) {
256
+ return this.api.post(this.withTeamSlug(`/work-items/${workItemId}/checks`, teamSlug), body);
257
+ }
253
258
  async claimWorkItemCheck(workItemId, checkId, teamSlug) {
254
259
  return this.api.post(this.withTeamSlug(`/work-items/${workItemId}/checks/${checkId}/claim`, teamSlug), {});
255
260
  }
@@ -502,6 +507,16 @@ export class WolfpackClient {
502
507
  const query = params.toString();
503
508
  return this.api.get(`/categories${query ? `?${query}` : ''}`);
504
509
  }
510
+ // Work pool methods (#2083)
511
+ async listWorkPools(teamSlug) {
512
+ return this.api.get(this.withTeamSlug('/work-pools', teamSlug));
513
+ }
514
+ async addWorkPoolMember(workPool, userId, teamSlug) {
515
+ return this.api.post(this.withTeamSlug(`/work-pools/${encodeURIComponent(workPool)}/members`, teamSlug), { userId });
516
+ }
517
+ async removeWorkPoolMember(workPool, userId, teamSlug) {
518
+ await this.api.delete(this.withTeamSlug(`/work-pools/${encodeURIComponent(workPool)}/members/${encodeURIComponent(userId)}`, teamSlug));
519
+ }
505
520
  // Tag methods
506
521
  async listTags(teamSlug) {
507
522
  const params = new URLSearchParams();
package/dist/index.js CHANGED
@@ -215,11 +215,32 @@ const SubmitWorkItemFormSchema = z.object({
215
215
  .optional()
216
216
  .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
217
217
  });
218
+ const WorkPoolMemberSchema = z.object({
219
+ work_pool: z.string().describe('Work pool id or name'),
220
+ user_id: z.string().describe('The user id to add or remove'),
221
+ project_slug: z
222
+ .string()
223
+ .optional()
224
+ .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
225
+ });
218
226
  const ListWorkItemChecksSchema = z.object({
219
227
  work_item_id: refIdString()
220
228
  .optional()
221
229
  .describe('The refId of a work item; omit for your reviewer inbox'),
222
230
  status: z.enum(['pending', 'passed', 'failed']).optional().describe('Filter by check status'),
231
+ kind: z.string().optional().describe('Filter by check kind, e.g. code-review or security-review'),
232
+ project_slug: z
233
+ .string()
234
+ .optional()
235
+ .describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
236
+ });
237
+ const AddWorkItemCheckSchema = z.object({
238
+ work_item_id: refIdString().describe('The refId of the work item'),
239
+ kind: z.string().describe('The check kind to add, e.g. security-review'),
240
+ comment: z
241
+ .string()
242
+ .optional()
243
+ .describe('Why the check is being requested — posted as a comment on the item'),
223
244
  project_slug: z
224
245
  .string()
225
246
  .optional()
@@ -1087,7 +1108,8 @@ class WolfpackMCPServer {
1087
1108
  'Checks on blocked items are left out — blocked work is not picked up, and claiming one is refused. ' +
1088
1109
  'REVIEW WORKFLOW: claim a check with claim_work_item_check, get_work_item to read the work, review it, ' +
1089
1110
  'then complete_work_item_check with "passed" or "failed" and a short summary. ' +
1090
- 'A failed check sends the item back to its developer with your summary as feedback; do not change the item status yourself.',
1111
+ 'A failed check sends the item back to its developer with your summary as feedback; do not change the item status yourself. ' +
1112
+ 'To request a further review of another kind on an item (e.g. security-review), use add_work_item_check.',
1091
1113
  inputSchema: {
1092
1114
  type: 'object',
1093
1115
  properties: {
@@ -1100,11 +1122,40 @@ class WolfpackMCPServer {
1100
1122
  enum: ['pending', 'passed', 'failed'],
1101
1123
  description: 'Filter by check status',
1102
1124
  },
1125
+ kind: {
1126
+ type: 'string',
1127
+ description: 'Filter by check kind (code-review, security-review, ...). A reviewer that answers one kind lists only that kind.',
1128
+ },
1129
+ project_slug: {
1130
+ type: 'string',
1131
+ description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1132
+ },
1133
+ },
1134
+ },
1135
+ },
1136
+ {
1137
+ name: 'add_work_item_check',
1138
+ description: 'Add a pending review check of a kind (e.g. security-review) to a work item you do not lead, so the reviewer that answers that kind picks it up from its inbox. ' +
1139
+ "Use it when a change touches a sensitive path and needs a second, specialised review. A case waiting on the item's checks keeps waiting until the new check is resolved. " +
1140
+ 'Refused for a kind already pending on the item, for person-only kinds, and on your own work.',
1141
+ inputSchema: {
1142
+ type: 'object',
1143
+ properties: {
1144
+ work_item_id: { type: 'string', description: 'The refId of the work item' },
1145
+ kind: {
1146
+ type: 'string',
1147
+ description: 'The check kind to add, e.g. security-review',
1148
+ },
1149
+ comment: {
1150
+ type: 'string',
1151
+ description: 'Why the check is being requested — posted as a comment on the item',
1152
+ },
1103
1153
  project_slug: {
1104
1154
  type: 'string',
1105
1155
  description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1106
1156
  },
1107
1157
  },
1158
+ required: ['work_item_id', 'kind'],
1108
1159
  },
1109
1160
  },
1110
1161
  {
@@ -1837,6 +1888,52 @@ class WolfpackMCPServer {
1837
1888
  },
1838
1889
  },
1839
1890
  },
1891
+ // Work pool tools (#2083)
1892
+ {
1893
+ name: 'list_work_pools',
1894
+ description: 'List the work pools in a project with their members. Reviewer and DevOps agents find their checks through pool membership, so this is how to see who is routed where.',
1895
+ inputSchema: {
1896
+ type: 'object',
1897
+ properties: {
1898
+ project_slug: {
1899
+ type: 'string',
1900
+ description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1901
+ },
1902
+ },
1903
+ },
1904
+ },
1905
+ {
1906
+ name: 'add_work_pool_member',
1907
+ description: "Add a user or agent (by user id, e.g. an agent profile's userId) to a work pool, named by id or name. Requires mcp:agents:update.",
1908
+ inputSchema: {
1909
+ type: 'object',
1910
+ properties: {
1911
+ work_pool: { type: 'string', description: 'Work pool id or name' },
1912
+ user_id: { type: 'string', description: 'The user id to add' },
1913
+ project_slug: {
1914
+ type: 'string',
1915
+ description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1916
+ },
1917
+ },
1918
+ required: ['work_pool', 'user_id'],
1919
+ },
1920
+ },
1921
+ {
1922
+ name: 'remove_work_pool_member',
1923
+ description: 'Remove a user or agent from a work pool. Requires mcp:agents:update.',
1924
+ inputSchema: {
1925
+ type: 'object',
1926
+ properties: {
1927
+ work_pool: { type: 'string', description: 'Work pool id or name' },
1928
+ user_id: { type: 'string', description: 'The user id to remove' },
1929
+ project_slug: {
1930
+ type: 'string',
1931
+ description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
1932
+ },
1933
+ },
1934
+ required: ['work_pool', 'user_id'],
1935
+ },
1936
+ },
1840
1937
  // Tag tools
1841
1938
  {
1842
1939
  name: 'list_tags',
@@ -2439,7 +2536,7 @@ class WolfpackMCPServer {
2439
2536
  case 'list_work_item_checks': {
2440
2537
  const parsed = ListWorkItemChecksSchema.parse(args);
2441
2538
  const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
2442
- const checks = await this.client.listWorkItemChecks({ workItemId: parsed.work_item_id, status: parsed.status }, teamSlug);
2539
+ const checks = await this.client.listWorkItemChecks({ workItemId: parsed.work_item_id, status: parsed.status, kind: parsed.kind }, teamSlug);
2443
2540
  const text = checks.length === 0
2444
2541
  ? parsed.work_item_id
2445
2542
  ? 'No review checks on this work item'
@@ -2447,6 +2544,19 @@ class WolfpackMCPServer {
2447
2544
  : JSON.stringify(checks.map(formatWorkItemCheck), null, 2);
2448
2545
  return { content: [{ type: 'text', text }] };
2449
2546
  }
2547
+ case 'add_work_item_check': {
2548
+ const parsed = AddWorkItemCheckSchema.parse(args);
2549
+ const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
2550
+ const check = await this.client.addWorkItemCheck(parsed.work_item_id, { kind: parsed.kind, comment: parsed.comment }, teamSlug);
2551
+ return {
2552
+ content: [
2553
+ {
2554
+ type: 'text',
2555
+ text: `Added ${check.kind} check to #${check.workItemRefId} "${check.workItemTitle}"\n\n${JSON.stringify(formatWorkItemCheck(check), null, 2)}`,
2556
+ },
2557
+ ],
2558
+ };
2559
+ }
2450
2560
  case 'claim_work_item_check': {
2451
2561
  const parsed = ClaimWorkItemCheckSchema.parse(args);
2452
2562
  const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
@@ -2938,6 +3048,36 @@ class WolfpackMCPServer {
2938
3048
  content: [{ type: 'text', text: JSON.stringify(categories, null, 2) }],
2939
3049
  };
2940
3050
  }
3051
+ // Work pool handlers (#2083)
3052
+ case 'list_work_pools': {
3053
+ const parsed = ListCategoriesSchema.parse(args);
3054
+ const pools = await this.client.listWorkPools(parsed.project_slug || this.client.getProjectSlug() || undefined);
3055
+ return { content: [{ type: 'text', text: JSON.stringify(pools, null, 2) }] };
3056
+ }
3057
+ case 'add_work_pool_member': {
3058
+ const parsed = WorkPoolMemberSchema.parse(args);
3059
+ await this.client.addWorkPoolMember(parsed.work_pool, parsed.user_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
3060
+ return {
3061
+ content: [
3062
+ {
3063
+ type: 'text',
3064
+ text: `Added ${parsed.user_id} to work pool "${parsed.work_pool}"`,
3065
+ },
3066
+ ],
3067
+ };
3068
+ }
3069
+ case 'remove_work_pool_member': {
3070
+ const parsed = WorkPoolMemberSchema.parse(args);
3071
+ await this.client.removeWorkPoolMember(parsed.work_pool, parsed.user_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
3072
+ return {
3073
+ content: [
3074
+ {
3075
+ type: 'text',
3076
+ text: `Removed ${parsed.user_id} from work pool "${parsed.work_pool}"`,
3077
+ },
3078
+ ],
3079
+ };
3080
+ }
2941
3081
  // Tag handlers
2942
3082
  case 'list_tags': {
2943
3083
  const parsed = ListTagsSchema.parse(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.90",
3
+ "version": "1.0.92",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",