@aaronsb/jira-cloud-mcp 0.4.1 → 0.4.2
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.
|
@@ -69,11 +69,17 @@ export class JiraClient {
|
|
|
69
69
|
return [
|
|
70
70
|
'summary',
|
|
71
71
|
'description',
|
|
72
|
+
'issuetype',
|
|
73
|
+
'priority',
|
|
72
74
|
'parent',
|
|
73
75
|
'assignee',
|
|
74
76
|
'reporter',
|
|
75
77
|
'status',
|
|
76
78
|
'resolution',
|
|
79
|
+
'labels',
|
|
80
|
+
'created',
|
|
81
|
+
'updated',
|
|
82
|
+
'resolutiondate',
|
|
77
83
|
'duedate',
|
|
78
84
|
this.customFields.startDate,
|
|
79
85
|
this.customFields.storyPoints,
|
|
@@ -88,11 +94,17 @@ export class JiraClient {
|
|
|
88
94
|
key: issue.key,
|
|
89
95
|
summary: fields?.summary,
|
|
90
96
|
description: issue.renderedFields?.description || '',
|
|
97
|
+
issueType: fields?.issuetype?.name || '',
|
|
98
|
+
priority: fields?.priority?.name || null,
|
|
91
99
|
parent: fields?.parent?.key || null,
|
|
92
100
|
assignee: fields?.assignee?.displayName || null,
|
|
93
101
|
reporter: fields?.reporter?.displayName || '',
|
|
94
102
|
status: fields?.status?.name || '',
|
|
95
103
|
resolution: fields?.resolution?.name || null,
|
|
104
|
+
labels: fields?.labels || [],
|
|
105
|
+
created: fields?.created || '',
|
|
106
|
+
updated: fields?.updated || '',
|
|
107
|
+
resolutionDate: fields?.resolutiondate || null,
|
|
96
108
|
dueDate: fields?.duedate || null,
|
|
97
109
|
startDate: fields?.[this.customFields.startDate] || null,
|
|
98
110
|
storyPoints: fields?.[this.customFields.storyPoints] || null,
|
|
@@ -378,6 +390,8 @@ export class JiraClient {
|
|
|
378
390
|
fields.priority = { id: params.priority };
|
|
379
391
|
if (params.labels)
|
|
380
392
|
fields.labels = params.labels;
|
|
393
|
+
if (params.dueDate !== undefined)
|
|
394
|
+
fields.duedate = params.dueDate;
|
|
381
395
|
if (params.customFields) {
|
|
382
396
|
Object.assign(fields, this.convertAdfFields(params.customFields));
|
|
383
397
|
}
|
|
@@ -877,6 +891,8 @@ export class JiraClient {
|
|
|
877
891
|
fields.assignee = { accountId: params.assignee };
|
|
878
892
|
if (params.labels)
|
|
879
893
|
fields.labels = params.labels;
|
|
894
|
+
if (params.dueDate)
|
|
895
|
+
fields.duedate = params.dueDate;
|
|
880
896
|
if (params.customFields) {
|
|
881
897
|
Object.assign(fields, this.convertAdfFields(params.customFields));
|
|
882
898
|
}
|
|
@@ -401,7 +401,7 @@ function generateQueueToolDocumentation(_schema) {
|
|
|
401
401
|
description: "Execute multiple Jira operations in a single call. Operations run sequentially with result references and per-operation error strategies.",
|
|
402
402
|
parameters: {
|
|
403
403
|
operations: {
|
|
404
|
-
type: "array (max
|
|
404
|
+
type: "array (max 16)",
|
|
405
405
|
description: "Ordered list of operations. Each has: tool (string), args (object), onError ('bail' | 'continue', default 'bail').",
|
|
406
406
|
},
|
|
407
407
|
},
|
|
@@ -61,8 +61,9 @@ function validateManageJiraIssueArgs(args) {
|
|
|
61
61
|
normalizedArgs.assignee === undefined &&
|
|
62
62
|
normalizedArgs.priority === undefined &&
|
|
63
63
|
normalizedArgs.labels === undefined &&
|
|
64
|
+
normalizedArgs.dueDate === undefined &&
|
|
64
65
|
normalizedArgs.customFields === undefined) {
|
|
65
|
-
throw new McpError(ErrorCode.InvalidParams, 'At least one update field (summary, description, parent, assignee, priority, labels, or customFields) must be provided for the update operation.');
|
|
66
|
+
throw new McpError(ErrorCode.InvalidParams, 'At least one update field (summary, description, parent, assignee, priority, labels, dueDate, or customFields) must be provided for the update operation.');
|
|
66
67
|
}
|
|
67
68
|
break;
|
|
68
69
|
case 'transition':
|
|
@@ -255,6 +256,7 @@ async function handleCreateIssue(jiraClient, args) {
|
|
|
255
256
|
priority: args.priority,
|
|
256
257
|
assignee: args.assignee,
|
|
257
258
|
labels: args.labels,
|
|
259
|
+
dueDate: args.dueDate ?? undefined,
|
|
258
260
|
customFields,
|
|
259
261
|
});
|
|
260
262
|
// Get the created issue and render to markdown
|
|
@@ -279,6 +281,7 @@ async function handleUpdateIssue(jiraClient, args) {
|
|
|
279
281
|
assignee: args.assignee,
|
|
280
282
|
priority: args.priority,
|
|
281
283
|
labels: args.labels,
|
|
284
|
+
dueDate: args.dueDate,
|
|
282
285
|
customFields,
|
|
283
286
|
});
|
|
284
287
|
// Get the updated issue and render to markdown
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
11
11
|
import { bulkOperationGuard } from '../utils/bulk-operation-guard.js';
|
|
12
12
|
// ── Constants ──────────────────────────────────────────────────────────
|
|
13
|
-
const MAX_OPERATIONS =
|
|
13
|
+
const MAX_OPERATIONS = 16;
|
|
14
14
|
const DESTRUCTIVE_OPERATIONS = new Set(['delete', 'move']);
|
|
15
15
|
// ── Queue Handler ──────────────────────────────────────────────────────
|
|
16
16
|
export function createQueueHandler(handlers, jiraHost) {
|
|
@@ -78,7 +78,7 @@ export function renderIssue(issue, transitions) {
|
|
|
78
78
|
lines.push(`# ${issue.key}: ${issue.summary}`);
|
|
79
79
|
lines.push('');
|
|
80
80
|
// Core fields
|
|
81
|
-
lines.push(`**Status:** ${formatStatus(issue.status)}`);
|
|
81
|
+
lines.push(`**Type:** ${issue.issueType} | **Status:** ${formatStatus(issue.status)}${issue.priority ? ` | **Priority:** ${issue.priority}` : ''}`);
|
|
82
82
|
if (issue.assignee) {
|
|
83
83
|
lines.push(`**Assignee:** ${issue.assignee}`);
|
|
84
84
|
}
|
|
@@ -89,12 +89,39 @@ export function renderIssue(issue, transitions) {
|
|
|
89
89
|
if (issue.parent) {
|
|
90
90
|
lines.push(`**Parent:** ${issue.parent}`);
|
|
91
91
|
}
|
|
92
|
-
if (issue.
|
|
93
|
-
lines.push(`**
|
|
94
|
-
}
|
|
92
|
+
if (issue.labels && issue.labels.length > 0) {
|
|
93
|
+
lines.push(`**Labels:** ${issue.labels.join(', ')}`);
|
|
94
|
+
}
|
|
95
|
+
// Dates
|
|
96
|
+
const dates = [];
|
|
97
|
+
if (issue.created)
|
|
98
|
+
dates.push(`Created ${formatDate(issue.created)}`);
|
|
99
|
+
if (issue.updated)
|
|
100
|
+
dates.push(`Updated ${formatDate(issue.updated)}`);
|
|
101
|
+
if (dates.length > 0)
|
|
102
|
+
lines.push(`**${dates.join(' | ')}**`);
|
|
103
|
+
const scheduleDates = [];
|
|
104
|
+
if (issue.startDate)
|
|
105
|
+
scheduleDates.push(`Start: ${formatDate(issue.startDate)}`);
|
|
106
|
+
if (issue.dueDate)
|
|
107
|
+
scheduleDates.push(`Due: ${formatDate(issue.dueDate)}`);
|
|
108
|
+
if (issue.resolutionDate)
|
|
109
|
+
scheduleDates.push(`Resolved: ${formatDate(issue.resolutionDate)}`);
|
|
110
|
+
if (scheduleDates.length > 0)
|
|
111
|
+
lines.push(`**${scheduleDates.join(' | ')}**`);
|
|
95
112
|
if (issue.storyPoints) {
|
|
96
113
|
lines.push(`**Points:** ${issue.storyPoints}`);
|
|
97
114
|
}
|
|
115
|
+
if (issue.timeEstimate) {
|
|
116
|
+
const hours = Math.floor(issue.timeEstimate / 3600);
|
|
117
|
+
const minutes = Math.floor((issue.timeEstimate % 3600) / 60);
|
|
118
|
+
const parts = [];
|
|
119
|
+
if (hours > 0)
|
|
120
|
+
parts.push(`${hours}h`);
|
|
121
|
+
if (minutes > 0)
|
|
122
|
+
parts.push(`${minutes}m`);
|
|
123
|
+
lines.push(`**Estimate:** ${parts.length > 0 ? parts.join(' ') : '0m'}`);
|
|
124
|
+
}
|
|
98
125
|
if (issue.resolution) {
|
|
99
126
|
lines.push(`**Resolution:** ${issue.resolution}`);
|
|
100
127
|
}
|
|
@@ -183,10 +210,17 @@ export function renderIssueSearchResults(issues, pagination, jql) {
|
|
|
183
210
|
const issue = issues[i];
|
|
184
211
|
const num = pagination.startAt + i + 1;
|
|
185
212
|
lines.push(`## ${num}. ${issue.key}: ${issue.summary}`);
|
|
186
|
-
|
|
187
|
-
if (issue.
|
|
188
|
-
|
|
189
|
-
|
|
213
|
+
const meta = [`${formatStatus(issue.status)}`, issue.assignee || 'Unassigned'];
|
|
214
|
+
if (issue.priority)
|
|
215
|
+
meta.push(issue.priority);
|
|
216
|
+
lines.push(meta.join(' | '));
|
|
217
|
+
const searchDates = [];
|
|
218
|
+
if (issue.dueDate)
|
|
219
|
+
searchDates.push(`Due: ${formatDate(issue.dueDate)}`);
|
|
220
|
+
if (issue.startDate)
|
|
221
|
+
searchDates.push(`Start: ${formatDate(issue.startDate)}`);
|
|
222
|
+
if (searchDates.length > 0)
|
|
223
|
+
lines.push(searchDates.join(' | '));
|
|
190
224
|
if (issue.description) {
|
|
191
225
|
const desc = stripHtml(issue.description);
|
|
192
226
|
if (desc.length > 0) {
|
|
@@ -188,6 +188,10 @@ export const toolSchemas = {
|
|
|
188
188
|
type: 'object',
|
|
189
189
|
description: 'Custom field values as key-value pairs.',
|
|
190
190
|
},
|
|
191
|
+
dueDate: {
|
|
192
|
+
type: ['string', 'null'],
|
|
193
|
+
description: 'Due date in ISO format (e.g., "2025-06-15") or null to clear. For create and update.',
|
|
194
|
+
},
|
|
191
195
|
parent: {
|
|
192
196
|
type: ['string', 'null'],
|
|
193
197
|
description: 'Parent issue key (e.g., PROJ-100) or null to remove.',
|
|
@@ -349,8 +353,8 @@ export const toolSchemas = {
|
|
|
349
353
|
},
|
|
350
354
|
required: ['tool', 'args'],
|
|
351
355
|
},
|
|
352
|
-
description: 'Ordered list of operations to execute (max
|
|
353
|
-
maxItems:
|
|
356
|
+
description: 'Ordered list of operations to execute (max 16).',
|
|
357
|
+
maxItems: 16,
|
|
354
358
|
},
|
|
355
359
|
detail: {
|
|
356
360
|
type: 'string',
|
package/package.json
CHANGED