@rui.branco/jira-mcp 1.7.6 → 1.7.8
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 +13 -0
- package/index.js +203 -102
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -225,6 +225,19 @@ For Server / Data Center deployments where Confluence lives on a different host,
|
|
|
225
225
|
|
|
226
226
|
**Why ADF for `confluence_get_page`?** The v1 `body.atlas_doc_format` expand is unreliable on modern Cloud pages — table cell background colors and some newer node types only survive the v2 `/api/v2/pages/<id>?body-format=atlas_doc_format` endpoint. `confluence_get_page` therefore does both requests in parallel and merges the v2 ADF body onto the v1 response, so callers get `body.view`, `body.storage` and `body.atlas_doc_format` in one shot.
|
|
227
227
|
|
|
228
|
+
### Confluence On-Demand Activation
|
|
229
|
+
|
|
230
|
+
By default, the 21 `confluence_*` tools are hidden from `tools/list` to reduce token footprint. A lightweight `confluence_enable` gateway tool is exposed instead. When a task needs Confluence, the client calls `confluence_enable` and the full tool set appears (the server sends `notifications/tools/list_changed`). Activation is per-process (not persisted to config) and does not bypass instance scopes.
|
|
231
|
+
|
|
232
|
+
To expose Confluence tools from boot (skip the activation step), set the `confluence` config key or the `JIRA_MCP_CONFLUENCE` environment variable:
|
|
233
|
+
|
|
234
|
+
| Method | Value |
|
|
235
|
+
|--------|-------|
|
|
236
|
+
| Config (`~/.config/jira-mcp/config.json`) | `"confluence": "always"` |
|
|
237
|
+
| Environment variable | `JIRA_MCP_CONFLUENCE=always` |
|
|
238
|
+
|
|
239
|
+
The default value is `"on-demand"`.
|
|
240
|
+
|
|
228
241
|
### Configuration
|
|
229
242
|
|
|
230
243
|
Config stored at `~/.config/jira-mcp/config.json`:
|
package/index.js
CHANGED
|
@@ -53,6 +53,15 @@ const jiraConfigPath = path.join(
|
|
|
53
53
|
);
|
|
54
54
|
const rawConfig = JSON.parse(fs.readFileSync(jiraConfigPath, "utf8"));
|
|
55
55
|
|
|
56
|
+
// Confluence tool visibility: 'on-demand' (default) hides the confluence_*
|
|
57
|
+
// tools until confluence_enable is called; 'always' exposes them from boot.
|
|
58
|
+
// Env JIRA_MCP_CONFLUENCE overrides the config key.
|
|
59
|
+
const confluenceMode = String(process.env.JIRA_MCP_CONFLUENCE || rawConfig.confluence || "on-demand").toLowerCase();
|
|
60
|
+
if (confluenceMode !== "always" && confluenceMode !== "on-demand") {
|
|
61
|
+
console.error(`jira-mcp: invalid confluence mode "${confluenceMode}", falling back to "on-demand"`);
|
|
62
|
+
}
|
|
63
|
+
let confluenceActive = confluenceMode === "always";
|
|
64
|
+
|
|
56
65
|
// Normalize config to multi-instance format
|
|
57
66
|
let instances;
|
|
58
67
|
if (rawConfig.instances) {
|
|
@@ -181,6 +190,8 @@ const TOOL_METADATA = {
|
|
|
181
190
|
jira_delete_ticket: { product: "jira", op: "destructive", category: "ticket" },
|
|
182
191
|
jira_remove_attachment: { product: "jira", op: "destructive", category: "attachment" },
|
|
183
192
|
jira_remove_instance: { product: "jira", op: "destructive", category: "config" },
|
|
193
|
+
// ---- Confluence activation ----
|
|
194
|
+
confluence_enable: { product: "confluence", op: "read" },
|
|
184
195
|
// ---- Confluence reads ----
|
|
185
196
|
confluence_get_spaces: { product: "confluence", op: "read" },
|
|
186
197
|
confluence_get_space: { product: "confluence", op: "read" },
|
|
@@ -758,7 +769,10 @@ function extractText(content, urls = []) {
|
|
|
758
769
|
} else if (node.type === "hardBreak") {
|
|
759
770
|
text += "\n";
|
|
760
771
|
} else if (node.type === "mention") {
|
|
761
|
-
text
|
|
772
|
+
// attrs.text already includes the leading "@" (e.g. "@Rui Branco").
|
|
773
|
+
// Don't prepend a second one.
|
|
774
|
+
const mentionText = node.attrs?.text || "@user";
|
|
775
|
+
text += mentionText.startsWith("@") ? mentionText : `@${mentionText}`;
|
|
762
776
|
} else if (node.type === "mediaGroup" || node.type === "mediaSingle") {
|
|
763
777
|
text += "[image attachment]\n";
|
|
764
778
|
} else if (
|
|
@@ -788,6 +802,14 @@ function extractTextSimple(content) {
|
|
|
788
802
|
return result.text;
|
|
789
803
|
}
|
|
790
804
|
|
|
805
|
+
// Prefix each line with "> " so echoed comments render as a markdown blockquote
|
|
806
|
+
function quoteText(text) {
|
|
807
|
+
return text
|
|
808
|
+
.split("\n")
|
|
809
|
+
.map((line) => (line.trim() ? `> ${line}` : ">"))
|
|
810
|
+
.join("\n");
|
|
811
|
+
}
|
|
812
|
+
|
|
791
813
|
// ============ USER SEARCH & MENTIONS ============
|
|
792
814
|
|
|
793
815
|
// Cache for user lookups to avoid repeated API calls
|
|
@@ -965,6 +987,54 @@ function autoLinkTextNodes(nodes, instance = defaultInstance) {
|
|
|
965
987
|
return result;
|
|
966
988
|
}
|
|
967
989
|
|
|
990
|
+
// Detect a markdown list item line. Returns {indent, ordered, text} or null.
|
|
991
|
+
// Bullets: -, *, + followed by a space. Ordered: "1." or "1)" followed by a space.
|
|
992
|
+
// The marker must be followed by whitespace so inline emphasis (*italic*) and
|
|
993
|
+
// horizontal rules (***) are NOT misread as list items.
|
|
994
|
+
function listItemMatch(line) {
|
|
995
|
+
const m = line.match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);
|
|
996
|
+
if (!m) return null;
|
|
997
|
+
return { indent: m[1].length, ordered: /\d/.test(m[2]), text: m[3] };
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Recursively parse a (possibly nested) markdown list starting at lines[startIdx].
|
|
1001
|
+
// baseIndent is the indentation of items at this level; more-indented items are
|
|
1002
|
+
// folded into the previous item as a nested list. Returns {node, nextIndex}.
|
|
1003
|
+
async function parseListBlock(lines, startIdx, baseIndent, instance) {
|
|
1004
|
+
const items = [];
|
|
1005
|
+
let i = startIdx;
|
|
1006
|
+
let ordered = null;
|
|
1007
|
+
while (i < lines.length) {
|
|
1008
|
+
if (!lines[i].trim()) break; // blank line ends the list
|
|
1009
|
+
const m = listItemMatch(lines[i]);
|
|
1010
|
+
if (!m) break;
|
|
1011
|
+
if (m.indent < baseIndent) break; // dedent: belongs to a parent list
|
|
1012
|
+
if (m.indent > baseIndent) {
|
|
1013
|
+
// Deeper indent: nest under the previous item at this level.
|
|
1014
|
+
const sub = await parseListBlock(lines, i, m.indent, instance);
|
|
1015
|
+
if (items.length > 0) {
|
|
1016
|
+
items[items.length - 1].content.push(sub.node);
|
|
1017
|
+
} else {
|
|
1018
|
+
items.push({ type: "listItem", content: [sub.node] });
|
|
1019
|
+
}
|
|
1020
|
+
i = sub.nextIndex;
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
if (ordered === null) ordered = m.ordered; // list type set by first item
|
|
1024
|
+
else if (m.ordered !== ordered) break; // marker switched: caller starts a new list
|
|
1025
|
+
const inlineContent = await parseInlineFormatting(m.text, instance);
|
|
1026
|
+
items.push({
|
|
1027
|
+
type: "listItem",
|
|
1028
|
+
content: [{ type: "paragraph", content: inlineContent }],
|
|
1029
|
+
});
|
|
1030
|
+
i++;
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
node: { type: ordered ? "orderedList" : "bulletList", content: items },
|
|
1034
|
+
nextIndex: i,
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
|
|
968
1038
|
// Parse text with markdown formatting and @mentions, build ADF content
|
|
969
1039
|
async function buildCommentADF(text, instance = defaultInstance) {
|
|
970
1040
|
// Sanitize: replace em dashes and en dashes with hyphen
|
|
@@ -1077,35 +1147,17 @@ async function buildCommentADF(text, instance = defaultInstance) {
|
|
|
1077
1147
|
continue;
|
|
1078
1148
|
}
|
|
1079
1149
|
|
|
1080
|
-
// ---
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
content.push({ type: "bulletList", content: listItems });
|
|
1093
|
-
continue;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// --- Ordered list (1. items) ---
|
|
1097
|
-
if (/^\d+\.\s/.test(trimmed)) {
|
|
1098
|
-
const listItems = [];
|
|
1099
|
-
while (i < lines.length && /^\d+\.\s/.test(lines[i].trim())) {
|
|
1100
|
-
const itemText = lines[i].trim().replace(/^\d+\.\s/, "");
|
|
1101
|
-
const inlineContent = await parseInlineFormatting(itemText, instance);
|
|
1102
|
-
listItems.push({
|
|
1103
|
-
type: "listItem",
|
|
1104
|
-
content: [{ type: "paragraph", content: inlineContent }],
|
|
1105
|
-
});
|
|
1106
|
-
i++;
|
|
1107
|
-
}
|
|
1108
|
-
content.push({ type: "orderedList", content: listItems });
|
|
1150
|
+
// --- Lists (bullet -,*,+ or ordered 1./1)) with nesting ---
|
|
1151
|
+
const listStart = listItemMatch(line);
|
|
1152
|
+
if (listStart) {
|
|
1153
|
+
const { node, nextIndex } = await parseListBlock(
|
|
1154
|
+
lines,
|
|
1155
|
+
i,
|
|
1156
|
+
listStart.indent,
|
|
1157
|
+
instance,
|
|
1158
|
+
);
|
|
1159
|
+
content.push(node);
|
|
1160
|
+
i = nextIndex;
|
|
1109
1161
|
continue;
|
|
1110
1162
|
}
|
|
1111
1163
|
|
|
@@ -1115,13 +1167,12 @@ async function buildCommentADF(text, instance = defaultInstance) {
|
|
|
1115
1167
|
i < lines.length &&
|
|
1116
1168
|
lines[i].trim() &&
|
|
1117
1169
|
!lines[i].trim().startsWith("```") &&
|
|
1118
|
-
|
|
1119
|
-
!lines[i].trim().startsWith("## ") &&
|
|
1120
|
-
!lines[i].trim().startsWith("### ") &&
|
|
1170
|
+
!/^#{1,6}\s/.test(lines[i].trim()) &&
|
|
1121
1171
|
!lines[i].trim().startsWith("> ") &&
|
|
1122
|
-
!lines[i]
|
|
1123
|
-
!/^\d+\.\s/.test(lines[i].trim()) &&
|
|
1172
|
+
!listItemMatch(lines[i]) &&
|
|
1124
1173
|
!/^-{3,}$/.test(lines[i].trim()) &&
|
|
1174
|
+
!/^\*{3,}$/.test(lines[i].trim()) &&
|
|
1175
|
+
!/^_{3,}$/.test(lines[i].trim()) &&
|
|
1125
1176
|
!(lines[i].trim().startsWith("|") && lines[i].trim().endsWith("|"))
|
|
1126
1177
|
) {
|
|
1127
1178
|
if (paragraphContent.length > 0) paragraphContent.push({ type: "hardBreak" });
|
|
@@ -1985,9 +2036,20 @@ async function getChangelogsBulk(jql, maxResults = 50, instance = defaultInstanc
|
|
|
1985
2036
|
|
|
1986
2037
|
// ============ MCP SERVER ============
|
|
1987
2038
|
|
|
2039
|
+
const SERVER_INSTRUCTIONS = `# jira-mcp usage rules
|
|
2040
|
+
|
|
2041
|
+
- \`instance\` (optional, on most tools): multi-instance setups only. Omit it — it auto-detects from the issue key prefix, else uses the default instance.
|
|
2042
|
+
- \`dryRun\` (optional, on mutating tools): if true, returns the HTTP request that would be sent (method, endpoint, body) without calling Atlassian. Multi-step tools only show the first write.
|
|
2043
|
+
${confluenceMode !== "always" ? "- Confluence tools are hidden until activated: call `confluence_enable` first when a task needs Confluence (pages, spaces, page comments, labels, attachments).\n" : ""}
|
|
2044
|
+
## Writing Jira comments (jira_add_comment / jira_reply_comment / jira_edit_comment)
|
|
2045
|
+
Write one short conversational paragraph: start with @DisplayName of who to notify (NOT [~accountId:...] syntax), say what changed, and end with the next step (e.g. 'Ready for verification.'). Keep it HIGH LEVEL for stakeholders/PO/QA — WHAT changed and the impact, not how it was built. Include technical detail (endpoints, payloads, API contracts) ONLY when the reader is a developer and it makes sense; otherwise leave out code, file paths, branch names, commit hashes, and framework-internal terms. NEVER use em dashes (—) or en dashes (–) — use commas, periods, or rewrite. Avoid bullet lists, headings, and bold unless the update genuinely needs them.
|
|
2046
|
+
|
|
2047
|
+
## Writing descriptions (jira_create_ticket / jira_update_ticket / jira_create_subtask)
|
|
2048
|
+
Structure with Markdown: a one/two-sentence overview, then ## / ### headings (Overview, Details, Acceptance Criteria), '-' bullet lists, numbered steps, tables for structured data, **bold** key terms, fenced \`\`\` blocks for code/payloads. Blank line between blocks. Concise and scannable. Never use em/en dashes.`;
|
|
2049
|
+
|
|
1988
2050
|
const server = new Server(
|
|
1989
2051
|
{ name: "jira-mcp", version: "1.0.0" },
|
|
1990
|
-
{ capabilities: { tools: {} } },
|
|
2052
|
+
{ capabilities: { tools: { listChanged: true } }, instructions: SERVER_INSTRUCTIONS },
|
|
1991
2053
|
);
|
|
1992
2054
|
|
|
1993
2055
|
// Inject `dryRun` into the schema of any mutating tool so MCP clients with
|
|
@@ -2006,13 +2068,16 @@ function _injectDryRunSchema(tool) {
|
|
|
2006
2068
|
...props,
|
|
2007
2069
|
dryRun: {
|
|
2008
2070
|
type: "boolean",
|
|
2009
|
-
description: "
|
|
2071
|
+
description: "Preview: return the would-be HTTP request without executing.",
|
|
2010
2072
|
},
|
|
2011
2073
|
},
|
|
2012
2074
|
},
|
|
2013
2075
|
};
|
|
2014
2076
|
}
|
|
2015
2077
|
|
|
2078
|
+
// Additive formatting guidance moved to SERVER_INSTRUCTIONS to reduce per-tool
|
|
2079
|
+
// token cost. Field descriptions retain their short base text only.
|
|
2080
|
+
|
|
2016
2081
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2017
2082
|
const rawTools = [
|
|
2018
2083
|
{
|
|
@@ -2024,7 +2089,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2024
2089
|
properties: {
|
|
2025
2090
|
instance: {
|
|
2026
2091
|
type: "string",
|
|
2027
|
-
description: "Instance name (
|
|
2092
|
+
description: "Instance name (optional).",
|
|
2028
2093
|
},
|
|
2029
2094
|
},
|
|
2030
2095
|
required: [],
|
|
@@ -2052,7 +2117,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2052
2117
|
},
|
|
2053
2118
|
instance: {
|
|
2054
2119
|
type: "string",
|
|
2055
|
-
description: "Instance name
|
|
2120
|
+
description: "Instance name (optional).",
|
|
2056
2121
|
},
|
|
2057
2122
|
},
|
|
2058
2123
|
required: ["issueKey"],
|
|
@@ -2078,7 +2143,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2078
2143
|
},
|
|
2079
2144
|
instance: {
|
|
2080
2145
|
type: "string",
|
|
2081
|
-
description: "Instance name (
|
|
2146
|
+
description: "Instance name (optional).",
|
|
2082
2147
|
},
|
|
2083
2148
|
},
|
|
2084
2149
|
required: ["jql"],
|
|
@@ -2087,7 +2152,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2087
2152
|
{
|
|
2088
2153
|
name: "jira_add_comment",
|
|
2089
2154
|
description:
|
|
2090
|
-
"Add a comment to a Jira ticket.
|
|
2155
|
+
"Add a comment to a Jira ticket. Follow the server instructions' comment style rules.",
|
|
2091
2156
|
inputSchema: {
|
|
2092
2157
|
type: "object",
|
|
2093
2158
|
properties: {
|
|
@@ -2095,10 +2160,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2095
2160
|
type: "string",
|
|
2096
2161
|
description: "The Jira issue key (e.g., MODS-123)",
|
|
2097
2162
|
},
|
|
2098
|
-
comment: {
|
|
2163
|
+
comment: {
|
|
2164
|
+
type: "string",
|
|
2165
|
+
description: "The comment text to add.",
|
|
2166
|
+
},
|
|
2099
2167
|
instance: {
|
|
2100
2168
|
type: "string",
|
|
2101
|
-
description: "Instance name
|
|
2169
|
+
description: "Instance name (optional).",
|
|
2102
2170
|
},
|
|
2103
2171
|
},
|
|
2104
2172
|
required: ["issueKey", "comment"],
|
|
@@ -2120,10 +2188,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2120
2188
|
description:
|
|
2121
2189
|
"The ID of the comment to reply to. Use jira_get_ticket to see comments and their IDs.",
|
|
2122
2190
|
},
|
|
2123
|
-
reply: {
|
|
2191
|
+
reply: {
|
|
2192
|
+
type: "string",
|
|
2193
|
+
description: "The reply text.",
|
|
2194
|
+
},
|
|
2124
2195
|
instance: {
|
|
2125
2196
|
type: "string",
|
|
2126
|
-
description: "Instance name
|
|
2197
|
+
description: "Instance name (optional).",
|
|
2127
2198
|
},
|
|
2128
2199
|
},
|
|
2129
2200
|
required: ["issueKey", "commentId", "reply"],
|
|
@@ -2132,7 +2203,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2132
2203
|
{
|
|
2133
2204
|
name: "jira_edit_comment",
|
|
2134
2205
|
description:
|
|
2135
|
-
"Edit an existing comment on a Jira ticket
|
|
2206
|
+
"Edit an existing comment on a Jira ticket (replaces the text). Follow the server instructions' comment style rules.",
|
|
2136
2207
|
inputSchema: {
|
|
2137
2208
|
type: "object",
|
|
2138
2209
|
properties: {
|
|
@@ -2145,10 +2216,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2145
2216
|
description:
|
|
2146
2217
|
"The ID of the comment to edit. Use jira_get_ticket to see comments and their IDs.",
|
|
2147
2218
|
},
|
|
2148
|
-
comment: {
|
|
2219
|
+
comment: {
|
|
2220
|
+
type: "string",
|
|
2221
|
+
description: "The new comment text.",
|
|
2222
|
+
},
|
|
2149
2223
|
instance: {
|
|
2150
2224
|
type: "string",
|
|
2151
|
-
description: "Instance name
|
|
2225
|
+
description: "Instance name (optional).",
|
|
2152
2226
|
},
|
|
2153
2227
|
},
|
|
2154
2228
|
required: ["issueKey", "commentId", "comment"],
|
|
@@ -2172,7 +2246,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2172
2246
|
},
|
|
2173
2247
|
instance: {
|
|
2174
2248
|
type: "string",
|
|
2175
|
-
description: "Instance name
|
|
2249
|
+
description: "Instance name (optional).",
|
|
2176
2250
|
},
|
|
2177
2251
|
},
|
|
2178
2252
|
required: ["issueKey", "commentId"],
|
|
@@ -2201,7 +2275,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2201
2275
|
},
|
|
2202
2276
|
instance: {
|
|
2203
2277
|
type: "string",
|
|
2204
|
-
description: "Instance name
|
|
2278
|
+
description: "Instance name (optional).",
|
|
2205
2279
|
},
|
|
2206
2280
|
},
|
|
2207
2281
|
required: ["issueKey"],
|
|
@@ -2262,7 +2336,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2262
2336
|
},
|
|
2263
2337
|
instance: {
|
|
2264
2338
|
type: "string",
|
|
2265
|
-
description: "Instance name
|
|
2339
|
+
description: "Instance name (optional).",
|
|
2266
2340
|
},
|
|
2267
2341
|
},
|
|
2268
2342
|
required: ["issueKey"],
|
|
@@ -2286,7 +2360,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2286
2360
|
},
|
|
2287
2361
|
instance: {
|
|
2288
2362
|
type: "string",
|
|
2289
|
-
description: "Instance name (
|
|
2363
|
+
description: "Instance name (optional).",
|
|
2290
2364
|
},
|
|
2291
2365
|
},
|
|
2292
2366
|
required: ["query"],
|
|
@@ -2316,7 +2390,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2316
2390
|
},
|
|
2317
2391
|
instance: {
|
|
2318
2392
|
type: "string",
|
|
2319
|
-
description: "Instance name (
|
|
2393
|
+
description: "Instance name (optional).",
|
|
2320
2394
|
},
|
|
2321
2395
|
},
|
|
2322
2396
|
required: [],
|
|
@@ -2408,7 +2482,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2408
2482
|
},
|
|
2409
2483
|
instance: {
|
|
2410
2484
|
type: "string",
|
|
2411
|
-
description: "Instance name
|
|
2485
|
+
description: "Instance name (optional).",
|
|
2412
2486
|
},
|
|
2413
2487
|
},
|
|
2414
2488
|
required: [],
|
|
@@ -2435,7 +2509,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2435
2509
|
},
|
|
2436
2510
|
description: {
|
|
2437
2511
|
type: "string",
|
|
2438
|
-
description:
|
|
2512
|
+
description:
|
|
2513
|
+
"The issue description text. Supports @mentions via @DisplayName.",
|
|
2439
2514
|
},
|
|
2440
2515
|
assignee: {
|
|
2441
2516
|
type: "string",
|
|
@@ -2478,7 +2553,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2478
2553
|
},
|
|
2479
2554
|
instance: {
|
|
2480
2555
|
type: "string",
|
|
2481
|
-
description: "Instance name
|
|
2556
|
+
description: "Instance name (optional).",
|
|
2482
2557
|
},
|
|
2483
2558
|
},
|
|
2484
2559
|
required: ["projectKey", "issueType", "summary"],
|
|
@@ -2501,7 +2576,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2501
2576
|
},
|
|
2502
2577
|
description: {
|
|
2503
2578
|
type: "string",
|
|
2504
|
-
description:
|
|
2579
|
+
description:
|
|
2580
|
+
"The subtask description text. Supports @mentions via @DisplayName.",
|
|
2505
2581
|
},
|
|
2506
2582
|
assignee: {
|
|
2507
2583
|
type: "string",
|
|
@@ -2522,7 +2598,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2522
2598
|
},
|
|
2523
2599
|
instance: {
|
|
2524
2600
|
type: "string",
|
|
2525
|
-
description: "Instance name
|
|
2601
|
+
description: "Instance name (optional).",
|
|
2526
2602
|
},
|
|
2527
2603
|
},
|
|
2528
2604
|
required: ["parentKey", "summary"],
|
|
@@ -2553,7 +2629,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2553
2629
|
},
|
|
2554
2630
|
instance: {
|
|
2555
2631
|
type: "string",
|
|
2556
|
-
description: "Instance name
|
|
2632
|
+
description: "Instance name (optional).",
|
|
2557
2633
|
},
|
|
2558
2634
|
},
|
|
2559
2635
|
required: ["inwardIssueKey", "outwardIssueKey", "linkType"],
|
|
@@ -2576,7 +2652,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2576
2652
|
},
|
|
2577
2653
|
instance: {
|
|
2578
2654
|
type: "string",
|
|
2579
|
-
description: "Instance name
|
|
2655
|
+
description: "Instance name (optional).",
|
|
2580
2656
|
},
|
|
2581
2657
|
},
|
|
2582
2658
|
required: ["issueKey"],
|
|
@@ -2607,7 +2683,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2607
2683
|
},
|
|
2608
2684
|
instance: {
|
|
2609
2685
|
type: "string",
|
|
2610
|
-
description: "Instance name
|
|
2686
|
+
description: "Instance name (optional).",
|
|
2611
2687
|
},
|
|
2612
2688
|
},
|
|
2613
2689
|
required: ["issueKey"],
|
|
@@ -2622,7 +2698,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2622
2698
|
properties: {
|
|
2623
2699
|
instance: {
|
|
2624
2700
|
type: "string",
|
|
2625
|
-
description: "Instance name (
|
|
2701
|
+
description: "Instance name (optional).",
|
|
2626
2702
|
},
|
|
2627
2703
|
},
|
|
2628
2704
|
required: [],
|
|
@@ -2641,7 +2717,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2641
2717
|
},
|
|
2642
2718
|
instance: {
|
|
2643
2719
|
type: "string",
|
|
2644
|
-
description: "Instance name
|
|
2720
|
+
description: "Instance name (optional).",
|
|
2645
2721
|
},
|
|
2646
2722
|
},
|
|
2647
2723
|
required: ["issueKey"],
|
|
@@ -2664,7 +2740,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2664
2740
|
},
|
|
2665
2741
|
instance: {
|
|
2666
2742
|
type: "string",
|
|
2667
|
-
description: "Instance name
|
|
2743
|
+
description: "Instance name (optional).",
|
|
2668
2744
|
},
|
|
2669
2745
|
},
|
|
2670
2746
|
required: ["issueKey", "linkedIssueKey"],
|
|
@@ -2691,7 +2767,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2691
2767
|
},
|
|
2692
2768
|
instance: {
|
|
2693
2769
|
type: "string",
|
|
2694
|
-
description: "Instance name
|
|
2770
|
+
description: "Instance name (optional).",
|
|
2695
2771
|
},
|
|
2696
2772
|
},
|
|
2697
2773
|
required: [],
|
|
@@ -2714,7 +2790,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2714
2790
|
},
|
|
2715
2791
|
instance: {
|
|
2716
2792
|
type: "string",
|
|
2717
|
-
description: "Instance name
|
|
2793
|
+
description: "Instance name (optional).",
|
|
2718
2794
|
},
|
|
2719
2795
|
},
|
|
2720
2796
|
required: ["issueKey", "accountId"],
|
|
@@ -2737,7 +2813,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2737
2813
|
},
|
|
2738
2814
|
instance: {
|
|
2739
2815
|
type: "string",
|
|
2740
|
-
description: "Instance name
|
|
2816
|
+
description: "Instance name (optional).",
|
|
2741
2817
|
},
|
|
2742
2818
|
},
|
|
2743
2819
|
required: ["issueKey", "accountId"],
|
|
@@ -2768,7 +2844,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2768
2844
|
},
|
|
2769
2845
|
instance: {
|
|
2770
2846
|
type: "string",
|
|
2771
|
-
description: "Instance name
|
|
2847
|
+
description: "Instance name (optional).",
|
|
2772
2848
|
},
|
|
2773
2849
|
},
|
|
2774
2850
|
required: ["issueKey", "timeSpent"],
|
|
@@ -2787,7 +2863,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2787
2863
|
},
|
|
2788
2864
|
instance: {
|
|
2789
2865
|
type: "string",
|
|
2790
|
-
description: "Instance name
|
|
2866
|
+
description: "Instance name (optional).",
|
|
2791
2867
|
},
|
|
2792
2868
|
},
|
|
2793
2869
|
required: ["issueKey"],
|
|
@@ -2818,7 +2894,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2818
2894
|
},
|
|
2819
2895
|
instance: {
|
|
2820
2896
|
type: "string",
|
|
2821
|
-
description: "Instance name
|
|
2897
|
+
description: "Instance name (optional).",
|
|
2822
2898
|
},
|
|
2823
2899
|
},
|
|
2824
2900
|
required: ["issueKey"],
|
|
@@ -2842,7 +2918,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2842
2918
|
},
|
|
2843
2919
|
instance: {
|
|
2844
2920
|
type: "string",
|
|
2845
|
-
description: "Instance name (
|
|
2921
|
+
description: "Instance name (optional).",
|
|
2846
2922
|
},
|
|
2847
2923
|
},
|
|
2848
2924
|
required: ["sprintId", "issueKeys"],
|
|
@@ -2865,7 +2941,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2865
2941
|
},
|
|
2866
2942
|
instance: {
|
|
2867
2943
|
type: "string",
|
|
2868
|
-
description: "Instance name (
|
|
2944
|
+
description: "Instance name (optional).",
|
|
2869
2945
|
},
|
|
2870
2946
|
},
|
|
2871
2947
|
required: ["boardId"],
|
|
@@ -2892,7 +2968,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2892
2968
|
},
|
|
2893
2969
|
instance: {
|
|
2894
2970
|
type: "string",
|
|
2895
|
-
description: "Instance name (
|
|
2971
|
+
description: "Instance name (optional).",
|
|
2896
2972
|
},
|
|
2897
2973
|
},
|
|
2898
2974
|
required: [],
|
|
@@ -2911,7 +2987,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2911
2987
|
},
|
|
2912
2988
|
instance: {
|
|
2913
2989
|
type: "string",
|
|
2914
|
-
description: "Instance name
|
|
2990
|
+
description: "Instance name (optional).",
|
|
2915
2991
|
},
|
|
2916
2992
|
},
|
|
2917
2993
|
required: ["projectKey"],
|
|
@@ -2926,7 +3002,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2926
3002
|
properties: {
|
|
2927
3003
|
instance: {
|
|
2928
3004
|
type: "string",
|
|
2929
|
-
description: "Instance name (
|
|
3005
|
+
description: "Instance name (optional).",
|
|
2930
3006
|
},
|
|
2931
3007
|
},
|
|
2932
3008
|
required: [],
|
|
@@ -2945,7 +3021,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2945
3021
|
},
|
|
2946
3022
|
instance: {
|
|
2947
3023
|
type: "string",
|
|
2948
|
-
description: "Instance name
|
|
3024
|
+
description: "Instance name (optional).",
|
|
2949
3025
|
},
|
|
2950
3026
|
},
|
|
2951
3027
|
required: ["projectKey"],
|
|
@@ -2964,7 +3040,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2964
3040
|
},
|
|
2965
3041
|
instance: {
|
|
2966
3042
|
type: "string",
|
|
2967
|
-
description: "Instance name
|
|
3043
|
+
description: "Instance name (optional).",
|
|
2968
3044
|
},
|
|
2969
3045
|
},
|
|
2970
3046
|
required: ["projectKey"],
|
|
@@ -2979,7 +3055,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2979
3055
|
properties: {
|
|
2980
3056
|
instance: {
|
|
2981
3057
|
type: "string",
|
|
2982
|
-
description: "Instance name
|
|
3058
|
+
description: "Instance name (optional).",
|
|
2983
3059
|
},
|
|
2984
3060
|
},
|
|
2985
3061
|
required: [],
|
|
@@ -2993,7 +3069,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2993
3069
|
type: "object",
|
|
2994
3070
|
properties: {
|
|
2995
3071
|
spaceKey: { type: "string", description: "Space key (e.g., 'ENG')." },
|
|
2996
|
-
instance: { type: "string", description: "Instance name
|
|
3072
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
2997
3073
|
},
|
|
2998
3074
|
required: ["spaceKey"],
|
|
2999
3075
|
},
|
|
@@ -3008,7 +3084,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3008
3084
|
spaceKey: { type: "string", description: "Unique space key (letters/numbers). Will be uppercased." },
|
|
3009
3085
|
name: { type: "string", description: "Human-readable space name." },
|
|
3010
3086
|
description: { type: "string", description: "Optional plain-text description." },
|
|
3011
|
-
instance: { type: "string", description: "Instance name
|
|
3087
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3012
3088
|
},
|
|
3013
3089
|
required: ["spaceKey", "name"],
|
|
3014
3090
|
},
|
|
@@ -3023,7 +3099,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3023
3099
|
spaceKey: { type: "string", description: "Space key to update." },
|
|
3024
3100
|
name: { type: "string", description: "New space name." },
|
|
3025
3101
|
description: { type: "string", description: "New plain-text description." },
|
|
3026
|
-
instance: { type: "string", description: "Instance name
|
|
3102
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3027
3103
|
},
|
|
3028
3104
|
required: ["spaceKey"],
|
|
3029
3105
|
},
|
|
@@ -3036,7 +3112,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3036
3112
|
type: "object",
|
|
3037
3113
|
properties: {
|
|
3038
3114
|
spaceKey: { type: "string", description: "Space key to delete." },
|
|
3039
|
-
instance: { type: "string", description: "Instance name
|
|
3115
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3040
3116
|
},
|
|
3041
3117
|
required: ["spaceKey"],
|
|
3042
3118
|
},
|
|
@@ -3052,7 +3128,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3052
3128
|
spaceKey: { type: "string", description: "Optional space key to scope the search." },
|
|
3053
3129
|
type: { type: "string", description: "Content type (default: page). e.g. page, blogpost, comment, attachment." },
|
|
3054
3130
|
limit: { type: "number", description: "Max results (default: 25)." },
|
|
3055
|
-
instance: { type: "string", description: "Instance name
|
|
3131
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3056
3132
|
},
|
|
3057
3133
|
required: ["query"],
|
|
3058
3134
|
},
|
|
@@ -3067,7 +3143,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3067
3143
|
spaceKey: { type: "string", description: "Optional space key to scope the query." },
|
|
3068
3144
|
sinceDays: { type: "number", description: "Days back from now (default: 30)." },
|
|
3069
3145
|
limit: { type: "number", description: "Max results (default: 25)." },
|
|
3070
|
-
instance: { type: "string", description: "Instance name
|
|
3146
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3071
3147
|
},
|
|
3072
3148
|
required: [],
|
|
3073
3149
|
},
|
|
@@ -3081,7 +3157,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3081
3157
|
properties: {
|
|
3082
3158
|
spaceKey: { type: "string", description: "Space key (required)." },
|
|
3083
3159
|
limit: { type: "number", description: "Max results (default: 50)." },
|
|
3084
|
-
instance: { type: "string", description: "Instance name
|
|
3160
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3085
3161
|
},
|
|
3086
3162
|
required: ["spaceKey"],
|
|
3087
3163
|
},
|
|
@@ -3095,7 +3171,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3095
3171
|
properties: {
|
|
3096
3172
|
pageId: { type: "string", description: "Parent page ID (required)." },
|
|
3097
3173
|
limit: { type: "number", description: "Max results (default: 50)." },
|
|
3098
|
-
instance: { type: "string", description: "Instance name
|
|
3174
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3099
3175
|
},
|
|
3100
3176
|
required: ["pageId"],
|
|
3101
3177
|
},
|
|
@@ -3109,7 +3185,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3109
3185
|
properties: {
|
|
3110
3186
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3111
3187
|
includeAdf: { type: "boolean", description: "Fetch ADF body via v2 API and merge (default: true)." },
|
|
3112
|
-
instance: { type: "string", description: "Instance name
|
|
3188
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3113
3189
|
},
|
|
3114
3190
|
required: ["pageId"],
|
|
3115
3191
|
},
|
|
@@ -3123,7 +3199,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3123
3199
|
properties: {
|
|
3124
3200
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3125
3201
|
limit: { type: "number", description: "Max results (default: 50)." },
|
|
3126
|
-
instance: { type: "string", description: "Instance name
|
|
3202
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3127
3203
|
},
|
|
3128
3204
|
required: ["pageId"],
|
|
3129
3205
|
},
|
|
@@ -3138,7 +3214,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3138
3214
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3139
3215
|
body: { type: "string", description: "Comment body (plain text by default, or storage XHTML if format=storage)." },
|
|
3140
3216
|
format: { type: "string", description: "'text' (default) or 'storage'." },
|
|
3141
|
-
instance: { type: "string", description: "Instance name
|
|
3217
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3142
3218
|
},
|
|
3143
3219
|
required: ["pageId", "body"],
|
|
3144
3220
|
},
|
|
@@ -3154,7 +3230,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3154
3230
|
title: { type: "string", description: "New page title (optional — retains current if omitted)." },
|
|
3155
3231
|
body: { type: "string", description: "New body as storage XHTML (optional — retains current if omitted)." },
|
|
3156
3232
|
version: { type: "number", description: "Explicit new version number. If omitted, current+1 is computed." },
|
|
3157
|
-
instance: { type: "string", description: "Instance name
|
|
3233
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3158
3234
|
},
|
|
3159
3235
|
required: ["pageId"],
|
|
3160
3236
|
},
|
|
@@ -3170,7 +3246,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3170
3246
|
title: { type: "string", description: "Page title (required)." },
|
|
3171
3247
|
body: { type: "string", description: "Storage-format XHTML body (required)." },
|
|
3172
3248
|
parentId: { type: "string", description: "Optional parent page ID to nest under." },
|
|
3173
|
-
instance: { type: "string", description: "Instance name
|
|
3249
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3174
3250
|
},
|
|
3175
3251
|
required: ["spaceKey", "title", "body"],
|
|
3176
3252
|
},
|
|
@@ -3182,7 +3258,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3182
3258
|
type: "object",
|
|
3183
3259
|
properties: {
|
|
3184
3260
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3185
|
-
instance: { type: "string", description: "Instance name
|
|
3261
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3186
3262
|
},
|
|
3187
3263
|
required: ["pageId"],
|
|
3188
3264
|
},
|
|
@@ -3194,7 +3270,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3194
3270
|
type: "object",
|
|
3195
3271
|
properties: {
|
|
3196
3272
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3197
|
-
instance: { type: "string", description: "Instance name
|
|
3273
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3198
3274
|
},
|
|
3199
3275
|
required: ["pageId"],
|
|
3200
3276
|
},
|
|
@@ -3207,7 +3283,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3207
3283
|
properties: {
|
|
3208
3284
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3209
3285
|
label: { type: "string", description: "Label name (required)." },
|
|
3210
|
-
instance: { type: "string", description: "Instance name
|
|
3286
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3211
3287
|
},
|
|
3212
3288
|
required: ["pageId", "label"],
|
|
3213
3289
|
},
|
|
@@ -3220,7 +3296,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3220
3296
|
properties: {
|
|
3221
3297
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3222
3298
|
label: { type: "string", description: "Label name (required)." },
|
|
3223
|
-
instance: { type: "string", description: "Instance name
|
|
3299
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3224
3300
|
},
|
|
3225
3301
|
required: ["pageId", "label"],
|
|
3226
3302
|
},
|
|
@@ -3233,7 +3309,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3233
3309
|
properties: {
|
|
3234
3310
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3235
3311
|
limit: { type: "number", description: "Max results (default: 50)." },
|
|
3236
|
-
instance: { type: "string", description: "Instance name
|
|
3312
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3237
3313
|
},
|
|
3238
3314
|
required: ["pageId"],
|
|
3239
3315
|
},
|
|
@@ -3250,7 +3326,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3250
3326
|
fileContent: { type: "string", description: "Base64-encoded file content (requires fileName)." },
|
|
3251
3327
|
fileName: { type: "string", description: "File name (required with fileContent; optional with filePath)." },
|
|
3252
3328
|
comment: { type: "string", description: "Optional attachment comment." },
|
|
3253
|
-
instance: { type: "string", description: "Instance name
|
|
3329
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3254
3330
|
},
|
|
3255
3331
|
required: ["pageId"],
|
|
3256
3332
|
},
|
|
@@ -3264,13 +3340,22 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
3264
3340
|
properties: {
|
|
3265
3341
|
pageId: { type: "string", description: "Page ID (required)." },
|
|
3266
3342
|
filename: { type: "string", description: "Attachment filename (required)." },
|
|
3267
|
-
instance: { type: "string", description: "Instance name
|
|
3343
|
+
instance: { type: "string", description: "Instance name (optional)." },
|
|
3268
3344
|
},
|
|
3269
3345
|
required: ["pageId", "filename"],
|
|
3270
3346
|
},
|
|
3271
3347
|
},
|
|
3272
3348
|
];
|
|
3273
|
-
|
|
3349
|
+
let tools = rawTools;
|
|
3350
|
+
if (!confluenceActive) {
|
|
3351
|
+
tools = rawTools.filter(t => !t.name.startsWith("confluence_"));
|
|
3352
|
+
tools.push({
|
|
3353
|
+
name: "confluence_enable",
|
|
3354
|
+
description: "Activate the Confluence tool set (pages, spaces, page comments, labels, attachments, search). Call this first when a task needs Confluence; the confluence_* tools then become available. Activation only changes tool visibility for this server process; per-instance scopes still apply to every Confluence operation.",
|
|
3355
|
+
inputSchema: { type: "object", properties: {}, required: [] },
|
|
3356
|
+
});
|
|
3357
|
+
}
|
|
3358
|
+
return { tools: tools.map(_injectDryRunSchema) };
|
|
3274
3359
|
});
|
|
3275
3360
|
|
|
3276
3361
|
async function runWithPolicy(name, args, handler) {
|
|
@@ -3388,6 +3473,19 @@ async function runWithPolicy(name, args, handler) {
|
|
|
3388
3473
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3389
3474
|
const { name, arguments: args } = request.params;
|
|
3390
3475
|
|
|
3476
|
+
if (name === "confluence_enable") {
|
|
3477
|
+
const wasActive = confluenceActive;
|
|
3478
|
+
confluenceActive = true;
|
|
3479
|
+
if (!wasActive) server.sendToolListChanged().catch((e) => console.error("jira-mcp: tools/list_changed notification failed:", e?.message || e));
|
|
3480
|
+
return { content: [{ type: "text", text: wasActive ? "Confluence tools were already active." : "Confluence tools activated — the confluence_* tools are now available." }] };
|
|
3481
|
+
}
|
|
3482
|
+
// A client with a cached tool list may call a confluence_* tool directly
|
|
3483
|
+
// while hidden — auto-activate instead of failing.
|
|
3484
|
+
if (!confluenceActive && TOOL_METADATA[name]?.product === "confluence" && name !== "confluence_enable") {
|
|
3485
|
+
confluenceActive = true;
|
|
3486
|
+
server.sendToolListChanged().catch((e) => console.error("jira-mcp: tools/list_changed notification failed:", e?.message || e));
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3391
3489
|
return runWithPolicy(name, args, async () => {
|
|
3392
3490
|
if (name === "jira_get_myself") {
|
|
3393
3491
|
const inst = getInstanceByName(args.instance);
|
|
@@ -3509,11 +3607,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3509
3607
|
}, inst);
|
|
3510
3608
|
const author = result.author?.displayName || "Unknown";
|
|
3511
3609
|
const created = new Date(result.created).toLocaleString();
|
|
3610
|
+
const postedText = quoteText(extractTextSimple(result.body).trim());
|
|
3512
3611
|
return {
|
|
3513
3612
|
content: [
|
|
3514
3613
|
{
|
|
3515
3614
|
type: "text",
|
|
3516
|
-
text: `Comment added to ${args.issueKey} by ${author} at ${created}
|
|
3615
|
+
text: `Comment added to ${args.issueKey} by ${author} at ${created}:\n\n${postedText}`,
|
|
3517
3616
|
},
|
|
3518
3617
|
],
|
|
3519
3618
|
};
|
|
@@ -3577,11 +3676,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3577
3676
|
}, inst);
|
|
3578
3677
|
const author = result.author?.displayName || "Unknown";
|
|
3579
3678
|
const created = new Date(result.created).toLocaleString();
|
|
3679
|
+
const postedText = quoteText(extractTextSimple(result.body).trim());
|
|
3580
3680
|
return {
|
|
3581
3681
|
content: [
|
|
3582
3682
|
{
|
|
3583
3683
|
type: "text",
|
|
3584
|
-
text: `Reply to ${originalAuthor}'s comment posted on ${args.issueKey} by ${author} at ${created}
|
|
3684
|
+
text: `Reply to ${originalAuthor}'s comment posted on ${args.issueKey} by ${author} at ${created}:\n\n${postedText}`,
|
|
3585
3685
|
},
|
|
3586
3686
|
],
|
|
3587
3687
|
};
|
|
@@ -3601,11 +3701,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3601
3701
|
{ method: "PUT", body },
|
|
3602
3702
|
inst,
|
|
3603
3703
|
);
|
|
3704
|
+
const editedText = quoteText(extractTextSimple(result.body).trim());
|
|
3604
3705
|
return {
|
|
3605
3706
|
content: [
|
|
3606
3707
|
{
|
|
3607
3708
|
type: "text",
|
|
3608
|
-
text: `Comment ${args.commentId} on ${args.issueKey} updated
|
|
3709
|
+
text: `Comment ${args.commentId} on ${args.issueKey} updated:\n\n${editedText}`,
|
|
3609
3710
|
},
|
|
3610
3711
|
],
|
|
3611
3712
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rui.branco/jira-mcp",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"description": "Jira & Confluence MCP server for any MCP-compatible AI client (Claude Code, Codex, Antigravity, Cursor, etc.) - fetch tickets, search with JQL, update tickets, manage comments, change status, get Figma designs. Optional per-tool scopes, dry-run, audit log, and rate limiting.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|