@aaronsb/jira-cloud-mcp 0.1.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 +70 -0
- package/build/client/jira-client.js +721 -0
- package/build/handlers/board-handlers.js +326 -0
- package/build/handlers/filter-handlers.js +427 -0
- package/build/handlers/issue-handlers.js +311 -0
- package/build/handlers/project-handlers.js +368 -0
- package/build/handlers/resource-handlers.js +320 -0
- package/build/handlers/search-handlers.js +103 -0
- package/build/handlers/sprint-handlers.js +433 -0
- package/build/handlers/tool-resource-handlers.js +1185 -0
- package/build/health-check.js +67 -0
- package/build/index.js +141 -0
- package/build/schemas/request-schemas.js +187 -0
- package/build/schemas/tool-schemas.js +450 -0
- package/build/types/index.js +1 -0
- package/build/utils/formatters/base-formatter.js +58 -0
- package/build/utils/formatters/board-formatter.js +63 -0
- package/build/utils/formatters/filter-formatter.js +66 -0
- package/build/utils/formatters/index.js +7 -0
- package/build/utils/formatters/issue-formatter.js +84 -0
- package/build/utils/formatters/project-formatter.js +55 -0
- package/build/utils/formatters/search-formatter.js +62 -0
- package/build/utils/formatters/sprint-formatter.js +111 -0
- package/build/utils/text-processing.js +343 -0
- package/package.json +65 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { SprintFormatter } from '../utils/formatters/sprint-formatter.js';
|
|
3
|
+
// Helper function to normalize parameter names (support both snake_case and camelCase)
|
|
4
|
+
function normalizeArgs(args) {
|
|
5
|
+
const normalized = {};
|
|
6
|
+
for (const [key, value] of Object.entries(args)) {
|
|
7
|
+
// Convert snake_case to camelCase
|
|
8
|
+
if (key === 'sprint_id') {
|
|
9
|
+
normalized['sprintId'] = value;
|
|
10
|
+
}
|
|
11
|
+
else if (key === 'board_id') {
|
|
12
|
+
normalized['boardId'] = value;
|
|
13
|
+
}
|
|
14
|
+
else if (key === 'start_date') {
|
|
15
|
+
normalized['startDate'] = value;
|
|
16
|
+
}
|
|
17
|
+
else if (key === 'end_date') {
|
|
18
|
+
normalized['endDate'] = value;
|
|
19
|
+
}
|
|
20
|
+
else if (key === 'max_results') {
|
|
21
|
+
normalized['maxResults'] = value;
|
|
22
|
+
}
|
|
23
|
+
else if (key === 'start_at') {
|
|
24
|
+
normalized['startAt'] = value;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
normalized[key] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return normalized;
|
|
31
|
+
}
|
|
32
|
+
// Validate the consolidated sprint management arguments
|
|
33
|
+
function validateManageJiraSprintArgs(args) {
|
|
34
|
+
if (typeof args !== 'object' || args === null) {
|
|
35
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid manage_jira_sprint arguments: Expected an object with an operation parameter');
|
|
36
|
+
}
|
|
37
|
+
const normalizedArgs = normalizeArgs(args);
|
|
38
|
+
// Validate operation parameter
|
|
39
|
+
if (typeof normalizedArgs.operation !== 'string' ||
|
|
40
|
+
!['get', 'create', 'update', 'delete', 'list', 'manage_issues'].includes(normalizedArgs.operation)) {
|
|
41
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid operation parameter. Valid values are: get, create, update, delete, list, manage_issues');
|
|
42
|
+
}
|
|
43
|
+
// Validate parameters based on operation
|
|
44
|
+
switch (normalizedArgs.operation) {
|
|
45
|
+
case 'get':
|
|
46
|
+
if (typeof normalizedArgs.sprintId !== 'number') {
|
|
47
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid sprintId parameter. Please provide a valid sprint ID as a number for the get operation.');
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'create':
|
|
51
|
+
if (typeof normalizedArgs.boardId !== 'number') {
|
|
52
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid boardId parameter. Please provide a valid board ID as a number for the create operation.');
|
|
53
|
+
}
|
|
54
|
+
if (typeof normalizedArgs.name !== 'string' || normalizedArgs.name.trim() === '') {
|
|
55
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid name parameter. Please provide a valid sprint name as a string for the create operation.');
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'update':
|
|
59
|
+
if (typeof normalizedArgs.sprintId !== 'number') {
|
|
60
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid sprintId parameter. Please provide a valid sprint ID as a number for the update operation.');
|
|
61
|
+
}
|
|
62
|
+
// Ensure at least one update field is provided
|
|
63
|
+
if (normalizedArgs.name === undefined &&
|
|
64
|
+
normalizedArgs.goal === undefined &&
|
|
65
|
+
normalizedArgs.startDate === undefined &&
|
|
66
|
+
normalizedArgs.endDate === undefined &&
|
|
67
|
+
normalizedArgs.state === undefined) {
|
|
68
|
+
throw new McpError(ErrorCode.InvalidParams, 'At least one update field (name, goal, startDate, endDate, or state) must be provided for the update operation.');
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'delete':
|
|
72
|
+
if (typeof normalizedArgs.sprintId !== 'number') {
|
|
73
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid sprintId parameter. Please provide a valid sprint ID as a number for the delete operation.');
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case 'list':
|
|
77
|
+
if (typeof normalizedArgs.boardId !== 'number') {
|
|
78
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid boardId parameter. Please provide a valid board ID as a number for the list operation.');
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case 'manage_issues':
|
|
82
|
+
if (typeof normalizedArgs.sprintId !== 'number') {
|
|
83
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid sprintId parameter. Please provide a valid sprint ID as a number for the manage_issues operation.');
|
|
84
|
+
}
|
|
85
|
+
// Ensure at least one of add or remove is provided
|
|
86
|
+
if (!normalizedArgs.add && !normalizedArgs.remove) {
|
|
87
|
+
throw new McpError(ErrorCode.InvalidParams, 'At least one of add or remove must be provided for the manage_issues operation.');
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
// Validate common optional parameters
|
|
92
|
+
if (normalizedArgs.startDate !== undefined && typeof normalizedArgs.startDate !== 'string') {
|
|
93
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid startDate parameter. Please provide a valid date string in ISO format.');
|
|
94
|
+
}
|
|
95
|
+
if (normalizedArgs.endDate !== undefined && typeof normalizedArgs.endDate !== 'string') {
|
|
96
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid endDate parameter. Please provide a valid date string in ISO format.');
|
|
97
|
+
}
|
|
98
|
+
if (normalizedArgs.goal !== undefined && typeof normalizedArgs.goal !== 'string') {
|
|
99
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid goal parameter. Please provide a valid goal as a string.');
|
|
100
|
+
}
|
|
101
|
+
if (normalizedArgs.state !== undefined) {
|
|
102
|
+
if (typeof normalizedArgs.state !== 'string' ||
|
|
103
|
+
!['future', 'active', 'closed'].includes(normalizedArgs.state)) {
|
|
104
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid state parameter. Valid values are: future, active, closed');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Validate pagination parameters
|
|
108
|
+
if (normalizedArgs.startAt !== undefined && typeof normalizedArgs.startAt !== 'number') {
|
|
109
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid startAt parameter. Please provide a valid number.');
|
|
110
|
+
}
|
|
111
|
+
if (normalizedArgs.maxResults !== undefined && typeof normalizedArgs.maxResults !== 'number') {
|
|
112
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid maxResults parameter. Please provide a valid number.');
|
|
113
|
+
}
|
|
114
|
+
// Validate expand parameter
|
|
115
|
+
if (normalizedArgs.expand !== undefined) {
|
|
116
|
+
if (!Array.isArray(normalizedArgs.expand)) {
|
|
117
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid expand parameter. Expected an array of strings.');
|
|
118
|
+
}
|
|
119
|
+
const validExpansions = ['issues', 'report', 'board'];
|
|
120
|
+
for (const expansion of normalizedArgs.expand) {
|
|
121
|
+
if (typeof expansion !== 'string' || !validExpansions.includes(expansion)) {
|
|
122
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid expansion: ${expansion}. Valid expansions are: ${validExpansions.join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Validate add and remove parameters for manage_issues operation
|
|
127
|
+
if (normalizedArgs.add !== undefined) {
|
|
128
|
+
if (!Array.isArray(normalizedArgs.add)) {
|
|
129
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid add parameter. Expected an array of issue keys.');
|
|
130
|
+
}
|
|
131
|
+
for (const issueKey of normalizedArgs.add) {
|
|
132
|
+
if (typeof issueKey !== 'string') {
|
|
133
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid issue key in add parameter. All issue keys must be strings.');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (normalizedArgs.remove !== undefined) {
|
|
138
|
+
if (!Array.isArray(normalizedArgs.remove)) {
|
|
139
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid remove parameter. Expected an array of issue keys.');
|
|
140
|
+
}
|
|
141
|
+
for (const issueKey of normalizedArgs.remove) {
|
|
142
|
+
if (typeof issueKey !== 'string') {
|
|
143
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid issue key in remove parameter. All issue keys must be strings.');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
// Handler functions for each operation
|
|
150
|
+
async function handleGetSprint(jiraClient, args) {
|
|
151
|
+
// Parse expansion options
|
|
152
|
+
const expansionOptions = {};
|
|
153
|
+
if (args.expand) {
|
|
154
|
+
for (const expansion of args.expand) {
|
|
155
|
+
if (expansion === 'issues' || expansion === 'report') {
|
|
156
|
+
expansionOptions[expansion] = true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Get the sprint
|
|
161
|
+
const sprint = await jiraClient.getSprint(args.sprintId);
|
|
162
|
+
// Get issues if requested
|
|
163
|
+
let issues = undefined;
|
|
164
|
+
if (expansionOptions.issues) {
|
|
165
|
+
issues = await jiraClient.getSprintIssues(args.sprintId);
|
|
166
|
+
}
|
|
167
|
+
// Get report if requested
|
|
168
|
+
let report = undefined;
|
|
169
|
+
if (expansionOptions.report && sprint.state === 'closed') {
|
|
170
|
+
report = await jiraClient.getSprintReport(sprint.boardId, args.sprintId);
|
|
171
|
+
}
|
|
172
|
+
// Combine data
|
|
173
|
+
const sprintData = {
|
|
174
|
+
...sprint,
|
|
175
|
+
issues,
|
|
176
|
+
report,
|
|
177
|
+
};
|
|
178
|
+
// Format the response
|
|
179
|
+
const formattedResponse = SprintFormatter.formatSprint(sprintData, expansionOptions);
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: 'text',
|
|
184
|
+
text: JSON.stringify(formattedResponse, null, 2),
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async function handleCreateSprint(jiraClient, args) {
|
|
190
|
+
// Create the sprint
|
|
191
|
+
const response = await jiraClient.createSprint(args.boardId, args.name, args.startDate, args.endDate, args.goal);
|
|
192
|
+
// Format the response
|
|
193
|
+
const formattedResponse = SprintFormatter.formatSprint(response);
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: 'text',
|
|
198
|
+
text: JSON.stringify(formattedResponse, null, 2),
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async function handleUpdateSprint(jiraClient, args) {
|
|
204
|
+
try {
|
|
205
|
+
// Validate sprint state before updating
|
|
206
|
+
const currentSprint = await jiraClient.getSprint(args.sprintId);
|
|
207
|
+
// Check if trying to update a closed sprint
|
|
208
|
+
if (currentSprint.state === 'closed' && args.state !== 'closed') {
|
|
209
|
+
throw new McpError(ErrorCode.InvalidParams, 'Cannot update a closed sprint. Closed sprints are read-only.');
|
|
210
|
+
}
|
|
211
|
+
// Update the sprint
|
|
212
|
+
await jiraClient.updateSprint(args.sprintId, args.name, args.goal, args.startDate, args.endDate, args.state);
|
|
213
|
+
// Get the updated sprint
|
|
214
|
+
const updatedSprint = await jiraClient.getSprint(args.sprintId);
|
|
215
|
+
// Format the response
|
|
216
|
+
const formattedResponse = SprintFormatter.formatSprint(updatedSprint);
|
|
217
|
+
return {
|
|
218
|
+
content: [
|
|
219
|
+
{
|
|
220
|
+
type: 'text',
|
|
221
|
+
text: JSON.stringify(formattedResponse, null, 2),
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
console.error('Error updating sprint:', error);
|
|
228
|
+
// Provide more specific error messages based on the error type
|
|
229
|
+
if (error instanceof McpError) {
|
|
230
|
+
throw error; // Re-throw MCP errors
|
|
231
|
+
}
|
|
232
|
+
else if (error instanceof Error) {
|
|
233
|
+
throw new McpError(ErrorCode.InternalError, `Failed to update sprint: ${error.message}`);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
throw new McpError(ErrorCode.InternalError, 'An unknown error occurred while updating the sprint');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function handleDeleteSprint(jiraClient, args) {
|
|
241
|
+
// Delete the sprint
|
|
242
|
+
await jiraClient.deleteSprint(args.sprintId);
|
|
243
|
+
return {
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: 'text',
|
|
247
|
+
text: JSON.stringify({
|
|
248
|
+
success: true,
|
|
249
|
+
message: `Sprint ${args.sprintId} has been deleted successfully.`,
|
|
250
|
+
}, null, 2),
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
async function handleListSprints(jiraClient, args) {
|
|
256
|
+
// Set default pagination values
|
|
257
|
+
const startAt = args.startAt !== undefined ? args.startAt : 0;
|
|
258
|
+
const maxResults = args.maxResults !== undefined ? args.maxResults : 50;
|
|
259
|
+
// Get sprints
|
|
260
|
+
const response = await jiraClient.listSprints(args.boardId, args.state, startAt, maxResults);
|
|
261
|
+
// Format the response
|
|
262
|
+
const formattedResponse = SprintFormatter.formatSprintList(response.sprints, {
|
|
263
|
+
startAt,
|
|
264
|
+
maxResults,
|
|
265
|
+
total: response.total,
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: 'text',
|
|
271
|
+
text: JSON.stringify(formattedResponse, null, 2),
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
async function handleManageIssues(jiraClient, args) {
|
|
277
|
+
try {
|
|
278
|
+
// Validate sprint state before managing issues
|
|
279
|
+
const currentSprint = await jiraClient.getSprint(args.sprintId);
|
|
280
|
+
// Check if trying to modify a closed sprint
|
|
281
|
+
if (currentSprint.state === 'closed') {
|
|
282
|
+
throw new McpError(ErrorCode.InvalidParams, 'Cannot add or remove issues from a closed sprint. Closed sprints are read-only.');
|
|
283
|
+
}
|
|
284
|
+
// Validate that the issues exist before trying to add them
|
|
285
|
+
if (args.add && args.add.length > 0) {
|
|
286
|
+
// We could add validation here to check if issues exist
|
|
287
|
+
console.error(`Attempting to add ${args.add.length} issues to sprint ${args.sprintId}`);
|
|
288
|
+
}
|
|
289
|
+
// Update sprint issues
|
|
290
|
+
await jiraClient.updateSprintIssues(args.sprintId, args.add, args.remove);
|
|
291
|
+
// Get the updated sprint with issues
|
|
292
|
+
const sprint = await jiraClient.getSprint(args.sprintId);
|
|
293
|
+
const issues = await jiraClient.getSprintIssues(args.sprintId);
|
|
294
|
+
// Combine data
|
|
295
|
+
const sprintData = {
|
|
296
|
+
...sprint,
|
|
297
|
+
issues,
|
|
298
|
+
};
|
|
299
|
+
// Format the response
|
|
300
|
+
const formattedResponse = SprintFormatter.formatSprint(sprintData, { issues: true });
|
|
301
|
+
return {
|
|
302
|
+
content: [
|
|
303
|
+
{
|
|
304
|
+
type: 'text',
|
|
305
|
+
text: JSON.stringify(formattedResponse, null, 2),
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
console.error('Error managing sprint issues:', error);
|
|
312
|
+
// Provide more specific error messages based on the error type
|
|
313
|
+
if (error instanceof McpError) {
|
|
314
|
+
throw error; // Re-throw MCP errors
|
|
315
|
+
}
|
|
316
|
+
else if (error instanceof Error) {
|
|
317
|
+
throw new McpError(ErrorCode.InternalError, `Failed to manage sprint issues: ${error.message}`);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
throw new McpError(ErrorCode.InternalError, 'An unknown error occurred while managing sprint issues');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Legacy handler function for backward compatibility
|
|
325
|
+
async function handleLegacySprintTools(name, args, jiraClient) {
|
|
326
|
+
console.error(`Handling legacy sprint tool: ${name}`);
|
|
327
|
+
const normalizedArgs = normalizeArgs(args);
|
|
328
|
+
// Map legacy tool to consolidated tool operation
|
|
329
|
+
let operation;
|
|
330
|
+
if (name === 'create_jira_sprint') {
|
|
331
|
+
operation = 'create';
|
|
332
|
+
}
|
|
333
|
+
else if (name === 'get_jira_sprint') {
|
|
334
|
+
operation = 'get';
|
|
335
|
+
}
|
|
336
|
+
else if (name === 'list_jira_sprints') {
|
|
337
|
+
operation = 'list';
|
|
338
|
+
}
|
|
339
|
+
else if (name === 'update_jira_sprint') {
|
|
340
|
+
operation = 'update';
|
|
341
|
+
}
|
|
342
|
+
else if (name === 'delete_jira_sprint') {
|
|
343
|
+
operation = 'delete';
|
|
344
|
+
}
|
|
345
|
+
else if (name === 'update_sprint_issues') {
|
|
346
|
+
operation = 'manage_issues';
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
350
|
+
}
|
|
351
|
+
// Create consolidated args
|
|
352
|
+
const consolidatedArgs = {
|
|
353
|
+
operation,
|
|
354
|
+
...normalizedArgs
|
|
355
|
+
};
|
|
356
|
+
// Process the operation
|
|
357
|
+
switch (operation) {
|
|
358
|
+
case 'get':
|
|
359
|
+
return await handleGetSprint(jiraClient, consolidatedArgs);
|
|
360
|
+
case 'create':
|
|
361
|
+
return await handleCreateSprint(jiraClient, consolidatedArgs);
|
|
362
|
+
case 'update':
|
|
363
|
+
return await handleUpdateSprint(jiraClient, consolidatedArgs);
|
|
364
|
+
case 'delete':
|
|
365
|
+
return await handleDeleteSprint(jiraClient, consolidatedArgs);
|
|
366
|
+
case 'list':
|
|
367
|
+
return await handleListSprints(jiraClient, consolidatedArgs);
|
|
368
|
+
case 'manage_issues':
|
|
369
|
+
return await handleManageIssues(jiraClient, consolidatedArgs);
|
|
370
|
+
default:
|
|
371
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown operation: ${operation}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Main handler function
|
|
375
|
+
export async function setupSprintHandlers(server, jiraClient, request) {
|
|
376
|
+
console.error('Handling sprint request...');
|
|
377
|
+
const { name } = request.params;
|
|
378
|
+
const args = request.params.arguments;
|
|
379
|
+
if (!args) {
|
|
380
|
+
throw new McpError(ErrorCode.InvalidParams, 'Missing arguments. Please provide the required parameters for this operation.');
|
|
381
|
+
}
|
|
382
|
+
// Handle legacy sprint tools for backward compatibility
|
|
383
|
+
if (name === 'create_jira_sprint' ||
|
|
384
|
+
name === 'get_jira_sprint' ||
|
|
385
|
+
name === 'list_jira_sprints' ||
|
|
386
|
+
name === 'update_jira_sprint' ||
|
|
387
|
+
name === 'delete_jira_sprint' ||
|
|
388
|
+
name === 'update_sprint_issues') {
|
|
389
|
+
return await handleLegacySprintTools(name, args, jiraClient);
|
|
390
|
+
}
|
|
391
|
+
// Handle the consolidated sprint management tool
|
|
392
|
+
if (name === 'manage_jira_sprint') {
|
|
393
|
+
// Normalize arguments to support both snake_case and camelCase
|
|
394
|
+
const normalizedArgs = normalizeArgs(args);
|
|
395
|
+
// Validate arguments
|
|
396
|
+
if (!validateManageJiraSprintArgs(normalizedArgs)) {
|
|
397
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid manage_jira_sprint arguments');
|
|
398
|
+
}
|
|
399
|
+
// Process the operation
|
|
400
|
+
switch (normalizedArgs.operation) {
|
|
401
|
+
case 'get': {
|
|
402
|
+
console.error('Processing get sprint operation');
|
|
403
|
+
return await handleGetSprint(jiraClient, normalizedArgs);
|
|
404
|
+
}
|
|
405
|
+
case 'create': {
|
|
406
|
+
console.error('Processing create sprint operation');
|
|
407
|
+
return await handleCreateSprint(jiraClient, normalizedArgs);
|
|
408
|
+
}
|
|
409
|
+
case 'update': {
|
|
410
|
+
console.error('Processing update sprint operation');
|
|
411
|
+
return await handleUpdateSprint(jiraClient, normalizedArgs);
|
|
412
|
+
}
|
|
413
|
+
case 'delete': {
|
|
414
|
+
console.error('Processing delete sprint operation');
|
|
415
|
+
return await handleDeleteSprint(jiraClient, normalizedArgs);
|
|
416
|
+
}
|
|
417
|
+
case 'list': {
|
|
418
|
+
console.error('Processing list sprints operation');
|
|
419
|
+
return await handleListSprints(jiraClient, normalizedArgs);
|
|
420
|
+
}
|
|
421
|
+
case 'manage_issues': {
|
|
422
|
+
console.error('Processing manage issues operation');
|
|
423
|
+
return await handleManageIssues(jiraClient, normalizedArgs);
|
|
424
|
+
}
|
|
425
|
+
default: {
|
|
426
|
+
console.error(`Unknown operation: ${normalizedArgs.operation}`);
|
|
427
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown operation: ${normalizedArgs.operation}`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
console.error(`Unknown tool requested: ${name}`);
|
|
432
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
433
|
+
}
|