@abdelrahmanhsn/jira-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ {
2
+ "snyk.advanced.autoSelectOrganization": true
3
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@abdelrahmanhsn/jira-mcp",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "description": "MCP server for Jira — query tickets, sprints, and issue details from any AI IDE",
6
+ "main": "server.js",
7
+ "bin": {
8
+ "jira-mcp": "./server.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node server.js"
12
+ },
13
+ "keywords": ["mcp", "jira", "atlassian", "model-context-protocol", "ai"],
14
+ "author": "Abdelrahman Hassan",
15
+ "license": "ISC",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": ""
19
+ },
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.12.1",
25
+ "axios": "^1.15.1"
26
+ }
27
+ }
package/server.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ import axios from "axios";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+
7
+ // ── Jira credentials (injected by MCP client via env) ──────────────────────
8
+ const JIRA_EMAIL = process.env.JIRA_EMAIL;
9
+ const JIRA_TOKEN = process.env.JIRA_TOKEN;
10
+ const JIRA_DOMAIN = process.env.JIRA_DOMAIN;
11
+
12
+ const missing = ["JIRA_EMAIL", "JIRA_TOKEN", "JIRA_DOMAIN"].filter(k => !process.env[k]);
13
+ if (missing.length) {
14
+ process.stderr.write(
15
+ `[jira-mcp] Missing required environment variables: ${missing.join(", ")}\n` +
16
+ `Set them in your MCP client config under the "env" key.\n`
17
+ );
18
+ process.exit(1);
19
+ }
20
+
21
+ const jiraClient = axios.create({
22
+ baseURL: `https://${JIRA_DOMAIN}/rest/api/3`,
23
+ auth: { username: JIRA_EMAIL, password: JIRA_TOKEN },
24
+ });
25
+
26
+ // ── Helper ───────────────────────────────────────────────────────────────────
27
+ async function searchJira(jql, fields = "summary,status,priority,description,issuetype,attachment,reporter") {
28
+ const response = await jiraClient.get("/search/jql", { params: { jql, fields } });
29
+ return (response.data.issues || []).map(i => ({
30
+ key: i.key,
31
+ summary: i.fields?.summary,
32
+ status: i.fields?.status?.name,
33
+ priority: i.fields?.priority?.name,
34
+ type: i.fields?.issuetype?.name,
35
+ reporter: i.fields?.reporter?.displayName,
36
+ description: JSON.stringify(i.fields?.description),
37
+ attachments: (i.fields?.attachment || []).map(a => a.content),
38
+ }));
39
+ }
40
+
41
+ // ── MCP Server ───────────────────────────────────────────────────────────────
42
+ const server = new McpServer({
43
+ name: "jira-mcp",
44
+ version: "1.0.0",
45
+ });
46
+
47
+ // Tool: get_my_tickets
48
+ server.tool(
49
+ "get_my_tickets",
50
+ "Get all Jira tickets assigned to the current user",
51
+ {},
52
+ async () => {
53
+ const result = await searchJira("assignee = currentUser() ORDER BY updated DESC");
54
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
55
+ }
56
+ );
57
+
58
+ // Tool: get_active_sprint_tickets
59
+ server.tool(
60
+ "get_active_sprint_tickets",
61
+ "Get user tickets in the active sprint of the Core Team board (STUD project)",
62
+ {},
63
+ async () => {
64
+ const result = await searchJira(
65
+ "project = 'STUD' AND sprint IN openSprints() AND assignee = currentUser()"
66
+ );
67
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
68
+ }
69
+ );
70
+
71
+ // Tool: get_issue_details
72
+ server.tool(
73
+ "get_issue_details",
74
+ "Get full details (description + attachments) for a specific Jira issue",
75
+ { issueKey: z.string().describe("The Jira issue key, e.g. STUD-17797") },
76
+ async ({ issueKey }) => {
77
+ const response = await jiraClient.get(`/issue/${issueKey}`);
78
+ return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
79
+ }
80
+ );
81
+
82
+ // ── Start ────────────────────────────────────────────────────────────────────
83
+ const transport = new StdioServerTransport();
84
+ await server.connect(transport);