mcp-jira-stdio 1.5.5 → 1.6.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 +9 -3
- package/dist/index.js +83 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -21,10 +21,13 @@ A Model Context Protocol (MCP) server for Jira API integration. Enables reading,
|
|
|
21
21
|
The fastest way to add this MCP server to Claude Code:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
claude mcp add jira npx mcp-jira-stdio@latest
|
|
24
|
+
claude mcp add jira npx mcp-jira-stdio@latest \
|
|
25
|
+
--env JIRA_BASE_URL=https://yourcompany.atlassian.net \
|
|
26
|
+
--env JIRA_EMAIL=your-email@example.com \
|
|
27
|
+
--env JIRA_API_TOKEN=your-api-token
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
Replace the values with your actual Jira credentials:
|
|
28
31
|
- **JIRA_BASE_URL**: Your Jira instance URL (e.g., `https://yourcompany.atlassian.net`)
|
|
29
32
|
- **JIRA_EMAIL**: Your Jira account email
|
|
30
33
|
- **JIRA_API_TOKEN**: Your Jira API token ([generate here](https://id.atlassian.com/manage-profile/security/api-tokens))
|
|
@@ -119,7 +122,10 @@ task jira:projects
|
|
|
119
122
|
Use the quick install command (recommended):
|
|
120
123
|
|
|
121
124
|
```bash
|
|
122
|
-
claude mcp add jira npx mcp-jira-stdio@latest
|
|
125
|
+
claude mcp add jira npx mcp-jira-stdio@latest \
|
|
126
|
+
--env JIRA_BASE_URL=https://yourcompany.atlassian.net \
|
|
127
|
+
--env JIRA_EMAIL=your-email@example.com \
|
|
128
|
+
--env JIRA_API_TOKEN=your-api-token
|
|
123
129
|
```
|
|
124
130
|
|
|
125
131
|
#### For Claude Desktop
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
4
4
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
+
import mdToAdf from 'md-to-adf';
|
|
7
8
|
|
|
8
9
|
var __create = Object.create;
|
|
9
10
|
var __defProp = Object.defineProperty;
|
|
@@ -439,7 +440,7 @@ var require_package2 = __commonJS({
|
|
|
439
440
|
"package.json"(exports, module) {
|
|
440
441
|
module.exports = {
|
|
441
442
|
name: "mcp-jira-stdio",
|
|
442
|
-
version: "1.
|
|
443
|
+
version: "1.6.0",
|
|
443
444
|
description: "Model Context Protocol (MCP) server for Jira API integration",
|
|
444
445
|
author: "graslt",
|
|
445
446
|
license: "MIT",
|
|
@@ -490,6 +491,7 @@ var require_package2 = __commonJS({
|
|
|
490
491
|
dependencies: {
|
|
491
492
|
"@modelcontextprotocol/sdk": "^1.17.1",
|
|
492
493
|
axios: "^1.7.0",
|
|
494
|
+
"md-to-adf": "^0.6.4",
|
|
493
495
|
zod: "^3.22.4"
|
|
494
496
|
},
|
|
495
497
|
devDependencies: {
|
|
@@ -759,7 +761,10 @@ var CreateIssueInputSchema = z.object({
|
|
|
759
761
|
customFields: z.record(z.any()).optional().describe(
|
|
760
762
|
'Additional Jira field mappings, e.g. { "customfield_12345": value }. Use for required custom fields.'
|
|
761
763
|
),
|
|
762
|
-
returnIssue: z.boolean().optional().describe("When false, skip fetching full issue after creation")
|
|
764
|
+
returnIssue: z.boolean().optional().describe("When false, skip fetching full issue after creation"),
|
|
765
|
+
format: z.enum(["markdown", "adf", "plain"]).optional().default("markdown").describe(
|
|
766
|
+
'Description format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"'
|
|
767
|
+
)
|
|
763
768
|
});
|
|
764
769
|
var UpdateIssueInputSchema = z.object({
|
|
765
770
|
issueKey: z.string().describe("Issue key to update").refine((v) => isValidIssueKey(v), "Invalid issue key format"),
|
|
@@ -769,7 +774,10 @@ var UpdateIssueInputSchema = z.object({
|
|
|
769
774
|
assignee: z.string().optional().describe("New assignee account ID"),
|
|
770
775
|
labels: z.array(z.string()).optional().describe("New labels (replaces existing)"),
|
|
771
776
|
components: z.array(z.string()).optional().describe("New components (replaces existing)"),
|
|
772
|
-
returnIssue: z.boolean().optional().describe("When false, skip fetching full issue after update")
|
|
777
|
+
returnIssue: z.boolean().optional().describe("When false, skip fetching full issue after update"),
|
|
778
|
+
format: z.enum(["markdown", "adf", "plain"]).optional().default("markdown").describe(
|
|
779
|
+
'Description format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"'
|
|
780
|
+
)
|
|
773
781
|
});
|
|
774
782
|
var GetMyIssuesInputSchema = z.object({
|
|
775
783
|
nextPageToken: z.string().optional().describe(
|
|
@@ -800,7 +808,10 @@ var AddCommentInputSchema = z.object({
|
|
|
800
808
|
visibility: z.object({
|
|
801
809
|
type: z.enum(["group", "role"]).describe("Visibility type"),
|
|
802
810
|
value: z.string().describe("Group name or role name")
|
|
803
|
-
}).optional().describe("Comment visibility restrictions")
|
|
811
|
+
}).optional().describe("Comment visibility restrictions"),
|
|
812
|
+
format: z.enum(["markdown", "adf", "plain"]).optional().default("markdown").describe(
|
|
813
|
+
'Comment format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"'
|
|
814
|
+
)
|
|
804
815
|
});
|
|
805
816
|
var GetProjectInfoInputSchema = z.object({
|
|
806
817
|
projectKey: z.string().describe("Project key to get detailed information for").refine((v) => isValidProjectKey(v), "Invalid project key format"),
|
|
@@ -813,7 +824,10 @@ var CreateSubtaskInputSchema = z.object({
|
|
|
813
824
|
priority: z.string().optional().describe("Subtask priority"),
|
|
814
825
|
assignee: z.string().optional().describe("Assignee account ID"),
|
|
815
826
|
labels: z.array(z.string()).optional().describe("Subtask labels"),
|
|
816
|
-
components: z.array(z.string()).optional().describe("Component names")
|
|
827
|
+
components: z.array(z.string()).optional().describe("Component names"),
|
|
828
|
+
format: z.enum(["markdown", "adf", "plain"]).optional().default("markdown").describe(
|
|
829
|
+
'Description format: "markdown" (converts Markdown to ADF), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting). Default: "markdown"'
|
|
830
|
+
)
|
|
817
831
|
});
|
|
818
832
|
var GetCreateMetaInputSchema = z.object({
|
|
819
833
|
projectKey: z.string().describe("Project key to get create metadata for").refine((v) => isValidProjectKey(v), "Invalid project key format"),
|
|
@@ -822,12 +836,21 @@ var GetCreateMetaInputSchema = z.object({
|
|
|
822
836
|
var GetCustomFieldsInputSchema = z.object({
|
|
823
837
|
projectKey: z.string().optional().describe("Project key to filter custom fields (optional)").refine((v) => v ? isValidProjectKey(v) : true, "Invalid project key format")
|
|
824
838
|
});
|
|
825
|
-
|
|
826
|
-
// src/utils/api-helpers.ts
|
|
827
|
-
function ensureAdfDescription(desc) {
|
|
839
|
+
function ensureAdfDescription(desc, format = "markdown") {
|
|
828
840
|
if (!desc) return desc;
|
|
829
841
|
if (typeof desc === "object") return desc;
|
|
830
842
|
if (typeof desc !== "string") return desc;
|
|
843
|
+
if (format === "markdown") {
|
|
844
|
+
try {
|
|
845
|
+
return mdToAdf(desc);
|
|
846
|
+
} catch (error) {
|
|
847
|
+
console.warn("Markdown to ADF conversion failed, falling back to plain text:", error);
|
|
848
|
+
format = "plain";
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
if (format === "adf") {
|
|
852
|
+
return desc;
|
|
853
|
+
}
|
|
831
854
|
const urlRegex = /https?:\/\/[^\s)]+/g;
|
|
832
855
|
const makeTextNodes = (text) => {
|
|
833
856
|
const nodes = [];
|
|
@@ -1010,7 +1033,10 @@ async function createIssue(issueData, options = { returnIssue: true }) {
|
|
|
1010
1033
|
issuetype: { name: issueData.issueType }
|
|
1011
1034
|
};
|
|
1012
1035
|
if (issueData.description !== void 0) {
|
|
1013
|
-
fields.description = ensureAdfDescription(
|
|
1036
|
+
fields.description = ensureAdfDescription(
|
|
1037
|
+
issueData.description,
|
|
1038
|
+
issueData.format || "markdown"
|
|
1039
|
+
);
|
|
1014
1040
|
}
|
|
1015
1041
|
if (issueData.priority) {
|
|
1016
1042
|
fields.priority = { name: issueData.priority };
|
|
@@ -1048,7 +1074,7 @@ async function updateIssue(issueKey, updates) {
|
|
|
1048
1074
|
fields.summary = updates.summary;
|
|
1049
1075
|
}
|
|
1050
1076
|
if (updates.description !== void 0) {
|
|
1051
|
-
fields.description = ensureAdfDescription(updates.description);
|
|
1077
|
+
fields.description = ensureAdfDescription(updates.description, updates.format || "markdown");
|
|
1052
1078
|
}
|
|
1053
1079
|
if (updates.priority !== void 0) {
|
|
1054
1080
|
fields.priority = { name: updates.priority };
|
|
@@ -1145,8 +1171,8 @@ async function getStatuses(options = {}) {
|
|
|
1145
1171
|
}
|
|
1146
1172
|
return await makeJiraRequest(config);
|
|
1147
1173
|
}
|
|
1148
|
-
async function addComment(issueKey, body, visibility) {
|
|
1149
|
-
const adfBody = ensureAdfDescription(body);
|
|
1174
|
+
async function addComment(issueKey, body, visibility, format) {
|
|
1175
|
+
const adfBody = ensureAdfDescription(body, format || "markdown");
|
|
1150
1176
|
const data = {
|
|
1151
1177
|
body: adfBody
|
|
1152
1178
|
};
|
|
@@ -1187,7 +1213,10 @@ async function createSubtask(parentIssueKey, subtaskData) {
|
|
|
1187
1213
|
issuetype: { id: subtaskType.id }
|
|
1188
1214
|
};
|
|
1189
1215
|
if (subtaskData.description !== void 0) {
|
|
1190
|
-
fields.description = ensureAdfDescription(
|
|
1216
|
+
fields.description = ensureAdfDescription(
|
|
1217
|
+
subtaskData.description,
|
|
1218
|
+
subtaskData.format || "markdown"
|
|
1219
|
+
);
|
|
1191
1220
|
}
|
|
1192
1221
|
if (subtaskData.priority) {
|
|
1193
1222
|
fields.priority = { name: subtaskData.priority };
|
|
@@ -2088,7 +2117,7 @@ async function handleGetStatuses(input) {
|
|
|
2088
2117
|
var log11 = createLogger("tool:create-issue");
|
|
2089
2118
|
var createIssueTool = {
|
|
2090
2119
|
name: TOOL_NAMES.CREATE_ISSUE,
|
|
2091
|
-
description: 'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description
|
|
2120
|
+
description: 'Creates a new Jira issue in the specified project. Supports setting issue type, priority, assignee, labels, components, and custom fields. Description format is controlled by the "format" parameter (default: markdown). For required custom fields, supply them via customFields (e.g., { "customfield_12345": { id: "..." } }). Returns the created issue with all details.',
|
|
2092
2121
|
inputSchema: {
|
|
2093
2122
|
type: "object",
|
|
2094
2123
|
properties: {
|
|
@@ -2103,7 +2132,7 @@ var createIssueTool = {
|
|
|
2103
2132
|
},
|
|
2104
2133
|
description: {
|
|
2105
2134
|
anyOf: [{ type: "string" }, { type: "object" }],
|
|
2106
|
-
description:
|
|
2135
|
+
description: 'Detailed issue description (optional). Format depends on the "format" parameter.'
|
|
2107
2136
|
},
|
|
2108
2137
|
issueType: {
|
|
2109
2138
|
type: "string",
|
|
@@ -2138,6 +2167,12 @@ var createIssueTool = {
|
|
|
2138
2167
|
type: "boolean",
|
|
2139
2168
|
description: "If false, returns only the issue key without fetching full details",
|
|
2140
2169
|
default: true
|
|
2170
|
+
},
|
|
2171
|
+
format: {
|
|
2172
|
+
type: "string",
|
|
2173
|
+
enum: ["markdown", "adf", "plain"],
|
|
2174
|
+
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2175
|
+
default: "markdown"
|
|
2141
2176
|
}
|
|
2142
2177
|
},
|
|
2143
2178
|
required: ["projectKey", "summary", "issueType"]
|
|
@@ -2158,6 +2193,7 @@ async function handleCreateIssue(input) {
|
|
|
2158
2193
|
if (validated.labels !== void 0) createParams.labels = validated.labels;
|
|
2159
2194
|
if (validated.components !== void 0) createParams.components = validated.components;
|
|
2160
2195
|
if (validated.customFields !== void 0) createParams.customFields = validated.customFields;
|
|
2196
|
+
if (validated.format !== void 0) createParams.format = validated.format;
|
|
2161
2197
|
let issueOrKey;
|
|
2162
2198
|
if (validated.returnIssue === false) {
|
|
2163
2199
|
issueOrKey = await createIssue(createParams, { returnIssue: false });
|
|
@@ -2182,7 +2218,7 @@ async function handleCreateIssue(input) {
|
|
|
2182
2218
|
var log12 = createLogger("tool:update-issue");
|
|
2183
2219
|
var updateIssueTool = {
|
|
2184
2220
|
name: TOOL_NAMES.UPDATE_ISSUE,
|
|
2185
|
-
description: 'Updates an existing Jira issue by its key. Supports updating summary, description, priority, assignee, labels, and components. Description
|
|
2221
|
+
description: 'Updates an existing Jira issue by its key. Supports updating summary, description, priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown). Only specified fields will be updated.',
|
|
2186
2222
|
inputSchema: {
|
|
2187
2223
|
type: "object",
|
|
2188
2224
|
properties: {
|
|
@@ -2196,7 +2232,7 @@ var updateIssueTool = {
|
|
|
2196
2232
|
},
|
|
2197
2233
|
description: {
|
|
2198
2234
|
anyOf: [{ type: "string" }, { type: "object" }],
|
|
2199
|
-
description:
|
|
2235
|
+
description: 'New issue description (optional). Format depends on the "format" parameter.'
|
|
2200
2236
|
},
|
|
2201
2237
|
priority: {
|
|
2202
2238
|
type: "string",
|
|
@@ -2220,6 +2256,12 @@ var updateIssueTool = {
|
|
|
2220
2256
|
type: "boolean",
|
|
2221
2257
|
description: "If false, returns a success message without fetching the updated issue",
|
|
2222
2258
|
default: true
|
|
2259
|
+
},
|
|
2260
|
+
format: {
|
|
2261
|
+
type: "string",
|
|
2262
|
+
enum: ["markdown", "adf", "plain"],
|
|
2263
|
+
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2264
|
+
default: "markdown"
|
|
2223
2265
|
}
|
|
2224
2266
|
},
|
|
2225
2267
|
required: ["issueKey"]
|
|
@@ -2236,6 +2278,7 @@ async function handleUpdateIssue(input) {
|
|
|
2236
2278
|
if (validated.assignee !== void 0) updateParams.assignee = validated.assignee;
|
|
2237
2279
|
if (validated.labels !== void 0) updateParams.labels = validated.labels;
|
|
2238
2280
|
if (validated.components !== void 0) updateParams.components = validated.components;
|
|
2281
|
+
if (validated.format !== void 0) updateParams.format = validated.format;
|
|
2239
2282
|
await updateIssue(validated.issueKey, updateParams);
|
|
2240
2283
|
if (validated.returnIssue === false) {
|
|
2241
2284
|
log12.info(`Updated issue ${validated.issueKey}`);
|
|
@@ -2254,7 +2297,7 @@ async function handleUpdateIssue(input) {
|
|
|
2254
2297
|
var log13 = createLogger("tool:add-comment");
|
|
2255
2298
|
var addCommentTool = {
|
|
2256
2299
|
name: TOOL_NAMES.ADD_COMMENT,
|
|
2257
|
-
description:
|
|
2300
|
+
description: 'Adds a comment to an issue. Supports visibility restrictions for groups or roles. Comment format is controlled by the "format" parameter (default: markdown). Returns the created comment with author details and timestamp.',
|
|
2258
2301
|
inputSchema: {
|
|
2259
2302
|
type: "object",
|
|
2260
2303
|
properties: {
|
|
@@ -2264,7 +2307,7 @@ var addCommentTool = {
|
|
|
2264
2307
|
},
|
|
2265
2308
|
body: {
|
|
2266
2309
|
type: "string",
|
|
2267
|
-
description:
|
|
2310
|
+
description: 'Comment body text. Format depends on the "format" parameter.',
|
|
2268
2311
|
minLength: 1
|
|
2269
2312
|
},
|
|
2270
2313
|
visibility: {
|
|
@@ -2282,6 +2325,12 @@ var addCommentTool = {
|
|
|
2282
2325
|
}
|
|
2283
2326
|
},
|
|
2284
2327
|
required: ["type", "value"]
|
|
2328
|
+
},
|
|
2329
|
+
format: {
|
|
2330
|
+
type: "string",
|
|
2331
|
+
enum: ["markdown", "adf", "plain"],
|
|
2332
|
+
description: 'Comment format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2333
|
+
default: "markdown"
|
|
2285
2334
|
}
|
|
2286
2335
|
},
|
|
2287
2336
|
required: ["issueKey", "body"]
|
|
@@ -2291,7 +2340,12 @@ async function handleAddComment(input) {
|
|
|
2291
2340
|
try {
|
|
2292
2341
|
const validated = validateInput(AddCommentInputSchema, input);
|
|
2293
2342
|
log13.info(`Adding comment to issue ${validated.issueKey}...`);
|
|
2294
|
-
const comment = await addComment(
|
|
2343
|
+
const comment = await addComment(
|
|
2344
|
+
validated.issueKey,
|
|
2345
|
+
validated.body,
|
|
2346
|
+
validated.visibility,
|
|
2347
|
+
validated.format
|
|
2348
|
+
);
|
|
2295
2349
|
log13.info(`Added comment to ${validated.issueKey}`);
|
|
2296
2350
|
return formatCommentResponse(comment);
|
|
2297
2351
|
} catch (error) {
|
|
@@ -2339,7 +2393,7 @@ async function handleGetProjectInfo(input) {
|
|
|
2339
2393
|
var log15 = createLogger("tool:create-subtask");
|
|
2340
2394
|
var createSubtaskTool = {
|
|
2341
2395
|
name: TOOL_NAMES.CREATE_SUBTASK,
|
|
2342
|
-
description:
|
|
2396
|
+
description: 'Creates a subtask under an existing parent issue. Automatically determines the correct project and subtask issue type. Supports setting priority, assignee, labels, and components. Description format is controlled by the "format" parameter (default: markdown).',
|
|
2343
2397
|
inputSchema: {
|
|
2344
2398
|
type: "object",
|
|
2345
2399
|
properties: {
|
|
@@ -2354,7 +2408,7 @@ var createSubtaskTool = {
|
|
|
2354
2408
|
},
|
|
2355
2409
|
description: {
|
|
2356
2410
|
type: "string",
|
|
2357
|
-
description:
|
|
2411
|
+
description: 'Detailed subtask description (optional). Format depends on the "format" parameter.'
|
|
2358
2412
|
},
|
|
2359
2413
|
priority: {
|
|
2360
2414
|
type: "string",
|
|
@@ -2375,6 +2429,12 @@ var createSubtaskTool = {
|
|
|
2375
2429
|
items: { type: "string" },
|
|
2376
2430
|
description: "Component names (optional)",
|
|
2377
2431
|
default: []
|
|
2432
|
+
},
|
|
2433
|
+
format: {
|
|
2434
|
+
type: "string",
|
|
2435
|
+
enum: ["markdown", "adf", "plain"],
|
|
2436
|
+
description: 'Description format: "markdown" (converts Markdown to ADF, default), "adf" (use as-is ADF object), "plain" (converts plain text to ADF with basic formatting)',
|
|
2437
|
+
default: "markdown"
|
|
2378
2438
|
}
|
|
2379
2439
|
},
|
|
2380
2440
|
required: ["parentIssueKey", "summary"]
|
|
@@ -2392,6 +2452,7 @@ async function handleCreateSubtask(input) {
|
|
|
2392
2452
|
if (validated.assignee !== void 0) subtaskParams.assignee = validated.assignee;
|
|
2393
2453
|
if (validated.labels !== void 0) subtaskParams.labels = validated.labels;
|
|
2394
2454
|
if (validated.components !== void 0) subtaskParams.components = validated.components;
|
|
2455
|
+
if (validated.format !== void 0) subtaskParams.format = validated.format;
|
|
2395
2456
|
const subtask = await createSubtask(validated.parentIssueKey, subtaskParams);
|
|
2396
2457
|
log15.info(`Created subtask ${subtask.key}`);
|
|
2397
2458
|
return formatIssueResponse(subtask);
|