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 +369 -0
- package/dist/apiClient.js +118 -0
- package/dist/client.js +229 -0
- package/dist/config.js +26 -0
- package/dist/index.js +939 -0
- package/dist/types.js +2 -0
- package/package.json +51 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { ApiClient } from './apiClient.js';
|
|
2
|
+
export class WolfpackClient {
|
|
3
|
+
api;
|
|
4
|
+
teamId = null;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.api = new ApiClient();
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Fetch and cache the team ID from the team slug.
|
|
10
|
+
* Uses the MCP team endpoint to get team info.
|
|
11
|
+
*/
|
|
12
|
+
async resolveTeamSlug(teamSlug) {
|
|
13
|
+
try {
|
|
14
|
+
const team = await this.api.get(`/team/${teamSlug}`);
|
|
15
|
+
this.teamId = team.id;
|
|
16
|
+
return team.id;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error(`Failed to resolve team slug "${teamSlug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
getTeamId() {
|
|
23
|
+
return this.teamId;
|
|
24
|
+
}
|
|
25
|
+
setTeamId(teamId) {
|
|
26
|
+
this.teamId = teamId;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all teams the authenticated user is a member of.
|
|
30
|
+
*/
|
|
31
|
+
async listTeams() {
|
|
32
|
+
return this.api.get('/teams');
|
|
33
|
+
}
|
|
34
|
+
// Work Item methods
|
|
35
|
+
async listWorkItems(options) {
|
|
36
|
+
const params = new URLSearchParams();
|
|
37
|
+
if (options?.teamId)
|
|
38
|
+
params.append('teamId', options.teamId.toString());
|
|
39
|
+
if (options?.status)
|
|
40
|
+
params.append('status', options.status);
|
|
41
|
+
if (options?.limit)
|
|
42
|
+
params.append('limit', options.limit.toString());
|
|
43
|
+
if (options?.offset)
|
|
44
|
+
params.append('offset', options.offset.toString());
|
|
45
|
+
const query = params.toString();
|
|
46
|
+
return this.api.get(`/work-items${query ? `?${query}` : ''}`);
|
|
47
|
+
}
|
|
48
|
+
async getWorkItem(workItemId, teamId) {
|
|
49
|
+
try {
|
|
50
|
+
const params = new URLSearchParams();
|
|
51
|
+
if (teamId)
|
|
52
|
+
params.append('teamId', teamId.toString());
|
|
53
|
+
const query = params.toString();
|
|
54
|
+
return await this.api.get(`/work-items/${workItemId}${query ? `?${query}` : ''}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async updateWorkProgress(workItemId, description) {
|
|
64
|
+
try {
|
|
65
|
+
return await this.api.put(`/work-items/${workItemId}/progress`, {
|
|
66
|
+
description,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async updateWorkItemStatus(workItemId, status) {
|
|
77
|
+
try {
|
|
78
|
+
return await this.api.put(`/work-items/${workItemId}/status`, { status });
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Radar Item (Initiative/Roadmap) methods
|
|
88
|
+
async listRadarItems(options) {
|
|
89
|
+
const params = new URLSearchParams();
|
|
90
|
+
if (options?.teamId)
|
|
91
|
+
params.append('teamId', options.teamId.toString());
|
|
92
|
+
if (options?.stage)
|
|
93
|
+
params.append('stage', options.stage);
|
|
94
|
+
if (options?.limit)
|
|
95
|
+
params.append('limit', options.limit.toString());
|
|
96
|
+
if (options?.offset)
|
|
97
|
+
params.append('offset', options.offset.toString());
|
|
98
|
+
const query = params.toString();
|
|
99
|
+
return this.api.get(`/radar-items${query ? `?${query}` : ''}`);
|
|
100
|
+
}
|
|
101
|
+
async getRadarItem(itemId, teamId) {
|
|
102
|
+
try {
|
|
103
|
+
const params = new URLSearchParams();
|
|
104
|
+
if (teamId)
|
|
105
|
+
params.append('teamId', teamId.toString());
|
|
106
|
+
const query = params.toString();
|
|
107
|
+
return await this.api.get(`/radar-items/${itemId}${query ? `?${query}` : ''}`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Issue methods
|
|
117
|
+
async listIssues(options) {
|
|
118
|
+
const params = new URLSearchParams();
|
|
119
|
+
if (options?.teamId)
|
|
120
|
+
params.append('teamId', options.teamId.toString());
|
|
121
|
+
if (options?.status)
|
|
122
|
+
params.append('status', options.status);
|
|
123
|
+
if (options?.severity)
|
|
124
|
+
params.append('severity', options.severity);
|
|
125
|
+
if (options?.type)
|
|
126
|
+
params.append('type', options.type);
|
|
127
|
+
if (options?.assignedToId)
|
|
128
|
+
params.append('assignedToId', options.assignedToId);
|
|
129
|
+
if (options?.limit)
|
|
130
|
+
params.append('limit', options.limit.toString());
|
|
131
|
+
if (options?.offset)
|
|
132
|
+
params.append('offset', options.offset.toString());
|
|
133
|
+
const query = params.toString();
|
|
134
|
+
return this.api.get(`/issues${query ? `?${query}` : ''}`);
|
|
135
|
+
}
|
|
136
|
+
async getIssue(issueId, teamId) {
|
|
137
|
+
try {
|
|
138
|
+
const params = new URLSearchParams();
|
|
139
|
+
if (teamId)
|
|
140
|
+
params.append('teamId', teamId.toString());
|
|
141
|
+
const query = params.toString();
|
|
142
|
+
return await this.api.get(`/issues/${issueId}${query ? `?${query}` : ''}`);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Create methods
|
|
152
|
+
async createWorkItem(data) {
|
|
153
|
+
return this.api.post('/work-items', data);
|
|
154
|
+
}
|
|
155
|
+
async createIssue(data) {
|
|
156
|
+
return this.api.post('/issues', data);
|
|
157
|
+
}
|
|
158
|
+
async updateIssue(issueId, data) {
|
|
159
|
+
return this.api.patch(`/issues/${issueId}`, data);
|
|
160
|
+
}
|
|
161
|
+
// Wiki Page methods
|
|
162
|
+
async listWikiPages(options) {
|
|
163
|
+
const params = new URLSearchParams();
|
|
164
|
+
if (options?.limit)
|
|
165
|
+
params.append('limit', options.limit.toString());
|
|
166
|
+
if (options?.offset)
|
|
167
|
+
params.append('offset', options.offset.toString());
|
|
168
|
+
const query = params.toString();
|
|
169
|
+
return this.api.get(`/wiki-pages${query ? `?${query}` : ''}`);
|
|
170
|
+
}
|
|
171
|
+
async getWikiPage(pageId) {
|
|
172
|
+
try {
|
|
173
|
+
return await this.api.get(`/wiki-pages/${encodeURIComponent(pageId)}`);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async createWikiPage(data) {
|
|
183
|
+
return this.api.post('/wiki-pages', data);
|
|
184
|
+
}
|
|
185
|
+
async updateWikiPage(pageId, data) {
|
|
186
|
+
return this.api.patch(`/wiki-pages/${pageId}`, data);
|
|
187
|
+
}
|
|
188
|
+
// Journal Entry methods
|
|
189
|
+
async listJournalEntries(options) {
|
|
190
|
+
const params = new URLSearchParams();
|
|
191
|
+
if (options?.limit)
|
|
192
|
+
params.append('limit', options.limit.toString());
|
|
193
|
+
if (options?.offset)
|
|
194
|
+
params.append('offset', options.offset.toString());
|
|
195
|
+
const query = params.toString();
|
|
196
|
+
return this.api.get(`/journal-entries${query ? `?${query}` : ''}`);
|
|
197
|
+
}
|
|
198
|
+
async getJournalEntry(entryId, teamId) {
|
|
199
|
+
try {
|
|
200
|
+
const params = new URLSearchParams();
|
|
201
|
+
if (teamId)
|
|
202
|
+
params.append('teamId', teamId.toString());
|
|
203
|
+
const query = params.toString();
|
|
204
|
+
return await this.api.get(`/journal-entries/${entryId}${query ? `?${query}` : ''}`);
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async createJournalEntry(data) {
|
|
214
|
+
return this.api.post('/journal-entries', data);
|
|
215
|
+
}
|
|
216
|
+
async updateJournalEntry(entryId, data) {
|
|
217
|
+
return this.api.patch(`/journal-entries/${entryId}`, data);
|
|
218
|
+
}
|
|
219
|
+
// Comment methods
|
|
220
|
+
async createWorkItemComment(workItemId, data) {
|
|
221
|
+
return this.api.post(`/work-items/${workItemId}/comments`, data);
|
|
222
|
+
}
|
|
223
|
+
async createIssueComment(issueId, data) {
|
|
224
|
+
return this.api.post(`/issues/${issueId}/comments`, data);
|
|
225
|
+
}
|
|
226
|
+
close() {
|
|
227
|
+
// No cleanup needed for API client
|
|
228
|
+
}
|
|
229
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const config = {
|
|
2
|
+
apiUrl: process.env.WOLFPACK_API_URL || 'https://wolfpacks.work/api/mcp',
|
|
3
|
+
apiKey: process.env.WOLFPACK_API_KEY,
|
|
4
|
+
teamSlug: process.env.WOLFPACK_TEAM_SLUG,
|
|
5
|
+
};
|
|
6
|
+
// Validate configuration on startup
|
|
7
|
+
export function validateConfig() {
|
|
8
|
+
if (!config.apiKey) {
|
|
9
|
+
console.error('Error: WOLFPACK_API_KEY environment variable is required');
|
|
10
|
+
console.error('Please set WOLFPACK_API_KEY to your API key from the Wolfpack application');
|
|
11
|
+
console.error('Example: WOLFPACK_API_KEY=wfp_sk_...');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
if (!config.apiKey.startsWith('wfp_sk_')) {
|
|
15
|
+
console.error('Error: Invalid API key format');
|
|
16
|
+
console.error('API keys should start with "wfp_sk_"');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
console.error(`MCP Server connecting to: ${config.apiUrl}`);
|
|
20
|
+
if (config.teamSlug) {
|
|
21
|
+
console.error(`Team configured: ${config.teamSlug}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.error('No team configured - will auto-detect or use list_teams tool');
|
|
25
|
+
}
|
|
26
|
+
}
|