wolfpack-mcp 1.0.36 → 1.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,36 +5,36 @@
5
5
  Connect your AI assistant to Wolfpack to manage work items, track issues, update documentation, and log progress—all
6
6
  through natural conversation.
7
7
 
8
- ## Installation
8
+ ## Quick Start
9
9
 
10
- ```bash
11
- npm install -g wolfpack-mcp
12
- ```
10
+ There are two ways to connect:
13
11
 
14
- Or use directly with npx (no installation required):
12
+ - **Claude Desktop** — Use the remote MCP server with OAuth (no API key needed)
13
+ - **Coding agents** (Claude Code, Cursor, Windsurf, etc.) — Use this npm package via stdio with an API key
15
14
 
16
- ```bash
17
- npx wolfpack-mcp
18
- ```
15
+ ### Claude Desktop (Remote MCP)
19
16
 
20
- ## Quick Start
17
+ Add to your Claude Desktop config file:
21
18
 
22
- 1. Generate an API key at [wolfpacks.work](https://wolfpacks.work) → Account Settings → API Keys
23
- 2. Add the server to Claude Desktop (see [Setup](#setup) below)
24
- 3. Restart Claude Desktop
25
- 4. Start asking Claude about your work!
19
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
20
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
26
21
 
27
- **Try these prompts:**
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "wolfpack": {
26
+ "type": "url",
27
+ "url": "https://wolfpacks.work/mcp"
28
+ }
29
+ }
30
+ }
31
+ ```
28
32
 
29
- - "What work items are assigned to me?"
30
- - "Show me open bugs"
31
- - "Create a work item to refactor the auth module"
32
- - "Update issue #42 status to in-progress"
33
- - "Add a journal entry about today's progress"
33
+ Restart Claude Desktop. You'll be prompted to sign in with your Wolfpack account via OAuth.
34
34
 
35
- ## Setup
35
+ ### Coding Agents (stdio)
36
36
 
37
- ### 1. Generate an API Key
37
+ #### 1. Generate an API Key
38
38
 
39
39
  1. Log in to [wolfpacks.work](https://wolfpacks.work)
40
40
  2. Go to **Account Settings** → **API Keys**
@@ -42,12 +42,9 @@ npx wolfpack-mcp
42
42
  4. Select the permissions you need (work items, issues, wiki, etc.)
43
43
  5. Copy your API key immediately—you won't see it again
44
44
 
45
- ### 2. Configure Claude Desktop
45
+ #### 2. Configure Your Agent
46
46
 
47
- Add to your Claude Desktop config file:
48
-
49
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
50
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
47
+ **Claude Code** (`~/.claude/settings.json` or project `.mcp.json`):
51
48
 
52
49
  ```json
53
50
  {
@@ -63,9 +60,27 @@ Add to your Claude Desktop config file:
63
60
  }
64
61
  ```
65
62
 
66
- ### 3. Restart Claude Desktop
63
+ **Cursor / Windsurf** use the same `command`, `args`, and `env` in your editor's MCP configuration.
67
64
 
68
- After saving the configuration, restart Claude Desktop to connect.
65
+ ## Installation
66
+
67
+ ```bash
68
+ npm install -g wolfpack-mcp
69
+ ```
70
+
71
+ Or use directly with npx (no installation required):
72
+
73
+ ```bash
74
+ npx wolfpack-mcp
75
+ ```
76
+
77
+ **Try these prompts:**
78
+
79
+ - "What work items are assigned to me?"
80
+ - "Show me open bugs"
81
+ - "Create a work item to refactor the auth module"
82
+ - "Update issue #42 status to in-progress"
83
+ - "Add a journal entry about today's progress"
69
84
 
70
85
  ## What You Can Do
71
86
 
@@ -79,12 +94,12 @@ After saving the configuration, restart Claude Desktop to connect.
79
94
 
80
95
  ## Multiple Projects
81
96
 
82
- If you belong to multiple project teams, Claude will ask which team you mean, or you can specify:
97
+ If you belong to multiple project teams, your AI assistant will ask which team you mean, or you can specify:
83
98
 
84
99
  - "Show my work items for the Platform team"
85
100
  - Use `list_teams` to see all your teams
86
101
 
87
- To pre-select a default team, add `WOLFPACK_TEAM_SLUG` to your config:
102
+ To pre-select a default project for coding agents, add `WOLFPACK_TEAM_SLUG` to your env config:
88
103
 
89
104
  ```json
90
105
  {
@@ -100,7 +115,7 @@ The MCP server is designed to work within **one project at a time**:
100
115
  - The agent will identify which project you're working in before taking actions
101
116
  - Once a project is identified, all operations stay within that project
102
117
  - The agent will not perform bulk actions across multiple projects
103
- - To switch projects, explicitly tell Claude (e.g., "switch to the Platform project")
118
+ - To switch projects, explicitly ask (e.g., "switch to the Platform project")
104
119
 
105
120
  ## Available Tools Reference
106
121
 
package/dist/apiClient.js CHANGED
@@ -8,6 +8,16 @@ export class ApiError extends Error {
8
8
  this.name = 'ApiError';
9
9
  }
10
10
  }
11
+ function formatError(error) {
12
+ if (error instanceof Error) {
13
+ const code = error.code;
14
+ if (code)
15
+ return `${error.message} (${code})`;
16
+ if (error.message)
17
+ return error.message;
18
+ }
19
+ return String(error) || 'unknown error';
20
+ }
11
21
  export class ApiClient {
12
22
  headers = {
13
23
  Authorization: `Bearer ${config.apiKey}`,
@@ -30,7 +40,7 @@ export class ApiClient {
30
40
  if (error instanceof ApiError) {
31
41
  throw error;
32
42
  }
33
- throw new Error(`Failed to GET ${path}: ${error}`);
43
+ throw new Error(`Failed to GET ${path}: ${formatError(error)}`);
34
44
  }
35
45
  }
36
46
  async post(path, body) {
@@ -51,7 +61,7 @@ export class ApiClient {
51
61
  if (error instanceof ApiError) {
52
62
  throw error;
53
63
  }
54
- throw new Error(`Failed to POST ${path}: ${error}`);
64
+ throw new Error(`Failed to POST ${path}: ${formatError(error)}`);
55
65
  }
56
66
  }
57
67
  async put(path, body) {
@@ -72,7 +82,7 @@ export class ApiClient {
72
82
  if (error instanceof ApiError) {
73
83
  throw error;
74
84
  }
75
- throw new Error(`Failed to PUT ${path}: ${error}`);
85
+ throw new Error(`Failed to PUT ${path}: ${formatError(error)}`);
76
86
  }
77
87
  }
78
88
  async patch(path, body) {
@@ -93,7 +103,7 @@ export class ApiClient {
93
103
  if (error instanceof ApiError) {
94
104
  throw error;
95
105
  }
96
- throw new Error(`Failed to PATCH ${path}: ${error}`);
106
+ throw new Error(`Failed to PATCH ${path}: ${formatError(error)}`);
97
107
  }
98
108
  }
99
109
  async getBuffer(path) {
@@ -119,7 +129,7 @@ export class ApiClient {
119
129
  if (error instanceof ApiError) {
120
130
  throw error;
121
131
  }
122
- throw new Error(`Failed to GET buffer ${path}: ${error}`);
132
+ throw new Error(`Failed to GET buffer ${path}: ${formatError(error)}`);
123
133
  }
124
134
  }
125
135
  async postMultipart(path, buffer, filename, mimeType) {
@@ -166,7 +176,7 @@ export class ApiClient {
166
176
  if (error instanceof ApiError) {
167
177
  throw error;
168
178
  }
169
- throw new Error(`Failed to DELETE ${path}: ${error}`);
179
+ throw new Error(`Failed to DELETE ${path}: ${formatError(error)}`);
170
180
  }
171
181
  }
172
182
  }
package/dist/client.js CHANGED
@@ -191,6 +191,28 @@ export class WolfpackClient {
191
191
  throw error;
192
192
  }
193
193
  }
