mcp-jira-stdio 1.7.0 → 1.7.1

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 CHANGED
@@ -338,6 +338,18 @@ jira_get_visible_projects({
338
338
  - Look for errors in Claude Desktop logs
339
339
  - Use `task inspector` to debug
340
340
 
341
+ **Timeout when running multiple instances with npx**
342
+
343
+ If you're running multiple Claude Code sessions simultaneously and experience timeouts, this is caused by `npx` cache/registry locking — not the MCP server itself. Each instance tries to verify the package, causing conflicts. To fix this, install the package globally instead:
344
+
345
+ ```bash
346
+ npm install -g mcp-jira-stdio
347
+ claude mcp add jira mcp-jira-stdio \
348
+ --env JIRA_BASE_URL=... \
349
+ --env JIRA_EMAIL=... \
350
+ --env JIRA_API_TOKEN=...
351
+ ```
352
+
341
353
  ### Debug Commands
342
354
 
343
355
  ```bash
package/dist/index.js CHANGED
@@ -440,7 +440,7 @@ var require_package2 = __commonJS({
440
440
  "package.json"(exports$1, module) {
441
441
  module.exports = {
442
442
  name: "mcp-jira-stdio",
443
- version: "1.7.0",
443
+ version: "1.7.1",
444
444
  description: "Model Context Protocol (MCP) server for Jira API integration",
445
445
  author: "graslt",
446
446
  license: "MIT",
@@ -564,7 +564,8 @@ var TOOL_NAMES = {
564
564
  CREATE_SUBTASK: "jira_create_subtask",
565
565
  GET_CREATE_META: "jira_get_create_meta",
566
566
  GET_CUSTOM_FIELDS: "jira_get_custom_fields",
567
- CREATE_ISSUE_LINK: "jira_create_issue_link"
567
+ CREATE_ISSUE_LINK: "jira_create_issue_link",
568
+ GET_COMMENTS: "jira_get_comments"
568
569
  };
569
570
 
570
571
  // src/utils/logger.ts
@@ -848,6 +849,12 @@ var CreateIssueLinkInputSchema = z.object({
848
849
  'Link type: "blocks", "is blocked by", "relates", "duplicates", "clones", or custom link type name'
849
850
  )
850
851
  });
852
+ var GetCommentsInputSchema = z.object({
853
+ issueKey: z.string().describe("Issue key to get comments for (e.g., PROJECT-123)").refine((v) => isValidIssueKey(v), "Invalid issue key format"),
854
+ maxResults: z.number().min(1).max(100).optional().describe("Maximum number of comments to return (default: 50)"),
855
+ orderBy: z.enum(["created", "-created", "+created"]).optional().describe('Sort order for comments: "created" (oldest first), "-created" (newest first)'),
856
+ startAt: z.number().min(0).optional().describe("Index of first comment to return (for pagination)")
857
+ });
851
858
  function ensureAdfDescription(desc, format = "markdown") {
852
859
  if (!desc) return desc;
853
860
  if (typeof desc === "object") return desc;
@@ -1198,6 +1205,24 @@ async function addComment(issueKey, body, visibility, format) {
1198
1205
  };
1199
1206
  return await makeJiraRequest(config);
1200
1207
  }
1208
+ async function getComments(issueKey, options = {}) {
1209
+ const params = {};
1210
+ if (options.maxResults !== void 0) {
1211
+ params.maxResults = options.maxResults;
1212
+ }
1213
+ if (options.orderBy !== void 0) {
1214
+ params.orderBy = options.orderBy;
1215
+ }
1216
+ if (options.startAt !== void 0) {
1217
+ params.startAt = options.startAt;
1218
+ }
1219
+ const config = {
1220
+ method: "GET",
1221
+ url: `/issue/${issueKey}/comment`,
1222
+ params
1223
+ };
1224
+ return await makeJiraRequest(config);
1225
+ }
1201
1226
  async function getProjectDetails(projectKey, expand) {
1202
1227
  const params = {};
1203
1228
  if (expand) {
@@ -1631,6 +1656,44 @@ ${comment.body}`
1631
1656
  ]
1632
1657
  };
1633
1658
  }
1659
+ function formatCommentsResponse(response, issueKey) {
1660
+ if (!response.comments || response.comments.length === 0) {
1661
+ return {
1662
+ content: [
1663
+ {
1664
+ type: "text",
1665
+ text: `No comments found for issue ${issueKey}.`
1666
+ }
1667
+ ]
1668
+ };
1669
+ }
1670
+ const commentsList = response.comments.map((comment) => {
1671
+ const bodyText = typeof comment.body === "string" ? comment.body : adfToPlainText(comment.body);
1672
+ const visibilityText = comment.visibility ? ` [${comment.visibility.type}: ${comment.visibility.value}]` : "";
1673
+ const authorName = comment.author?.displayName || "Unknown";
1674
+ const createdDate = comment.created ? new Date(comment.created).toISOString() : "N/A";
1675
+ const updatedDate = comment.updated ? new Date(comment.updated).toISOString() : "N/A";
1676
+ const wasEdited = comment.created !== comment.updated;
1677
+ return `**${authorName}** - ${createdDate}${wasEdited ? ` (edited: ${updatedDate})` : ""}${visibilityText}
1678
+ ${bodyText}`;
1679
+ }).join("\n\n---\n\n");
1680
+ const total = response.total;
1681
+ const showingStart = response.startAt + 1;
1682
+ const showingEnd = Math.min(response.startAt + response.comments.length, total);
1683
+ const paginationInfo = total > response.comments.length ? `
1684
+
1685
+ *Showing ${showingStart}-${showingEnd} of ${total} comments*` : "";
1686
+ return {
1687
+ content: [
1688
+ {
1689
+ type: "text",
1690
+ text: `**Comments for ${issueKey}** (${response.comments.length} comment${response.comments.length !== 1 ? "s" : ""}):
1691
+
1692
+ ${commentsList}${paginationInfo}`
1693
+ }
1694
+ ]
1695
+ };
1696
+ }
1634
1697
  function formatProjectDetailsResponse(project) {
1635
1698
  const leadText = project.lead ? `${project.lead.displayName} (${project.lead.accountId})` : "No lead assigned";
1636
1699
  const componentsText = project.components.length > 0 ? project.components.map((c) => c.name).join(", ") : "None";
@@ -2622,6 +2685,61 @@ async function handleCreateIssueLink(input) {
2622
2685
  }
2623
2686
  }
