wolfpack-mcp 1.0.0

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 ADDED
@@ -0,0 +1,369 @@
1
+ # Wolfpack MCP Server
2
+
3
+ The Wolfpack MCP (Model Context Protocol) server enables AI assistants to interact with Wolfpack team projects, providing full CRUD operations for work items, issues, wiki pages, journal entries, and more.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g wolfpack-mcp
9
+ ```
10
+
11
+ Or use directly with npx (no installation required):
12
+
13
+ ```bash
14
+ npx wolfpack-mcp
15
+ ```
16
+
17
+ ## Setup
18
+
19
+ ### 1. Generate an API Key
20
+
21
+ 1. Log in to your Wolfpack application at [wolfpacks.work](https://wolfpacks.work)
22
+ 2. Navigate to **Account Settings** → **API Keys**
23
+ 3. Click **Create New Key**
24
+ 4. Give your key a descriptive name (e.g., "Claude MCP Server")
25
+ 5. Select the MCP permissions you want to grant (e.g., work items, issues, wiki)
26
+ 6. Choose an expiration period (or "Never expires" for permanent keys)
27
+ 7. Click **Create Key**
28
+ 8. **Important**: Copy your API key immediately - you won't be able to see it again!
29
+
30
+ ### 2. Configure Claude Desktop
31
+
32
+ Add the MCP server to your Claude Desktop configuration:
33
+
34
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
35
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "wolfpack": {
41
+ "command": "npx",
42
+ "args": ["-y", "wolfpack-mcp"],
43
+ "env": {
44
+ "WOLFPACK_API_KEY": "wfp_sk_your_api_key_here"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ Replace `wfp_sk_your_api_key_here` with your actual API key.
52
+
53
+ **Team Selection**: If you belong to only one team, it will be selected automatically. If you have multiple teams, use the `list_teams` tool to see them, then specify `team_id` in your tool calls.
54
+
55
+ **Optional**: To pre-select a specific team, add `WOLFPACK_TEAM_SLUG` to the env:
56
+
57
+ ```json
58
+ "env": {
59
+ "WOLFPACK_API_KEY": "wfp_sk_your_api_key_here",
60
+ "WOLFPACK_TEAM_SLUG": "your-team-slug"
61
+ }
62
+ ```
63
+
64
+ ### 3. Restart Claude Desktop
65
+
66
+ After updating the configuration, restart Claude Desktop to load the MCP server.
67
+
68
+ ## API Key Permissions
69
+
70
+ Each API key has granular permissions that control which MCP tools are available:
71
+
72
+ | Permission | Tools Enabled |
73
+ | ----------------------- | -------------------------------------------------- |
74
+ | `mcp:work_items:read` | `list_work_items`, `get_work_item` |
75
+ | `mcp:work_items:create` | `create_work_item` |
76
+ | `mcp:work_items:update` | `update_work_progress`, `update_work_item_status` |
77
+ | `mcp:issues:read` | `list_issues`, `get_issue` |
78
+ | `mcp:issues:create` | `create_issue` |
79
+ | `mcp:issues:update` | `update_issue` |
80
+ | `mcp:wiki:read` | `list_wiki_pages`, `get_wiki_page` |
81
+ | `mcp:wiki:create` | `create_wiki_page` |
82
+ | `mcp:wiki:update` | `update_wiki_page` |
83
+ | `mcp:journal:read` | `list_journal_entries`, `get_journal_entry` |
84
+ | `mcp:journal:create` | `create_journal_entry` |
85
+ | `mcp:journal:update` | `update_journal_entry` |
86
+ | `mcp:comments:create` | `create_work_item_comment`, `create_issue_comment` |
87
+ | `mcp:radar:read` | `list_radar_items`, `get_radar_item` |
88
+
89
+ ## Available Tools
90
+
91
+ ### Teams
92
+
93
+ #### `list_teams`
94
+
95
+ List all teams you have access to. Use this to discover available teams and get team IDs.
96
+
97
+ - **Parameters:** None
98
+ - **Returns:** Array of team objects with `id`, `slug`, and `name`
99
+
100
+ ### Work Items
101
+
102
+ Work items are tasks or tickets assigned to team members.
103
+
104
+ #### `list_work_items`
105
+
106
+ Lists work items assigned to you.
107
+
108
+ - **Parameters:**
109
+ - `team_id` (number, optional): Team ID (use `list_teams` to get IDs)
110
+ - `status` (string, optional): Filter by status (new, doing, review, completed, blocked)
111
+ - `limit` (number, optional): Maximum number of items to return
112
+ - `offset` (number, optional): Number of items to skip for pagination
113
+ - **Returns:** Array of work item objects
114
+
115
+ #### `get_work_item`
116
+
117
+ Gets a specific work item by ID or reference number.
118
+
119
+ - **Parameters:**
120
+ - `work_item_id` (string, required): The work item ID (UUID) or refId (number)
121
+ - `team_id` (number, optional): Team ID (required when using refId)
122
+ - **Returns:** Work item object with full description
123
+
124
+ #### `create_work_item`
125
+
126
+ Creates a new work item. Requires `mcp:work_items:create` permission.
127
+
128
+ - **Parameters:**
129
+ - `title` (string, required): Title of the work item
130
+ - `description` (string, optional): Description/notes (markdown)
131
+ - `status` (string, optional): Initial status (new, doing, review, completed, blocked - defaults to 'new')
132
+ - `priority` (number, optional): Priority level (0-4, higher is more important)
133
+ - `leading_user_id` (string, optional): User ID to assign
134
+ - **Returns:** The created work item object
135
+
136
+ #### `update_work_progress`
137
+
138
+ Updates the description/notes on a work item. Requires `mcp:work_items:update` permission.
139
+
140
+ - **Parameters:**
141
+ - `work_item_id` (string, required): The work item ID
142
+ - `description` (string, required): Complete updated description (markdown)
143
+ - **Returns:** The updated work item object
144
+
145
+ #### `update_work_item_status`
146
+
147
+ Changes work item status. Requires `mcp:work_items:update` permission.
148
+
149
+ - **Parameters:**
150
+ - `work_item_id` (string, required): The work item ID
151
+ - `status` (string, required): New status (new, doing, review, completed, blocked)
152
+ - **Returns:** The updated work item object
153
+
154
+ ### Issues
155
+
156
+ Issues track bugs, feature requests, and other items in the issue tracker.
157
+
158
+ #### `list_issues`
159
+
160
+ Lists issues from the team issue tracker.
161
+
162
+ - **Parameters:**
163
+ - `team_id` (number, optional): Team ID to filter issues
164
+ - `status` (string, optional): Filter by status (open, in-progress, resolved, closed)
165
+ - `severity` (string, optional): Filter by severity (low, medium, high, critical)
166
+ - `type` (string, optional): Filter by type (bug, feature-request, task, improvement, question)
167
+ - `assigned_to_id` (string, optional): Filter by assignee ('unassigned' or 'me' for special cases)
168
+ - `limit` (number, optional): Maximum number of items
169
+ - `offset` (number, optional): Items to skip
170
+ - **Returns:** Array of issue objects
171
+
172
+ #### `get_issue`
173
+
174
+ Gets a specific issue by ID or reference number.
175
+
176
+ - **Parameters:**
177
+ - `issue_id` (string, required): The issue ID (UUID) or refId (number)
178
+ - `team_id` (number, optional): Team ID (required when using refId)
179
+ - **Returns:** Issue object with comment and attachment counts
180
+
181
+ #### `create_issue`
182
+
183
+ Creates a new issue. Requires `mcp:issues:create` permission.
184
+
185
+ - **Parameters:**
186
+ - `title` (string, required): Issue title
187
+ - `description` (string, optional): Issue description
188
+ - `severity` (string, optional): Severity level (low, medium, high, critical)
189
+ - `type` (string, optional): Issue type (bug, feature-request, task, improvement, question)
190
+ - `assigned_to_id` (string, optional): User ID to assign
191
+ - `environment` (string, optional): Environment where issue occurred
192
+ - `affected_version` (string, optional): Version affected
193
+ - `reproducible` (boolean, optional): Whether reproducible
194
+ - `steps_to_reproduce` (string, optional): Steps to reproduce
195
+ - `expected_behavior` (string, optional): Expected behavior
196
+ - `actual_behavior` (string, optional): Actual behavior observed
197
+ - **Returns:** The created issue object
198
+
199
+ #### `update_issue`
200
+
201
+ Updates an existing issue. Requires `mcp:issues:update` permission.
202
+
203
+ - **Parameters:**
204
+ - `issue_id` (string, required): The issue UUID
205
+ - `title` (string, optional): Updated title
206
+ - `description` (string, optional): Updated description
207
+ - `status` (string, optional): Updated status (open, in-progress, resolved, closed)
208
+ - `severity` (string, optional): Updated severity
209
+ - `assigned_to_id` (string, optional): Updated assignee
210
+ - `closing_note` (string, optional): Note when closing
211
+ - **Returns:** The updated issue object
212
+
213
+ ### Wiki Pages
214
+
215
+ Wiki pages store team documentation and knowledge base articles.
216
+
217
+ #### `list_wiki_pages`
218
+
219
+ Lists wiki pages from your accessible teams.
220
+
221
+ - **Parameters:**
222
+ - `limit` (number, optional): Maximum pages to return
223
+ - `offset` (number, optional): Pages to skip
224
+ - **Returns:** Array of wiki page objects
225
+
226
+ #### `get_wiki_page`
227
+
228
+ Gets a specific wiki page by ID or slug.
229
+
230
+ - **Parameters:**
231
+ - `page_id` (string, required): The page UUID or slug (URL path like "getting-started")
232
+ - **Returns:** Wiki page object with content
233
+
234
+ #### `create_wiki_page`
235
+
236
+ Creates a new wiki page. Requires `mcp:wiki:create` permission.
237
+
238
+ - **Parameters:**
239
+ - `slug` (string, required): URL slug for the page (without team prefix)
240
+ - `title` (string, required): Page title
241
+ - `content` (string, required): Page content (markdown)
242
+ - **Returns:** The created wiki page object
243
+
244
+ #### `update_wiki_page`
245
+
246
+ Updates an existing wiki page. Requires `mcp:wiki:update` permission.
247
+
248
+ - **Parameters:**
249
+ - `page_id` (string, required): The page UUID
250
+ - `title` (string, optional): Updated title
251
+ - `content` (string, optional): Updated content (markdown)
252
+ - **Returns:** The updated wiki page object
253
+
254
+ ### Journal Entries
255
+
256
+ Journal entries are daily logs, standup notes, or progress updates.
257
+
258
+ #### `list_journal_entries`
259
+
260
+ Lists journal entries from your accessible teams.
261
+
262
+ - **Parameters:**
263
+ - `limit` (number, optional): Maximum entries to return
264
+ - `offset` (number, optional): Entries to skip
265
+ - **Returns:** Array of journal entry objects
266
+
267
+ #### `get_journal_entry`
268
+
269
+ Gets a specific journal entry by ID or reference number.
270
+
271
+ - **Parameters:**
272
+ - `entry_id` (string, required): The entry UUID or refId
273
+ - `team_id` (number, optional): Team ID (required when using refId)
274
+ - **Returns:** Journal entry object
275
+
276
+ #### `create_journal_entry`
277
+
278
+ Creates a new journal entry. Requires `mcp:journal:create` permission.
279
+
280
+ - **Parameters:**
281
+ - `title` (string, required): Entry title
282
+ - `content` (string, required): Entry content (markdown)
283
+ - `date` (string, optional): Entry date (ISO format, defaults to now)
284
+ - **Returns:** The created journal entry object
285
+
286
+ #### `update_journal_entry`
287
+
288
+ Updates an existing journal entry. Requires `mcp:journal:update` permission.
289
+
290
+ - **Parameters:**
291
+ - `entry_id` (string, required): The entry UUID
292
+ - `title` (string, optional): Updated title
293
+ - `content` (string, optional): Updated content (markdown)
294
+ - **Returns:** The updated journal entry object
295
+
296
+ ### Comments
297
+
298
+ #### `create_work_item_comment`
299
+
300
+ Adds a comment to a work item. Requires `mcp:comments:create` permission.
301
+
302
+ - **Parameters:**
303
+ - `work_item_id` (string, required): The work item UUID
304
+ - `content` (string, required): Comment content (markdown)
305
+ - **Returns:** The created comment object
306
+
307
+ #### `create_issue_comment`
308
+
309
+ Adds a comment to an issue. Requires `mcp:comments:create` permission.
310
+
311
+ - **Parameters:**
312
+ - `issue_id` (string, required): The issue UUID
313
+ - `content` (string, required): Comment content (markdown)
314
+ - **Returns:** The created comment object
315
+
316
+ ### Radar Items (Initiatives)
317
+
318
+ Radar items are strategic initiatives or roadmap items that group related work.
319
+
320
+ #### `list_radar_items`
321
+
322
+ Lists radar items from the team.
323
+
324
+ - **Parameters:**
325
+ - `team_id` (number, optional): Team ID to filter
326
+ - `stage` (string, optional): Filter by stage (pending, now, next, later, completed)
327
+ - `limit` (number, optional): Maximum items to return
328
+ - `offset` (number, optional): Items to skip
329
+ - **Returns:** Array of radar item objects
330
+
331
+ #### `get_radar_item`
332
+
333
+ Gets a specific radar item by ID or reference number.
334
+
335
+ - **Parameters:**
336
+ - `item_id` (string, required): The radar item ID (UUID) or refId (number)
337
+ - `team_id` (number, optional): Team ID (required when using refId)
338
+ - **Returns:** Radar item object with work items and participants
339
+
340
+ ## Security
341
+
342
+ - API keys authenticate with your Wolfpack account
343
+ - Each key has configurable permissions for granular access control
344
+ - Two-layer permission system: API key permissions checked first, then team role permissions
345
+ - All operations are scoped to teams you are a member of
346
+ - API keys can be revoked at any time from the Wolfpack application
347
+ - All changes are logged with `source: 'mcp'` for audit trails
348
+
349
+ ## Troubleshooting
350
+
351
+ ### "WOLFPACK_API_KEY environment variable is required"
352
+
353
+ This error means the API key is not configured. Check your Claude Desktop configuration file and ensure the `WOLFPACK_API_KEY` is set correctly.
354
+
355
+ ### "Invalid API key"
356
+
357
+ Your API key may be incorrect or has been revoked. Generate a new API key from the Wolfpack application.
358
+
359
+ ### "API key does not have permission: mcp:..."
360
+
361
+ Your API key doesn't have the required MCP permission. Create a new key with the appropriate permissions enabled.
362
+
363
+ ### Connection errors
364
+
365
+ Ensure:
366
+
367
+ 1. The Wolfpack service is available at [wolfpacks.work](https://wolfpacks.work)
368
+ 2. Your network allows connections to the backend
369
+ 3. If self-hosting, verify `WOLFPACK_API_URL` points to the correct backend URL
@@ -0,0 +1,118 @@
1
+ import fetch from 'node-fetch';
2
+ import { config } from './config.js';
3
+ export class ApiError extends Error {
4
+ status;
5
+ constructor(status, message) {
6
+ super(message);
7
+ this.status = status;
8
+ this.name = 'ApiError';
9
+ }
10
+ }
11
+ export class ApiClient {
12
+ headers = {
13
+ Authorization: `Bearer ${config.apiKey}`,
14
+ 'Content-Type': 'application/json',
15
+ };
16
+ async get(path) {
17
+ const url = `${config.apiUrl}${path}`;
18
+ try {
19
+ const response = await fetch(url, {
20
+ method: 'GET',
21
+ headers: this.headers,
22
+ });
23
+ if (!response.ok) {
24
+ const errorText = await response.text();
25
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
26
+ }
27
+ return (await response.json());
28
+ }
29
+ catch (error) {
30
+ if (error instanceof ApiError) {
31
+ throw error;
32
+ }
33
+ throw new Error(`Failed to GET ${path}: ${error}`);
34
+ }
35
+ }
36
+ async post(path, body) {
37
+ const url = `${config.apiUrl}${path}`;
38
+ try {
39
+ const response = await fetch(url, {
40
+ method: 'POST',
41
+ headers: this.headers,
42
+ body: JSON.stringify(body),
43
+ });
44
+ if (!response.ok) {
45
+ const errorText = await response.text();
46
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
47
+ }
48
+ return (await response.json());
49
+ }
50
+ catch (error) {
51
+ if (error instanceof ApiError) {
52
+ throw error;
53
+ }
54
+ throw new Error(`Failed to POST ${path}: ${error}`);
55
+ }
56
+ }
57
+ async put(path, body) {
58
+ const url = `${config.apiUrl}${path}`;
59
+ try {
60
+ const response = await fetch(url, {
61
+ method: 'PUT',
62
+ headers: this.headers,
63
+ body: JSON.stringify(body),
64
+ });
65
+ if (!response.ok) {
66
+ const errorText = await response.text();
67
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
68
+ }
69
+ return (await response.json());
70
+ }
71
+ catch (error) {
72
+ if (error instanceof ApiError) {
73
+ throw error;
74
+ }
75
+ throw new Error(`Failed to PUT ${path}: ${error}`);
76
+ }
77
+ }
78
+ async patch(path, body) {
79
+ const url = `${config.apiUrl}${path}`;
80
+ try {
81
+ const response = await fetch(url, {
82
+ method: 'PATCH',
83
+ headers: this.headers,
84
+ body: JSON.stringify(body),
85
+ });
86
+ if (!response.ok) {
87
+ const errorText = await response.text();
88
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
89
+ }
90
+ return (await response.json());
91
+ }
92
+ catch (error) {
93
+ if (error instanceof ApiError) {
94
+ throw error;
95
+ }
96
+ throw new Error(`Failed to PATCH ${path}: ${error}`);
97
+ }
98
+ }
99
+ async delete(path) {
100
+ const url = `${config.apiUrl}${path}`;
101
+ try {
102
+ const response = await fetch(url, {
103
+ method: 'DELETE',
104
+ headers: this.headers,
105
+ });
106
+ if (!response.ok) {
107
+ const errorText = await response.text();
108
+ throw new ApiError(response.status, `API error: ${response.statusText} - ${errorText}`);
109
+ }
110
+ }
111
+ catch (error) {
112
+ if (error instanceof ApiError) {
113
+ throw error;
114
+ }
115
+ throw new Error(`Failed to DELETE ${path}: ${error}`);
116
+ }
117
+ }
118
+ }