@aaronsb/jira-cloud-mcp 0.5.8 → 0.5.9
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/build/client/jira-client.js +46 -0
- package/build/handlers/filter-handlers.js +54 -6
- package/build/index.js +14 -0
- package/package.json +1 -1
|
@@ -1003,6 +1003,52 @@ export class JiraClient {
|
|
|
1003
1003
|
const response = await this.client.issues.createIssue({ fields });
|
|
1004
1004
|
return { key: response.key };
|
|
1005
1005
|
}
|
|
1006
|
+
async createFilter(name, jql, description, favourite) {
|
|
1007
|
+
const result = await this.client.filters.createFilter({
|
|
1008
|
+
name,
|
|
1009
|
+
jql,
|
|
1010
|
+
description: description || '',
|
|
1011
|
+
favourite: favourite ?? false,
|
|
1012
|
+
});
|
|
1013
|
+
if (!result.id || !result.name) {
|
|
1014
|
+
throw new Error('Invalid filter response from Jira');
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
id: result.id,
|
|
1018
|
+
name: result.name,
|
|
1019
|
+
owner: result.owner?.displayName || 'Unknown',
|
|
1020
|
+
favourite: result.favourite || false,
|
|
1021
|
+
viewUrl: result.viewUrl || '',
|
|
1022
|
+
description: result.description || '',
|
|
1023
|
+
jql: result.jql || '',
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
async updateFilter(filterId, updates) {
|
|
1027
|
+
// Fetch existing filter to merge with updates (API requires name)
|
|
1028
|
+
const existing = await this.client.filters.getFilter({ id: parseInt(filterId, 10) });
|
|
1029
|
+
const result = await this.client.filters.updateFilter({
|
|
1030
|
+
id: parseInt(filterId, 10),
|
|
1031
|
+
name: updates.name || existing.name || '',
|
|
1032
|
+
jql: updates.jql ?? existing.jql,
|
|
1033
|
+
description: updates.description ?? existing.description,
|
|
1034
|
+
favourite: updates.favourite ?? existing.favourite,
|
|
1035
|
+
});
|
|
1036
|
+
if (!result.id || !result.name) {
|
|
1037
|
+
throw new Error('Invalid filter response from Jira');
|
|
1038
|
+
}
|
|
1039
|
+
return {
|
|
1040
|
+
id: result.id,
|
|
1041
|
+
name: result.name,
|
|
1042
|
+
owner: result.owner?.displayName || 'Unknown',
|
|
1043
|
+
favourite: result.favourite || false,
|
|
1044
|
+
viewUrl: result.viewUrl || '',
|
|
1045
|
+
description: result.description || '',
|
|
1046
|
+
jql: result.jql || '',
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
async deleteFilter(filterId) {
|
|
1050
|
+
await this.client.filters.deleteFilter(filterId);
|
|
1051
|
+
}
|
|
1006
1052
|
async listMyFilters(expand = false) {
|
|
1007
1053
|
const filters = await this.client.filters.getMyFilters();
|
|
1008
1054
|
return Promise.all(filters.map(async (filter) => {
|
|
@@ -207,14 +207,62 @@ async function handleListFilters(jiraClient, args) {
|
|
|
207
207
|
],
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
|
-
async function handleCreateFilter(
|
|
211
|
-
|
|
210
|
+
async function handleCreateFilter(jiraClient, args) {
|
|
211
|
+
if (!args.name) {
|
|
212
|
+
throw new McpError(ErrorCode.InvalidParams, 'name is required for create operation');
|
|
213
|
+
}
|
|
214
|
+
if (!args.jql) {
|
|
215
|
+
throw new McpError(ErrorCode.InvalidParams, 'jql is required for create operation');
|
|
216
|
+
}
|
|
217
|
+
const filter = await jiraClient.createFilter(args.name, args.jql, args.description, args.favourite);
|
|
218
|
+
const lines = [
|
|
219
|
+
`# Filter Created: ${filter.name}`,
|
|
220
|
+
'',
|
|
221
|
+
`**ID:** ${filter.id}`,
|
|
222
|
+
`**JQL:** \`${filter.jql}\``,
|
|
223
|
+
`**Owner:** ${filter.owner}`,
|
|
224
|
+
filter.description ? `**Description:** ${filter.description}` : '',
|
|
225
|
+
`**Favourite:** ${filter.favourite ? 'Yes' : 'No'}`,
|
|
226
|
+
'',
|
|
227
|
+
`[View in Jira](${filter.viewUrl})`,
|
|
228
|
+
].filter(Boolean);
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: 'text', text: lines.join('\n') + filterNextSteps('create', filter.id) }],
|
|
231
|
+
};
|
|
212
232
|
}
|
|
213
|
-
async function handleUpdateFilter(
|
|
214
|
-
|
|
233
|
+
async function handleUpdateFilter(jiraClient, args) {
|
|
234
|
+
if (!args.filterId) {
|
|
235
|
+
throw new McpError(ErrorCode.InvalidParams, 'filterId is required for update operation');
|
|
236
|
+
}
|
|
237
|
+
const updates = {};
|
|
238
|
+
if (args.name)
|
|
239
|
+
updates.name = args.name;
|
|
240
|
+
if (args.jql)
|
|
241
|
+
updates.jql = args.jql;
|
|
242
|
+
if (args.description !== undefined)
|
|
243
|
+
updates.description = args.description;
|
|
244
|
+
if (args.favourite !== undefined)
|
|
245
|
+
updates.favourite = args.favourite;
|
|
246
|
+
const filter = await jiraClient.updateFilter(args.filterId, updates);
|
|
247
|
+
const lines = [
|
|
248
|
+
`# Filter Updated: ${filter.name}`,
|
|
249
|
+
'',
|
|
250
|
+
`**ID:** ${filter.id}`,
|
|
251
|
+
`**JQL:** \`${filter.jql}\``,
|
|
252
|
+
`**Owner:** ${filter.owner}`,
|
|
253
|
+
];
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: 'text', text: lines.join('\n') + filterNextSteps('get', filter.id) }],
|
|
256
|
+
};
|
|
215
257
|
}
|
|
216
|
-
async function handleDeleteFilter(
|
|
217
|
-
|
|
258
|
+
async function handleDeleteFilter(jiraClient, args) {
|
|
259
|
+
if (!args.filterId) {
|
|
260
|
+
throw new McpError(ErrorCode.InvalidParams, 'filterId is required for delete operation');
|
|
261
|
+
}
|
|
262
|
+
await jiraClient.deleteFilter(args.filterId);
|
|
263
|
+
return {
|
|
264
|
+
content: [{ type: 'text', text: `Filter ${args.filterId} deleted.` }],
|
|
265
|
+
};
|
|
218
266
|
}
|
|
219
267
|
async function handleExecuteFilter(jiraClient, _args) {
|
|
220
268
|
const filterId = _args.filterId;
|
package/build/index.js
CHANGED
|
@@ -95,6 +95,9 @@ class JiraServer {
|
|
|
95
95
|
const { name, arguments: args } = request.params;
|
|
96
96
|
return getPrompt(name, args);
|
|
97
97
|
});
|
|
98
|
+
// Track consecutive single-issue calls to suggest queue tool
|
|
99
|
+
const QUEUE_HINT_THRESHOLD = 3;
|
|
100
|
+
let consecutiveIssueCalls = 0;
|
|
98
101
|
// Set up tool handlers
|
|
99
102
|
this.server.setRequestHandler(CallToolRequestSchema, async (request, _extra) => {
|
|
100
103
|
console.error('Received request:', JSON.stringify(request, null, 2));
|
|
@@ -121,6 +124,17 @@ class JiraServer {
|
|
|
121
124
|
if (!response) {
|
|
122
125
|
throw new McpError(ErrorCode.InternalError, `No response from handler for tool: ${name}`);
|
|
123
126
|
}
|
|
127
|
+
// Track consecutive manage_jira_issue calls and suggest queue tool
|
|
128
|
+
if (name === 'manage_jira_issue') {
|
|
129
|
+
consecutiveIssueCalls++;
|
|
130
|
+
if (consecutiveIssueCalls >= QUEUE_HINT_THRESHOLD && response.content?.[0]?.text) {
|
|
131
|
+
response.content[0].text += `\n\n---\n**💡 Efficiency tip:** You've made ${consecutiveIssueCalls} consecutive \`manage_jira_issue\` calls. Consider using \`queue_jira_operations\` to batch multiple issue operations into a single call — it's faster and uses less context.`;
|
|
132
|
+
consecutiveIssueCalls = 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
consecutiveIssueCalls = 0;
|
|
137
|
+
}
|
|
124
138
|
return response;
|
|
125
139
|
}
|
|
126
140
|
catch (error) {
|
package/package.json
CHANGED