194
+ async updateWorkItemTitle(workItemId, title) {
195
+ try {
196
+ return await this.api.put(`/work-items/${workItemId}/title`, { title });
197
+ }
198
+ catch (error) {
199
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
200
+ return null;
201
+ }
202
+ throw error;
203
+ }
204
+ }
205
+ async updateWorkItemInitiative(workItemId, radarItemId) {
206
+ try {
207
+ return await this.api.put(`/work-items/${workItemId}/initiative`, { radarItemId });
208
+ }
209
+ catch (error) {
210
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
211
+ return null;
212
+ }
213
+ throw error;
214
+ }
215
+ }
194
216
  async pullWorkItem(workItemId, data) {
195
217
  try {
196
218
  return await this.api.post(`/work-items/${workItemId}/pull`, data || {});
@@ -202,6 +224,19 @@ export class WolfpackClient {
202
224
  throw error;
203
225
  }
204
226
  }
227
+ async submitWorkItemForm(workItemId, formValues) {
228
+ try {
229
+ return await this.api.put(`/work-items/${workItemId}/form`, {
230
+ formValues,
231
+ });
232
+ }
233
+ catch (error) {
234
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
235
+ return null;
236
+ }
237
+ throw error;
238
+ }
239
+ }
205
240
  // Radar Item (Initiative/Roadmap) methods
