org-jira-mcp-adapter 1.1.0 → 1.2.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,64 @@
1
+ import { JiraService } from './jira-service.js';
2
+ import * as process from 'node:process';
3
+
4
+ const JIRA_HOST = 'jira.tech.shopstat.ru';
5
+ const JIRA_TOKEN = process.argv[2];
6
+
7
+ if (!JIRA_TOKEN) {
8
+ console.error('Please provide Jira API Token as argument: node cleanup_ot_690.js <TOKEN>');
9
+ process.exit(1);
10
+ }
11
+
12
+ // Clean host for constructor if needed, but JiraService handles it.
13
+ // Passing JIRA_HOST and JIRA_TOKEN.
14
+ const service = new JiraService(JIRA_HOST, JIRA_TOKEN);
15
+ const issueKey = 'OT-690';
16
+
17
+ async function main() {
18
+ console.log(`Starting cleanup for ${issueKey}...`);
19
+
20
+ // 1. Delete Worklogs
21
+ try {
22
+ console.log('Fetching worklogs...');
23
+ const worklogsData = await service.getIssueWorklogs(issueKey);
24
+ // handle both array or object with worklogs property
25
+ const worklogs = Array.isArray(worklogsData) ? worklogsData : (worklogsData.worklogs || []);
26
+
27
+ console.log(`Found ${worklogs.length} worklogs.`);
28
+
29
+ for (const w of worklogs) {
30
+ console.log(`Deleting worklog ${w.id}...`);
31
+ await service.deleteWorklog(issueKey, w.id);
32
+ console.log(`Deleted worklog ${w.id}`);
33
+ }
34
+ } catch (e) {
35
+ console.error('Error handling worklogs:', e.message);
36
+ if (e.response) {
37
+ console.error('Response data:', e.response.data);
38
+ }
39
+ }
40
+
41
+ // 2. Delete Comments
42
+ try {
43
+ console.log('Fetching comments...');
44
+ const commentsData = await service.getIssueComments(issueKey);
45
+ const comments = Array.isArray(commentsData) ? commentsData : (commentsData.comments || []);
46
+
47
+ console.log(`Found ${comments.length} comments.`);
48
+
49
+ for (const c of comments) {
50
+ console.log(`Deleting comment ${c.id}...`);
51
+ await service.deleteComment(issueKey, c.id);
52
+ console.log(`Deleted comment ${c.id}`);
53
+ }
54
+ } catch (e) {
55
+ console.error('Error handling comments:', e.message);
56
+ if (e.response) {
57
+ console.error('Response data:', e.response.data);
58
+ }
59
+ }
60
+
61
+ console.log('Cleanup complete.');
62
+ }
63
+
64
+ main();
package/index.js CHANGED
@@ -59,6 +59,36 @@ server.tool("jira_transitionIssue", `Perform a transition on a JIRA issue in the
59
59
  return formatToolResponse(result);
60
60
  });
61
61
 
62
+ server.tool("jira_getVotes", `Get votes for a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.getVotes, async ({ issueKey }) => {
63
+ const result = await jiraService.getVotes(issueKey);
64
+ return formatToolResponse(result);
65
+ });
66
+
67
+ server.tool("jira_addVote", `Add vote to a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.addVote, async ({ issueKey }) => {
68
+ const result = await jiraService.addVote(issueKey);
69
+ return formatToolResponse(result);
70
+ });
71
+
72
+ server.tool("jira_removeVote", `Remove vote from a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.removeVote, async ({ issueKey }) => {
73
+ const result = await jiraService.removeVote(issueKey);
74
+ return formatToolResponse(result);
75
+ });
76
+
77
+ server.tool("jira_getIssueWatchers", `Get watchers for a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.getIssueWatchers, async ({ issueKey }) => {
78
+ const result = await jiraService.getIssueWatchers(issueKey);
79
+ return formatToolResponse(result);
80
+ });
81
+
82
+ server.tool("jira_addWatcher", `Add watcher to a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.addWatcher, async ({ issueKey, username }) => {
83
+ const result = await jiraService.addWatcher(issueKey, username);
84
+ return formatToolResponse(result);
85
+ });
86
+
87
+ server.tool("jira_removeWatcher", `Remove watcher from a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.removeWatcher, async ({ issueKey, username }) => {
88
+ const result = await jiraService.removeWatcher(issueKey, username);
89
+ return formatToolResponse(result);
90
+ });
91
+
62
92
  server.tool("jira_addWorklog", `Add a worklog entry to a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.addWorklog, async ({ issueKey, timeSpent, comment, started }) => {
63
93
  const result = await jiraService.addWorklog(issueKey, timeSpent, comment, started);
64
94
  return formatToolResponse(result);
@@ -69,6 +99,16 @@ server.tool("jira_getIssueWorklogs", `Get worklogs for a JIRA issue in the ${jir
69
99
  return formatToolResponse(result);
70
100
  });
71
101
 
102
+ server.tool("jira_deleteWorklog", `Delete a worklog from a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.deleteWorklog, async ({ issueKey, worklogId }) => {
103
+ const result = await jiraService.deleteWorklog(issueKey, worklogId);
104
+ return formatToolResponse(result);
105
+ });
106
+
107
+ server.tool("jira_deleteComment", `Delete a comment from a JIRA issue in the ${jiraInstanceType}`, jiraToolSchemas.deleteComment, async ({ issueKey, commentId }) => {
108
+ const result = await jiraService.deleteComment(issueKey, commentId);
109
+ return formatToolResponse(result);
110
+ });
111
+
72
112
  server.tool("jira_getAllProjects", `Get all visible projects in the ${jiraInstanceType}`, jiraToolSchemas.getAllProjects, async ({ recent }) => {
73
113
  const result = await jiraService.getAllProjects(recent);
74
114
  return formatToolResponse(result);
package/jira-service.js CHANGED
@@ -75,6 +75,61 @@ export class JiraService {
75
75
  }, 'Error updating issue');
76
76
  }
77
77
 
78
+ async getTransitions(issueKey) {
79
+ return handleApiOperation(() => IssueService.getTransitions(issueKey), 'Error getting transitions');
80
+ }
81
+
82
+ async transitionIssue(issueKey, transitionId, comment) {
83
+ return handleApiOperation(() => {
84
+ const body = {
85
+ transition: { id: transitionId }
86
+ };
87
+ if (comment) {
88
+ body.update = {
89
+ comment: [{
90
+ add: { body: comment }
91
+ }]
92
+ };
93
+ }
94
+ return IssueService.doTransition(issueKey, body);
95
+ }, 'Error transitioning issue');
96
+ }
97
+
98
+ async addWorklog(issueKey, timeSpent, comment, started) {
99
+ return handleApiOperation(() => {
100
+ const body = {
101
+ timeSpent,
102
+ comment,
103
+ started: started || new Date().toISOString().replace('Z', '+0000')
104
+ };
105
+ return IssueService.addWorklog(issueKey, undefined, undefined, undefined, body);
106
+ }, 'Error adding worklog');
107
+ }
108
+
109
+ async getIssueWorklogs(issueKey) {
110
+ return handleApiOperation(() => IssueService.getIssueWorklog(issueKey), 'Error getting worklogs');
111
+ }
112
+
113
+ async deleteWorklog(issueKey, worklogId) {
114
+ return handleApiOperation(() => IssueService.deleteWorklog(issueKey, worklogId), 'Error deleting worklog');
115
+ }
116
+
117
+ async deleteComment(issueKey, commentId) {
118
+ return handleApiOperation(() => IssueService.deleteComment(issueKey, commentId), 'Error deleting comment');
119
+ }
120
+
121
+ async getAllProjects(recent = false) {
122
+ return handleApiOperation(() => ProjectService.getAllProjects(undefined, undefined, recent ? true : undefined, undefined), 'Error getting projects');
123
+ }
124
+
125
+ async getCurrentUser() {
126
+ return handleApiOperation(() => MyselfService.getUser(), 'Error getting current user');
127
+ }
128
+
129
+ async findUsers(query, maxResults = 10) {
130
+ return handleApiOperation(() => GroupuserpickerService.findUsersAndGroups(undefined, maxResults, query, undefined, undefined, undefined), 'Error finding users');
131
+ }
132
+
78
133
  static validateConfig() {
79
134
  const requiredEnvVars = ['JIRA_API_TOKEN'];
80
135
  const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);
@@ -99,23 +154,51 @@ export const jiraToolSchemas = {
99
154
  expand: z.string().optional().describe("Comma separated fields to expand")
100
155
  },
101
156
  getTransitions: {
102
- issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
103
- },
104
- transitionIssue: {
105
- issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
106
- transitionId: z.string().describe("Transition ID to perform"),
107
- comment: z.string().optional().describe("Comment to add with transition")
108
- },
109
- addWorklog: {
157
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
158
+ },
159
+ transitionIssue: {
160
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
161
+ transitionId: z.string().describe("Transition ID to perform"),
162
+ comment: z.string().optional().describe("Comment to add with transition")
163
+ },
164
+ getVotes: {
165
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
166
+ },
167
+ addVote: {
168
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
169
+ },
170
+ removeVote: {
171
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
172
+ },
173
+ getIssueWatchers: {
174
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
175
+ },
176
+ addWatcher: {
177
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
178
+ username: z.string().optional().describe("Username to add as watcher (defaults to current user)")
179
+ },
180
+ removeWatcher: {
181
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
182
+ username: z.string().describe("Username to remove from watchers")
183
+ },
184
+ addWorklog: {
110
185
  issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
111
186
  timeSpent: z.string().describe("Time spent (e.g. 1h 30m)"),
112
187
  comment: z.string().optional().describe("Worklog comment"),
113
188
  started: z.string().optional().describe("Start time (ISO 8601 string), defaults to now")
114
189
  },
115
190
  getIssueWorklogs: {
116
- issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
117
- },
118
- getAllProjects: {
191
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)")
192
+ },
193
+ deleteWorklog: {
194
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
195
+ worklogId: z.string().describe("ID of the worklog to delete")
196
+ },
197
+ deleteComment: {
198
+ issueKey: z.string().describe("JIRA issue key (e.g., PROJ-123)"),
199
+ commentId: z.string().describe("ID of the comment to delete")
200
+ },
201
+ getAllProjects: {
119
202
  recent: z.boolean().optional().describe("Return only recent projects")
120
203
  },
121
204
  getCurrentUser: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "org-jira-mcp-adapter",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for Jira Data Center/Server (On-Premise)",
5
5
  "type": "module",
6
6
  "main": "index.js",