@rokealvo/jira-mcp 1.1.1 → 1.2.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/build/dev-server.d.ts +1 -0
- package/build/index.d.ts +8 -2
- package/build/index.js +41 -33
- package/build/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Server as
|
|
3
|
-
import { StdioServerTransport as
|
|
4
|
-
import { ListPromptsRequestSchema as
|
|
5
|
-
class
|
|
2
|
+
import { Server as f } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport as h } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { ListPromptsRequestSchema as g, GetPromptRequestSchema as I, McpError as c, ErrorCode as p, ListToolsRequestSchema as w, CallToolRequestSchema as _ } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
class y {
|
|
6
6
|
baseUrl;
|
|
7
7
|
headers;
|
|
8
8
|
constructor(t, e, s, i = "basic") {
|
|
@@ -474,7 +474,7 @@ class w {
|
|
|
474
474
|
};
|
|
475
475
|
}
|
|
476
476
|
}
|
|
477
|
-
class
|
|
477
|
+
class b extends y {
|
|
478
478
|
constructor(t, e, s, i = "basic") {
|
|
479
479
|
super(t, e, s, i);
|
|
480
480
|
}
|
|
@@ -602,12 +602,15 @@ class T extends w {
|
|
|
602
602
|
}));
|
|
603
603
|
}
|
|
604
604
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
605
|
+
function A() {
|
|
606
|
+
const l = process.env.JIRA_API_TOKEN ?? "", t = process.env.JIRA_BASE_URL ?? "", e = process.env.JIRA_USER_EMAIL ?? "", s = process.env.JIRA_TYPE === "server" ? "server" : "cloud", i = process.env.JIRA_AUTH_TYPE === "bearer" ? "bearer" : "basic";
|
|
607
|
+
if (!l || !t || !e)
|
|
608
|
+
throw new Error(
|
|
609
|
+
"JIRA_API_TOKEN, JIRA_USER_EMAIL and JIRA_BASE_URL environment variables are required"
|
|
610
|
+
);
|
|
611
|
+
return { JIRA_API_TOKEN: l, JIRA_BASE_URL: t, JIRA_USER_EMAIL: e, JIRA_TYPE: s, JIRA_AUTH_TYPE: i };
|
|
612
|
+
}
|
|
613
|
+
const m = {
|
|
611
614
|
jira_guidelines: {
|
|
612
615
|
description: "Общие правила и регламенты работы с Jira в компании",
|
|
613
616
|
content: `# Регламент работы с Jira
|
|
@@ -856,11 +859,11 @@ get_users(query) // поиск по имени или email
|
|
|
856
859
|
\`\`\``
|
|
857
860
|
}
|
|
858
861
|
};
|
|
859
|
-
class
|
|
862
|
+
class S {
|
|
860
863
|
server;
|
|
861
864
|
jiraApi;
|
|
862
865
|
constructor() {
|
|
863
|
-
this.server = new
|
|
866
|
+
this.server = new f(
|
|
864
867
|
{
|
|
865
868
|
name: "jira-mcp",
|
|
866
869
|
version: "0.3.0"
|
|
@@ -871,29 +874,31 @@ class j {
|
|
|
871
874
|
prompts: {}
|
|
872
875
|
}
|
|
873
876
|
}
|
|
874
|
-
)
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
877
|
+
);
|
|
878
|
+
const { JIRA_API_TOKEN: t, JIRA_BASE_URL: e, JIRA_USER_EMAIL: s, JIRA_TYPE: i, JIRA_AUTH_TYPE: a } = A();
|
|
879
|
+
i === "server" ? this.jiraApi = new b(
|
|
880
|
+
e,
|
|
881
|
+
s,
|
|
882
|
+
t,
|
|
883
|
+
a
|
|
884
|
+
) : this.jiraApi = new y(
|
|
885
|
+
e,
|
|
886
|
+
s,
|
|
887
|
+
t,
|
|
888
|
+
a
|
|
889
|
+
), this.setupToolHandlers(), this.server.onerror = (r) => {
|
|
885
890
|
}, process.on("SIGINT", async () => {
|
|
886
891
|
await this.server.close(), process.exit(0);
|
|
887
892
|
});
|
|
888
893
|
}
|
|
889
894
|
setupToolHandlers() {
|
|
890
|
-
this.server.setRequestHandler(
|
|
891
|
-
prompts: Object.entries(
|
|
895
|
+
this.server.setRequestHandler(g, async () => ({
|
|
896
|
+
prompts: Object.entries(m).map(([t, { description: e }]) => ({
|
|
892
897
|
name: t,
|
|
893
898
|
description: e
|
|
894
899
|
}))
|
|
895
|
-
})), this.server.setRequestHandler(
|
|
896
|
-
const { name: e } = t.params, s =
|
|
900
|
+
})), this.server.setRequestHandler(I, async (t) => {
|
|
901
|
+
const { name: e } = t.params, s = m[e];
|
|
897
902
|
if (!s)
|
|
898
903
|
throw new c(p.InvalidParams, `Unknown prompt: ${e}`);
|
|
899
904
|
return {
|
|
@@ -907,7 +912,7 @@ class j {
|
|
|
907
912
|
}
|
|
908
913
|
]
|
|
909
914
|
};
|
|
910
|
-
}), this.server.setRequestHandler(
|
|
915
|
+
}), this.server.setRequestHandler(w, async () => ({
|
|
911
916
|
tools: [
|
|
912
917
|
{
|
|
913
918
|
name: "search_issues",
|
|
@@ -1218,7 +1223,7 @@ Remember to add a comment with cancellation reason first.`,
|
|
|
1218
1223
|
}
|
|
1219
1224
|
}
|
|
1220
1225
|
]
|
|
1221
|
-
})), this.server.setRequestHandler(
|
|
1226
|
+
})), this.server.setRequestHandler(_, async (t) => {
|
|
1222
1227
|
try {
|
|
1223
1228
|
const e = t.params.arguments;
|
|
1224
1229
|
switch (t.params.name) {
|
|
@@ -1511,11 +1516,14 @@ Remember to add a comment with cancellation reason first.`,
|
|
|
1511
1516
|
});
|
|
1512
1517
|
}
|
|
1513
1518
|
async run() {
|
|
1514
|
-
const t = new
|
|
1519
|
+
const t = new h();
|
|
1515
1520
|
await this.server.connect(t);
|
|
1516
1521
|
}
|
|
1517
1522
|
}
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1523
|
+
const J = process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("jira-mcp");
|
|
1524
|
+
J && new S().run().catch(() => {
|
|
1520
1525
|
});
|
|
1526
|
+
export {
|
|
1527
|
+
S as JiraServer
|
|
1528
|
+
};
|
|
1521
1529
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/services/jira-api.ts","../src/services/jira-server-api.ts","../src/index.ts"],"sourcesContent":["import {\n AddCommentResponse,\n AdfDoc,\n CleanAttachment,\n CleanComment,\n CleanJiraIssue,\n JiraCommentResponse,\n SearchIssuesResponse,\n} from \"../types/jira.js\";\n\nexport class JiraApiService {\n protected baseUrl: string;\n protected headers: Headers;\n\n constructor(baseUrl: string, email: string, apiToken: string, authType: 'basic' | 'bearer' = 'basic') {\n this.baseUrl = baseUrl;\n \n let authHeader: string;\n if (authType === 'bearer') {\n // For Jira Data Center Personal Access Tokens (PATs)\n authHeader = `Bearer ${apiToken}`;\n } else {\n // For Basic authentication with username/password or API token\n const auth = Buffer.from(`${email}:${apiToken}`).toString(\"base64\");\n authHeader = `Basic ${auth}`;\n }\n \n this.headers = new Headers({\n Authorization: authHeader,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n });\n }\n\n protected async handleFetchError(\n response: Response,\n url?: string\n ): Promise<never> {\n if (!response.ok) {\n let message = response.statusText;\n let errorData: any = {};\n try {\n errorData = await response.json();\n\n // Try different error formats that Jira uses\n if (\n Array.isArray(errorData.errorMessages) &&\n errorData.errorMessages.length > 0\n ) {\n // Format: { errorMessages: [\"msg1\", \"msg2\"] }\n message = errorData.errorMessages.join(\"; \");\n } else if (errorData.message) {\n // Format: { message: \"error message\" }\n message = errorData.message;\n } else if (errorData.errorMessage) {\n // Format: { errorMessage: \"error message\" }\n message = errorData.errorMessage;\n } else if (errorData.errors && typeof errorData.errors === \"object\") {\n // Format: { errors: { fieldName: \"error for field\", anotherField: \"another error\" } }\n const errorMessages = Object.entries(errorData.errors)\n .map(([field, msg]) => `${field}: ${msg}`)\n .join(\"; \");\n if (errorMessages) {\n message = errorMessages;\n }\n }\n\n // If we still only have statusText but have error data, stringify it\n if (message === response.statusText && Object.keys(errorData).length > 0) {\n message = JSON.stringify(errorData);\n }\n } catch (e) {\n // Could not parse as JSON, try to get text\n try {\n const text = await response.text();\n if (text) {\n message = text.substring(0, 500); // Limit length\n }\n } catch {\n // Ignore\n }\n }\n\n throw new Error(\n `JIRA API Error: ${message} (Status: ${response.status})`\n );\n }\n\n throw new Error(\"Unknown error occurred during fetch operation.\");\n }\n\n /**\n * Extracts issue mentions from Atlassian document content\n * Looks for nodes that were auto-converted to issue links\n */\n protected extractIssueMentions(\n content: any[],\n source: \"description\" | \"comment\",\n commentId?: string\n ): CleanJiraIssue[\"relatedIssues\"] {\n const mentions: NonNullable<CleanJiraIssue[\"relatedIssues\"]> = [];\n\n const processNode = (node: any) => {\n if (node.type === \"inlineCard\" && node.attrs?.url) {\n const match = node.attrs.url.match(/\\/browse\\/([A-Z]+-\\d+)/);\n if (match) {\n mentions.push({\n key: match[1],\n type: \"mention\",\n source,\n commentId,\n });\n }\n }\n\n if (node.type === \"text\" && node.text) {\n const matches = node.text.match(/[A-Z]+-\\d+/g) || [];\n matches.forEach((key: string) => {\n mentions.push({\n key,\n type: \"mention\",\n source,\n commentId,\n });\n });\n }\n\n if (node.content) {\n node.content.forEach(processNode);\n }\n };\n\n content.forEach(processNode);\n return [...new Map(mentions.map((m) => [m.key, m])).values()];\n }\n\n protected cleanComment(comment: {\n id: string;\n body?: {\n content?: any[];\n };\n author?: {\n displayName?: string;\n };\n created: string;\n updated: string;\n }): CleanComment {\n const body = comment.body?.content\n ? this.extractTextContent(comment.body.content)\n : \"\";\n const mentions = comment.body?.content\n ? this.extractIssueMentions(comment.body.content, \"comment\", comment.id)\n : [];\n\n return {\n id: comment.id,\n body,\n author: comment.author?.displayName,\n created: comment.created,\n updated: comment.updated,\n mentions: mentions,\n };\n }\n\n protected cleanAttachment(attachment: any): CleanAttachment {\n return {\n id: attachment.id,\n filename: attachment.filename,\n mimeType: attachment.mimeType,\n size: attachment.size,\n created: attachment.created,\n author: attachment.author?.displayName,\n content: attachment.content,\n thumbnail: attachment.thumbnail,\n };\n }\n\n /**\n * Recursively extracts text content from Atlassian Document Format nodes\n */\n protected extractTextContent(content: any[]): string {\n if (!Array.isArray(content)) return \"\";\n\n return content\n .map((node) => {\n if (node.type === \"text\") {\n return node.text || \"\";\n }\n if (node.content) {\n return this.extractTextContent(node.content);\n }\n return \"\";\n })\n .join(\"\");\n }\n\n protected cleanIssue(issue: any): CleanJiraIssue {\n let description = \"\";\n if (issue.fields?.description) {\n if (typeof issue.fields.description === \"string\") {\n // Jira Server: plain text\n description = issue.fields.description;\n } else if (issue.fields.description.content) {\n // Jira Cloud: ADF format\n description = this.extractTextContent(issue.fields.description.content);\n }\n }\n\n const cleanedIssue: CleanJiraIssue = {\n id: issue.id,\n key: issue.key,\n summary: issue.fields?.summary,\n status: issue.fields?.status?.name,\n created: issue.fields?.created,\n updated: issue.fields?.updated,\n description,\n relatedIssues: [],\n };\n\n if (issue.fields?.description?.content) {\n const mentions = this.extractIssueMentions(\n issue.fields.description.content,\n \"description\"\n );\n if (mentions.length > 0) {\n cleanedIssue.relatedIssues = mentions;\n }\n }\n\n if (issue.fields?.issuelinks?.length > 0) {\n const links = issue.fields.issuelinks.map((link: any) => {\n const linkedIssue = link.inwardIssue || link.outwardIssue;\n const relationship = link.type.inward || link.type.outward;\n return {\n key: linkedIssue.key,\n summary: linkedIssue.fields?.summary,\n type: \"link\" as const,\n relationship,\n source: \"description\" as const,\n };\n });\n\n cleanedIssue.relatedIssues = [\n ...(cleanedIssue.relatedIssues || []),\n ...links,\n ];\n }\n\n if (issue.fields?.parent) {\n cleanedIssue.parent = {\n id: issue.fields.parent.id,\n key: issue.fields.parent.key,\n summary: issue.fields.parent.fields?.summary,\n };\n }\n\n if (issue.fields?.customfield_10014) {\n cleanedIssue.epicLink = {\n id: issue.fields.customfield_10014,\n key: issue.fields.customfield_10014,\n summary: undefined,\n };\n }\n\n if (issue.fields?.subtasks?.length > 0) {\n cleanedIssue.children = issue.fields.subtasks.map((subtask: any) => ({\n id: subtask.id,\n key: subtask.key,\n summary: subtask.fields?.summary,\n }));\n }\n\n if (issue.fields?.attachment?.length > 0) {\n cleanedIssue.attachments = issue.fields.attachment.map((a: any) =>\n this.cleanAttachment(a)\n );\n }\n\n return cleanedIssue;\n }\n\n protected async fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const response = await fetch(this.baseUrl + url, {\n ...init,\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response, url);\n }\n\n return response.json();\n }\n\n async searchIssues(searchString: string): Promise<SearchIssuesResponse> {\n const params = new URLSearchParams({\n jql: searchString,\n maxResults: \"50\",\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n const data = await this.fetchJson<any>(`/rest/api/3/search?${params}`);\n\n return {\n total: data.total,\n issues: data.issues.map((issue: any) => this.cleanIssue(issue)),\n };\n }\n\n async getEpicChildren(epicKey: string): Promise<CleanJiraIssue[]> {\n const params = new URLSearchParams({\n jql: `\"Epic Link\" = ${epicKey}`,\n maxResults: \"100\",\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n const data = await this.fetchJson<any>(`/rest/api/3/search?${params}`);\n\n const issuesWithComments = await Promise.all(\n data.issues.map(async (issue: any) => {\n const commentsData = await this.fetchJson<any>(\n `/rest/api/3/issue/${issue.key}/comment`\n );\n const cleanedIssue = this.cleanIssue(issue);\n const comments = commentsData.comments.map((comment: any) =>\n this.cleanComment(comment)\n );\n\n const commentMentions = comments.flatMap(\n (comment: CleanComment) => comment.mentions\n );\n cleanedIssue.relatedIssues = [\n ...cleanedIssue.relatedIssues,\n ...commentMentions,\n ];\n\n cleanedIssue.comments = comments;\n return cleanedIssue;\n })\n );\n\n return issuesWithComments;\n }\n\n async getIssueWithComments(issueId: string): Promise<CleanJiraIssue> {\n const params = new URLSearchParams({\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n \"attachment\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n let issueData, commentsData;\n try {\n [issueData, commentsData] = await Promise.all([\n this.fetchJson<any>(`/rest/api/3/issue/${issueId}?${params}`),\n this.fetchJson<any>(`/rest/api/3/issue/${issueId}/comment`),\n ]);\n } catch (error: any) {\n if (error instanceof Error && error.message.includes(\"(Status: 404)\")) {\n throw new Error(`Issue not found: ${issueId}`);\n }\n\n throw error;\n }\n\n const issue = this.cleanIssue(issueData);\n const comments = commentsData.comments.map((comment: any) =>\n this.cleanComment(comment)\n );\n\n const commentMentions = comments.flatMap(\n (comment: CleanComment) => comment.mentions\n );\n issue.relatedIssues = [...issue.relatedIssues, ...commentMentions];\n\n issue.comments = comments;\n\n if (issue.epicLink) {\n try {\n const epicData = await this.fetchJson<any>(\n `/rest/api/3/issue/${issue.epicLink.key}?fields=summary`\n );\n issue.epicLink.summary = epicData.fields?.summary;\n } catch (error) {\n console.error(\"Failed to fetch epic details:\", error);\n }\n }\n\n return issue;\n }\n\n async createIssue(\n projectKey: string,\n issueType: string,\n summary: string,\n description?: string,\n fields?: Record<string, any>\n ): Promise<{ id: string; key: string }> {\n const payload = {\n fields: {\n project: {\n key: projectKey,\n },\n summary,\n issuetype: {\n name: issueType,\n },\n ...(description && { description }),\n ...fields,\n },\n };\n\n return this.fetchJson<{ id: string; key: string }>(\"/rest/api/3/issue\", {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n }\n\n async getCreateMeta(\n projectKey: string,\n issueTypeName?: string,\n compact?: boolean\n ): Promise<any> {\n // Get available issue types for the project\n const issueTypesData = await this.fetchJson<{ issueTypes: Array<{ id: string; name: string; description?: string; subtask: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes`\n );\n\n let issueTypes = issueTypesData.issueTypes || [];\n\n // Filter by issue type name if provided\n if (issueTypeName) {\n issueTypes = issueTypes.filter(\n (it) => it.name.toLowerCase() === issueTypeName.toLowerCase()\n );\n }\n\n // Get fields for each issue type\n const result = {\n projectKey,\n issueTypes: await Promise.all(\n issueTypes.map(async (issueType) => {\n try {\n const fieldsData = await this.fetchJson<{ fields: Array<{ fieldId: string; name: string; required: boolean; schema?: any; allowedValues?: any[]; hasDefaultValue?: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueType.id}`\n );\n\n let fields = fieldsData.fields || [];\n\n // In compact mode, replace allowedValues with count\n if (compact) {\n fields = fields.map((f) => ({\n fieldId: f.fieldId,\n name: f.name,\n required: f.required,\n schema: f.schema,\n hasDefaultValue: f.hasDefaultValue,\n allowedValuesCount: f.allowedValues?.length ?? 0,\n }));\n }\n\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields,\n };\n } catch (error) {\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields: [],\n error: error instanceof Error ? error.message : \"Failed to fetch fields\",\n };\n }\n })\n ),\n };\n\n return result;\n }\n\n async getFieldOptions(\n projectKey: string,\n issueTypeId: string,\n fieldId: string\n ): Promise<any[]> {\n const fieldsData = await this.fetchJson<{ fields: Array<{ fieldId: string; allowedValues?: any[] }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueTypeId}`\n );\n\n const field = (fieldsData.fields || []).find((f) => f.fieldId === fieldId);\n return field?.allowedValues ?? [];\n }\n\n async updateIssue(\n issueKey: string,\n fields: Record<string, any>\n ): Promise<void> {\n await this.fetchJson(`/rest/api/3/issue/${issueKey}`, {\n method: \"PUT\",\n body: JSON.stringify({ fields }),\n });\n }\n\n async getTransitions(\n issueKey: string\n ): Promise<Array<{ id: string; name: string; to: { name: string } }>> {\n const data = await this.fetchJson<any>(\n `/rest/api/3/issue/${issueKey}/transitions`\n );\n return data.transitions;\n }\n\n async transitionIssue(\n issueKey: string,\n transitionId: string,\n comment?: string\n ): Promise<void> {\n const payload: any = {\n transition: { id: transitionId },\n };\n\n if (comment) {\n payload.update = {\n comment: [\n {\n add: {\n body: {\n type: \"doc\",\n version: 1,\n content: [\n {\n type: \"paragraph\",\n content: [\n {\n type: \"text\",\n text: comment,\n },\n ],\n },\n ],\n },\n },\n },\n ],\n };\n }\n\n await this.fetchJson(`/rest/api/3/issue/${issueKey}/transitions`, {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n }\n\n async addAttachment(\n issueKey: string,\n file: Buffer,\n filename: string\n ): Promise<{ id: string; filename: string }> {\n const formData = new FormData();\n formData.append(\"file\", new Blob([new Uint8Array(file)]), filename);\n\n const headers = new Headers(this.headers);\n headers.delete(\"Content-Type\");\n headers.set(\"X-Atlassian-Token\", \"no-check\");\n\n const response = await fetch(\n `${this.baseUrl}/rest/api/3/issue/${issueKey}/attachments`,\n {\n method: \"POST\",\n headers,\n body: formData,\n }\n );\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n\n const data = await response.json();\n\n const attachment = data[0];\n return {\n id: attachment.id,\n filename: attachment.filename,\n };\n }\n\n /**\n * Converts plain text to a basic Atlassian Document Format (ADF) structure.\n */\n private createAdfFromBody(text: string): AdfDoc {\n return {\n version: 1,\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n content: [\n {\n type: \"text\",\n text: text,\n },\n ],\n },\n ],\n };\n }\n\n /**\n * Adds a comment to a JIRA issue.\n */\n async addCommentToIssue(\n issueIdOrKey: string,\n body: string\n ): Promise<AddCommentResponse> {\n const adfBody = this.createAdfFromBody(body);\n\n const payload = {\n body: adfBody,\n };\n\n const response = await this.fetchJson<JiraCommentResponse>(\n `/rest/api/3/issue/${issueIdOrKey}/comment`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n }\n );\n\n return {\n id: response.id,\n author: response.author.displayName,\n created: response.created,\n updated: response.updated,\n body: this.extractTextContent(response.body.content),\n };\n }\n\n async getServerInfo(): Promise<{\n version: string;\n versionNumbers: number[];\n deploymentType: string;\n buildNumber: number;\n serverTitle: string;\n }> {\n return this.fetchJson(`/rest/api/3/serverInfo`);\n }\n\n async getProjects(): Promise<Array<{\n id: string;\n key: string;\n name: string;\n projectTypeKey: string;\n lead?: { displayName: string; accountId?: string };\n }>> {\n const data = await this.fetchJson<any[]>(`/rest/api/3/project`);\n return data.map((project) => ({\n id: project.id,\n key: project.key,\n name: project.name,\n projectTypeKey: project.projectTypeKey,\n lead: project.lead ? {\n displayName: project.lead.displayName,\n accountId: project.lead.accountId,\n } : undefined,\n }));\n }\n\n async getUsers(query: string, maxResults: number = 50): Promise<Array<{\n accountId: string;\n displayName: string;\n emailAddress?: string;\n active: boolean;\n }>> {\n const params = new URLSearchParams({\n query,\n maxResults: maxResults.toString(),\n });\n const data = await this.fetchJson<any[]>(`/rest/api/3/user/search?${params}`);\n return data.map((user) => ({\n accountId: user.accountId,\n displayName: user.displayName,\n emailAddress: user.emailAddress,\n active: user.active,\n }));\n }\n\n async deleteIssue(issueKey: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/rest/api/3/issue/${issueKey}`, {\n method: \"DELETE\",\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n }\n\n async getAttachment(attachmentId: string): Promise<{\n content: string; // base64 encoded\n filename: string;\n mimeType: string;\n }> {\n // First, get attachment metadata to get the content URL\n const metadata = await this.fetchJson<{\n id: string;\n filename: string;\n mimeType: string;\n content: string;\n }>(`/rest/api/3/attachment/${attachmentId}`);\n\n // Fetch the actual content from the content URL\n const response = await fetch(metadata.content, {\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const base64 = Buffer.from(arrayBuffer).toString(\"base64\");\n\n return {\n content: base64,\n filename: metadata.filename,\n mimeType: metadata.mimeType,\n };\n }\n}\n","// JiraServerApiService: Jira Server (Data Center) implementation\n// This class should override methods as needed for Jira Server differences\nimport { JiraApiService } from \"./jira-api.js\";\nimport type { CleanComment, CleanJiraIssue } from \"../types/jira.js\";\n\nexport class JiraServerApiService extends JiraApiService {\n constructor(baseUrl: string, email: string, apiToken: string, authType: 'basic' | 'bearer' = 'basic') {\n // For Jira Server/Data Center:\n // - Basic Auth: username/password or API token (traditional method)\n // - Bearer Auth: Personal Access Tokens (PATs) available in Data Center 8.14.0+\n super(baseUrl, email, apiToken, authType);\n }\n\n // Example: Override fetchJson to use /rest/api/2/ instead of /rest/api/3/\n protected overrideApiPath(path: string): string {\n // Replace /rest/api/3/ with /rest/api/2/ for Jira Server\n return path.replace(\"/rest/api/3/\", \"/rest/api/2/\");\n }\n\n // Override fetchJson to use the correct API path\n protected async fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const serverUrl = this.overrideApiPath(url);\n return super.fetchJson<T>(serverUrl, init);\n }\n\n // Override getCreateMeta to use API v2 endpoints for Jira Server 9.0+\n async getCreateMeta(\n projectKey: string,\n issueTypeName?: string,\n compact?: boolean\n ): Promise<any> {\n // For Jira Server 9.0+, use the new paginated endpoints (same structure as Cloud but API v2)\n const issueTypesData = await this.fetchJson<{ values: Array<{ id: string; name: string; description?: string; subtask: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes`\n );\n\n let issueTypes = issueTypesData.values || [];\n\n // Filter by issue type name if provided\n if (issueTypeName) {\n issueTypes = issueTypes.filter(\n (it) => it.name.toLowerCase() === issueTypeName.toLowerCase()\n );\n }\n\n // Get fields for each issue type\n const result = {\n projectKey,\n issueTypes: await Promise.all(\n issueTypes.map(async (issueType) => {\n try {\n const fieldsData = await this.fetchJson<{ values: Array<{ fieldId: string; name: string; required: boolean; schema?: any; allowedValues?: any[]; hasDefaultValue?: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueType.id}`\n );\n\n let fields = fieldsData.values || [];\n\n // In compact mode, replace allowedValues with count\n if (compact) {\n fields = fields.map((f) => ({\n fieldId: f.fieldId,\n name: f.name,\n required: f.required,\n schema: f.schema,\n hasDefaultValue: f.hasDefaultValue,\n allowedValuesCount: f.allowedValues?.length ?? 0,\n }));\n }\n\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields,\n };\n } catch (error) {\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields: [],\n error: error instanceof Error ? error.message : \"Failed to fetch fields\",\n };\n }\n })\n ),\n };\n\n return result;\n }\n\n // Override getFieldOptions for Jira Server (uses 'values' instead of 'fields')\n async getFieldOptions(\n projectKey: string,\n issueTypeId: string,\n fieldId: string\n ): Promise<any[]> {\n const fieldsData = await this.fetchJson<{ values: Array<{ fieldId: string; allowedValues?: any[] }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueTypeId}`\n );\n\n const field = (fieldsData.values || []).find((f) => f.fieldId === fieldId);\n return field?.allowedValues ?? [];\n }\n\n // Override getUsers for Jira Server (uses 'username' parameter instead of 'query')\n async getUsers(query: string, maxResults: number = 50): Promise<Array<{\n accountId: string;\n displayName: string;\n emailAddress?: string;\n active: boolean;\n }>> {\n const params = new URLSearchParams({\n username: query,\n maxResults: maxResults.toString(),\n });\n const data = await this.fetchJson<any[]>(`/rest/api/3/user/search?${params}`);\n return data.map((user) => ({\n // Jira Server uses 'name' or 'key' instead of 'accountId'\n accountId: user.key || user.name,\n displayName: user.displayName,\n emailAddress: user.emailAddress,\n active: user.active,\n }));\n }\n\n // Override addCommentToIssue for Jira Server (uses plain text instead of ADF)\n async addCommentToIssue(\n issueIdOrKey: string,\n body: string\n ): Promise<{\n id: string;\n author: string;\n created: string;\n updated: string;\n body: string;\n }> {\n // Jira Server API v2 expects plain text body, not ADF\n const payload = {\n body: body,\n };\n\n const response = await this.fetchJson<{\n id: string;\n author: { displayName: string };\n created: string;\n updated: string;\n body: string;\n }>(\n `/rest/api/3/issue/${issueIdOrKey}/comment`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n }\n );\n\n return {\n id: response.id,\n author: response.author.displayName,\n created: response.created,\n updated: response.updated,\n body: response.body,\n };\n }\n\n // Override deleteIssue for Jira Server (uses API v2)\n async deleteIssue(issueKey: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/rest/api/2/issue/${issueKey}`, {\n method: \"DELETE\",\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n }\n\n // Override cleanComment for Jira Server (body is plain text, not ADF)\n protected cleanComment(comment: {\n id: string;\n body?: string | { content?: any[] };\n author?: {\n displayName?: string;\n };\n created: string;\n updated: string;\n }): CleanComment {\n // Debug: log raw comment to understand API response format\n console.error(\"[DEBUG cleanComment] Raw comment:\", JSON.stringify(comment, null, 2));\n\n // Jira Server API v2 returns body as plain text string\n // Jira Cloud API v3 returns body as ADF object with content array\n let body: string;\n let mentions: CleanJiraIssue[\"relatedIssues\"] = [];\n\n if (typeof comment.body === \"string\") {\n // Jira Server: body is plain text\n body = comment.body;\n // Extract issue mentions from plain text (e.g., PROJECT-123)\n mentions = this.extractIssueMentionsFromText(body, \"comment\", comment.id);\n } else if (comment.body?.content) {\n // Jira Cloud: body is ADF object\n body = this.extractTextContent(comment.body.content);\n mentions = this.extractIssueMentions(comment.body.content, \"comment\", comment.id);\n } else {\n body = \"\";\n }\n\n return {\n id: comment.id,\n body,\n author: comment.author?.displayName,\n created: comment.created,\n updated: comment.updated,\n mentions,\n };\n }\n\n // Extract issue mentions from plain text (for Jira Server)\n protected extractIssueMentionsFromText(\n text: string,\n source: \"description\" | \"comment\",\n commentId?: string\n ): CleanJiraIssue[\"relatedIssues\"] {\n if (!text) return [];\n\n const matches = text.match(/[A-Z]+-\\d+/g) || [];\n const uniqueKeys = [...new Set(matches)];\n\n return uniqueKeys.map((key) => ({\n key,\n type: \"mention\" as const,\n source,\n commentId,\n }));\n }\n}\n","#!/usr/bin/env node\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ErrorCode,\n ListToolsRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n McpError,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { JiraApiService } from \"./services/jira-api.js\";\nimport { JiraServerApiService } from \"./services/jira-server-api.js\";\n\nconst JIRA_API_TOKEN = process.env.JIRA_API_TOKEN ?? \"\";\nconst JIRA_BASE_URL = process.env.JIRA_BASE_URL ?? \"\";\nconst JIRA_USER_EMAIL = process.env.JIRA_USER_EMAIL ?? \"\";\nconst JIRA_TYPE = (process.env.JIRA_TYPE === \"server\" ? \"server\" : \"cloud\") as\n | \"cloud\"\n | \"server\";\nconst JIRA_AUTH_TYPE = (process.env.JIRA_AUTH_TYPE === \"bearer\" ? \"bearer\" : \"basic\") as\n | \"basic\"\n | \"bearer\";\n\nif (!JIRA_API_TOKEN || !JIRA_BASE_URL || !JIRA_USER_EMAIL) {\n throw new Error(\n \"JIRA_API_TOKEN, JIRA_USER_EMAIL and JIRA_BASE_URL environment variables are required\",\n );\n}\n\n// ============================================================================\n// PROMPTS - Инструкции и регламенты для агентов\n// ============================================================================\n\nconst JIRA_PROMPTS: Record<string, { description: string; content: string }> = {\n jira_guidelines: {\n description: \"Общие правила и регламенты работы с Jira в компании\",\n content: `# Регламент работы с Jira\n\n## Общие принципы\n- Все изменения статусов должны отражать реальное состояние работы\n- Комментарии пишутся на русском языке\n- При любых изменениях, затрагивающих других участников, оставляй комментарий\n\n## Статусы и переходы\n\n### Workflow задачи:\n1. **Бэклог** — задача запланирована, но работа не начата\n2. **Очередь** — задача в очереди на выполнение\n3. **В работе** — код в процессе написания\n4. **Ревью** — код готов к проверке, создан PR/MR\n5. **Local test** — задача на локальном тестировании\n6. **Dev** — код в ветке dev\n7. **Stage (не проверено)** — код в ветке stage, тестирование не проведено\n8. **Релиз-кандидат** — проверено на stage, готово к релизу\n9. **Тест на проде** — код на проде, ожидает проверки\n10. **Готово на проде** — задача завершена и проверена\n\n### Особые статусы:\n- **Заблокирована** — работа приостановлена (указать причину в комментарии)\n- **Отложено** — задача отложена на неопределённый срок\n- **Отмена** — задача отменена (ОБЯЗАТЕЛЬНО с комментарием о причине!)\n\n## Создание задач\n- Summary должен быть кратким и информативным (не более 100 символов)\n- Description должен содержать достаточно информации для понимания задачи\n- Обязательно указывай компонент (component) для правильной маршрутизации\n- Для багов: шаги воспроизведения, ожидаемый и фактический результат\n\n## Отмена задач\n- ЗАПРЕЩЕНО отменять задачу без указания причины в комментарии\n- Причина должна быть информативной: \"дубликат IM3-1234\", \"неактуально после релиза X\", и т.д.\n\n## Удаление задач\n- Удаление задач запрещено политикой безопасности\n- Вместо удаления используй статус \"Отмена\" с комментарием\n\n## Комментарии\n- Используй комментарии для важной информации, которая должна остаться в истории\n- При блокировке — указывай причину и ссылку на блокирующую задачу\n- При передаче задачи — описывай текущее состояние и что осталось сделать`,\n },\n\n create_issue_workflow: {\n description: \"Пошаговый процесс создания задачи в Jira\",\n content: `# Создание задачи в Jira\n\n## Перед созданием ОБЯЗАТЕЛЬНО уточни у пользователя:\n\n### Основная информация:\n1. **Проект** — в каком проекте создать (IM3, SD, FT, ETPP и т.д.)\n2. **Тип задачи** — Баг, Story, Task, Sub-task\n3. **Краткое описание** (summary) — что нужно сделать, до 100 символов\n4. **Подробное описание** (description) — детали задачи\n\n### Для багов дополнительно запроси:\n- Шаги воспроизведения (пронумерованный список)\n- Ожидаемый результат\n- Фактический результат\n- Окружение (браузер, ОС, URL) — если релевантно\n- Скриншоты или логи — если есть\n\n### Для Story/Task уточни:\n- Критерии приёмки (acceptance criteria)\n- Связанные задачи (если есть)\n\n## Порядок действий:\n\n1. **Получи схему полей:**\n \\`\\`\\`\n get_create_meta(projectKey, issueTypeName, compact=true)\n \\`\\`\\`\n\n2. **Для обязательных полей с вариантами получи опции:**\n \\`\\`\\`\n get_field_options(projectKey, issueTypeId, fieldId)\n \\`\\`\\`\n\n3. **Покажи пользователю** итоговые данные перед созданием\n\n4. **Создай задачу:**\n \\`\\`\\`\n create_issue(projectKey, issueType, summary, description, fields)\n \\`\\`\\`\n\n5. **Верни пользователю** ключ и ссылку на созданную задачу\n\n## Пример описания бага:\n\n\\`\\`\\`\nШаги воспроизведения:\n1. Открыть страницу /checkout\n2. Добавить товар в корзину\n3. Нажать \"Оформить заказ\"\n\nОжидаемый результат:\nОткрывается форма оформления заказа\n\nФактический результат:\nСтраница показывает ошибку 500\n\nОкружение:\n- URL: https://example.com/checkout\n- Браузер: Chrome 120\n- ОС: Windows 11\n\\`\\`\\``,\n },\n\n cancel_issue_workflow: {\n description: \"Процесс отмены задачи (требует указания причины)\",\n content: `# Отмена задачи в Jira\n\n## ⚠️ ВАЖНО: Задачу НЕЛЬЗЯ отменять без причины!\n\n## Порядок действий:\n\n### 1. Спроси причину отмены\nПрежде чем отменять задачу, ОБЯЗАТЕЛЬНО спроси у пользователя:\n- \"Почему задача отменяется?\"\n- \"Укажите причину отмены для комментария\"\n\n### 2. Примеры корректных причин:\n- \"Дубликат задачи IM3-1234\"\n- \"Неактуально после релиза версии 2.5\"\n- \"Функционал реализован в рамках IM3-5678\"\n- \"Отменено по решению Product Owner (имя)\"\n- \"Требования изменились, создана новая задача IM3-9999\"\n\n### 3. Добавь комментарий с причиной:\n\\`\\`\\`\nadd_comment(issueKey, \"Причина отмены: <причина от пользователя>\")\n\\`\\`\\`\n\n### 4. Получи ID перехода \"Отмена\":\n\\`\\`\\`\nget_transitions(issueKey)\n// Найди переход с name=\"Отмена\"\n\\`\\`\\`\n\n### 5. Выполни переход:\n\\`\\`\\`\ntransition_issue(issueKey, transitionId)\n\\`\\`\\`\n\n## Запрещено:\n- ❌ Отменять задачу без комментария с причиной\n- ❌ Использовать причины типа \"не нужно\", \"отмена\" без пояснения\n\n## Если пользователь не хочет указывать причину:\nОбъясни, что это требование регламента компании, и причина важна для:\n- Истории проекта\n- Понимания, почему задача не была выполнена\n- Аудита и отчётности`,\n },\n\n transition_issue_workflow: {\n description: \"Правила смены статусов задач\",\n content: `# Смена статуса задачи в Jira\n\n## Общие правила:\n- Статус должен отражать реальное состояние работы\n- Не пропускай промежуточные статусы без веской причины\n- При переходе в финальные статусы убедись, что работа действительно завершена\n\n## Особые случаи:\n\n### Переход в \"Отмена\":\n⚠️ ОБЯЗАТЕЛЬНО сначала добавь комментарий с причиной отмены!\nСм. prompt \"cancel_issue_workflow\" для подробностей.\n\n### Переход в \"Заблокирована\":\n- Укажи в комментарии причину блокировки\n- Добавь ссылку на блокирующую задачу (если есть)\n- Пример: \"Заблокировано: ждём завершения IM3-1234 (интеграция с API)\"\n\n### Переход в \"Ревью\":\n- Должен существовать Pull Request / Merge Request\n- Желательно добавить ссылку на PR в комментарий\n\n### Переход в \"Dev\" / \"Stage\":\n- Код должен быть смержен в соответствующую ветку\n- Задача задеплоена на окружение\n\n### Переход в \"Тест на проде\":\n- Код задеплоен на production\n- Задача готова к финальной проверке\n\n### Переход в \"Готово на проде\":\n- Задача проверена на production\n- Все acceptance criteria выполнены\n- Нет открытых sub-tasks\n\n## Получение доступных переходов:\n\\`\\`\\`\nget_transitions(issueKey)\n// Вернёт список доступных переходов с их ID\n\\`\\`\\`\n\n## Выполнение перехода:\n\\`\\`\\`\ntransition_issue(issueKey, transitionId, comment?)\n// comment — опциональный комментарий к переходу\n\\`\\`\\``,\n },\n\n update_issue_workflow: {\n description: \"Правила обновления задач\",\n content: `# Обновление задачи в Jira\n\n## Что можно обновлять:\n- summary — краткое описание\n- description — подробное описание\n- assignee — исполнитель\n- priority — приоритет\n- labels — метки\n- components — компоненты\n- customfield_* — кастомные поля\n\n## Правила:\n\n### При изменении исполнителя (assignee):\n- Если задача в работе — согласуй с текущим исполнителем\n- Добавь комментарий о причине переназначения\n\n### При изменении приоритета:\n- Повышение приоритета — укажи причину в комментарии\n- Понижение приоритета — согласуй с автором задачи\n\n### При изменении описания:\n- Не удаляй важную информацию\n- Если меняешь суть задачи — лучше создай новую\n\n## Пример обновления:\n\\`\\`\\`\nupdate_issue(issueKey, {\n summary: \"Новый заголовок\",\n priority: { name: \"High\" },\n assignee: { name: \"username\" }\n})\n\\`\\`\\`\n\n## Для поиска пользователей:\n\\`\\`\\`\nget_users(query) // поиск по имени или email\n\\`\\`\\``,\n },\n};\n\nclass JiraServer {\n private server: Server;\n private jiraApi: JiraApiService;\n\n constructor() {\n this.server = new Server(\n {\n name: \"jira-mcp\",\n version: \"0.3.0\",\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n },\n },\n );\n\n if (JIRA_TYPE === \"server\") {\n this.jiraApi = new JiraServerApiService(\n JIRA_BASE_URL,\n JIRA_USER_EMAIL,\n JIRA_API_TOKEN,\n JIRA_AUTH_TYPE,\n );\n } else {\n this.jiraApi = new JiraApiService(\n JIRA_BASE_URL,\n JIRA_USER_EMAIL,\n JIRA_API_TOKEN,\n JIRA_AUTH_TYPE,\n );\n }\n\n this.setupToolHandlers();\n\n this.server.onerror = (error) => {};\n process.on(\"SIGINT\", async () => {\n await this.server.close();\n process.exit(0);\n });\n }\n\n private setupToolHandlers() {\n // ========================================================================\n // PROMPTS HANDLERS\n // ========================================================================\n\n this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({\n prompts: Object.entries(JIRA_PROMPTS).map(([name, { description }]) => ({\n name,\n description,\n })),\n }));\n\n this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const { name } = request.params;\n const prompt = JIRA_PROMPTS[name];\n\n if (!prompt) {\n throw new McpError(ErrorCode.InvalidParams, `Unknown prompt: ${name}`);\n }\n\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: prompt.content,\n },\n },\n ],\n };\n });\n\n // ========================================================================\n // TOOLS HANDLERS\n // ========================================================================\n\n this.server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: \"search_issues\",\n description: \"Search JIRA issues using JQL\",\n inputSchema: {\n type: \"object\",\n properties: {\n searchString: {\n type: \"string\",\n description: \"JQL search string\",\n },\n },\n required: [\"searchString\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_epic_children\",\n description:\n \"Get all child issues in an epic including their comments\",\n inputSchema: {\n type: \"object\",\n properties: {\n epicKey: {\n type: \"string\",\n description: \"The key of the epic issue\",\n },\n },\n required: [\"epicKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_issue\",\n description:\n \"Get detailed information about a specific JIRA issue including comments\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueId: {\n type: \"string\",\n description: \"The ID or key of the JIRA issue\",\n },\n },\n required: [\"issueId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"create_issue\",\n description: `Create a new JIRA issue.\n\n📋 BEFORE CREATING: Ask user for project, issue type, summary, and description.\nFor bugs: also ask for reproduction steps, expected/actual results.\nUse get_create_meta first to check required fields.\nSee prompt \"create_issue_workflow\" for detailed guidelines.`,\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key where the issue will be created\",\n },\n issueType: {\n type: \"string\",\n description:\n 'The type of issue to create (e.g., \"Bug\", \"Story\", \"Task\")',\n },\n summary: {\n type: \"string\",\n description: \"The issue summary/title\",\n },\n description: {\n type: \"string\",\n description: \"The issue description\",\n },\n fields: {\n type: \"object\",\n description: \"Additional fields to set on the issue\",\n additionalProperties: true,\n },\n },\n required: [\"projectKey\", \"issueType\", \"summary\"],\n additionalProperties: false,\n },\n },\n {\n name: \"update_issue\",\n description: `Update an existing JIRA issue.\n\n📝 When changing assignee or priority, consider adding a comment explaining why.\nSee prompt \"update_issue_workflow\" for guidelines.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to update\",\n },\n fields: {\n type: \"object\",\n description: \"Fields to update on the issue\",\n additionalProperties: true,\n },\n },\n required: [\"issueKey\", \"fields\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_transitions\",\n description: \"Get available status transitions for a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to get transitions for\",\n },\n },\n required: [\"issueKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"transition_issue\",\n description: `Change the status of a JIRA issue by performing a transition.\n\n⚠️ CANCELLATION RULE: When transitioning to \"Отмена\" (Cancel), you MUST first:\n1. Ask user for cancellation reason\n2. Add comment with the reason using add_comment\n3. Only then perform the transition\nSee prompt \"cancel_issue_workflow\" for details.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to transition\",\n },\n transitionId: {\n type: \"string\",\n description: \"The ID of the transition to perform\",\n },\n comment: {\n type: \"string\",\n description: \"Optional comment to add with the transition\",\n },\n },\n required: [\"issueKey\", \"transitionId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"add_attachment\",\n description: \"Add a file attachment to a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to add attachment to\",\n },\n fileContent: {\n type: \"string\",\n description: \"Base64 encoded content of the file\",\n },\n filename: {\n type: \"string\",\n description: \"Name of the file to be attached\",\n },\n },\n required: [\"issueKey\", \"fileContent\", \"filename\"],\n additionalProperties: false,\n },\n },\n {\n name: \"add_comment\",\n description: \"Add a comment to a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueIdOrKey: {\n type: \"string\",\n description: \"The ID or key of the issue to add the comment to\",\n },\n body: {\n type: \"string\",\n description: \"The content of the comment (plain text)\",\n },\n },\n required: [\"issueIdOrKey\", \"body\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_create_meta\",\n description: \"Get metadata for creating issues in a project, including available issue types and required fields. Use compact=true to get a smaller response with field counts instead of full allowedValues arrays.\",\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key to get creation metadata for\",\n },\n issueTypeName: {\n type: \"string\",\n description: \"Optional: filter to a specific issue type name\",\n },\n compact: {\n type: \"boolean\",\n description: \"If true, returns allowedValuesCount instead of full allowedValues arrays (reduces response size significantly)\",\n },\n },\n required: [\"projectKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_field_options\",\n description: \"Get allowed values for a specific field when creating issues. Use this after get_create_meta with compact=true to fetch options for fields that have allowedValuesCount > 0.\",\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key\",\n },\n issueTypeId: {\n type: \"string\",\n description: \"The issue type ID (from get_create_meta response)\",\n },\n fieldId: {\n type: \"string\",\n description: \"The field ID to get allowed values for (e.g., 'components', 'customfield_12405')\",\n },\n },\n required: [\"projectKey\", \"issueTypeId\", \"fieldId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_server_info\",\n description: \"Get JIRA server information including version and deployment type\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: \"get_projects\",\n description: \"Get all JIRA projects accessible to the current user\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: \"get_users\",\n description: \"Search for JIRA users by name or email. Useful for finding assignees.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Search query (name or email)\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results to return (default: 50)\",\n },\n },\n required: [\"query\"],\n additionalProperties: false,\n },\n },\n {\n name: \"delete_issue\",\n description: `Delete a JIRA issue permanently.\n\n⚠️ NOTE: Most users don't have delete permissions.\nIf deletion fails, use transition to \"Отмена\" (Cancel) status instead.\nRemember to add a comment with cancellation reason first.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to delete (e.g., IM3-1234)\",\n },\n },\n required: [\"issueKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_attachment\",\n description: \"Download a JIRA attachment by ID. Returns base64 encoded content. Use get_issue first to see available attachments with their IDs.\",\n inputSchema: {\n type: \"object\",\n properties: {\n attachmentId: {\n type: \"string\",\n description: \"The ID of the attachment to download\",\n },\n },\n required: [\"attachmentId\"],\n additionalProperties: false,\n },\n },\n ],\n }));\n\n this.server.setRequestHandler(CallToolRequestSchema, async (request) => {\n try {\n const args = request.params.arguments as Record<string, any>;\n\n switch (request.params.name) {\n case \"search_issues\": {\n if (!args.searchString || typeof args.searchString !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Search string is required\",\n );\n }\n const response = await this.jiraApi.searchIssues(args.searchString);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_epic_children\": {\n if (!args.epicKey || typeof args.epicKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Epic key is required\",\n );\n }\n const response = await this.jiraApi.getEpicChildren(args.epicKey);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_issue\": {\n if (!args.issueId || typeof args.issueId !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Issue ID is required\",\n );\n }\n const response = await this.jiraApi.getIssueWithComments(\n args.issueId,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"create_issue\": {\n // Basic validation\n if (\n !args.projectKey ||\n typeof args.projectKey !== \"string\" ||\n !args.issueType ||\n typeof args.issueType !== \"string\" ||\n !args.summary ||\n typeof args.summary !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey, issueType, and summary are required\",\n );\n }\n const response = await this.jiraApi.createIssue(\n args.projectKey,\n args.issueType,\n args.summary,\n args.description as string | undefined,\n args.fields as Record<string, any> | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"update_issue\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.fields ||\n typeof args.fields !== \"object\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey and fields object are required\",\n );\n }\n await this.jiraApi.updateIssue(args.issueKey, args.fields);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { message: `Issue ${args.issueKey} updated successfully` },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"get_transitions\": {\n if (!args.issueKey || typeof args.issueKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Issue key is required\",\n );\n }\n const response = await this.jiraApi.getTransitions(args.issueKey);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"transition_issue\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.transitionId ||\n typeof args.transitionId !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey and transitionId are required\",\n );\n }\n await this.jiraApi.transitionIssue(\n args.issueKey,\n args.transitionId,\n args.comment as string | undefined,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n message: `Issue ${args.issueKey} transitioned successfully${args.comment ? \" with comment\" : \"\"}`,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"add_attachment\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.fileContent ||\n typeof args.fileContent !== \"string\" ||\n !args.filename ||\n typeof args.filename !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey, fileContent, and filename are required\",\n );\n }\n const fileBuffer = Buffer.from(args.fileContent, \"base64\");\n const result = await this.jiraApi.addAttachment(\n args.issueKey,\n fileBuffer,\n args.filename,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n message: `File ${args.filename} attached successfully to issue ${args.issueKey}`,\n attachmentId: result.id,\n filename: result.filename,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"add_comment\": {\n if (\n !args.issueIdOrKey ||\n typeof args.issueIdOrKey !== \"string\" ||\n !args.body ||\n typeof args.body !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueIdOrKey and body are required\",\n );\n }\n const response = await this.jiraApi.addCommentToIssue(\n args.issueIdOrKey,\n args.body,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_create_meta\": {\n if (!args.projectKey || typeof args.projectKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey is required\",\n );\n }\n const meta = await this.jiraApi.getCreateMeta(\n args.projectKey,\n args.issueTypeName as string | undefined,\n args.compact as boolean | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(meta, null, 2) },\n ],\n };\n }\n case \"get_field_options\": {\n if (\n !args.projectKey ||\n typeof args.projectKey !== \"string\" ||\n !args.issueTypeId ||\n typeof args.issueTypeId !== \"string\" ||\n !args.fieldId ||\n typeof args.fieldId !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey, issueTypeId, and fieldId are required\",\n );\n }\n const options = await this.jiraApi.getFieldOptions(\n args.projectKey,\n args.issueTypeId,\n args.fieldId,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(options, null, 2) },\n ],\n };\n }\n case \"get_server_info\": {\n const serverInfo = await this.jiraApi.getServerInfo();\n return {\n content: [\n { type: \"text\", text: JSON.stringify(serverInfo, null, 2) },\n ],\n };\n }\n case \"get_projects\": {\n const projects = await this.jiraApi.getProjects();\n return {\n content: [\n { type: \"text\", text: JSON.stringify(projects, null, 2) },\n ],\n };\n }\n case \"get_users\": {\n if (!args.query || typeof args.query !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"query is required\",\n );\n }\n const users = await this.jiraApi.getUsers(\n args.query,\n args.maxResults as number | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(users, null, 2) },\n ],\n };\n }\n case \"delete_issue\": {\n if (!args.issueKey || typeof args.issueKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey is required\",\n );\n }\n await this.jiraApi.deleteIssue(args.issueKey);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { message: `Issue ${args.issueKey} deleted successfully` },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"get_attachment\": {\n if (!args.attachmentId || typeof args.attachmentId !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"attachmentId is required\",\n );\n }\n const attachment = await this.jiraApi.getAttachment(args.attachmentId);\n\n // Check if it's an image type that Claude can view\n const isImage = attachment.mimeType.startsWith(\"image/\");\n\n if (isImage) {\n return {\n content: [\n {\n type: \"text\",\n text: `Attachment: ${attachment.filename} (${attachment.mimeType})`,\n },\n {\n type: \"image\",\n data: attachment.content,\n mimeType: attachment.mimeType,\n } as any,\n ],\n };\n }\n\n // For non-image files, return base64 as text\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(attachment, null, 2),\n },\n ],\n };\n }\n default:\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n } catch (error) {\n // Keep generic error handling\n if (error instanceof McpError) {\n throw error;\n }\n throw new McpError(\n ErrorCode.InternalError,\n error instanceof Error ? error.message : \"Unknown error occurred\",\n );\n }\n });\n }\n\n async run() {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n // JIRA MCP server running on stdio\n }\n}\n\nconst server = new JiraServer();\nserver.run().catch(() => {});\n"],"names":["JiraApiService","baseUrl","email","apiToken","authType","authHeader","response","url","message","errorData","errorMessages","field","msg","text","content","source","commentId","mentions","processNode","node","match","key","m","comment","body","attachment","issue","description","cleanedIssue","links","link","linkedIssue","relationship","subtask","a","init","searchString","params","data","epicKey","commentsData","comments","commentMentions","issueId","issueData","error","epicData","projectKey","issueType","summary","fields","payload","issueTypeName","compact","issueTypes","it","f","issueTypeId","fieldId","issueKey","transitionId","file","filename","formData","headers","issueIdOrKey","project","query","maxResults","user","attachmentId","metadata","arrayBuffer","JiraServerApiService","path","serverUrl","matches","JIRA_API_TOKEN","JIRA_BASE_URL","JIRA_USER_EMAIL","JIRA_TYPE","JIRA_AUTH_TYPE","JIRA_PROMPTS","JiraServer","Server","ListPromptsRequestSchema","name","GetPromptRequestSchema","request","prompt","McpError","ErrorCode","ListToolsRequestSchema","CallToolRequestSchema","args","fileBuffer","result","meta","options","serverInfo","projects","users","transport","StdioServerTransport","server"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/services/jira-api.ts","../src/services/jira-server-api.ts","../src/index.ts"],"sourcesContent":["import {\n AddCommentResponse,\n AdfDoc,\n CleanAttachment,\n CleanComment,\n CleanJiraIssue,\n JiraCommentResponse,\n SearchIssuesResponse,\n} from \"../types/jira.js\";\n\nexport class JiraApiService {\n protected baseUrl: string;\n protected headers: Headers;\n\n constructor(baseUrl: string, email: string, apiToken: string, authType: 'basic' | 'bearer' = 'basic') {\n this.baseUrl = baseUrl;\n \n let authHeader: string;\n if (authType === 'bearer') {\n // For Jira Data Center Personal Access Tokens (PATs)\n authHeader = `Bearer ${apiToken}`;\n } else {\n // For Basic authentication with username/password or API token\n const auth = Buffer.from(`${email}:${apiToken}`).toString(\"base64\");\n authHeader = `Basic ${auth}`;\n }\n \n this.headers = new Headers({\n Authorization: authHeader,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n });\n }\n\n protected async handleFetchError(\n response: Response,\n url?: string\n ): Promise<never> {\n if (!response.ok) {\n let message = response.statusText;\n let errorData: any = {};\n try {\n errorData = await response.json();\n\n // Try different error formats that Jira uses\n if (\n Array.isArray(errorData.errorMessages) &&\n errorData.errorMessages.length > 0\n ) {\n // Format: { errorMessages: [\"msg1\", \"msg2\"] }\n message = errorData.errorMessages.join(\"; \");\n } else if (errorData.message) {\n // Format: { message: \"error message\" }\n message = errorData.message;\n } else if (errorData.errorMessage) {\n // Format: { errorMessage: \"error message\" }\n message = errorData.errorMessage;\n } else if (errorData.errors && typeof errorData.errors === \"object\") {\n // Format: { errors: { fieldName: \"error for field\", anotherField: \"another error\" } }\n const errorMessages = Object.entries(errorData.errors)\n .map(([field, msg]) => `${field}: ${msg}`)\n .join(\"; \");\n if (errorMessages) {\n message = errorMessages;\n }\n }\n\n // If we still only have statusText but have error data, stringify it\n if (message === response.statusText && Object.keys(errorData).length > 0) {\n message = JSON.stringify(errorData);\n }\n } catch (e) {\n // Could not parse as JSON, try to get text\n try {\n const text = await response.text();\n if (text) {\n message = text.substring(0, 500); // Limit length\n }\n } catch {\n // Ignore\n }\n }\n\n throw new Error(\n `JIRA API Error: ${message} (Status: ${response.status})`\n );\n }\n\n throw new Error(\"Unknown error occurred during fetch operation.\");\n }\n\n /**\n * Extracts issue mentions from Atlassian document content\n * Looks for nodes that were auto-converted to issue links\n */\n protected extractIssueMentions(\n content: any[],\n source: \"description\" | \"comment\",\n commentId?: string\n ): CleanJiraIssue[\"relatedIssues\"] {\n const mentions: NonNullable<CleanJiraIssue[\"relatedIssues\"]> = [];\n\n const processNode = (node: any) => {\n if (node.type === \"inlineCard\" && node.attrs?.url) {\n const match = node.attrs.url.match(/\\/browse\\/([A-Z]+-\\d+)/);\n if (match) {\n mentions.push({\n key: match[1],\n type: \"mention\",\n source,\n commentId,\n });\n }\n }\n\n if (node.type === \"text\" && node.text) {\n const matches = node.text.match(/[A-Z]+-\\d+/g) || [];\n matches.forEach((key: string) => {\n mentions.push({\n key,\n type: \"mention\",\n source,\n commentId,\n });\n });\n }\n\n if (node.content) {\n node.content.forEach(processNode);\n }\n };\n\n content.forEach(processNode);\n return [...new Map(mentions.map((m) => [m.key, m])).values()];\n }\n\n protected cleanComment(comment: {\n id: string;\n body?: {\n content?: any[];\n };\n author?: {\n displayName?: string;\n };\n created: string;\n updated: string;\n }): CleanComment {\n const body = comment.body?.content\n ? this.extractTextContent(comment.body.content)\n : \"\";\n const mentions = comment.body?.content\n ? this.extractIssueMentions(comment.body.content, \"comment\", comment.id)\n : [];\n\n return {\n id: comment.id,\n body,\n author: comment.author?.displayName,\n created: comment.created,\n updated: comment.updated,\n mentions: mentions,\n };\n }\n\n protected cleanAttachment(attachment: any): CleanAttachment {\n return {\n id: attachment.id,\n filename: attachment.filename,\n mimeType: attachment.mimeType,\n size: attachment.size,\n created: attachment.created,\n author: attachment.author?.displayName,\n content: attachment.content,\n thumbnail: attachment.thumbnail,\n };\n }\n\n /**\n * Recursively extracts text content from Atlassian Document Format nodes\n */\n protected extractTextContent(content: any[]): string {\n if (!Array.isArray(content)) return \"\";\n\n return content\n .map((node) => {\n if (node.type === \"text\") {\n return node.text || \"\";\n }\n if (node.content) {\n return this.extractTextContent(node.content);\n }\n return \"\";\n })\n .join(\"\");\n }\n\n protected cleanIssue(issue: any): CleanJiraIssue {\n let description = \"\";\n if (issue.fields?.description) {\n if (typeof issue.fields.description === \"string\") {\n // Jira Server: plain text\n description = issue.fields.description;\n } else if (issue.fields.description.content) {\n // Jira Cloud: ADF format\n description = this.extractTextContent(issue.fields.description.content);\n }\n }\n\n const cleanedIssue: CleanJiraIssue = {\n id: issue.id,\n key: issue.key,\n summary: issue.fields?.summary,\n status: issue.fields?.status?.name,\n created: issue.fields?.created,\n updated: issue.fields?.updated,\n description,\n relatedIssues: [],\n };\n\n if (issue.fields?.description?.content) {\n const mentions = this.extractIssueMentions(\n issue.fields.description.content,\n \"description\"\n );\n if (mentions.length > 0) {\n cleanedIssue.relatedIssues = mentions;\n }\n }\n\n if (issue.fields?.issuelinks?.length > 0) {\n const links = issue.fields.issuelinks.map((link: any) => {\n const linkedIssue = link.inwardIssue || link.outwardIssue;\n const relationship = link.type.inward || link.type.outward;\n return {\n key: linkedIssue.key,\n summary: linkedIssue.fields?.summary,\n type: \"link\" as const,\n relationship,\n source: \"description\" as const,\n };\n });\n\n cleanedIssue.relatedIssues = [\n ...(cleanedIssue.relatedIssues || []),\n ...links,\n ];\n }\n\n if (issue.fields?.parent) {\n cleanedIssue.parent = {\n id: issue.fields.parent.id,\n key: issue.fields.parent.key,\n summary: issue.fields.parent.fields?.summary,\n };\n }\n\n if (issue.fields?.customfield_10014) {\n cleanedIssue.epicLink = {\n id: issue.fields.customfield_10014,\n key: issue.fields.customfield_10014,\n summary: undefined,\n };\n }\n\n if (issue.fields?.subtasks?.length > 0) {\n cleanedIssue.children = issue.fields.subtasks.map((subtask: any) => ({\n id: subtask.id,\n key: subtask.key,\n summary: subtask.fields?.summary,\n }));\n }\n\n if (issue.fields?.attachment?.length > 0) {\n cleanedIssue.attachments = issue.fields.attachment.map((a: any) =>\n this.cleanAttachment(a)\n );\n }\n\n return cleanedIssue;\n }\n\n protected async fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const response = await fetch(this.baseUrl + url, {\n ...init,\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response, url);\n }\n\n return response.json();\n }\n\n async searchIssues(searchString: string): Promise<SearchIssuesResponse> {\n const params = new URLSearchParams({\n jql: searchString,\n maxResults: \"50\",\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n const data = await this.fetchJson<any>(`/rest/api/3/search?${params}`);\n\n return {\n total: data.total,\n issues: data.issues.map((issue: any) => this.cleanIssue(issue)),\n };\n }\n\n async getEpicChildren(epicKey: string): Promise<CleanJiraIssue[]> {\n const params = new URLSearchParams({\n jql: `\"Epic Link\" = ${epicKey}`,\n maxResults: \"100\",\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n const data = await this.fetchJson<any>(`/rest/api/3/search?${params}`);\n\n const issuesWithComments = await Promise.all(\n data.issues.map(async (issue: any) => {\n const commentsData = await this.fetchJson<any>(\n `/rest/api/3/issue/${issue.key}/comment`\n );\n const cleanedIssue = this.cleanIssue(issue);\n const comments = commentsData.comments.map((comment: any) =>\n this.cleanComment(comment)\n );\n\n const commentMentions = comments.flatMap(\n (comment: CleanComment) => comment.mentions\n );\n cleanedIssue.relatedIssues = [\n ...cleanedIssue.relatedIssues,\n ...commentMentions,\n ];\n\n cleanedIssue.comments = comments;\n return cleanedIssue;\n })\n );\n\n return issuesWithComments;\n }\n\n async getIssueWithComments(issueId: string): Promise<CleanJiraIssue> {\n const params = new URLSearchParams({\n fields: [\n \"id\",\n \"key\",\n \"summary\",\n \"description\",\n \"status\",\n \"created\",\n \"updated\",\n \"parent\",\n \"subtasks\",\n \"customfield_10014\",\n \"issuelinks\",\n \"attachment\",\n ].join(\",\"),\n expand: \"names,renderedFields\",\n });\n\n let issueData, commentsData;\n try {\n [issueData, commentsData] = await Promise.all([\n this.fetchJson<any>(`/rest/api/3/issue/${issueId}?${params}`),\n this.fetchJson<any>(`/rest/api/3/issue/${issueId}/comment`),\n ]);\n } catch (error: any) {\n if (error instanceof Error && error.message.includes(\"(Status: 404)\")) {\n throw new Error(`Issue not found: ${issueId}`);\n }\n\n throw error;\n }\n\n const issue = this.cleanIssue(issueData);\n const comments = commentsData.comments.map((comment: any) =>\n this.cleanComment(comment)\n );\n\n const commentMentions = comments.flatMap(\n (comment: CleanComment) => comment.mentions\n );\n issue.relatedIssues = [...issue.relatedIssues, ...commentMentions];\n\n issue.comments = comments;\n\n if (issue.epicLink) {\n try {\n const epicData = await this.fetchJson<any>(\n `/rest/api/3/issue/${issue.epicLink.key}?fields=summary`\n );\n issue.epicLink.summary = epicData.fields?.summary;\n } catch (error) {\n console.error(\"Failed to fetch epic details:\", error);\n }\n }\n\n return issue;\n }\n\n async createIssue(\n projectKey: string,\n issueType: string,\n summary: string,\n description?: string,\n fields?: Record<string, any>\n ): Promise<{ id: string; key: string }> {\n const payload = {\n fields: {\n project: {\n key: projectKey,\n },\n summary,\n issuetype: {\n name: issueType,\n },\n ...(description && { description }),\n ...fields,\n },\n };\n\n return this.fetchJson<{ id: string; key: string }>(\"/rest/api/3/issue\", {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n }\n\n async getCreateMeta(\n projectKey: string,\n issueTypeName?: string,\n compact?: boolean\n ): Promise<any> {\n // Get available issue types for the project\n const issueTypesData = await this.fetchJson<{ issueTypes: Array<{ id: string; name: string; description?: string; subtask: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes`\n );\n\n let issueTypes = issueTypesData.issueTypes || [];\n\n // Filter by issue type name if provided\n if (issueTypeName) {\n issueTypes = issueTypes.filter(\n (it) => it.name.toLowerCase() === issueTypeName.toLowerCase()\n );\n }\n\n // Get fields for each issue type\n const result = {\n projectKey,\n issueTypes: await Promise.all(\n issueTypes.map(async (issueType) => {\n try {\n const fieldsData = await this.fetchJson<{ fields: Array<{ fieldId: string; name: string; required: boolean; schema?: any; allowedValues?: any[]; hasDefaultValue?: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueType.id}`\n );\n\n let fields = fieldsData.fields || [];\n\n // In compact mode, replace allowedValues with count\n if (compact) {\n fields = fields.map((f) => ({\n fieldId: f.fieldId,\n name: f.name,\n required: f.required,\n schema: f.schema,\n hasDefaultValue: f.hasDefaultValue,\n allowedValuesCount: f.allowedValues?.length ?? 0,\n }));\n }\n\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields,\n };\n } catch (error) {\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields: [],\n error: error instanceof Error ? error.message : \"Failed to fetch fields\",\n };\n }\n })\n ),\n };\n\n return result;\n }\n\n async getFieldOptions(\n projectKey: string,\n issueTypeId: string,\n fieldId: string\n ): Promise<any[]> {\n const fieldsData = await this.fetchJson<{ fields: Array<{ fieldId: string; allowedValues?: any[] }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueTypeId}`\n );\n\n const field = (fieldsData.fields || []).find((f) => f.fieldId === fieldId);\n return field?.allowedValues ?? [];\n }\n\n async updateIssue(\n issueKey: string,\n fields: Record<string, any>\n ): Promise<void> {\n await this.fetchJson(`/rest/api/3/issue/${issueKey}`, {\n method: \"PUT\",\n body: JSON.stringify({ fields }),\n });\n }\n\n async getTransitions(\n issueKey: string\n ): Promise<Array<{ id: string; name: string; to: { name: string } }>> {\n const data = await this.fetchJson<any>(\n `/rest/api/3/issue/${issueKey}/transitions`\n );\n return data.transitions;\n }\n\n async transitionIssue(\n issueKey: string,\n transitionId: string,\n comment?: string\n ): Promise<void> {\n const payload: any = {\n transition: { id: transitionId },\n };\n\n if (comment) {\n payload.update = {\n comment: [\n {\n add: {\n body: {\n type: \"doc\",\n version: 1,\n content: [\n {\n type: \"paragraph\",\n content: [\n {\n type: \"text\",\n text: comment,\n },\n ],\n },\n ],\n },\n },\n },\n ],\n };\n }\n\n await this.fetchJson(`/rest/api/3/issue/${issueKey}/transitions`, {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n }\n\n async addAttachment(\n issueKey: string,\n file: Buffer,\n filename: string\n ): Promise<{ id: string; filename: string }> {\n const formData = new FormData();\n formData.append(\"file\", new Blob([new Uint8Array(file)]), filename);\n\n const headers = new Headers(this.headers);\n headers.delete(\"Content-Type\");\n headers.set(\"X-Atlassian-Token\", \"no-check\");\n\n const response = await fetch(\n `${this.baseUrl}/rest/api/3/issue/${issueKey}/attachments`,\n {\n method: \"POST\",\n headers,\n body: formData,\n }\n );\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n\n const data = await response.json();\n\n const attachment = data[0];\n return {\n id: attachment.id,\n filename: attachment.filename,\n };\n }\n\n /**\n * Converts plain text to a basic Atlassian Document Format (ADF) structure.\n */\n private createAdfFromBody(text: string): AdfDoc {\n return {\n version: 1,\n type: \"doc\",\n content: [\n {\n type: \"paragraph\",\n content: [\n {\n type: \"text\",\n text: text,\n },\n ],\n },\n ],\n };\n }\n\n /**\n * Adds a comment to a JIRA issue.\n */\n async addCommentToIssue(\n issueIdOrKey: string,\n body: string\n ): Promise<AddCommentResponse> {\n const adfBody = this.createAdfFromBody(body);\n\n const payload = {\n body: adfBody,\n };\n\n const response = await this.fetchJson<JiraCommentResponse>(\n `/rest/api/3/issue/${issueIdOrKey}/comment`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n }\n );\n\n return {\n id: response.id,\n author: response.author.displayName,\n created: response.created,\n updated: response.updated,\n body: this.extractTextContent(response.body.content),\n };\n }\n\n async getServerInfo(): Promise<{\n version: string;\n versionNumbers: number[];\n deploymentType: string;\n buildNumber: number;\n serverTitle: string;\n }> {\n return this.fetchJson(`/rest/api/3/serverInfo`);\n }\n\n async getProjects(): Promise<Array<{\n id: string;\n key: string;\n name: string;\n projectTypeKey: string;\n lead?: { displayName: string; accountId?: string };\n }>> {\n const data = await this.fetchJson<any[]>(`/rest/api/3/project`);\n return data.map((project) => ({\n id: project.id,\n key: project.key,\n name: project.name,\n projectTypeKey: project.projectTypeKey,\n lead: project.lead ? {\n displayName: project.lead.displayName,\n accountId: project.lead.accountId,\n } : undefined,\n }));\n }\n\n async getUsers(query: string, maxResults: number = 50): Promise<Array<{\n accountId: string;\n displayName: string;\n emailAddress?: string;\n active: boolean;\n }>> {\n const params = new URLSearchParams({\n query,\n maxResults: maxResults.toString(),\n });\n const data = await this.fetchJson<any[]>(`/rest/api/3/user/search?${params}`);\n return data.map((user) => ({\n accountId: user.accountId,\n displayName: user.displayName,\n emailAddress: user.emailAddress,\n active: user.active,\n }));\n }\n\n async deleteIssue(issueKey: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/rest/api/3/issue/${issueKey}`, {\n method: \"DELETE\",\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n }\n\n async getAttachment(attachmentId: string): Promise<{\n content: string; // base64 encoded\n filename: string;\n mimeType: string;\n }> {\n // First, get attachment metadata to get the content URL\n const metadata = await this.fetchJson<{\n id: string;\n filename: string;\n mimeType: string;\n content: string;\n }>(`/rest/api/3/attachment/${attachmentId}`);\n\n // Fetch the actual content from the content URL\n const response = await fetch(metadata.content, {\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const base64 = Buffer.from(arrayBuffer).toString(\"base64\");\n\n return {\n content: base64,\n filename: metadata.filename,\n mimeType: metadata.mimeType,\n };\n }\n}\n","// JiraServerApiService: Jira Server (Data Center) implementation\n// This class should override methods as needed for Jira Server differences\nimport { JiraApiService } from \"./jira-api.js\";\nimport type { CleanComment, CleanJiraIssue } from \"../types/jira.js\";\n\nexport class JiraServerApiService extends JiraApiService {\n constructor(baseUrl: string, email: string, apiToken: string, authType: 'basic' | 'bearer' = 'basic') {\n // For Jira Server/Data Center:\n // - Basic Auth: username/password or API token (traditional method)\n // - Bearer Auth: Personal Access Tokens (PATs) available in Data Center 8.14.0+\n super(baseUrl, email, apiToken, authType);\n }\n\n // Example: Override fetchJson to use /rest/api/2/ instead of /rest/api/3/\n protected overrideApiPath(path: string): string {\n // Replace /rest/api/3/ with /rest/api/2/ for Jira Server\n return path.replace(\"/rest/api/3/\", \"/rest/api/2/\");\n }\n\n // Override fetchJson to use the correct API path\n protected async fetchJson<T>(url: string, init?: RequestInit): Promise<T> {\n const serverUrl = this.overrideApiPath(url);\n return super.fetchJson<T>(serverUrl, init);\n }\n\n // Override getCreateMeta to use API v2 endpoints for Jira Server 9.0+\n async getCreateMeta(\n projectKey: string,\n issueTypeName?: string,\n compact?: boolean\n ): Promise<any> {\n // For Jira Server 9.0+, use the new paginated endpoints (same structure as Cloud but API v2)\n const issueTypesData = await this.fetchJson<{ values: Array<{ id: string; name: string; description?: string; subtask: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes`\n );\n\n let issueTypes = issueTypesData.values || [];\n\n // Filter by issue type name if provided\n if (issueTypeName) {\n issueTypes = issueTypes.filter(\n (it) => it.name.toLowerCase() === issueTypeName.toLowerCase()\n );\n }\n\n // Get fields for each issue type\n const result = {\n projectKey,\n issueTypes: await Promise.all(\n issueTypes.map(async (issueType) => {\n try {\n const fieldsData = await this.fetchJson<{ values: Array<{ fieldId: string; name: string; required: boolean; schema?: any; allowedValues?: any[]; hasDefaultValue?: boolean }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueType.id}`\n );\n\n let fields = fieldsData.values || [];\n\n // In compact mode, replace allowedValues with count\n if (compact) {\n fields = fields.map((f) => ({\n fieldId: f.fieldId,\n name: f.name,\n required: f.required,\n schema: f.schema,\n hasDefaultValue: f.hasDefaultValue,\n allowedValuesCount: f.allowedValues?.length ?? 0,\n }));\n }\n\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields,\n };\n } catch (error) {\n return {\n id: issueType.id,\n name: issueType.name,\n description: issueType.description,\n subtask: issueType.subtask,\n fields: [],\n error: error instanceof Error ? error.message : \"Failed to fetch fields\",\n };\n }\n })\n ),\n };\n\n return result;\n }\n\n // Override getFieldOptions for Jira Server (uses 'values' instead of 'fields')\n async getFieldOptions(\n projectKey: string,\n issueTypeId: string,\n fieldId: string\n ): Promise<any[]> {\n const fieldsData = await this.fetchJson<{ values: Array<{ fieldId: string; allowedValues?: any[] }> }>(\n `/rest/api/3/issue/createmeta/${projectKey}/issuetypes/${issueTypeId}`\n );\n\n const field = (fieldsData.values || []).find((f) => f.fieldId === fieldId);\n return field?.allowedValues ?? [];\n }\n\n // Override getUsers for Jira Server (uses 'username' parameter instead of 'query')\n async getUsers(query: string, maxResults: number = 50): Promise<Array<{\n accountId: string;\n displayName: string;\n emailAddress?: string;\n active: boolean;\n }>> {\n const params = new URLSearchParams({\n username: query,\n maxResults: maxResults.toString(),\n });\n const data = await this.fetchJson<any[]>(`/rest/api/3/user/search?${params}`);\n return data.map((user) => ({\n // Jira Server uses 'name' or 'key' instead of 'accountId'\n accountId: user.key || user.name,\n displayName: user.displayName,\n emailAddress: user.emailAddress,\n active: user.active,\n }));\n }\n\n // Override addCommentToIssue for Jira Server (uses plain text instead of ADF)\n async addCommentToIssue(\n issueIdOrKey: string,\n body: string\n ): Promise<{\n id: string;\n author: string;\n created: string;\n updated: string;\n body: string;\n }> {\n // Jira Server API v2 expects plain text body, not ADF\n const payload = {\n body: body,\n };\n\n const response = await this.fetchJson<{\n id: string;\n author: { displayName: string };\n created: string;\n updated: string;\n body: string;\n }>(\n `/rest/api/3/issue/${issueIdOrKey}/comment`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n }\n );\n\n return {\n id: response.id,\n author: response.author.displayName,\n created: response.created,\n updated: response.updated,\n body: response.body,\n };\n }\n\n // Override deleteIssue for Jira Server (uses API v2)\n async deleteIssue(issueKey: string): Promise<void> {\n const response = await fetch(`${this.baseUrl}/rest/api/2/issue/${issueKey}`, {\n method: \"DELETE\",\n headers: this.headers,\n });\n\n if (!response.ok) {\n await this.handleFetchError(response);\n }\n }\n\n // Override cleanComment for Jira Server (body is plain text, not ADF)\n protected cleanComment(comment: {\n id: string;\n body?: string | { content?: any[] };\n author?: {\n displayName?: string;\n };\n created: string;\n updated: string;\n }): CleanComment {\n // Debug: log raw comment to understand API response format\n console.error(\"[DEBUG cleanComment] Raw comment:\", JSON.stringify(comment, null, 2));\n\n // Jira Server API v2 returns body as plain text string\n // Jira Cloud API v3 returns body as ADF object with content array\n let body: string;\n let mentions: CleanJiraIssue[\"relatedIssues\"] = [];\n\n if (typeof comment.body === \"string\") {\n // Jira Server: body is plain text\n body = comment.body;\n // Extract issue mentions from plain text (e.g., PROJECT-123)\n mentions = this.extractIssueMentionsFromText(body, \"comment\", comment.id);\n } else if (comment.body?.content) {\n // Jira Cloud: body is ADF object\n body = this.extractTextContent(comment.body.content);\n mentions = this.extractIssueMentions(comment.body.content, \"comment\", comment.id);\n } else {\n body = \"\";\n }\n\n return {\n id: comment.id,\n body,\n author: comment.author?.displayName,\n created: comment.created,\n updated: comment.updated,\n mentions,\n };\n }\n\n // Extract issue mentions from plain text (for Jira Server)\n protected extractIssueMentionsFromText(\n text: string,\n source: \"description\" | \"comment\",\n commentId?: string\n ): CleanJiraIssue[\"relatedIssues\"] {\n if (!text) return [];\n\n const matches = text.match(/[A-Z]+-\\d+/g) || [];\n const uniqueKeys = [...new Set(matches)];\n\n return uniqueKeys.map((key) => ({\n key,\n type: \"mention\" as const,\n source,\n commentId,\n }));\n }\n}\n","#!/usr/bin/env node\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ErrorCode,\n ListToolsRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n McpError,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { JiraApiService } from \"./services/jira-api.js\";\nimport { JiraServerApiService } from \"./services/jira-server-api.js\";\n\nfunction getEnvConfig() {\n const JIRA_API_TOKEN = process.env.JIRA_API_TOKEN ?? \"\";\n const JIRA_BASE_URL = process.env.JIRA_BASE_URL ?? \"\";\n const JIRA_USER_EMAIL = process.env.JIRA_USER_EMAIL ?? \"\";\n const JIRA_TYPE = (process.env.JIRA_TYPE === \"server\" ? \"server\" : \"cloud\") as\n | \"cloud\"\n | \"server\";\n const JIRA_AUTH_TYPE = (process.env.JIRA_AUTH_TYPE === \"bearer\" ? \"bearer\" : \"basic\") as\n | \"basic\"\n | \"bearer\";\n\n if (!JIRA_API_TOKEN || !JIRA_BASE_URL || !JIRA_USER_EMAIL) {\n throw new Error(\n \"JIRA_API_TOKEN, JIRA_USER_EMAIL and JIRA_BASE_URL environment variables are required\",\n );\n }\n\n return { JIRA_API_TOKEN, JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_TYPE, JIRA_AUTH_TYPE };\n}\n\n// ============================================================================\n// PROMPTS - Инструкции и регламенты для агентов\n// ============================================================================\n\nconst JIRA_PROMPTS: Record<string, { description: string; content: string }> = {\n jira_guidelines: {\n description: \"Общие правила и регламенты работы с Jira в компании\",\n content: `# Регламент работы с Jira\n\n## Общие принципы\n- Все изменения статусов должны отражать реальное состояние работы\n- Комментарии пишутся на русском языке\n- При любых изменениях, затрагивающих других участников, оставляй комментарий\n\n## Статусы и переходы\n\n### Workflow задачи:\n1. **Бэклог** — задача запланирована, но работа не начата\n2. **Очередь** — задача в очереди на выполнение\n3. **В работе** — код в процессе написания\n4. **Ревью** — код готов к проверке, создан PR/MR\n5. **Local test** — задача на локальном тестировании\n6. **Dev** — код в ветке dev\n7. **Stage (не проверено)** — код в ветке stage, тестирование не проведено\n8. **Релиз-кандидат** — проверено на stage, готово к релизу\n9. **Тест на проде** — код на проде, ожидает проверки\n10. **Готово на проде** — задача завершена и проверена\n\n### Особые статусы:\n- **Заблокирована** — работа приостановлена (указать причину в комментарии)\n- **Отложено** — задача отложена на неопределённый срок\n- **Отмена** — задача отменена (ОБЯЗАТЕЛЬНО с комментарием о причине!)\n\n## Создание задач\n- Summary должен быть кратким и информативным (не более 100 символов)\n- Description должен содержать достаточно информации для понимания задачи\n- Обязательно указывай компонент (component) для правильной маршрутизации\n- Для багов: шаги воспроизведения, ожидаемый и фактический результат\n\n## Отмена задач\n- ЗАПРЕЩЕНО отменять задачу без указания причины в комментарии\n- Причина должна быть информативной: \"дубликат IM3-1234\", \"неактуально после релиза X\", и т.д.\n\n## Удаление задач\n- Удаление задач запрещено политикой безопасности\n- Вместо удаления используй статус \"Отмена\" с комментарием\n\n## Комментарии\n- Используй комментарии для важной информации, которая должна остаться в истории\n- При блокировке — указывай причину и ссылку на блокирующую задачу\n- При передаче задачи — описывай текущее состояние и что осталось сделать`,\n },\n\n create_issue_workflow: {\n description: \"Пошаговый процесс создания задачи в Jira\",\n content: `# Создание задачи в Jira\n\n## Перед созданием ОБЯЗАТЕЛЬНО уточни у пользователя:\n\n### Основная информация:\n1. **Проект** — в каком проекте создать (IM3, SD, FT, ETPP и т.д.)\n2. **Тип задачи** — Баг, Story, Task, Sub-task\n3. **Краткое описание** (summary) — что нужно сделать, до 100 символов\n4. **Подробное описание** (description) — детали задачи\n\n### Для багов дополнительно запроси:\n- Шаги воспроизведения (пронумерованный список)\n- Ожидаемый результат\n- Фактический результат\n- Окружение (браузер, ОС, URL) — если релевантно\n- Скриншоты или логи — если есть\n\n### Для Story/Task уточни:\n- Критерии приёмки (acceptance criteria)\n- Связанные задачи (если есть)\n\n## Порядок действий:\n\n1. **Получи схему полей:**\n \\`\\`\\`\n get_create_meta(projectKey, issueTypeName, compact=true)\n \\`\\`\\`\n\n2. **Для обязательных полей с вариантами получи опции:**\n \\`\\`\\`\n get_field_options(projectKey, issueTypeId, fieldId)\n \\`\\`\\`\n\n3. **Покажи пользователю** итоговые данные перед созданием\n\n4. **Создай задачу:**\n \\`\\`\\`\n create_issue(projectKey, issueType, summary, description, fields)\n \\`\\`\\`\n\n5. **Верни пользователю** ключ и ссылку на созданную задачу\n\n## Пример описания бага:\n\n\\`\\`\\`\nШаги воспроизведения:\n1. Открыть страницу /checkout\n2. Добавить товар в корзину\n3. Нажать \"Оформить заказ\"\n\nОжидаемый результат:\nОткрывается форма оформления заказа\n\nФактический результат:\nСтраница показывает ошибку 500\n\nОкружение:\n- URL: https://example.com/checkout\n- Браузер: Chrome 120\n- ОС: Windows 11\n\\`\\`\\``,\n },\n\n cancel_issue_workflow: {\n description: \"Процесс отмены задачи (требует указания причины)\",\n content: `# Отмена задачи в Jira\n\n## ⚠️ ВАЖНО: Задачу НЕЛЬЗЯ отменять без причины!\n\n## Порядок действий:\n\n### 1. Спроси причину отмены\nПрежде чем отменять задачу, ОБЯЗАТЕЛЬНО спроси у пользователя:\n- \"Почему задача отменяется?\"\n- \"Укажите причину отмены для комментария\"\n\n### 2. Примеры корректных причин:\n- \"Дубликат задачи IM3-1234\"\n- \"Неактуально после релиза версии 2.5\"\n- \"Функционал реализован в рамках IM3-5678\"\n- \"Отменено по решению Product Owner (имя)\"\n- \"Требования изменились, создана новая задача IM3-9999\"\n\n### 3. Добавь комментарий с причиной:\n\\`\\`\\`\nadd_comment(issueKey, \"Причина отмены: <причина от пользователя>\")\n\\`\\`\\`\n\n### 4. Получи ID перехода \"Отмена\":\n\\`\\`\\`\nget_transitions(issueKey)\n// Найди переход с name=\"Отмена\"\n\\`\\`\\`\n\n### 5. Выполни переход:\n\\`\\`\\`\ntransition_issue(issueKey, transitionId)\n\\`\\`\\`\n\n## Запрещено:\n- ❌ Отменять задачу без комментария с причиной\n- ❌ Использовать причины типа \"не нужно\", \"отмена\" без пояснения\n\n## Если пользователь не хочет указывать причину:\nОбъясни, что это требование регламента компании, и причина важна для:\n- Истории проекта\n- Понимания, почему задача не была выполнена\n- Аудита и отчётности`,\n },\n\n transition_issue_workflow: {\n description: \"Правила смены статусов задач\",\n content: `# Смена статуса задачи в Jira\n\n## Общие правила:\n- Статус должен отражать реальное состояние работы\n- Не пропускай промежуточные статусы без веской причины\n- При переходе в финальные статусы убедись, что работа действительно завершена\n\n## Особые случаи:\n\n### Переход в \"Отмена\":\n⚠️ ОБЯЗАТЕЛЬНО сначала добавь комментарий с причиной отмены!\nСм. prompt \"cancel_issue_workflow\" для подробностей.\n\n### Переход в \"Заблокирована\":\n- Укажи в комментарии причину блокировки\n- Добавь ссылку на блокирующую задачу (если есть)\n- Пример: \"Заблокировано: ждём завершения IM3-1234 (интеграция с API)\"\n\n### Переход в \"Ревью\":\n- Должен существовать Pull Request / Merge Request\n- Желательно добавить ссылку на PR в комментарий\n\n### Переход в \"Dev\" / \"Stage\":\n- Код должен быть смержен в соответствующую ветку\n- Задача задеплоена на окружение\n\n### Переход в \"Тест на проде\":\n- Код задеплоен на production\n- Задача готова к финальной проверке\n\n### Переход в \"Готово на проде\":\n- Задача проверена на production\n- Все acceptance criteria выполнены\n- Нет открытых sub-tasks\n\n## Получение доступных переходов:\n\\`\\`\\`\nget_transitions(issueKey)\n// Вернёт список доступных переходов с их ID\n\\`\\`\\`\n\n## Выполнение перехода:\n\\`\\`\\`\ntransition_issue(issueKey, transitionId, comment?)\n// comment — опциональный комментарий к переходу\n\\`\\`\\``,\n },\n\n update_issue_workflow: {\n description: \"Правила обновления задач\",\n content: `# Обновление задачи в Jira\n\n## Что можно обновлять:\n- summary — краткое описание\n- description — подробное описание\n- assignee — исполнитель\n- priority — приоритет\n- labels — метки\n- components — компоненты\n- customfield_* — кастомные поля\n\n## Правила:\n\n### При изменении исполнителя (assignee):\n- Если задача в работе — согласуй с текущим исполнителем\n- Добавь комментарий о причине переназначения\n\n### При изменении приоритета:\n- Повышение приоритета — укажи причину в комментарии\n- Понижение приоритета — согласуй с автором задачи\n\n### При изменении описания:\n- Не удаляй важную информацию\n- Если меняешь суть задачи — лучше создай новую\n\n## Пример обновления:\n\\`\\`\\`\nupdate_issue(issueKey, {\n summary: \"Новый заголовок\",\n priority: { name: \"High\" },\n assignee: { name: \"username\" }\n})\n\\`\\`\\`\n\n## Для поиска пользователей:\n\\`\\`\\`\nget_users(query) // поиск по имени или email\n\\`\\`\\``,\n },\n};\n\nexport class JiraServer {\n public server: Server;\n private jiraApi: JiraApiService;\n\n constructor() {\n this.server = new Server(\n {\n name: \"jira-mcp\",\n version: \"0.3.0\",\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n },\n },\n );\n\n const { JIRA_API_TOKEN, JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_TYPE, JIRA_AUTH_TYPE } = getEnvConfig();\n\n if (JIRA_TYPE === \"server\") {\n this.jiraApi = new JiraServerApiService(\n JIRA_BASE_URL,\n JIRA_USER_EMAIL,\n JIRA_API_TOKEN,\n JIRA_AUTH_TYPE,\n );\n } else {\n this.jiraApi = new JiraApiService(\n JIRA_BASE_URL,\n JIRA_USER_EMAIL,\n JIRA_API_TOKEN,\n JIRA_AUTH_TYPE,\n );\n }\n\n this.setupToolHandlers();\n\n this.server.onerror = (error) => {};\n process.on(\"SIGINT\", async () => {\n await this.server.close();\n process.exit(0);\n });\n }\n\n private setupToolHandlers() {\n // ========================================================================\n // PROMPTS HANDLERS\n // ========================================================================\n\n this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({\n prompts: Object.entries(JIRA_PROMPTS).map(([name, { description }]) => ({\n name,\n description,\n })),\n }));\n\n this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const { name } = request.params;\n const prompt = JIRA_PROMPTS[name];\n\n if (!prompt) {\n throw new McpError(ErrorCode.InvalidParams, `Unknown prompt: ${name}`);\n }\n\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: prompt.content,\n },\n },\n ],\n };\n });\n\n // ========================================================================\n // TOOLS HANDLERS\n // ========================================================================\n\n this.server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: \"search_issues\",\n description: \"Search JIRA issues using JQL\",\n inputSchema: {\n type: \"object\",\n properties: {\n searchString: {\n type: \"string\",\n description: \"JQL search string\",\n },\n },\n required: [\"searchString\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_epic_children\",\n description:\n \"Get all child issues in an epic including their comments\",\n inputSchema: {\n type: \"object\",\n properties: {\n epicKey: {\n type: \"string\",\n description: \"The key of the epic issue\",\n },\n },\n required: [\"epicKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_issue\",\n description:\n \"Get detailed information about a specific JIRA issue including comments\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueId: {\n type: \"string\",\n description: \"The ID or key of the JIRA issue\",\n },\n },\n required: [\"issueId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"create_issue\",\n description: `Create a new JIRA issue.\n\n📋 BEFORE CREATING: Ask user for project, issue type, summary, and description.\nFor bugs: also ask for reproduction steps, expected/actual results.\nUse get_create_meta first to check required fields.\nSee prompt \"create_issue_workflow\" for detailed guidelines.`,\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key where the issue will be created\",\n },\n issueType: {\n type: \"string\",\n description:\n 'The type of issue to create (e.g., \"Bug\", \"Story\", \"Task\")',\n },\n summary: {\n type: \"string\",\n description: \"The issue summary/title\",\n },\n description: {\n type: \"string\",\n description: \"The issue description\",\n },\n fields: {\n type: \"object\",\n description: \"Additional fields to set on the issue\",\n additionalProperties: true,\n },\n },\n required: [\"projectKey\", \"issueType\", \"summary\"],\n additionalProperties: false,\n },\n },\n {\n name: \"update_issue\",\n description: `Update an existing JIRA issue.\n\n📝 When changing assignee or priority, consider adding a comment explaining why.\nSee prompt \"update_issue_workflow\" for guidelines.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to update\",\n },\n fields: {\n type: \"object\",\n description: \"Fields to update on the issue\",\n additionalProperties: true,\n },\n },\n required: [\"issueKey\", \"fields\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_transitions\",\n description: \"Get available status transitions for a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to get transitions for\",\n },\n },\n required: [\"issueKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"transition_issue\",\n description: `Change the status of a JIRA issue by performing a transition.\n\n⚠️ CANCELLATION RULE: When transitioning to \"Отмена\" (Cancel), you MUST first:\n1. Ask user for cancellation reason\n2. Add comment with the reason using add_comment\n3. Only then perform the transition\nSee prompt \"cancel_issue_workflow\" for details.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to transition\",\n },\n transitionId: {\n type: \"string\",\n description: \"The ID of the transition to perform\",\n },\n comment: {\n type: \"string\",\n description: \"Optional comment to add with the transition\",\n },\n },\n required: [\"issueKey\", \"transitionId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"add_attachment\",\n description: \"Add a file attachment to a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to add attachment to\",\n },\n fileContent: {\n type: \"string\",\n description: \"Base64 encoded content of the file\",\n },\n filename: {\n type: \"string\",\n description: \"Name of the file to be attached\",\n },\n },\n required: [\"issueKey\", \"fileContent\", \"filename\"],\n additionalProperties: false,\n },\n },\n {\n name: \"add_comment\",\n description: \"Add a comment to a JIRA issue\",\n inputSchema: {\n type: \"object\",\n properties: {\n issueIdOrKey: {\n type: \"string\",\n description: \"The ID or key of the issue to add the comment to\",\n },\n body: {\n type: \"string\",\n description: \"The content of the comment (plain text)\",\n },\n },\n required: [\"issueIdOrKey\", \"body\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_create_meta\",\n description: \"Get metadata for creating issues in a project, including available issue types and required fields. Use compact=true to get a smaller response with field counts instead of full allowedValues arrays.\",\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key to get creation metadata for\",\n },\n issueTypeName: {\n type: \"string\",\n description: \"Optional: filter to a specific issue type name\",\n },\n compact: {\n type: \"boolean\",\n description: \"If true, returns allowedValuesCount instead of full allowedValues arrays (reduces response size significantly)\",\n },\n },\n required: [\"projectKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_field_options\",\n description: \"Get allowed values for a specific field when creating issues. Use this after get_create_meta with compact=true to fetch options for fields that have allowedValuesCount > 0.\",\n inputSchema: {\n type: \"object\",\n properties: {\n projectKey: {\n type: \"string\",\n description: \"The project key\",\n },\n issueTypeId: {\n type: \"string\",\n description: \"The issue type ID (from get_create_meta response)\",\n },\n fieldId: {\n type: \"string\",\n description: \"The field ID to get allowed values for (e.g., 'components', 'customfield_12405')\",\n },\n },\n required: [\"projectKey\", \"issueTypeId\", \"fieldId\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_server_info\",\n description: \"Get JIRA server information including version and deployment type\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: \"get_projects\",\n description: \"Get all JIRA projects accessible to the current user\",\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: \"get_users\",\n description: \"Search for JIRA users by name or email. Useful for finding assignees.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Search query (name or email)\",\n },\n maxResults: {\n type: \"number\",\n description: \"Maximum number of results to return (default: 50)\",\n },\n },\n required: [\"query\"],\n additionalProperties: false,\n },\n },\n {\n name: \"delete_issue\",\n description: `Delete a JIRA issue permanently.\n\n⚠️ NOTE: Most users don't have delete permissions.\nIf deletion fails, use transition to \"Отмена\" (Cancel) status instead.\nRemember to add a comment with cancellation reason first.`,\n inputSchema: {\n type: \"object\",\n properties: {\n issueKey: {\n type: \"string\",\n description: \"The key of the issue to delete (e.g., IM3-1234)\",\n },\n },\n required: [\"issueKey\"],\n additionalProperties: false,\n },\n },\n {\n name: \"get_attachment\",\n description: \"Download a JIRA attachment by ID. Returns base64 encoded content. Use get_issue first to see available attachments with their IDs.\",\n inputSchema: {\n type: \"object\",\n properties: {\n attachmentId: {\n type: \"string\",\n description: \"The ID of the attachment to download\",\n },\n },\n required: [\"attachmentId\"],\n additionalProperties: false,\n },\n },\n ],\n }));\n\n this.server.setRequestHandler(CallToolRequestSchema, async (request) => {\n try {\n const args = request.params.arguments as Record<string, any>;\n\n switch (request.params.name) {\n case \"search_issues\": {\n if (!args.searchString || typeof args.searchString !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Search string is required\",\n );\n }\n const response = await this.jiraApi.searchIssues(args.searchString);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_epic_children\": {\n if (!args.epicKey || typeof args.epicKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Epic key is required\",\n );\n }\n const response = await this.jiraApi.getEpicChildren(args.epicKey);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_issue\": {\n if (!args.issueId || typeof args.issueId !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Issue ID is required\",\n );\n }\n const response = await this.jiraApi.getIssueWithComments(\n args.issueId,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"create_issue\": {\n // Basic validation\n if (\n !args.projectKey ||\n typeof args.projectKey !== \"string\" ||\n !args.issueType ||\n typeof args.issueType !== \"string\" ||\n !args.summary ||\n typeof args.summary !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey, issueType, and summary are required\",\n );\n }\n const response = await this.jiraApi.createIssue(\n args.projectKey,\n args.issueType,\n args.summary,\n args.description as string | undefined,\n args.fields as Record<string, any> | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"update_issue\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.fields ||\n typeof args.fields !== \"object\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey and fields object are required\",\n );\n }\n await this.jiraApi.updateIssue(args.issueKey, args.fields);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { message: `Issue ${args.issueKey} updated successfully` },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"get_transitions\": {\n if (!args.issueKey || typeof args.issueKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"Issue key is required\",\n );\n }\n const response = await this.jiraApi.getTransitions(args.issueKey);\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"transition_issue\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.transitionId ||\n typeof args.transitionId !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey and transitionId are required\",\n );\n }\n await this.jiraApi.transitionIssue(\n args.issueKey,\n args.transitionId,\n args.comment as string | undefined,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n message: `Issue ${args.issueKey} transitioned successfully${args.comment ? \" with comment\" : \"\"}`,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"add_attachment\": {\n if (\n !args.issueKey ||\n typeof args.issueKey !== \"string\" ||\n !args.fileContent ||\n typeof args.fileContent !== \"string\" ||\n !args.filename ||\n typeof args.filename !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey, fileContent, and filename are required\",\n );\n }\n const fileBuffer = Buffer.from(args.fileContent, \"base64\");\n const result = await this.jiraApi.addAttachment(\n args.issueKey,\n fileBuffer,\n args.filename,\n );\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n message: `File ${args.filename} attached successfully to issue ${args.issueKey}`,\n attachmentId: result.id,\n filename: result.filename,\n },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"add_comment\": {\n if (\n !args.issueIdOrKey ||\n typeof args.issueIdOrKey !== \"string\" ||\n !args.body ||\n typeof args.body !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueIdOrKey and body are required\",\n );\n }\n const response = await this.jiraApi.addCommentToIssue(\n args.issueIdOrKey,\n args.body,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n case \"get_create_meta\": {\n if (!args.projectKey || typeof args.projectKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey is required\",\n );\n }\n const meta = await this.jiraApi.getCreateMeta(\n args.projectKey,\n args.issueTypeName as string | undefined,\n args.compact as boolean | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(meta, null, 2) },\n ],\n };\n }\n case \"get_field_options\": {\n if (\n !args.projectKey ||\n typeof args.projectKey !== \"string\" ||\n !args.issueTypeId ||\n typeof args.issueTypeId !== \"string\" ||\n !args.fieldId ||\n typeof args.fieldId !== \"string\"\n ) {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"projectKey, issueTypeId, and fieldId are required\",\n );\n }\n const options = await this.jiraApi.getFieldOptions(\n args.projectKey,\n args.issueTypeId,\n args.fieldId,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(options, null, 2) },\n ],\n };\n }\n case \"get_server_info\": {\n const serverInfo = await this.jiraApi.getServerInfo();\n return {\n content: [\n { type: \"text\", text: JSON.stringify(serverInfo, null, 2) },\n ],\n };\n }\n case \"get_projects\": {\n const projects = await this.jiraApi.getProjects();\n return {\n content: [\n { type: \"text\", text: JSON.stringify(projects, null, 2) },\n ],\n };\n }\n case \"get_users\": {\n if (!args.query || typeof args.query !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"query is required\",\n );\n }\n const users = await this.jiraApi.getUsers(\n args.query,\n args.maxResults as number | undefined,\n );\n return {\n content: [\n { type: \"text\", text: JSON.stringify(users, null, 2) },\n ],\n };\n }\n case \"delete_issue\": {\n if (!args.issueKey || typeof args.issueKey !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"issueKey is required\",\n );\n }\n await this.jiraApi.deleteIssue(args.issueKey);\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n { message: `Issue ${args.issueKey} deleted successfully` },\n null,\n 2,\n ),\n },\n ],\n };\n }\n case \"get_attachment\": {\n if (!args.attachmentId || typeof args.attachmentId !== \"string\") {\n throw new McpError(\n ErrorCode.InvalidParams,\n \"attachmentId is required\",\n );\n }\n const attachment = await this.jiraApi.getAttachment(args.attachmentId);\n\n // Check if it's an image type that Claude can view\n const isImage = attachment.mimeType.startsWith(\"image/\");\n\n if (isImage) {\n return {\n content: [\n {\n type: \"text\",\n text: `Attachment: ${attachment.filename} (${attachment.mimeType})`,\n },\n {\n type: \"image\",\n data: attachment.content,\n mimeType: attachment.mimeType,\n } as any,\n ],\n };\n }\n\n // For non-image files, return base64 as text\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(attachment, null, 2),\n },\n ],\n };\n }\n default:\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n } catch (error) {\n // Keep generic error handling\n if (error instanceof McpError) {\n throw error;\n }\n throw new McpError(\n ErrorCode.InternalError,\n error instanceof Error ? error.message : \"Unknown error occurred\",\n );\n }\n });\n }\n\n async run() {\n const transport = new StdioServerTransport();\n await this.server.connect(transport);\n // JIRA MCP server running on stdio\n }\n}\n\n// Only run stdio transport when this file is the main entry point\n// When run via npx, argv[1] is the bin name (jira-mcp), not index.js\nconst isMainModule =\n process.argv[1]?.endsWith(\"index.js\") ||\n process.argv[1]?.endsWith(\"index.ts\") ||\n process.argv[1]?.endsWith(\"jira-mcp\");\nif (isMainModule) {\n const server = new JiraServer();\n server.run().catch(() => {});\n}\n"],"names":["JiraApiService","baseUrl","email","apiToken","authType","authHeader","response","url","message","errorData","errorMessages","field","msg","text","content","source","commentId","mentions","processNode","node","match","key","m","comment","body","attachment","issue","description","cleanedIssue","links","link","linkedIssue","relationship","subtask","a","init","searchString","params","data","epicKey","commentsData","comments","commentMentions","issueId","issueData","error","epicData","projectKey","issueType","summary","fields","payload","issueTypeName","compact","issueTypes","it","f","issueTypeId","fieldId","issueKey","transitionId","file","filename","formData","headers","issueIdOrKey","project","query","maxResults","user","attachmentId","metadata","arrayBuffer","JiraServerApiService","path","serverUrl","matches","getEnvConfig","JIRA_API_TOKEN","JIRA_BASE_URL","JIRA_USER_EMAIL","JIRA_TYPE","JIRA_AUTH_TYPE","JIRA_PROMPTS","JiraServer","Server","ListPromptsRequestSchema","name","GetPromptRequestSchema","request","prompt","McpError","ErrorCode","ListToolsRequestSchema","CallToolRequestSchema","args","fileBuffer","result","meta","options","serverInfo","projects","users","transport","StdioServerTransport","isMainModule"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokealvo/jira-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "JIRA MCP Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"build": "vite build && chmod +x build/index.js",
|
|
17
17
|
"start": "node build/index.js",
|
|
18
18
|
"dev": "vite",
|
|
19
|
+
"dev:http": "npx tsx watch src/dev-server.ts",
|
|
19
20
|
"test": "vitest run",
|
|
20
21
|
"test:watch": "vitest"
|
|
21
22
|
},
|