@rui.branco/jira-mcp 1.2.0 → 1.3.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 +1 -1
- package/index.js +55 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ To enable Figma integration:
|
|
|
156
156
|
| `jira_reply_comment` | Reply to a specific comment with quote and mention | `issueKey` (required), `commentId` (required), `reply` (required) |
|
|
157
157
|
| `jira_edit_comment` | Edit an existing comment | `issueKey` (required), `commentId` (required), `comment` (required) |
|
|
158
158
|
| `jira_delete_comment` | Delete a comment (irreversible) | `issueKey` (required), `commentId` (required) |
|
|
159
|
-
| `jira_transition` | Change ticket status
|
|
159
|
+
| `jira_transition` | Change ticket status by name or ID (auto-handles intermediate steps) | `issueKey` (required), `targetStatus` or `transitionId` |
|
|
160
160
|
| `jira_update_ticket` | Update ticket fields (summary, description, assignee, priority, labels) | `issueKey` (required), plus optional field parameters |
|
|
161
161
|
|
|
162
162
|
### Configuration
|
package/index.js
CHANGED
|
@@ -814,12 +814,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
814
814
|
},
|
|
815
815
|
{
|
|
816
816
|
name: "jira_transition",
|
|
817
|
-
description: "Change the status of a Jira ticket. Use
|
|
817
|
+
description: "Change the status of a Jira ticket. Use targetStatus to transition by name (auto-handles intermediate steps like In Progress), transitionId for direct transition, or omit both to list available transitions.",
|
|
818
818
|
inputSchema: {
|
|
819
819
|
type: "object",
|
|
820
820
|
properties: {
|
|
821
821
|
issueKey: { type: "string", description: "The Jira issue key (e.g., MODS-123)" },
|
|
822
822
|
transitionId: { type: "string", description: "The transition ID to execute. Omit to list available transitions." },
|
|
823
|
+
targetStatus: { type: "string", description: "Target status name (e.g., 'Review', 'Done'). Will auto-transition through intermediate states if needed." },
|
|
823
824
|
},
|
|
824
825
|
required: ["issueKey"],
|
|
825
826
|
},
|
|
@@ -990,7 +991,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
990
991
|
return { content: [{ type: "text", text: `Comment ${args.commentId} on ${args.issueKey} deleted.` }] };
|
|
991
992
|
|
|
992
993
|
} else if (name === "jira_transition") {
|
|
993
|
-
if (!args.transitionId) {
|
|
994
|
+
if (!args.transitionId && !args.targetStatus) {
|
|
994
995
|
// List available transitions
|
|
995
996
|
const result = await fetchJira(`/issue/${args.issueKey}/transitions`);
|
|
996
997
|
let output = `# Available transitions for ${args.issueKey}\n\n`;
|
|
@@ -1002,7 +1003,58 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1002
1003
|
}
|
|
1003
1004
|
return { content: [{ type: "text", text: output }] };
|
|
1004
1005
|
}
|
|
1005
|
-
|
|
1006
|
+
|
|
1007
|
+
// If targetStatus is provided, find the transition by status name
|
|
1008
|
+
if (args.targetStatus) {
|
|
1009
|
+
const targetLower = args.targetStatus.toLowerCase();
|
|
1010
|
+
const transitions = [];
|
|
1011
|
+
|
|
1012
|
+
// Try to reach target status, with up to 3 intermediate transitions
|
|
1013
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1014
|
+
const result = await fetchJira(`/issue/${args.issueKey}/transitions`);
|
|
1015
|
+
const available = result.transitions || [];
|
|
1016
|
+
|
|
1017
|
+
// Check if target status is directly available
|
|
1018
|
+
const directMatch = available.find(t =>
|
|
1019
|
+
t.to?.name?.toLowerCase() === targetLower ||
|
|
1020
|
+
t.name?.toLowerCase() === targetLower
|
|
1021
|
+
);
|
|
1022
|
+
|
|
1023
|
+
if (directMatch) {
|
|
1024
|
+
await fetchJira(`/issue/${args.issueKey}/transitions`, {
|
|
1025
|
+
method: "POST",
|
|
1026
|
+
body: { transition: { id: directMatch.id } },
|
|
1027
|
+
});
|
|
1028
|
+
transitions.push(directMatch.to?.name || directMatch.name);
|
|
1029
|
+
return { content: [{ type: "text", text: `Transitioned ${args.issueKey} to ${transitions.join(" → ")}.` }] };
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Target not available, try "In Progress" as intermediate step
|
|
1033
|
+
const inProgress = available.find(t =>
|
|
1034
|
+
t.to?.name?.toLowerCase() === "in progress" ||
|
|
1035
|
+
t.name?.toLowerCase() === "in progress"
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
if (inProgress) {
|
|
1039
|
+
await fetchJira(`/issue/${args.issueKey}/transitions`, {
|
|
1040
|
+
method: "POST",
|
|
1041
|
+
body: { transition: { id: inProgress.id } },
|
|
1042
|
+
});
|
|
1043
|
+
transitions.push(inProgress.to?.name || "In Progress");
|
|
1044
|
+
continue; // Try again to find target
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// No path found
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// Could not reach target status
|
|
1052
|
+
const result = await fetchJira(`/issue/${args.issueKey}/transitions`);
|
|
1053
|
+
const availableNames = (result.transitions || []).map(t => t.to?.name || t.name).join(", ");
|
|
1054
|
+
return { content: [{ type: "text", text: `Could not transition to "${args.targetStatus}". Available: ${availableNames}` }] };
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// Execute transition by ID
|
|
1006
1058
|
await fetchJira(`/issue/${args.issueKey}/transitions`, {
|
|
1007
1059
|
method: "POST",
|
|
1008
1060
|
body: { transition: { id: args.transitionId } },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rui.branco/jira-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Jira MCP server for Claude Code - fetch tickets, search with JQL, update tickets, manage comments, change status, and get Figma designs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|