206
241
  async listRadarItems(options) {
207
242
  const params = new URLSearchParams();
package/dist/index.js CHANGED
@@ -113,6 +113,17 @@ const UpdateWorkItemAssigneeSchema = z.object({
113
113
  .nullable()
114
114
  .describe('User ID to assign as leading user, or null to unassign'),
115
115
  });
116
+ const UpdateWorkItemTitleSchema = z.object({
117
+ work_item_id: z.string().describe('The ID of the work item'),
118
+ title: z.string().describe('New title for the work item'),
119
+ });
120
+ const UpdateWorkItemInitiativeSchema = z.object({
121
+ work_item_id: z.string().describe('The ID of the work item'),
122
+ radar_item_id: z
123
+ .string()
124
+ .nullable()
125
+ .describe('Radar/initiative item ID to link to, or null to unlink'),
126
+ });
116
127
  const PullWorkItemSchema = z.object({
117
128
  work_item_id: z.string().describe('The ID of the work item to pull from backlog'),
118
129
  leading_user_id: z
@@ -120,6 +131,10 @@ const PullWorkItemSchema = z.object({
120
131
  .optional()
121
132
  .describe('User ID to assign as leading user (defaults to API key owner)'),
122
133
  });
134
+ const SubmitWorkItemFormSchema = z.object({
135
+ work_item_id: z.string().describe('The ID of the work item'),
136
+ form_values: z.record(z.any()).describe('Key-value pairs matching formDefinition field names'),
137
+ });
123
138
  // Radar Item (Initiative/Roadmap) schemas
124
139
  const ListRadarItemsSchema = z.object({
125
140
  project_slug: z.string().optional().describe('Project slug to filter radar items'),
@@ -185,6 +200,10 @@ const CreateWorkItemSchema = z.object({
185
200
  .optional()
186
201
  .describe('Initial status: "pending" (backlog), "new" (to do), "doing", "review", "ready", "blocked", "completed". Defaults to "new".'),
187
202
  priority: z.number().optional().describe('Priority level (0-4, higher is more important)'),
203
+ size: z
204
+ .enum(['S', 'M', 'L'])
205
+ .optional()
206
+ .describe('Size estimate: "S" (small), "M" (medium), "L" (large)'),
188
207
  leading_user_id: z.string().optional().describe('User ID to assign as leading user'),
189
208
  category_id: z.string().optional().describe('Category ID to organize the work item'),
190
209
  radar_item_id: z.string().optional().describe('Radar/initiative item ID to link to'),
@@ -444,6 +463,7 @@ class WolfpackMCPServer {
444
463
  'WORKFLOW: When asked to work on an item, check its status and follow the required state transitions ' +
445
464
  '(pending→pull first, new→doing, blocked/ready/completed/closed→new→doing, then review when done). ' +
446
465
  '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. ' +
466
+ '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. ' +
447
467
  'IMAGES: Image references in the description (e.g. `![alt](/api/files/images/...)`) can be viewed using the download_image tool.',
448
468
  inputSchema: {
449
469
  type: 'object',
@@ -534,6 +554,44 @@ class WolfpackMCPServer {
534
554
  required: ['work_item_id', 'leading_user_id'],
535
555
  },
536
556
  },
557
+ {
558
+ name: 'update_work_item_title',
559
+ description: 'Change the title of a work item. ' +
560
+ 'Use this to rename or update the title of an existing work item.',
561
+ inputSchema: {
562
+ type: 'object',
563
+ properties: {
564
+ work_item_id: {
565
+ type: 'string',
566
+ description: 'The ID of the work item',
567
+ },
568
+ title: {
569
+ type: 'string',
570
+ description: 'New title for the work item',
571
+ },
572
+ },
573
+ required: ['work_item_id', 'title'],
574
+ },
575
+ },
576
+ {
577
+ name: 'update_work_item_initiative',
578
+ description: 'Link or unlink a work item to/from a radar item (initiative). ' +
579
+ 'Pass a radar_item_id to link, or null to remove the initiative link.',
580
+ inputSchema: {
581
+ type: 'object',
582
+ properties: {
583
+ work_item_id: {
584
+ type: 'string',
585
+ description: 'The ID of the work item',
586
+ },
587
+ radar_item_id: {
588
+ type: ['string', 'null'],
589
+ description: 'Radar/initiative item ID to link to, or null to unlink',
590
+ },
591
+ },
592
+ required: ['work_item_id', 'radar_item_id'],
593
+ },
594
+ },
537
595
  {
538
596
  name: 'pull_work_item',
539
597
  description: 'Pull a specific work item from the backlog to the board. ' +
@@ -557,6 +615,26 @@ class WolfpackMCPServer {
557
615
  required: ['work_item_id'],
558
616
  },
559
617
  },
618
+ {
619
+ name: 'submit_work_item_form',
620
+ description: 'Submit form values for a procedure-created work item. ' +
621
+ 'Use get_work_item first to see formDefinition (field names, types, required) and current formValues. ' +
622
+ 'Then call this with form_values mapping field names to values.',
623
+ inputSchema: {
624
+ type: 'object',
625
+ properties: {
626
+ work_item_id: {
627
+ type: 'string',
628
+ description: 'The ID of the work item',
629
+ },
630
+ form_values: {
631
+ type: 'object',
632
+ description: 'Key-value pairs matching formDefinition field names',
633
+ },
634
+ },
635
+ required: ['work_item_id', 'form_values'],
636
+ },
637
+ },
560
638
  // Radar Item (Initiative/Roadmap) tools
561
639
  {
562
640
  name: 'list_radar_items',
@@ -714,6 +792,11 @@ class WolfpackMCPServer {
714
792
  type: 'number',
715
793
  description: 'Priority level (0-4, higher is more important)',
716
794
  },
795
+ size: {
796
+ type: 'string',
797
+ enum: ['S', 'M', 'L'],
798
+ description: 'Size estimate: "S" (small), "M" (medium), "L" (large)',
799
+ },
717
800
  leading_user_id: {
718
801
  type: 'string',
719
802
  description: 'User ID to assign as leading user',
@@ -1183,6 +1266,43 @@ class WolfpackMCPServer {
1183
1266
  content: [{ type: 'text', text: 'Work item not found' }],
1184
1267
  };
1185
1268
  }
1269
+ case 'update_work_item_title': {
1270
+ const parsed = UpdateWorkItemTitleSchema.parse(args);
1271
+ const workItem = await this.client.updateWorkItemTitle(parsed.work_item_id, parsed.title);
1272
+ if (workItem) {
1273
+ return {
1274
+ content: [
1275
+ {
1276
+ type: 'text',
1277
+ text: `Updated title to "${workItem.title}"\n\n${JSON.stringify(workItem, null, 2)}`,
1278
+ },
1279
+ ],
1280
+ };
1281
+ }
1282
+ return {
1283
+ content: [{ type: 'text', text: 'Work item not found' }],
1284
+ };
1285
+ }
1286
+ case 'update_work_item_initiative': {
1287
+ const parsed = UpdateWorkItemInitiativeSchema.parse(args);
1288
+ const workItem = await this.client.updateWorkItemInitiative(parsed.work_item_id, parsed.radar_item_id);
1289
+ if (workItem) {
1290
+ const initiativeText = parsed.radar_item_id
1291
+ ? `linked to initiative ${parsed.radar_item_id}`
1292
+ : 'unlinked from initiative';
1293
+ return {
1294
+ content: [
1295
+ {
1296
+ type: 'text',
1297
+ text: `Updated "${workItem.title}" - ${initiativeText}\n\n${JSON.stringify(workItem, null, 2)}`,
1298
+ },
1299
+ ],
1300
+ };
1301
+ }
1302
+ return {
1303
+ content: [{ type: 'text', text: 'Work item not found' }],
1304
+ };
1305
+ }
1186
1306
  case 'pull_work_item': {
1187
1307
  const parsed = PullWorkItemSchema.parse(args);
1188
1308
  const workItem = await this.client.pullWorkItem(parsed.work_item_id, {
@@ -1202,6 +1322,23 @@ class WolfpackMCPServer {
1202
1322
  content: [{ type: 'text', text: 'Work item not found' }],
1203
1323
  };
1204
1324
  }
1325
+ case 'submit_work_item_form': {
1326
+ const parsed = SubmitWorkItemFormSchema.parse(args);
1327
+ const workItem = await this.client.submitWorkItemForm(parsed.work_item_id, parsed.form_values);
1328
+ if (workItem) {
1329
+ return {
1330
+ content: [
1331
+ {
1332
+ type: 'text',
1333
+ text: `Submitted form values for "${workItem.title}"\n\n${JSON.stringify(workItem, null, 2)}`,
1334
+ },
1335
+ ],
1336
+ };
1337
+ }
1338
+ return {
1339
+ content: [{ type: 'text', text: 'Work item not found' }],
1340
+ };
1341
+ }
1205
1342
  // Radar Item handlers
1206
1343
  case 'list_radar_items': {
1207
1344
  const parsed = ListRadarItemsSchema.parse(args);
@@ -1277,6 +1414,7 @@ class WolfpackMCPServer {
1277
1414
  description: parsed.description,
1278
1415
  status: parsed.status,
1279
1416
  priority: parsed.priority,
1417
+ size: parsed.size,
1280
1418
  leadingUserId: parsed.leading_user_id,
1281
1419
  categoryId: parsed.category_id,
1282
1420
  radarItemId: parsed.radar_item_id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolfpack-mcp",
3
- "version": "1.0.36",
3
+ "version": "1.0.38",
4
4
  "description": "MCP server for Wolfpack AI-enhanced software delivery tools",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",