@rui.branco/jira-mcp 1.6.9 → 1.6.11
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/index.js +66 -34
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1256,6 +1256,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1256
1256
|
description:
|
|
1257
1257
|
"Fetch linked Figma designs and export images (default: true)",
|
|
1258
1258
|
},
|
|
1259
|
+
instance: {
|
|
1260
|
+
type: "string",
|
|
1261
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1262
|
+
},
|
|
1259
1263
|
},
|
|
1260
1264
|
required: ["issueKey"],
|
|
1261
1265
|
},
|
|
@@ -1298,6 +1302,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1298
1302
|
description: "The Jira issue key (e.g., MODS-123)",
|
|
1299
1303
|
},
|
|
1300
1304
|
comment: { type: "string", description: "The comment text to add" },
|
|
1305
|
+
instance: {
|
|
1306
|
+
type: "string",
|
|
1307
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1308
|
+
},
|
|
1301
1309
|
},
|
|
1302
1310
|
required: ["issueKey", "comment"],
|
|
1303
1311
|
},
|
|
@@ -1319,6 +1327,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1319
1327
|
"The ID of the comment to reply to. Use jira_get_ticket to see comments and their IDs.",
|
|
1320
1328
|
},
|
|
1321
1329
|
reply: { type: "string", description: "The reply text" },
|
|
1330
|
+
instance: {
|
|
1331
|
+
type: "string",
|
|
1332
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1333
|
+
},
|
|
1322
1334
|
},
|
|
1323
1335
|
required: ["issueKey", "commentId", "reply"],
|
|
1324
1336
|
},
|
|
@@ -1340,6 +1352,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1340
1352
|
"The ID of the comment to edit. Use jira_get_ticket to see comments and their IDs.",
|
|
1341
1353
|
},
|
|
1342
1354
|
comment: { type: "string", description: "The new comment text" },
|
|
1355
|
+
instance: {
|
|
1356
|
+
type: "string",
|
|
1357
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1358
|
+
},
|
|
1343
1359
|
},
|
|
1344
1360
|
required: ["issueKey", "commentId", "comment"],
|
|
1345
1361
|
},
|
|
@@ -1360,6 +1376,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1360
1376
|
description:
|
|
1361
1377
|
"The ID of the comment to delete. Use jira_get_ticket to see comments and their IDs.",
|
|
1362
1378
|
},
|
|
1379
|
+
instance: {
|
|
1380
|
+
type: "string",
|
|
1381
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1382
|
+
},
|
|
1363
1383
|
},
|
|
1364
1384
|
required: ["issueKey", "commentId"],
|
|
1365
1385
|
},
|
|
@@ -1385,6 +1405,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1385
1405
|
description:
|
|
1386
1406
|
"Target status name (e.g., 'Review', 'Done'). Will auto-transition through intermediate states if needed.",
|
|
1387
1407
|
},
|
|
1408
|
+
instance: {
|
|
1409
|
+
type: "string",
|
|
1410
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1411
|
+
},
|
|
1388
1412
|
},
|
|
1389
1413
|
required: ["issueKey"],
|
|
1390
1414
|
},
|
|
@@ -1438,6 +1462,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1438
1462
|
items: { type: "string" },
|
|
1439
1463
|
description: "Labels to set on the ticket",
|
|
1440
1464
|
},
|
|
1465
|
+
instance: {
|
|
1466
|
+
type: "string",
|
|
1467
|
+
description: "Instance name override. Auto-detected from issue key prefix if omitted.",
|
|
1468
|
+
},
|
|
1441
1469
|
},
|
|
1442
1470
|
required: ["issueKey"],
|
|
1443
1471
|
},
|
|
@@ -1499,7 +1527,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1499
1527
|
{
|
|
1500
1528
|
name: "jira_add_instance",
|
|
1501
1529
|
description:
|
|
1502
|
-
"Add or update a Jira instance configuration. Saves to config and makes it available immediately without restart.
|
|
1530
|
+
"Add or update a Jira instance configuration. Saves to config and makes it available immediately without restart. To add a new instance, provide name + email + token + baseUrl. To update an existing instance (e.g. change projects or set as default), just provide name and the fields to change.",
|
|
1503
1531
|
inputSchema: {
|
|
1504
1532
|
type: "object",
|
|
1505
1533
|
properties: {
|
|
@@ -1509,27 +1537,27 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1509
1537
|
},
|
|
1510
1538
|
email: {
|
|
1511
1539
|
type: "string",
|
|
1512
|
-
description: "Jira account email",
|
|
1540
|
+
description: "Jira account email (required for new instances)",
|
|
1513
1541
|
},
|
|
1514
1542
|
token: {
|
|
1515
1543
|
type: "string",
|
|
1516
|
-
description: "Jira API token (
|
|
1544
|
+
description: "Jira API token (required for new instances)",
|
|
1517
1545
|
},
|
|
1518
1546
|
baseUrl: {
|
|
1519
1547
|
type: "string",
|
|
1520
|
-
description: "Jira base URL (e.g., https://company.atlassian.net)",
|
|
1548
|
+
description: "Jira base URL (required for new instances, e.g., https://company.atlassian.net)",
|
|
1521
1549
|
},
|
|
1522
1550
|
projects: {
|
|
1523
1551
|
type: "array",
|
|
1524
1552
|
items: { type: "string" },
|
|
1525
|
-
description: "Project key prefixes to auto-route to this instance (e.g., ['PROJ', 'ENG'])",
|
|
1553
|
+
description: "Project key prefixes to auto-route to this instance (e.g., ['PROJ', 'ENG']). Replaces existing projects.",
|
|
1526
1554
|
},
|
|
1527
1555
|
setDefault: {
|
|
1528
1556
|
type: "boolean",
|
|
1529
1557
|
description: "Set this instance as the default (default: false)",
|
|
1530
1558
|
},
|
|
1531
1559
|
},
|
|
1532
|
-
required: ["name"
|
|
1560
|
+
required: ["name"],
|
|
1533
1561
|
},
|
|
1534
1562
|
},
|
|
1535
1563
|
{
|
|
@@ -1609,7 +1637,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1609
1637
|
} else if (name === "jira_get_ticket") {
|
|
1610
1638
|
const downloadImages = args.downloadImages !== false;
|
|
1611
1639
|
const fetchFigma = args.fetchFigma !== false;
|
|
1612
|
-
const
|
|
1640
|
+
const inst = args.instance ? getInstanceByName(args.instance) : null;
|
|
1641
|
+
const result = await getTicket(args.issueKey, downloadImages, fetchFigma, inst);
|
|
1613
1642
|
|
|
1614
1643
|
const content = [{ type: "text", text: result.text }];
|
|
1615
1644
|
|
|
@@ -1657,7 +1686,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1657
1686
|
const result = await searchTickets(args.jql, args.maxResults || 10, args.fields || null, inst);
|
|
1658
1687
|
return { content: [{ type: "text", text: result }] };
|
|
1659
1688
|
} else if (name === "jira_add_comment") {
|
|
1660
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1689
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1661
1690
|
// Build ADF content with mention support
|
|
1662
1691
|
const adfContent = await buildCommentADF(args.comment, inst);
|
|
1663
1692
|
const body = {
|
|
@@ -1682,7 +1711,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1682
1711
|
],
|
|
1683
1712
|
};
|
|
1684
1713
|
} else if (name === "jira_reply_comment") {
|
|
1685
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1714
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1686
1715
|
// Fetch the original comment
|
|
1687
1716
|
const original = await fetchJira(
|
|
1688
1717
|
`/issue/${args.issueKey}/comment/${args.commentId}`,
|
|
@@ -1750,7 +1779,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1750
1779
|
],
|
|
1751
1780
|
};
|
|
1752
1781
|
} else if (name === "jira_edit_comment") {
|
|
1753
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1782
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1754
1783
|
// Build ADF content with mention support
|
|
1755
1784
|
const adfContent = await buildCommentADF(args.comment, inst);
|
|
1756
1785
|
const body = {
|
|
@@ -1774,7 +1803,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1774
1803
|
],
|
|
1775
1804
|
};
|
|
1776
1805
|
} else if (name === "jira_delete_comment") {
|
|
1777
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1806
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1778
1807
|
await fetchJira(`/issue/${args.issueKey}/comment/${args.commentId}`, {
|
|
1779
1808
|
method: "DELETE",
|
|
1780
1809
|
}, inst);
|
|
@@ -1787,7 +1816,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1787
1816
|
],
|
|
1788
1817
|
};
|
|
1789
1818
|
} else if (name === "jira_transition") {
|
|
1790
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1819
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1791
1820
|
if (!args.transitionId && !args.targetStatus) {
|
|
1792
1821
|
// List available transitions
|
|
1793
1822
|
const result = await fetchJira(`/issue/${args.issueKey}/transitions`, {}, inst);
|
|
@@ -1883,7 +1912,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1883
1912
|
],
|
|
1884
1913
|
};
|
|
1885
1914
|
} else if (name === "jira_update_ticket") {
|
|
1886
|
-
const inst = getInstanceForKey(args.issueKey);
|
|
1915
|
+
const inst = args.instance ? getInstanceByName(args.instance) : getInstanceForKey(args.issueKey);
|
|
1887
1916
|
const fields = {};
|
|
1888
1917
|
if (args.summary) {
|
|
1889
1918
|
if (args.replaceSummary) {
|
|
@@ -2006,31 +2035,34 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2006
2035
|
}
|
|
2007
2036
|
} else if (name === "jira_add_instance") {
|
|
2008
2037
|
const instName = args.name.trim();
|
|
2009
|
-
const
|
|
2010
|
-
const
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
}
|
|
2038
|
+
const existingIdx = instances.findIndex((i) => i.name === instName);
|
|
2039
|
+
const isUpdate = existingIdx >= 0;
|
|
2040
|
+
|
|
2041
|
+
// For new instances, email/token/baseUrl are required
|
|
2042
|
+
if (!isUpdate && (!args.email || !args.token || !args.baseUrl)) {
|
|
2043
|
+
return {
|
|
2044
|
+
content: [{ type: "text", text: "New instance requires email, token, and baseUrl." }],
|
|
2045
|
+
isError: true,
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
// Merge with existing or create new
|
|
2050
|
+
const existing = isUpdate ? instances[existingIdx] : {};
|
|
2051
|
+
const email = args.email || existing.email;
|
|
2052
|
+
const token = args.token || existing.token;
|
|
2053
|
+
const baseUrl = args.baseUrl ? args.baseUrl.replace(/\/$/, "") : existing.baseUrl;
|
|
2054
|
+
const projects = args.projects ? args.projects.map((p) => p.toUpperCase()) : (existing.projects || []);
|
|
2055
|
+
const authStr = Buffer.from(`${email}:${token}`).toString("base64");
|
|
2056
|
+
|
|
2057
|
+
const newInstance = { name: instName, email, token, baseUrl, projects, auth: authStr };
|
|
2019
2058
|
|
|
2020
2059
|
// Update in-memory instances
|
|
2021
|
-
|
|
2022
|
-
if (existingIdx >= 0) {
|
|
2060
|
+
if (isUpdate) {
|
|
2023
2061
|
instances[existingIdx] = newInstance;
|
|
2024
2062
|
} else {
|
|
2025
2063
|
instances.push(newInstance);
|
|
2026
2064
|
}
|
|
2027
2065
|
|
|
2028
|
-
// Update default if requested or if it's the first instance
|
|
2029
|
-
if (args.setDefault || instances.length === 1) {
|
|
2030
|
-
// Can't reassign const, but defaultInstance is used via getInstanceByName/getInstanceForKey
|
|
2031
|
-
// which search the instances array, so this is handled by rawConfig.defaultInstance below
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
2066
|
// Persist to config file
|
|
2035
2067
|
const savedConfig = loadConfigFile();
|
|
2036
2068
|
if (!savedConfig.instances) {
|
|
@@ -2053,7 +2085,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2053
2085
|
}
|
|
2054
2086
|
|
|
2055
2087
|
// Save without the computed auth field
|
|
2056
|
-
const toSave = { name: instName, email
|
|
2088
|
+
const toSave = { name: instName, email, token, baseUrl, projects };
|
|
2057
2089
|
const savedIdx = savedConfig.instances.findIndex((i) => i.name === instName);
|
|
2058
2090
|
if (savedIdx >= 0) {
|
|
2059
2091
|
savedConfig.instances[savedIdx] = toSave;
|
|
@@ -2065,8 +2097,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2065
2097
|
}
|
|
2066
2098
|
fs.writeFileSync(jiraConfigPath, JSON.stringify(savedConfig, null, 2));
|
|
2067
2099
|
|
|
2068
|
-
const action =
|
|
2069
|
-
let text = `${action} instance "${instName}" (${
|
|
2100
|
+
const action = isUpdate ? "Updated" : "Added";
|
|
2101
|
+
let text = `${action} instance "${instName}" (${baseUrl}).`;
|
|
2070
2102
|
if (projects.length > 0) text += ` Projects: ${projects.join(", ")}.`;
|
|
2071
2103
|
if (args.setDefault) text += " Set as default.";
|
|
2072
2104
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rui.branco/jira-mcp",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.11",
|
|
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": {
|