2624
2687
 
2688
+ // src/tools/get-comments.ts
2689
+ var log19 = createLogger("tool:get-comments");
2690
+ var getCommentsTool = {
2691
+ name: TOOL_NAMES.GET_COMMENTS,
2692
+ description: "Retrieves all comments for a Jira issue. Returns comment author, content, timestamps, and visibility settings. Supports pagination for issues with many comments.",
2693
+ inputSchema: {
2694
+ type: "object",
2695
+ properties: {
2696
+ issueKey: {
2697
+ type: "string",
2698
+ description: "Issue key to get comments for (e.g., PROJECT-123)"
2699
+ },
2700
+ maxResults: {
2701
+ type: "number",
2702
+ description: "Maximum number of comments to return (default: 50, max: 100)",
2703
+ minimum: 1,
2704
+ maximum: 100
2705
+ },
2706
+ orderBy: {
2707
+ type: "string",
2708
+ enum: ["created", "-created", "+created"],
2709
+ description: 'Sort order for comments: "created" or "+created" (oldest first), "-created" (newest first)'
2710
+ },
2711
+ startAt: {
2712
+ type: "number",
2713
+ description: "Index of first comment to return (for pagination, default: 0)",
2714
+ minimum: 0
2715
+ }
2716
+ },
2717
+ required: ["issueKey"]
2718
+ }
2719
+ };
2720
+ async function handleGetComments(input) {
2721
+ try {
2722
+ const validated = validateInput(GetCommentsInputSchema, input);
2723
+ log19.info(`Getting comments for issue ${validated.issueKey}...`);
2724
+ const options = {};
2725
+ if (validated.maxResults !== void 0) {
2726
+ options.maxResults = validated.maxResults;
2727
+ }
2728
+ if (validated.orderBy !== void 0) {
2729
+ options.orderBy = validated.orderBy;
2730
+ }
2731
+ if (validated.startAt !== void 0) {
2732
+ options.startAt = validated.startAt;
2733
+ }
2734
+ const comments = await getComments(validated.issueKey, options);
2735
+ log19.info(`Retrieved ${comments.comments.length} comment(s) for ${validated.issueKey}`);
2736
+ return formatCommentsResponse(comments, validated.issueKey);
2737
+ } catch (error) {
2738
+ log19.error("Error in handleGetComments:", error);
2739
+ return handleError(error);
2740
+ }
2741
+ }
2742
+
2625
2743
  // src/index.ts
2626
2744
  if (process.env.NODE_ENV !== "production") {
2627
2745
  try {
@@ -2630,7 +2748,7 @@ if (process.env.NODE_ENV !== "production") {
2630
2748
  } catch {
2631
2749
  }
2632
2750
  }
2633
- var log19 = createLogger("server");
2751
+ var log20 = createLogger("server");
2634
2752
  var toolHandlers = /* @__PURE__ */ new Map([
2635
2753
  [TOOL_NAMES.GET_VISIBLE_PROJECTS, handleGetVisibleProjects],
2636
2754
  [TOOL_NAMES.GET_ISSUE, handleGetIssue],
@@ -2647,7 +2765,8 @@ var toolHandlers = /* @__PURE__ */ new Map([
2647
2765
  [TOOL_NAMES.CREATE_SUBTASK, handleCreateSubtask],
2648
2766
  [TOOL_NAMES.GET_CREATE_META, handleGetCreateMeta],
2649
2767
  [TOOL_NAMES.GET_CUSTOM_FIELDS, handleGetCustomFields],
2650
- [TOOL_NAMES.CREATE_ISSUE_LINK, handleCreateIssueLink]
2768
+ [TOOL_NAMES.CREATE_ISSUE_LINK, handleCreateIssueLink],
2769
+ [TOOL_NAMES.GET_COMMENTS, handleGetComments]
2651
2770
  ]);
2652
2771
  var allTools = [
2653
2772
  getVisibleProjectsTool,
@@ -2665,7 +2784,8 @@ var allTools = [
2665
2784
  createSubtaskTool,
2666
2785
  getCreateMetaTool,
2667
2786
  getCustomFieldsTool,
2668
- createIssueLinkTool
2787
+ createIssueLinkTool,
2788
+ getCommentsTool
2669
2789
  ];
2670
2790
  async function main() {
2671
2791
  const isDryRun = (process.env.DRY_RUN || "").toLowerCase() === "1" || (process.env.DRY_RUN || "").toLowerCase() === "true";
@@ -2736,7 +2856,7 @@ async function main() {
2736
2856
  console.error("\u{1F680} Jira MCP server running on stdio");
2737
2857
  }
2738
2858
  main().catch((error) => {
2739
- log19.error("Fatal error:", error);
2859
+ log20.error("Fatal error:", error);
2740
2860
  process.exit(1);
2741
2861
  });
2742
2862
  //# sourceMappingURL=index.js.map