@ecubelabs/atlassian-mcp 1.2.0-next.4 → 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.
package/dist/index.js CHANGED
@@ -1,38 +1,38 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { z } from "zod";
5
- import { JiraService } from "./libs/jira-client.js";
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ import { JiraService } from './libs/jira-client.js';
6
6
  // Create server instance
7
7
  const server = new McpServer({
8
- name: "jira",
9
- version: "1.0.0",
8
+ name: 'jira',
9
+ version: '1.0.0',
10
10
  });
11
11
  // Initialize Jira service
12
12
  const jiraService = new JiraService();
13
13
  // Register Jira tools
14
- server.tool("get-issue", "Get details of a Jira issue by key", {
15
- issueKey: z.string().describe("Jira issue key (e.g. PROJ-123)"),
14
+ server.tool('get-issue', 'Get details of a Jira issue by key', {
15
+ issueKey: z.string().describe('Jira issue key (e.g. PROJ-123)'),
16
16
  expand: z
17
17
  .enum([
18
- "renderedFields",
19
- "names",
20
- "schema",
21
- "transitions",
22
- "editmeta",
23
- "changelog",
24
- "versionedRepresentations",
18
+ 'renderedFields',
19
+ 'names',
20
+ 'schema',
21
+ 'transitions',
22
+ 'editmeta',
23
+ 'changelog',
24
+ 'versionedRepresentations',
25
25
  ])
26
26
  .array()
27
27
  .optional()
28
- .describe("Optional fields to expand in the response"),
28
+ .describe('Optional fields to expand in the response. Options include: renderedFields (HTML format), names (display names), schema (field type descriptions), transitions (possible transitions), editmeta (field editing info), changelog (recent updates), versionedRepresentations (field value history)'),
29
29
  }, async ({ issueKey, expand }) => {
30
30
  try {
31
31
  const issue = await jiraService.getIssue(issueKey, expand);
32
32
  return {
33
33
  content: [
34
34
  {
35
- type: "text",
35
+ type: 'text',
36
36
  text: JSON.stringify(issue),
37
37
  },
38
38
  ],
@@ -42,36 +42,58 @@ server.tool("get-issue", "Get details of a Jira issue by key", {
42
42
  return {
43
43
  content: [
44
44
  {
45
- type: "text",
45
+ type: 'text',
46
46
  text: `Failed to retrieve issue: ${error instanceof Error ? error.message : String(error)}`,
47
47
  },
48
48
  ],
49
49
  };
50
50
  }
51
51
  });
52
- server.tool("search-issues", "Search Jira issues using JQL", {
53
- jql: z.string().describe("JQL query string"),
54
- fields: z.array(z.string()).optional().describe("Fields to include"),
55
- maxResults: z.number().min(1).max(5000).optional().describe("Max results"),
56
- nextPageToken: z.string().optional().describe("Next page token"),
52
+ server.tool('search-issues', 'Search Jira issues using JQL', {
53
+ jql: z.string().describe('JQL query string. Must be a bounded query with search restrictions.'),
54
+ fields: z
55
+ .array(z.string())
56
+ .optional()
57
+ .describe("Optional fields to include in the response. Examples: ['summary', 'comment'] or ['*all', '-comment']"),
58
+ maxResults: z
59
+ .number()
60
+ .min(1)
61
+ .max(5000)
62
+ .optional()
63
+ .describe('Maximum number of results to return per page (default: 50, max: 5000)'),
64
+ nextPageToken: z
65
+ .string()
66
+ .optional()
67
+ .describe('Token for fetching the next page of results. The first page has null nextPageToken.'),
57
68
  expand: z
58
69
  .enum([
59
- "renderedFields",
60
- "names",
61
- "schema",
62
- "transitions",
63
- "editmeta",
64
- "changelog",
65
- "versionedRepresentations",
70
+ 'renderedFields',
71
+ 'names',
72
+ 'schema',
73
+ 'transitions',
74
+ 'editmeta',
75
+ 'changelog',
76
+ 'versionedRepresentations',
66
77
  ])
67
78
  .array()
68
79
  .optional()
69
- .describe("Fields to expand"),
70
- properties: z.array(z.string()).max(5).optional().describe("Properties to include"),
71
- fieldsByKeys: z.boolean().optional().describe("Use field keys"),
72
- failFast: z.boolean().optional().describe("Fail fast mode"),
73
- reconcileIssues: z.array(z.number()).max(50).optional().describe("Issue IDs to reconcile"),
74
- }, async ({ jql, fields, maxResults, nextPageToken, expand, properties, fieldsByKeys, failFast, reconcileIssues, }) => {
80
+ .describe('Comma-separated values to expand in response: renderedFields, names, schema, transitions, operations, editmeta, changelog, versionedRepresentations'),
81
+ properties: z
82
+ .array(z.string())
83
+ .max(5)
84
+ .optional()
85
+ .describe('List of up to 5 issue properties to include in results'),
86
+ fieldsByKeys: z.boolean().optional().describe('Reference fields by their key rather than ID (default: false)'),
87
+ failFast: z
88
+ .boolean()
89
+ .optional()
90
+ .describe("Fail request early if we can't retrieve all field data (default: false)"),
91
+ reconcileIssues: z
92
+ .array(z.number())
93
+ .max(50)
94
+ .optional()
95
+ .describe('Strong consistency issue IDs to be reconciled with search results (max: 50 IDs)'),
96
+ }, async ({ jql, fields, maxResults, nextPageToken, expand, properties, fieldsByKeys, failFast, reconcileIssues }) => {
75
97
  try {
76
98
  const result = await jiraService.searchIssues({
77
99
  jql,
@@ -87,7 +109,7 @@ server.tool("search-issues", "Search Jira issues using JQL", {
87
109
  return {
88
110
  content: [
89
111
  {
90
- type: "text",
112
+ type: 'text',
91
113
  text: JSON.stringify(result),
92
114
  },
93
115
  ],
@@ -97,19 +119,29 @@ server.tool("search-issues", "Search Jira issues using JQL", {
97
119
  return {
98
120
  content: [
99
121
  {
100
- type: "text",
122
+ type: 'text',
101
123
  text: `Failed to search issues: ${error instanceof Error ? error.message : String(error)}`,
102
124
  },
103
125
  ],
104
126
  };
105
127
  }
106
128
  });
107
- server.tool("get-comments", "Get comments for a Jira issue", {
108
- issueKey: z.string().describe("Jira issue key (e.g. PROJ-123)"),
109
- startAt: z.number().min(0).optional().describe("Page offset"),
110
- maxResults: z.number().min(1).max(100).optional().describe("Max results"),
111
- orderBy: z.enum(["created", "-created", "+created"]).optional().describe("Order by"),
112
- expand: z.array(z.enum(["renderedBody"])).optional().describe("Fields to expand"),
129
+ server.tool('get-comments', 'Get comments for a Jira issue', {
130
+ issueKey: z.string().describe('Jira issue key (e.g. PROJ-123)'),
131
+ startAt: z
132
+ .number()
133
+ .min(0)
134
+ .optional()
135
+ .describe('The index of the first item to return (page offset). Default: 0'),
136
+ maxResults: z.number().min(1).max(100).optional().describe('Maximum number of items per page. Default: 100'),
137
+ orderBy: z
138
+ .enum(['created', '-created', '+created'])
139
+ .optional()
140
+ .describe('Order comments by creation date. Default: created'),
141
+ expand: z
142
+ .array(z.enum(['renderedBody']))
143
+ .optional()
144
+ .describe('Include additional information: renderedBody (comment body in HTML format)'),
113
145
  }, async ({ issueKey, startAt, maxResults, orderBy, expand }) => {
114
146
  try {
115
147
  const result = await jiraService.getComments(issueKey, {
@@ -121,7 +153,7 @@ server.tool("get-comments", "Get comments for a Jira issue", {
121
153
  return {
122
154
  content: [
123
155
  {
124
- type: "text",
156
+ type: 'text',
125
157
  text: JSON.stringify(result),
126
158
  },
127
159
  ],
@@ -131,38 +163,75 @@ server.tool("get-comments", "Get comments for a Jira issue", {
131
163
  return {
132
164
  content: [
133
165
  {
134
- type: "text",
166
+ type: 'text',
135
167
  text: `Failed to retrieve comments: ${error instanceof Error ? error.message : String(error)}`,
136
168
  },
137
169
  ],
138
170
  };
139
171
  }
140
172
  });
141
- server.tool("get-projects", "Get list of Jira projects", {
142
- startAt: z.number().min(0).optional().describe("Page offset"),
143
- maxResults: z.number().min(1).max(100).optional().describe("Max results"),
173
+ server.tool('get-projects', 'Get list of Jira projects', {
174
+ startAt: z
175
+ .number()
176
+ .min(0)
177
+ .optional()
178
+ .describe('The index of the first item to return (page offset). Default: 0'),
179
+ maxResults: z
180
+ .number()
181
+ .min(1)
182
+ .max(100)
183
+ .optional()
184
+ .describe('Maximum number of items per page. Default: 50, Maximum: 100'),
144
185
  orderBy: z
145
186
  .enum([
146
- "category", "-category", "+category",
147
- "key", "-key", "+key",
148
- "name", "-name", "+name",
149
- "owner", "-owner", "+owner",
150
- "issueCount", "-issueCount", "+issueCount",
151
- "lastIssueUpdatedTime", "-lastIssueUpdatedTime", "+lastIssueUpdatedTime",
152
- "archivedDate", "-archivedDate", "+archivedDate",
153
- "deletedDate", "-deletedDate", "+deletedDate"
187
+ 'category',
188
+ '-category',
189
+ '+category',
190
+ 'key',
191
+ '-key',
192
+ '+key',
193
+ 'name',
194
+ '-name',
195
+ '+name',
196
+ 'owner',
197
+ '-owner',
198
+ '+owner',
199
+ 'issueCount',
200
+ '-issueCount',
201
+ '+issueCount',
202
+ 'lastIssueUpdatedTime',
203
+ '-lastIssueUpdatedTime',
204
+ '+lastIssueUpdatedTime',
205
+ 'archivedDate',
206
+ '-archivedDate',
207
+ '+archivedDate',
208
+ 'deletedDate',
209
+ '-deletedDate',
210
+ '+deletedDate',
154
211
  ])
155
212
  .optional()
156
- .describe("Sort order"),
157
- id: z.array(z.number().int()).max(50).optional().describe("Project IDs"),
158
- keys: z.array(z.string()).max(50).optional().describe("Project keys"),
159
- query: z.string().optional().describe("Search query"),
160
- typeKey: z.string().optional().describe("Project type"),
161
- categoryId: z.number().int().optional().describe("Category ID"),
162
- action: z.enum(["view", "browse", "edit", "create"]).optional().describe("Permission filter"),
163
- expand: z.array(z.enum(["description", "projectKeys", "lead", "issueTypes", "url", "insight"])).optional().describe("Fields to expand"),
164
- status: z.array(z.enum(["live", "archived", "deleted"])).optional().describe("Status filter"),
165
- }, async ({ startAt, maxResults, orderBy, id, keys, query, typeKey, categoryId, action, expand, status, }) => {
213
+ .describe('Field to order results by. Default: key'),
214
+ id: z.array(z.number().int()).max(50).optional().describe('Filter by project IDs. Maximum: 50 IDs'),
215
+ keys: z.array(z.string()).max(50).optional().describe('Filter by project keys. Maximum: 50 keys'),
216
+ query: z.string().optional().describe('Filter by matching key or name (case insensitive)'),
217
+ typeKey: z
218
+ .string()
219
+ .optional()
220
+ .describe('Filter by project type. Accepts comma-separated list: business, service_desk, software'),
221
+ categoryId: z.number().int().optional().describe('Filter by project category ID'),
222
+ action: z
223
+ .enum(['view', 'browse', 'edit', 'create'])
224
+ .optional()
225
+ .describe("Filter by user's project permissions. Default: view"),
226
+ expand: z
227
+ .array(z.enum(['description', 'projectKeys', 'lead', 'issueTypes', 'url', 'insight']))
228
+ .optional()
229
+ .describe('Additional fields to include: description, projectKeys, lead, issueTypes, url, insight'),
230
+ status: z
231
+ .array(z.enum(['live', 'archived', 'deleted']))
232
+ .optional()
233
+ .describe('EXPERIMENTAL. Filter by project status'),
234
+ }, async ({ startAt, maxResults, orderBy, id, keys, query, typeKey, categoryId, action, expand, status }) => {
166
235
  try {
167
236
  const result = await jiraService.getProjects({
168
237
  startAt,
@@ -180,7 +249,7 @@ server.tool("get-projects", "Get list of Jira projects", {
180
249
  return {
181
250
  content: [
182
251
  {
183
- type: "text",
252
+ type: 'text',
184
253
  text: JSON.stringify(result),
185
254
  },
186
255
  ],
@@ -190,24 +259,22 @@ server.tool("get-projects", "Get list of Jira projects", {
190
259
  return {
191
260
  content: [
192
261
  {
193
- type: "text",
262
+ type: 'text',
194
263
  text: `Failed to retrieve projects: ${error instanceof Error ? error.message : String(error)}`,
195
264
  },
196
265
  ],
197
266
  };
198
267
  }
199
268
  });
200
- server.tool("get-create-metadata-issue-types", "Get issue types available for creating issues in a project", {
201
- projectIdOrKey: z
202
- .string()
203
- .describe("Project ID (numeric) or project key (e.g. PROJ)"),
269
+ server.tool('get-create-metadata-issue-types', 'Get issue types available for creating issues in a project', {
270
+ projectIdOrKey: z.string().describe('Project ID (numeric) or project key (e.g. PROJ)'),
204
271
  }, async ({ projectIdOrKey }) => {
205
272
  try {
206
273
  const result = await jiraService.getCreateMetadataIssueTypes(projectIdOrKey);
207
274
  return {
208
275
  content: [
209
276
  {
210
- type: "text",
277
+ type: 'text',
211
278
  text: JSON.stringify(result),
212
279
  },
213
280
  ],
@@ -217,25 +284,23 @@ server.tool("get-create-metadata-issue-types", "Get issue types available for cr
217
284
  return {
218
285
  content: [
219
286
  {
220
- type: "text",
287
+ type: 'text',
221
288
  text: `Failed to retrieve issue types: ${error instanceof Error ? error.message : String(error)}`,
222
289
  },
223
290
  ],
224
291
  };
225
292
  }
226
293
  });
227
- server.tool("get-create-field-metadata", "Get create field metadata for a project and issue type id", {
228
- projectIdOrKey: z
229
- .string()
230
- .describe("Project ID (numeric) or project key (e.g. PROJ)"),
231
- issueTypeId: z.string().describe("Issue type ID"),
294
+ server.tool('get-create-field-metadata', 'Get create field metadata for a project and issue type id', {
295
+ projectIdOrKey: z.string().describe('Project ID (numeric) or project key (e.g. PROJ)'),
296
+ issueTypeId: z.string().describe('Issue type ID'),
232
297
  }, async ({ projectIdOrKey, issueTypeId }) => {
233
298
  try {
234
299
  const result = await jiraService.getCreateFieldMetadata(projectIdOrKey, issueTypeId);
235
300
  return {
236
301
  content: [
237
302
  {
238
- type: "text",
303
+ type: 'text',
239
304
  text: JSON.stringify(result),
240
305
  },
241
306
  ],
@@ -245,34 +310,19 @@ server.tool("get-create-field-metadata", "Get create field metadata for a projec
245
310
  return {
246
311
  content: [
247
312
  {
248
- type: "text",
313
+ type: 'text',
249
314
  text: `Failed to retrieve field metadata: ${error instanceof Error ? error.message : String(error)}`,
250
315
  },
251
316
  ],
252
317
  };
253
318
  }
254
319
  });
255
- server.tool("get-fields", "Get Jira fields (optionally search/paginate)", {
256
- type: z
257
- .enum(["all", "custom", "system"])
258
- .optional()
259
- .describe("Field type to filter"),
260
- query: z.string().optional().describe("Search string to filter fields"),
261
- orderBy: z
262
- .enum(["name", "-name"])
263
- .optional()
264
- .describe("Order results by name ascending/descending"),
265
- startAt: z
266
- .number()
267
- .min(0)
268
- .optional()
269
- .describe("Index of the first item to return"),
270
- maxResults: z
271
- .number()
272
- .min(1)
273
- .max(1000)
274
- .optional()
275
- .describe("Max number of items to return"),
320
+ server.tool('get-fields', 'Get Jira fields (optionally search/paginate)', {
321
+ type: z.enum(['all', 'custom', 'system']).optional().describe('Field type to filter'),
322
+ query: z.string().optional().describe('Search string to filter fields'),
323
+ orderBy: z.enum(['name', '-name']).optional().describe('Order results by name ascending/descending'),
324
+ startAt: z.number().min(0).optional().describe('Index of the first item to return'),
325
+ maxResults: z.number().min(1).max(1000).optional().describe('Max number of items to return'),
276
326
  }, async ({ type, query, orderBy, startAt, maxResults }) => {
277
327
  try {
278
328
  const result = await jiraService.getFields({
@@ -285,7 +335,7 @@ server.tool("get-fields", "Get Jira fields (optionally search/paginate)", {
285
335
  return {
286
336
  content: [
287
337
  {
288
- type: "text",
338
+ type: 'text',
289
339
  text: JSON.stringify(result),
290
340
  },
291
341
  ],
@@ -295,26 +345,23 @@ server.tool("get-fields", "Get Jira fields (optionally search/paginate)", {
295
345
  return {
296
346
  content: [
297
347
  {
298
- type: "text",
348
+ type: 'text',
299
349
  text: `Failed to retrieve fields: ${error instanceof Error ? error.message : String(error)}`,
300
350
  },
301
351
  ],
302
352
  };
303
353
  }
304
354
  });
305
- server.tool("parse-jql", "Parse a JQL query and return its AST", {
306
- query: z.string().describe("JQL query to parse"),
307
- validation: z
308
- .enum(["strict", "warn"])
309
- .optional()
310
- .describe("Validation level during parse (default: strict)"),
355
+ server.tool('parse-jql', 'Parse a JQL query and return its AST', {
356
+ query: z.string().describe('JQL query to parse'),
357
+ validation: z.enum(['strict', 'warn']).optional().describe('Validation level during parse (default: strict)'),
311
358
  }, async ({ query, validation }) => {
312
359
  try {
313
360
  const result = await jiraService.parseJql(query, validation);
314
361
  return {
315
362
  content: [
316
363
  {
317
- type: "text",
364
+ type: 'text',
318
365
  text: JSON.stringify(result),
319
366
  },
320
367
  ],
@@ -324,36 +371,27 @@ server.tool("parse-jql", "Parse a JQL query and return its AST", {
324
371
  return {
325
372
  content: [
326
373
  {
327
- type: "text",
374
+ type: 'text',
328
375
  text: `Failed to parse JQL: ${error instanceof Error ? error.message : String(error)}`,
329
376
  },
330
377
  ],
331
378
  };
332
379
  }
333
380
  });
334
- server.tool("create-issue", "Create a new Jira issue", {
335
- projectKey: z.string().describe("Project key (e.g. PROJ)"),
336
- summary: z.string().describe("Issue summary"),
337
- issueTypeId: z.string().optional().describe("Issue type ID"),
338
- issueTypeName: z.string().optional().describe("Issue type name"),
339
- description: z
340
- .string()
341
- .optional()
342
- .describe("Issue description (plain text)"),
343
- assigneeAccountId: z
344
- .string()
345
- .optional()
346
- .describe("Assignee accountId (Jira Cloud)"),
381
+ server.tool('create-issue', 'Create a new Jira issue', {
382
+ projectKey: z.string().describe('Project key (e.g. PROJ)'),
383
+ summary: z.string().describe('Issue summary'),
384
+ issueTypeId: z.string().optional().describe('Issue type ID'),
385
+ issueTypeName: z.string().optional().describe('Issue type name'),
386
+ description: z.string().optional().describe('Issue description (plain text)'),
387
+ assigneeAccountId: z.string().optional().describe('Assignee accountId (Jira Cloud)'),
347
388
  reporterAccountId: z
348
389
  .string()
349
390
  .optional()
350
- .describe("Reporter accountId. If omitted, server attempts to use current user when allowed"),
351
- priorityId: z.string().optional().describe("Priority ID"),
352
- labels: z.array(z.string()).optional().describe("Labels to apply"),
353
- additionalFields: z
354
- .record(z.any())
355
- .optional()
356
- .describe("Additional raw Jira fields to include under fields"),
391
+ .describe('Reporter accountId. If omitted, server attempts to use current user when allowed'),
392
+ priorityId: z.string().optional().describe('Priority ID'),
393
+ labels: z.array(z.string()).optional().describe('Labels to apply'),
394
+ additionalFields: z.record(z.any()).optional().describe('Additional raw Jira fields to include under fields'),
357
395
  }, async ({ projectKey, summary, issueTypeId, issueTypeName, description, assigneeAccountId, reporterAccountId, priorityId, labels, additionalFields, }) => {
358
396
  try {
359
397
  const issue = await jiraService.createIssue({
@@ -371,7 +409,7 @@ server.tool("create-issue", "Create a new Jira issue", {
371
409
  return {
372
410
  content: [
373
411
  {
374
- type: "text",
412
+ type: 'text',
375
413
  text: JSON.stringify(issue),
376
414
  },
377
415
  ],
@@ -381,23 +419,17 @@ server.tool("create-issue", "Create a new Jira issue", {
381
419
  return {
382
420
  content: [
383
421
  {
384
- type: "text",
422
+ type: 'text',
385
423
  text: `Failed to create issue: ${error instanceof Error ? error.message : String(error)}`,
386
424
  },
387
425
  ],
388
426
  };
389
427
  }
390
428
  });
391
- server.tool("assign-issue", "Assign or unassign a Jira issue", {
392
- issueKey: z.string().describe("Jira issue key (e.g. PROJ-123)"),
393
- assigneeAccountId: z
394
- .string()
395
- .optional()
396
- .describe("AccountId of assignee. Omit if unassigning."),
397
- unassign: z
398
- .boolean()
399
- .optional()
400
- .describe("Set true to remove current assignee"),
429
+ server.tool('assign-issue', 'Assign or unassign a Jira issue', {
430
+ issueKey: z.string().describe('Jira issue key (e.g. PROJ-123)'),
431
+ assigneeAccountId: z.string().optional().describe('AccountId of assignee. Omit if unassigning.'),
432
+ unassign: z.boolean().optional().describe('Set true to remove current assignee'),
401
433
  }, async ({ issueKey, assigneeAccountId, unassign }) => {
402
434
  try {
403
435
  if (unassign) {
@@ -409,8 +441,8 @@ server.tool("assign-issue", "Assign or unassign a Jira issue", {
409
441
  return {
410
442
  content: [
411
443
  {
412
- type: "text",
413
- text: "Issue assigned successfully",
444
+ type: 'text',
445
+ text: 'Issue assigned successfully',
414
446
  },
415
447
  ],
416
448
  };
@@ -419,31 +451,22 @@ server.tool("assign-issue", "Assign or unassign a Jira issue", {
419
451
  return {
420
452
  content: [
421
453
  {
422
- type: "text",
454
+ type: 'text',
423
455
  text: `Failed to assign issue: ${error instanceof Error ? error.message : String(error)}`,
424
456
  },
425
457
  ],
426
458
  };
427
459
  }
428
460
  });
429
- server.tool("edit-issue", "Edit fields on a Jira issue", {
430
- issueKey: z.string().describe("Jira issue key (e.g. PROJ-123)"),
431
- summary: z.string().optional().describe("New summary"),
432
- description: z.string().optional().describe("New description (plain text)"),
433
- assigneeAccountId: z
434
- .string()
435
- .optional()
436
- .describe("New assignee accountId. Use with unassignAssignee=false"),
437
- unassignAssignee: z
438
- .boolean()
439
- .optional()
440
- .describe("Set true to remove current assignee"),
441
- priorityId: z.string().optional().describe("New priority ID"),
442
- labels: z.array(z.string()).optional().describe("Replace labels"),
443
- additionalFields: z
444
- .record(z.any())
445
- .optional()
446
- .describe("Additional raw fields to include under fields"),
461
+ server.tool('edit-issue', 'Edit fields on a Jira issue', {
462
+ issueKey: z.string().describe('Jira issue key (e.g. PROJ-123)'),
463
+ summary: z.string().optional().describe('New summary'),
464
+ description: z.string().optional().describe('New description (plain text)'),
465
+ assigneeAccountId: z.string().optional().describe('New assignee accountId. Use with unassignAssignee=false'),
466
+ unassignAssignee: z.boolean().optional().describe('Set true to remove current assignee'),
467
+ priorityId: z.string().optional().describe('New priority ID'),
468
+ labels: z.array(z.string()).optional().describe('Replace labels'),
469
+ additionalFields: z.record(z.any()).optional().describe('Additional raw fields to include under fields'),
447
470
  }, async ({ issueKey, summary, description, assigneeAccountId, unassignAssignee, priorityId, labels, additionalFields, }) => {
448
471
  try {
449
472
  await jiraService.editIssue(issueKey, {
@@ -458,8 +481,8 @@ server.tool("edit-issue", "Edit fields on a Jira issue", {
458
481
  return {
459
482
  content: [
460
483
  {
461
- type: "text",
462
- text: "Issue updated successfully",
484
+ type: 'text',
485
+ text: 'Issue updated successfully',
463
486
  },
464
487
  ],
465
488
  };
@@ -468,31 +491,19 @@ server.tool("edit-issue", "Edit fields on a Jira issue", {
468
491
  return {
469
492
  content: [
470
493
  {
471
- type: "text",
494
+ type: 'text',
472
495
  text: `Failed to update issue: ${error instanceof Error ? error.message : String(error)}`,
473
496
  },
474
497
  ],
475
498
  };
476
499
  }
477
500
  });
478
- server.tool("search-users", "Search for users", {
479
- query: z.string().optional().describe("Query string to search users"),
480
- accountId: z.string().optional().describe("Account ID to search for"),
481
- startAt: z
482
- .number()
483
- .min(0)
484
- .optional()
485
- .describe("The index of the first item to return"),
486
- maxResults: z
487
- .number()
488
- .min(1)
489
- .max(1000)
490
- .optional()
491
- .describe("Maximum number of items to return"),
492
- property: z
493
- .string()
494
- .optional()
495
- .describe("Property key to search for in user properties"),
501
+ server.tool('search-users', 'Search for users', {
502
+ query: z.string().optional().describe('Query string to search users'),
503
+ accountId: z.string().optional().describe('Account ID to search for'),
504
+ startAt: z.number().min(0).optional().describe('The index of the first item to return'),
505
+ maxResults: z.number().min(1).max(1000).optional().describe('Maximum number of items to return'),
506
+ property: z.string().optional().describe('Property key to search for in user properties'),
496
507
  }, async ({ query, accountId, startAt, maxResults, property }) => {
497
508
  try {
498
509
  const users = await jiraService.searchUsers({
@@ -505,7 +516,7 @@ server.tool("search-users", "Search for users", {
505
516
  return {
506
517
  content: [
507
518
  {
508
- type: "text",
519
+ type: 'text',
509
520
  text: JSON.stringify(users),
510
521
  },
511
522
  ],
@@ -515,36 +526,22 @@ server.tool("search-users", "Search for users", {
515
526
  return {
516
527
  content: [
517
528
  {
518
- type: "text",
529
+ type: 'text',
519
530
  text: `Failed to search users: ${error instanceof Error ? error.message : String(error)}`,
520
531
  },
521
532
  ],
522
533
  };
523
534
  }
524
535
  });
525
- server.tool("get-user-picker", "Get user picker suggestions for autocomplete", {
526
- query: z.string().describe("Query string for user search"),
527
- maxResults: z
528
- .number()
529
- .min(1)
530
- .max(1000)
531
- .optional()
532
- .describe("Maximum number of users to return"),
533
- showAvatar: z.boolean().optional().describe("Whether to show user avatars"),
534
- exclude: z
535
- .array(z.string())
536
- .optional()
537
- .describe("List of users to exclude from results"),
538
- excludeAccountIds: z
539
- .array(z.string())
540
- .optional()
541
- .describe("List of account IDs to exclude"),
542
- avatarSize: z.string().optional().describe("Size of avatars to return"),
543
- excludeConnectUsers: z
544
- .boolean()
545
- .optional()
546
- .describe("Whether to exclude Connect app users"),
547
- }, async ({ query, maxResults, showAvatar, exclude, excludeAccountIds, avatarSize, excludeConnectUsers, }) => {
536
+ server.tool('get-user-picker', 'Get user picker suggestions for autocomplete', {
537
+ query: z.string().describe('Query string for user search'),
538
+ maxResults: z.number().min(1).max(1000).optional().describe('Maximum number of users to return'),
539
+ showAvatar: z.boolean().optional().describe('Whether to show user avatars'),
540
+ exclude: z.array(z.string()).optional().describe('List of users to exclude from results'),
541
+ excludeAccountIds: z.array(z.string()).optional().describe('List of account IDs to exclude'),
542
+ avatarSize: z.string().optional().describe('Size of avatars to return'),
543
+ excludeConnectUsers: z.boolean().optional().describe('Whether to exclude Connect app users'),
544
+ }, async ({ query, maxResults, showAvatar, exclude, excludeAccountIds, avatarSize, excludeConnectUsers }) => {
548
545
  try {
549
546
  const result = await jiraService.getUserPicker({
550
547
  query,
@@ -558,7 +555,7 @@ server.tool("get-user-picker", "Get user picker suggestions for autocomplete", {
558
555
  return {
559
556
  content: [
560
557
  {
561
- type: "text",
558
+ type: 'text',
562
559
  text: JSON.stringify(result),
563
560
  },
564
561
  ],
@@ -568,32 +565,20 @@ server.tool("get-user-picker", "Get user picker suggestions for autocomplete", {
568
565
  return {
569
566
  content: [
570
567
  {
571
- type: "text",
568
+ type: 'text',
572
569
  text: `Failed to get user picker suggestions: ${error instanceof Error ? error.message : String(error)}`,
573
570
  },
574
571
  ],
575
572
  };
576
573
  }
577
574
  });
578
- server.tool("search-assignable-users", "Search for users who can be assigned to issues", {
579
- projectKeys: z
580
- .array(z.string())
581
- .optional()
582
- .describe("Project keys to search assignable users for"),
583
- query: z.string().optional().describe("Query string to search users"),
584
- username: z.string().optional().describe("Username to search for"),
585
- accountId: z.string().optional().describe("Account ID to search for"),
586
- startAt: z
587
- .number()
588
- .min(0)
589
- .optional()
590
- .describe("The index of the first item to return"),
591
- maxResults: z
592
- .number()
593
- .min(1)
594
- .max(1000)
595
- .optional()
596
- .describe("Maximum number of items to return"),
575
+ server.tool('search-assignable-users', 'Search for users who can be assigned to issues', {
576
+ projectKeys: z.array(z.string()).optional().describe('Project keys to search assignable users for'),
577
+ query: z.string().optional().describe('Query string to search users'),
578
+ username: z.string().optional().describe('Username to search for'),
579
+ accountId: z.string().optional().describe('Account ID to search for'),
580
+ startAt: z.number().min(0).optional().describe('The index of the first item to return'),
581
+ maxResults: z.number().min(1).max(1000).optional().describe('Maximum number of items to return'),
597
582
  }, async ({ projectKeys, query, username, accountId, startAt, maxResults }) => {
598
583
  try {
599
584
  const users = await jiraService.searchAssignableUsers({
@@ -607,7 +592,7 @@ server.tool("search-assignable-users", "Search for users who can be assigned to
607
592
  return {
608
593
  content: [
609
594
  {
610
- type: "text",
595
+ type: 'text',
611
596
  text: JSON.stringify(users),
612
597
  },
613
598
  ],
@@ -617,40 +602,23 @@ server.tool("search-assignable-users", "Search for users who can be assigned to
617
602
  return {
618
603
  content: [
619
604
  {
620
- type: "text",
605
+ type: 'text',
621
606
  text: `Failed to search assignable users: ${error instanceof Error ? error.message : String(error)}`,
622
607
  },
623
608
  ],
624
609
  };
625
610
  }
626
611
  });
627
- server.tool("search-users-by-permission", "Search for users who have specific permissions", {
628
- permissions: z
629
- .string()
630
- .describe("Comma-separated list of permissions (e.g., BROWSE_PROJECTS,EDIT_ISSUES)"),
631
- projectKey: z
632
- .string()
633
- .optional()
634
- .describe("Project key to check permissions for"),
635
- issueKey: z
636
- .string()
637
- .optional()
638
- .describe("Issue key to check permissions for"),
639
- query: z.string().optional().describe("Query string to search users"),
640
- username: z.string().optional().describe("Username to search for"),
641
- accountId: z.string().optional().describe("Account ID to search for"),
642
- startAt: z
643
- .number()
644
- .min(0)
645
- .optional()
646
- .describe("The index of the first item to return"),
647
- maxResults: z
648
- .number()
649
- .min(1)
650
- .max(1000)
651
- .optional()
652
- .describe("Maximum number of items to return"),
653
- }, async ({ permissions, projectKey, issueKey, query, username, accountId, startAt, maxResults, }) => {
612
+ server.tool('search-users-by-permission', 'Search for users who have specific permissions', {
613
+ permissions: z.string().describe('Comma-separated list of permissions (e.g., BROWSE_PROJECTS,EDIT_ISSUES)'),
614
+ projectKey: z.string().optional().describe('Project key to check permissions for'),
615
+ issueKey: z.string().optional().describe('Issue key to check permissions for'),
616
+ query: z.string().optional().describe('Query string to search users'),
617
+ username: z.string().optional().describe('Username to search for'),
618
+ accountId: z.string().optional().describe('Account ID to search for'),
619
+ startAt: z.number().min(0).optional().describe('The index of the first item to return'),
620
+ maxResults: z.number().min(1).max(1000).optional().describe('Maximum number of items to return'),
621
+ }, async ({ permissions, projectKey, issueKey, query, username, accountId, startAt, maxResults }) => {
654
622
  try {
655
623
  const users = await jiraService.searchUsersByPermission({
656
624
  permissions,
@@ -665,7 +633,7 @@ server.tool("search-users-by-permission", "Search for users who have specific pe
665
633
  return {
666
634
  content: [
667
635
  {
668
- type: "text",
636
+ type: 'text',
669
637
  text: JSON.stringify(users),
670
638
  },
671
639
  ],
@@ -675,25 +643,25 @@ server.tool("search-users-by-permission", "Search for users who have specific pe
675
643
  return {
676
644
  content: [
677
645
  {
678
- type: "text",
646
+ type: 'text',
679
647
  text: `Failed to search users by permission: ${error instanceof Error ? error.message : String(error)}`,
680
648
  },
681
649
  ],
682
650
  };
683
651
  }
684
652
  });
685
- server.tool("get-myself", "Get current user information", {
653
+ server.tool('get-myself', 'Get current user information', {
686
654
  expand: z
687
- .array(z.enum(["groups", "applicationRoles"]))
655
+ .array(z.enum(['groups', 'applicationRoles']))
688
656
  .optional()
689
- .describe("List of fields to expand"),
657
+ .describe('List of fields to expand'),
690
658
  }, async ({ expand }) => {
691
659
  try {
692
660
  const user = await jiraService.getMyself(expand);
693
661
  return {
694
662
  content: [
695
663
  {
696
- type: "text",
664
+ type: 'text',
697
665
  text: JSON.stringify(user),
698
666
  },
699
667
  ],
@@ -703,43 +671,22 @@ server.tool("get-myself", "Get current user information", {
703
671
  return {
704
672
  content: [
705
673
  {
706
- type: "text",
674
+ type: 'text',
707
675
  text: `Failed to get current user info: ${error instanceof Error ? error.message : String(error)}`,
708
676
  },
709
677
  ],
710
678
  };
711
679
  }
712
680
  });
713
- server.tool("get-my-permissions", "Get current user's permissions", {
714
- projectKey: z
715
- .string()
716
- .optional()
717
- .describe("Project key to check permissions for"),
718
- projectId: z
719
- .string()
720
- .optional()
721
- .describe("Project ID to check permissions for"),
722
- issueKey: z
723
- .string()
724
- .optional()
725
- .describe("Issue key to check permissions for"),
726
- issueId: z
727
- .string()
728
- .optional()
729
- .describe("Issue ID to check permissions for"),
730
- permissions: z
731
- .string()
732
- .optional()
733
- .describe("Comma-separated list of permission keys to check"),
734
- projectUuid: z.string().optional().describe("Project UUID"),
735
- projectConfigurationUuid: z
736
- .string()
737
- .optional()
738
- .describe("Project configuration UUID"),
739
- commentId: z
740
- .string()
741
- .optional()
742
- .describe("Comment ID to check permissions for"),
681
+ server.tool('get-my-permissions', "Get current user's permissions", {
682
+ projectKey: z.string().optional().describe('Project key to check permissions for'),
683
+ projectId: z.string().optional().describe('Project ID to check permissions for'),
684
+ issueKey: z.string().optional().describe('Issue key to check permissions for'),
685
+ issueId: z.string().optional().describe('Issue ID to check permissions for'),
686
+ permissions: z.string().optional().describe('Comma-separated list of permission keys to check'),
687
+ projectUuid: z.string().optional().describe('Project UUID'),
688
+ projectConfigurationUuid: z.string().optional().describe('Project configuration UUID'),
689
+ commentId: z.string().optional().describe('Comment ID to check permissions for'),
743
690
  }, async ({ projectKey, projectId, issueKey, issueId, permissions, projectUuid, projectConfigurationUuid, commentId, }) => {
744
691
  try {
745
692
  const result = await jiraService.getMyPermissions({
@@ -755,7 +702,7 @@ server.tool("get-my-permissions", "Get current user's permissions", {
755
702
  return {
756
703
  content: [
757
704
  {
758
- type: "text",
705
+ type: 'text',
759
706
  text: JSON.stringify(result),
760
707
  },
761
708
  ],
@@ -765,20 +712,17 @@ server.tool("get-my-permissions", "Get current user's permissions", {
765
712
  return {
766
713
  content: [
767
714
  {
768
- type: "text",
715
+ type: 'text',
769
716
  text: `Failed to get permissions: ${error instanceof Error ? error.message : String(error)}`,
770
717
  },
771
718
  ],
772
719
  };
773
720
  }
774
721
  });
775
- server.tool("update-myself", "Update current user's profile information", {
776
- emailAddress: z.string().email().optional().describe("New email address"),
777
- displayName: z.string().optional().describe("New display name"),
778
- timeZone: z
779
- .string()
780
- .optional()
781
- .describe("New timezone (e.g., 'America/New_York')"),
722
+ server.tool('update-myself', "Update current user's profile information", {
723
+ emailAddress: z.string().email().optional().describe('New email address'),
724
+ displayName: z.string().optional().describe('New display name'),
725
+ timeZone: z.string().optional().describe("New timezone (e.g., 'America/New_York')"),
782
726
  locale: z.string().optional().describe("New locale (e.g., 'en_US')"),
783
727
  }, async ({ emailAddress, displayName, timeZone, locale }) => {
784
728
  try {
@@ -791,7 +735,7 @@ server.tool("update-myself", "Update current user's profile information", {
791
735
  return {
792
736
  content: [
793
737
  {
794
- type: "text",
738
+ type: 'text',
795
739
  text: JSON.stringify(user),
796
740
  },
797
741
  ],
@@ -801,22 +745,22 @@ server.tool("update-myself", "Update current user's profile information", {
801
745
  return {
802
746
  content: [
803
747
  {
804
- type: "text",
748
+ type: 'text',
805
749
  text: `Failed to update user profile: ${error instanceof Error ? error.message : String(error)}`,
806
750
  },
807
751
  ],
808
752
  };
809
753
  }
810
754
  });
811
- server.tool("get-my-preferences", "Get current user's preferences", {
812
- key: z.string().optional().describe("Specific preference key to retrieve"),
755
+ server.tool('get-my-preferences', "Get current user's preferences", {
756
+ key: z.string().optional().describe('Specific preference key to retrieve'),
813
757
  }, async ({ key }) => {
814
758
  try {
815
759
  const preferences = await jiraService.getMyPreferences(key);
816
760
  return {
817
761
  content: [
818
762
  {
819
- type: "text",
763
+ type: 'text',
820
764
  text: JSON.stringify(preferences),
821
765
  },
822
766
  ],
@@ -826,23 +770,23 @@ server.tool("get-my-preferences", "Get current user's preferences", {
826
770
  return {
827
771
  content: [
828
772
  {
829
- type: "text",
773
+ type: 'text',
830
774
  text: `Failed to get preferences: ${error instanceof Error ? error.message : String(error)}`,
831
775
  },
832
776
  ],
833
777
  };
834
778
  }
835
779
  });
836
- server.tool("update-my-preferences", "Update current user's preferences", {
837
- key: z.string().describe("Preference key to update"),
838
- value: z.any().describe("New value for the preference"),
780
+ server.tool('update-my-preferences', "Update current user's preferences", {
781
+ key: z.string().describe('Preference key to update'),
782
+ value: z.any().describe('New value for the preference'),
839
783
  }, async ({ key, value }) => {
840
784
  try {
841
785
  const result = await jiraService.updateMyPreferences(key, value);
842
786
  return {
843
787
  content: [
844
788
  {
845
- type: "text",
789
+ type: 'text',
846
790
  text: JSON.stringify(result),
847
791
  },
848
792
  ],
@@ -852,20 +796,20 @@ server.tool("update-my-preferences", "Update current user's preferences", {
852
796
  return {
853
797
  content: [
854
798
  {
855
- type: "text",
799
+ type: 'text',
856
800
  text: `Failed to update preferences: ${error instanceof Error ? error.message : String(error)}`,
857
801
  },
858
802
  ],
859
803
  };
860
804
  }
861
805
  });
862
- server.tool("get-my-locale", "Get current user's locale setting", {}, async () => {
806
+ server.tool('get-my-locale', "Get current user's locale setting", {}, async () => {
863
807
  try {
864
808
  const locale = await jiraService.getMyLocale();
865
809
  return {
866
810
  content: [
867
811
  {
868
- type: "text",
812
+ type: 'text',
869
813
  text: JSON.stringify(locale),
870
814
  },
871
815
  ],
@@ -875,14 +819,14 @@ server.tool("get-my-locale", "Get current user's locale setting", {}, async () =
875
819
  return {
876
820
  content: [
877
821
  {
878
- type: "text",
822
+ type: 'text',
879
823
  text: `Failed to get locale: ${error instanceof Error ? error.message : String(error)}`,
880
824
  },
881
825
  ],
882
826
  };
883
827
  }
884
828
  });
885
- server.tool("update-my-locale", "Update current user's locale setting", {
829
+ server.tool('update-my-locale', "Update current user's locale setting", {
886
830
  locale: z.string().describe("New locale (e.g., 'en_US', 'ko_KR')"),
887
831
  }, async ({ locale }) => {
888
832
  try {
@@ -890,7 +834,7 @@ server.tool("update-my-locale", "Update current user's locale setting", {
890
834
  return {
891
835
  content: [
892
836
  {
893
- type: "text",
837
+ type: 'text',
894
838
  text: JSON.stringify(result),
895
839
  },
896
840
  ],
@@ -900,20 +844,20 @@ server.tool("update-my-locale", "Update current user's locale setting", {
900
844
  return {
901
845
  content: [
902
846
  {
903
- type: "text",
847
+ type: 'text',
904
848
  text: `Failed to update locale: ${error instanceof Error ? error.message : String(error)}`,
905
849
  },
906
850
  ],
907
851
  };
908
852
  }
909
853
  });
910
- server.tool("get-priorities", "Get all priorities", {}, async () => {
854
+ server.tool('get-priorities', 'Get all priorities', {}, async () => {
911
855
  try {
912
856
  const priorities = await jiraService.getPriorities();
913
857
  return {
914
858
  content: [
915
859
  {
916
- type: "text",
860
+ type: 'text',
917
861
  text: JSON.stringify(priorities),
918
862
  },
919
863
  ],
@@ -923,26 +867,26 @@ server.tool("get-priorities", "Get all priorities", {}, async () => {
923
867
  return {
924
868
  content: [
925
869
  {
926
- type: "text",
870
+ type: 'text',
927
871
  text: `Failed to get priorities: ${error instanceof Error ? error.message : String(error)}`,
928
872
  },
929
873
  ],
930
874
  };
931
875
  }
932
876
  });
933
- server.tool("get-issue-transitions", "Get available transitions for an issue", {
934
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
877
+ server.tool('get-issue-transitions', 'Get available transitions for an issue', {
878
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
935
879
  expand: z
936
- .array(z.enum(["transitions.fields", "fields"]))
880
+ .array(z.enum(['transitions.fields', 'fields']))
937
881
  .optional()
938
- .describe("Fields to expand in the response"),
882
+ .describe('Fields to expand in the response'),
939
883
  }, async ({ issueKey, expand }) => {
940
884
  try {
941
885
  const result = await jiraService.getIssueTransitions(issueKey, expand);
942
886
  return {
943
887
  content: [
944
888
  {
945
- type: "text",
889
+ type: 'text',
946
890
  text: JSON.stringify(result),
947
891
  },
948
892
  ],
@@ -952,46 +896,40 @@ server.tool("get-issue-transitions", "Get available transitions for an issue", {
952
896
  return {
953
897
  content: [
954
898
  {
955
- type: "text",
899
+ type: 'text',
956
900
  text: `Failed to get issue transitions: ${error instanceof Error ? error.message : String(error)}`,
957
901
  },
958
902
  ],
959
903
  };
960
904
  }
961
905
  });
962
- server.tool("transition-issue", "Transition an issue to a new status", {
963
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
964
- transitionId: z.string().describe("ID of the transition to perform"),
906
+ server.tool('transition-issue', 'Transition an issue to a new status', {
907
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
908
+ transitionId: z.string().describe('ID of the transition to perform'),
965
909
  comment: z
966
910
  .object({
967
- body: z.string().describe("Comment text"),
911
+ body: z.string().describe('Comment text'),
968
912
  visibility: z
969
913
  .object({
970
- type: z.enum(["group", "role"]).describe("Visibility type"),
971
- value: z.string().describe("Group name or role name"),
914
+ type: z.enum(['group', 'role']).describe('Visibility type'),
915
+ value: z.string().describe('Group name or role name'),
972
916
  })
973
917
  .optional()
974
- .describe("Comment visibility restrictions"),
918
+ .describe('Comment visibility restrictions'),
975
919
  })
976
920
  .optional()
977
- .describe("Comment to add when transitioning"),
978
- fields: z
979
- .record(z.any())
980
- .optional()
981
- .describe("Fields to update during transition"),
982
- update: z
983
- .record(z.any())
984
- .optional()
985
- .describe("Additional update operations"),
986
- historyMetadata: z.record(z.any()).optional().describe("History metadata"),
921
+ .describe('Comment to add when transitioning'),
922
+ fields: z.record(z.any()).optional().describe('Fields to update during transition'),
923
+ update: z.record(z.any()).optional().describe('Additional update operations'),
924
+ historyMetadata: z.record(z.any()).optional().describe('History metadata'),
987
925
  properties: z
988
926
  .array(z.object({
989
- key: z.string().describe("Property key"),
990
- value: z.any().describe("Property value"),
927
+ key: z.string().describe('Property key'),
928
+ value: z.any().describe('Property value'),
991
929
  }))
992
930
  .optional()
993
- .describe("Issue properties to set"),
994
- }, async ({ issueKey, transitionId, comment, fields, update, historyMetadata, properties, }) => {
931
+ .describe('Issue properties to set'),
932
+ }, async ({ issueKey, transitionId, comment, fields, update, historyMetadata, properties }) => {
995
933
  try {
996
934
  await jiraService.transitionIssue(issueKey, {
997
935
  transitionId,
@@ -1004,8 +942,8 @@ server.tool("transition-issue", "Transition an issue to a new status", {
1004
942
  return {
1005
943
  content: [
1006
944
  {
1007
- type: "text",
1008
- text: "Issue transitioned successfully",
945
+ type: 'text',
946
+ text: 'Issue transitioned successfully',
1009
947
  },
1010
948
  ],
1011
949
  };
@@ -1014,20 +952,20 @@ server.tool("transition-issue", "Transition an issue to a new status", {
1014
952
  return {
1015
953
  content: [
1016
954
  {
1017
- type: "text",
955
+ type: 'text',
1018
956
  text: `Failed to transition issue: ${error instanceof Error ? error.message : String(error)}`,
1019
957
  },
1020
958
  ],
1021
959
  };
1022
960
  }
1023
961
  });
1024
- server.tool("get-statuses", "Get all workflow statuses", {}, async () => {
962
+ server.tool('get-statuses', 'Get all workflow statuses', {}, async () => {
1025
963
  try {
1026
964
  const statuses = await jiraService.getStatuses();
1027
965
  return {
1028
966
  content: [
1029
967
  {
1030
- type: "text",
968
+ type: 'text',
1031
969
  text: JSON.stringify(statuses),
1032
970
  },
1033
971
  ],
@@ -1037,22 +975,22 @@ server.tool("get-statuses", "Get all workflow statuses", {}, async () => {
1037
975
  return {
1038
976
  content: [
1039
977
  {
1040
- type: "text",
978
+ type: 'text',
1041
979
  text: `Failed to get statuses: ${error instanceof Error ? error.message : String(error)}`,
1042
980
  },
1043
981
  ],
1044
982
  };
1045
983
  }
1046
984
  });
1047
- server.tool("get-status", "Get a specific status by ID or name", {
1048
- idOrName: z.string().describe("Status ID or name"),
985
+ server.tool('get-status', 'Get a specific status by ID or name', {
986
+ idOrName: z.string().describe('Status ID or name'),
1049
987
  }, async ({ idOrName }) => {
1050
988
  try {
1051
989
  const status = await jiraService.getStatus(idOrName);
1052
990
  return {
1053
991
  content: [
1054
992
  {
1055
- type: "text",
993
+ type: 'text',
1056
994
  text: JSON.stringify(status),
1057
995
  },
1058
996
  ],
@@ -1062,34 +1000,19 @@ server.tool("get-status", "Get a specific status by ID or name", {
1062
1000
  return {
1063
1001
  content: [
1064
1002
  {
1065
- type: "text",
1003
+ type: 'text',
1066
1004
  text: `Failed to get status: ${error instanceof Error ? error.message : String(error)}`,
1067
1005
  },
1068
1006
  ],
1069
1007
  };
1070
1008
  }
1071
1009
  });
1072
- server.tool("search-statuses", "Search statuses with filters", {
1073
- startAt: z
1074
- .number()
1075
- .min(0)
1076
- .optional()
1077
- .describe("The index of the first item to return"),
1078
- maxResults: z
1079
- .number()
1080
- .min(1)
1081
- .max(100)
1082
- .optional()
1083
- .describe("Maximum number of items to return"),
1084
- searchString: z
1085
- .string()
1086
- .optional()
1087
- .describe("Search string to filter statuses"),
1088
- projectId: z
1089
- .string()
1090
- .optional()
1091
- .describe("Project ID to filter statuses for"),
1092
- expand: z.string().optional().describe("Fields to expand in the response"),
1010
+ server.tool('search-statuses', 'Search statuses with filters', {
1011
+ startAt: z.number().min(0).optional().describe('The index of the first item to return'),
1012
+ maxResults: z.number().min(1).max(100).optional().describe('Maximum number of items to return'),
1013
+ searchString: z.string().optional().describe('Search string to filter statuses'),
1014
+ projectId: z.string().optional().describe('Project ID to filter statuses for'),
1015
+ expand: z.string().optional().describe('Fields to expand in the response'),
1093
1016
  }, async ({ startAt, maxResults, searchString, projectId, expand }) => {
1094
1017
  try {
1095
1018
  const result = await jiraService.searchStatuses({
@@ -1102,7 +1025,7 @@ server.tool("search-statuses", "Search statuses with filters", {
1102
1025
  return {
1103
1026
  content: [
1104
1027
  {
1105
- type: "text",
1028
+ type: 'text',
1106
1029
  text: JSON.stringify(result),
1107
1030
  },
1108
1031
  ],
@@ -1112,22 +1035,22 @@ server.tool("search-statuses", "Search statuses with filters", {
1112
1035
  return {
1113
1036
  content: [
1114
1037
  {
1115
- type: "text",
1038
+ type: 'text',
1116
1039
  text: `Failed to search statuses: ${error instanceof Error ? error.message : String(error)}`,
1117
1040
  },
1118
1041
  ],
1119
1042
  };
1120
1043
  }
1121
1044
  });
1122
- server.tool("get-priority", "Get a specific priority by ID", {
1123
- id: z.string().describe("Priority ID"),
1045
+ server.tool('get-priority', 'Get a specific priority by ID', {
1046
+ id: z.string().describe('Priority ID'),
1124
1047
  }, async ({ id }) => {
1125
1048
  try {
1126
1049
  const priority = await jiraService.getPriority(id);
1127
1050
  return {
1128
1051
  content: [
1129
1052
  {
1130
- type: "text",
1053
+ type: 'text',
1131
1054
  text: JSON.stringify(priority),
1132
1055
  },
1133
1056
  ],
@@ -1137,38 +1060,20 @@ server.tool("get-priority", "Get a specific priority by ID", {
1137
1060
  return {
1138
1061
  content: [
1139
1062
  {
1140
- type: "text",
1063
+ type: 'text',
1141
1064
  text: `Failed to get priority: ${error instanceof Error ? error.message : String(error)}`,
1142
1065
  },
1143
1066
  ],
1144
1067
  };
1145
1068
  }
1146
1069
  });
1147
- server.tool("search-priorities", "Search priorities with filters", {
1148
- startAt: z
1149
- .number()
1150
- .min(0)
1151
- .optional()
1152
- .describe("The index of the first item to return"),
1153
- maxResults: z
1154
- .number()
1155
- .min(1)
1156
- .max(100)
1157
- .optional()
1158
- .describe("Maximum number of items to return"),
1159
- id: z
1160
- .array(z.string())
1161
- .optional()
1162
- .describe("List of priority IDs to filter by"),
1163
- projectId: z
1164
- .array(z.string())
1165
- .optional()
1166
- .describe("List of project IDs to filter by"),
1167
- priorityName: z.string().optional().describe("Priority name to search for"),
1168
- onlyDefault: z
1169
- .boolean()
1170
- .optional()
1171
- .describe("Whether to return only default priority"),
1070
+ server.tool('search-priorities', 'Search priorities with filters', {
1071
+ startAt: z.number().min(0).optional().describe('The index of the first item to return'),
1072
+ maxResults: z.number().min(1).max(100).optional().describe('Maximum number of items to return'),
1073
+ id: z.array(z.string()).optional().describe('List of priority IDs to filter by'),
1074
+ projectId: z.array(z.string()).optional().describe('List of project IDs to filter by'),
1075
+ priorityName: z.string().optional().describe('Priority name to search for'),
1076
+ onlyDefault: z.boolean().optional().describe('Whether to return only default priority'),
1172
1077
  }, async ({ startAt, maxResults, id, projectId, priorityName, onlyDefault }) => {
1173
1078
  try {
1174
1079
  const result = await jiraService.searchPriorities({
@@ -1182,7 +1087,7 @@ server.tool("search-priorities", "Search priorities with filters", {
1182
1087
  return {
1183
1088
  content: [
1184
1089
  {
1185
- type: "text",
1090
+ type: 'text',
1186
1091
  text: JSON.stringify(result),
1187
1092
  },
1188
1093
  ],
@@ -1192,30 +1097,30 @@ server.tool("search-priorities", "Search priorities with filters", {
1192
1097
  return {
1193
1098
  content: [
1194
1099
  {
1195
- type: "text",
1100
+ type: 'text',
1196
1101
  text: `Failed to search priorities: ${error instanceof Error ? error.message : String(error)}`,
1197
1102
  },
1198
1103
  ],
1199
1104
  };
1200
1105
  }
1201
1106
  });
1202
- server.tool("create-comment", "Add a comment to an issue", {
1203
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1204
- body: z.string().describe("Comment text"),
1107
+ server.tool('create-comment', 'Add a comment to an issue', {
1108
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1109
+ body: z.string().describe('Comment text'),
1205
1110
  visibility: z
1206
1111
  .object({
1207
- type: z.enum(["group", "role"]).describe("Visibility type"),
1208
- value: z.string().describe("Group name or role name"),
1112
+ type: z.enum(['group', 'role']).describe('Visibility type'),
1113
+ value: z.string().describe('Group name or role name'),
1209
1114
  })
1210
1115
  .optional()
1211
- .describe("Comment visibility restrictions"),
1116
+ .describe('Comment visibility restrictions'),
1212
1117
  properties: z
1213
1118
  .array(z.object({
1214
- key: z.string().describe("Property key"),
1215
- value: z.any().describe("Property value"),
1119
+ key: z.string().describe('Property key'),
1120
+ value: z.any().describe('Property value'),
1216
1121
  }))
1217
1122
  .optional()
1218
- .describe("Comment properties"),
1123
+ .describe('Comment properties'),
1219
1124
  }, async ({ issueKey, body, visibility, properties }) => {
1220
1125
  try {
1221
1126
  const comment = await jiraService.createComment(issueKey, {
@@ -1226,7 +1131,7 @@ server.tool("create-comment", "Add a comment to an issue", {
1226
1131
  return {
1227
1132
  content: [
1228
1133
  {
1229
- type: "text",
1134
+ type: 'text',
1230
1135
  text: JSON.stringify(comment),
1231
1136
  },
1232
1137
  ],
@@ -1236,31 +1141,31 @@ server.tool("create-comment", "Add a comment to an issue", {
1236
1141
  return {
1237
1142
  content: [
1238
1143
  {
1239
- type: "text",
1144
+ type: 'text',
1240
1145
  text: `Failed to create comment: ${error instanceof Error ? error.message : String(error)}`,
1241
1146
  },
1242
1147
  ],
1243
1148
  };
1244
1149
  }
1245
1150
  });
1246
- server.tool("update-comment", "Update an existing comment", {
1247
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1248
- commentId: z.string().describe("Comment ID to update"),
1249
- body: z.string().describe("New comment text"),
1151
+ server.tool('update-comment', 'Update an existing comment', {
1152
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1153
+ commentId: z.string().describe('Comment ID to update'),
1154
+ body: z.string().describe('New comment text'),
1250
1155
  visibility: z
1251
1156
  .object({
1252
- type: z.enum(["group", "role"]).describe("Visibility type"),
1253
- value: z.string().describe("Group name or role name"),
1157
+ type: z.enum(['group', 'role']).describe('Visibility type'),
1158
+ value: z.string().describe('Group name or role name'),
1254
1159
  })
1255
1160
  .optional()
1256
- .describe("Comment visibility restrictions"),
1161
+ .describe('Comment visibility restrictions'),
1257
1162
  properties: z
1258
1163
  .array(z.object({
1259
- key: z.string().describe("Property key"),
1260
- value: z.any().describe("Property value"),
1164
+ key: z.string().describe('Property key'),
1165
+ value: z.any().describe('Property value'),
1261
1166
  }))
1262
1167
  .optional()
1263
- .describe("Comment properties"),
1168
+ .describe('Comment properties'),
1264
1169
  }, async ({ issueKey, commentId, body, visibility, properties }) => {
1265
1170
  try {
1266
1171
  const comment = await jiraService.updateComment(issueKey, commentId, {
@@ -1271,7 +1176,7 @@ server.tool("update-comment", "Update an existing comment", {
1271
1176
  return {
1272
1177
  content: [
1273
1178
  {
1274
- type: "text",
1179
+ type: 'text',
1275
1180
  text: JSON.stringify(comment),
1276
1181
  },
1277
1182
  ],
@@ -1281,24 +1186,24 @@ server.tool("update-comment", "Update an existing comment", {
1281
1186
  return {
1282
1187
  content: [
1283
1188
  {
1284
- type: "text",
1189
+ type: 'text',
1285
1190
  text: `Failed to update comment: ${error instanceof Error ? error.message : String(error)}`,
1286
1191
  },
1287
1192
  ],
1288
1193
  };
1289
1194
  }
1290
1195
  });
1291
- server.tool("delete-comment", "Delete a comment from an issue", {
1292
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1293
- commentId: z.string().describe("Comment ID to delete"),
1196
+ server.tool('delete-comment', 'Delete a comment from an issue', {
1197
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1198
+ commentId: z.string().describe('Comment ID to delete'),
1294
1199
  }, async ({ issueKey, commentId }) => {
1295
1200
  try {
1296
1201
  await jiraService.deleteComment(issueKey, commentId);
1297
1202
  return {
1298
1203
  content: [
1299
1204
  {
1300
- type: "text",
1301
- text: "Comment deleted successfully",
1205
+ type: 'text',
1206
+ text: 'Comment deleted successfully',
1302
1207
  },
1303
1208
  ],
1304
1209
  };
@@ -1307,27 +1212,24 @@ server.tool("delete-comment", "Delete a comment from an issue", {
1307
1212
  return {
1308
1213
  content: [
1309
1214
  {
1310
- type: "text",
1215
+ type: 'text',
1311
1216
  text: `Failed to delete comment: ${error instanceof Error ? error.message : String(error)}`,
1312
1217
  },
1313
1218
  ],
1314
1219
  };
1315
1220
  }
1316
1221
  });
1317
- server.tool("delete-issue", "Delete an issue", {
1318
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1319
- deleteSubtasks: z
1320
- .boolean()
1321
- .optional()
1322
- .describe("Whether to delete subtasks (default: false)"),
1222
+ server.tool('delete-issue', 'Delete an issue', {
1223
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1224
+ deleteSubtasks: z.boolean().optional().describe('Whether to delete subtasks (default: false)'),
1323
1225
  }, async ({ issueKey, deleteSubtasks }) => {
1324
1226
  try {
1325
1227
  await jiraService.deleteIssue(issueKey, deleteSubtasks);
1326
1228
  return {
1327
1229
  content: [
1328
1230
  {
1329
- type: "text",
1330
- text: "Issue deleted successfully",
1231
+ type: 'text',
1232
+ text: 'Issue deleted successfully',
1331
1233
  },
1332
1234
  ],
1333
1235
  };
@@ -1336,20 +1238,20 @@ server.tool("delete-issue", "Delete an issue", {
1336
1238
  return {
1337
1239
  content: [
1338
1240
  {
1339
- type: "text",
1241
+ type: 'text',
1340
1242
  text: `Failed to delete issue: ${error instanceof Error ? error.message : String(error)}`,
1341
1243
  },
1342
1244
  ],
1343
1245
  };
1344
1246
  }
1345
1247
  });
1346
- server.tool("get-issue-link-types", "Get available issue link types", {}, async () => {
1248
+ server.tool('get-issue-link-types', 'Get available issue link types', {}, async () => {
1347
1249
  try {
1348
1250
  const result = await jiraService.getIssueLinkTypes();
1349
1251
  return {
1350
1252
  content: [
1351
1253
  {
1352
- type: "text",
1254
+ type: 'text',
1353
1255
  text: JSON.stringify(result),
1354
1256
  },
1355
1257
  ],
@@ -1359,22 +1261,22 @@ server.tool("get-issue-link-types", "Get available issue link types", {}, async
1359
1261
  return {
1360
1262
  content: [
1361
1263
  {
1362
- type: "text",
1264
+ type: 'text',
1363
1265
  text: `Failed to get issue link types: ${error instanceof Error ? error.message : String(error)}`,
1364
1266
  },
1365
1267
  ],
1366
1268
  };
1367
1269
  }
1368
1270
  });
1369
- server.tool("get-issue-link-type", "Get a specific issue link type by ID", {
1370
- issueLinkTypeId: z.string().describe("Issue link type ID"),
1271
+ server.tool('get-issue-link-type', 'Get a specific issue link type by ID', {
1272
+ issueLinkTypeId: z.string().describe('Issue link type ID'),
1371
1273
  }, async ({ issueLinkTypeId }) => {
1372
1274
  try {
1373
1275
  const result = await jiraService.getIssueLinkType(issueLinkTypeId);
1374
1276
  return {
1375
1277
  content: [
1376
1278
  {
1377
- type: "text",
1279
+ type: 'text',
1378
1280
  text: JSON.stringify(result),
1379
1281
  },
1380
1282
  ],
@@ -1384,62 +1286,56 @@ server.tool("get-issue-link-type", "Get a specific issue link type by ID", {
1384
1286
  return {
1385
1287
  content: [
1386
1288
  {
1387
- type: "text",
1289
+ type: 'text',
1388
1290
  text: `Failed to get issue link type: ${error instanceof Error ? error.message : String(error)}`,
1389
1291
  },
1390
1292
  ],
1391
1293
  };
1392
1294
  }
1393
1295
  });
1394
- server.tool("create-issue-link", "Create a link between two issues", {
1395
- linkTypeId: z
1396
- .string()
1397
- .optional()
1398
- .describe("Link type ID (either this or linkTypeName must be provided)"),
1399
- linkTypeName: z
1400
- .string()
1401
- .optional()
1402
- .describe("Link type name (either this or linkTypeId must be provided)"),
1296
+ server.tool('create-issue-link', 'Create a link between two issues', {
1297
+ linkTypeId: z.string().optional().describe('Link type ID (either this or linkTypeName must be provided)'),
1298
+ linkTypeName: z.string().optional().describe('Link type name (either this or linkTypeId must be provided)'),
1403
1299
  inwardIssueId: z
1404
1300
  .string()
1405
1301
  .optional()
1406
- .describe("Inward issue ID (either this or inwardIssueKey must be provided)"),
1302
+ .describe('Inward issue ID (either this or inwardIssueKey must be provided)'),
1407
1303
  inwardIssueKey: z
1408
1304
  .string()
1409
1305
  .optional()
1410
- .describe("Inward issue key (either this or inwardIssueId must be provided)"),
1306
+ .describe('Inward issue key (either this or inwardIssueId must be provided)'),
1411
1307
  outwardIssueId: z
1412
1308
  .string()
1413
1309
  .optional()
1414
- .describe("Outward issue ID (either this or outwardIssueKey must be provided)"),
1310
+ .describe('Outward issue ID (either this or outwardIssueKey must be provided)'),
1415
1311
  outwardIssueKey: z
1416
1312
  .string()
1417
1313
  .optional()
1418
- .describe("Outward issue key (either this or outwardIssueId must be provided)"),
1314
+ .describe('Outward issue key (either this or outwardIssueId must be provided)'),
1419
1315
  comment: z
1420
1316
  .object({
1421
- body: z.string().describe("Comment text"),
1317
+ body: z.string().describe('Comment text'),
1422
1318
  visibility: z
1423
1319
  .object({
1424
- type: z.enum(["group", "role"]).describe("Visibility type"),
1425
- value: z.string().describe("Group name or role name"),
1320
+ type: z.enum(['group', 'role']).describe('Visibility type'),
1321
+ value: z.string().describe('Group name or role name'),
1426
1322
  })
1427
1323
  .optional()
1428
- .describe("Comment visibility restrictions"),
1324
+ .describe('Comment visibility restrictions'),
1429
1325
  })
1430
1326
  .optional()
1431
- .describe("Optional comment when creating the link"),
1432
- }, async ({ linkTypeId, linkTypeName, inwardIssueId, inwardIssueKey, outwardIssueId, outwardIssueKey, comment, }) => {
1327
+ .describe('Optional comment when creating the link'),
1328
+ }, async ({ linkTypeId, linkTypeName, inwardIssueId, inwardIssueKey, outwardIssueId, outwardIssueKey, comment }) => {
1433
1329
  try {
1434
1330
  // Validate required parameters
1435
1331
  if (!linkTypeId && !linkTypeName) {
1436
- throw new Error("Either linkTypeId or linkTypeName must be provided");
1332
+ throw new Error('Either linkTypeId or linkTypeName must be provided');
1437
1333
  }
1438
1334
  if (!inwardIssueId && !inwardIssueKey) {
1439
- throw new Error("Either inwardIssueId or inwardIssueKey must be provided");
1335
+ throw new Error('Either inwardIssueId or inwardIssueKey must be provided');
1440
1336
  }
1441
1337
  if (!outwardIssueId && !outwardIssueKey) {
1442
- throw new Error("Either outwardIssueId or outwardIssueKey must be provided");
1338
+ throw new Error('Either outwardIssueId or outwardIssueKey must be provided');
1443
1339
  }
1444
1340
  const type = {};
1445
1341
  if (linkTypeId)
@@ -1465,8 +1361,8 @@ server.tool("create-issue-link", "Create a link between two issues", {
1465
1361
  return {
1466
1362
  content: [
1467
1363
  {
1468
- type: "text",
1469
- text: "Issue link created successfully",
1364
+ type: 'text',
1365
+ text: 'Issue link created successfully',
1470
1366
  },
1471
1367
  ],
1472
1368
  };
@@ -1475,22 +1371,22 @@ server.tool("create-issue-link", "Create a link between two issues", {
1475
1371
  return {
1476
1372
  content: [
1477
1373
  {
1478
- type: "text",
1374
+ type: 'text',
1479
1375
  text: `Failed to create issue link: ${error instanceof Error ? error.message : String(error)}`,
1480
1376
  },
1481
1377
  ],
1482
1378
  };
1483
1379
  }
1484
1380
  });
1485
- server.tool("get-issue-link", "Get details of a specific issue link", {
1486
- linkId: z.string().describe("Issue link ID"),
1381
+ server.tool('get-issue-link', 'Get details of a specific issue link', {
1382
+ linkId: z.string().describe('Issue link ID'),
1487
1383
  }, async ({ linkId }) => {
1488
1384
  try {
1489
1385
  const result = await jiraService.getIssueLink(linkId);
1490
1386
  return {
1491
1387
  content: [
1492
1388
  {
1493
- type: "text",
1389
+ type: 'text',
1494
1390
  text: JSON.stringify(result),
1495
1391
  },
1496
1392
  ],
@@ -1500,23 +1396,23 @@ server.tool("get-issue-link", "Get details of a specific issue link", {
1500
1396
  return {
1501
1397
  content: [
1502
1398
  {
1503
- type: "text",
1399
+ type: 'text',
1504
1400
  text: `Failed to get issue link: ${error instanceof Error ? error.message : String(error)}`,
1505
1401
  },
1506
1402
  ],
1507
1403
  };
1508
1404
  }
1509
1405
  });
1510
- server.tool("delete-issue-link", "Delete a link between issues", {
1511
- linkId: z.string().describe("Issue link ID to delete"),
1406
+ server.tool('delete-issue-link', 'Delete a link between issues', {
1407
+ linkId: z.string().describe('Issue link ID to delete'),
1512
1408
  }, async ({ linkId }) => {
1513
1409
  try {
1514
1410
  await jiraService.deleteIssueLink(linkId);
1515
1411
  return {
1516
1412
  content: [
1517
1413
  {
1518
- type: "text",
1519
- text: "Issue link deleted successfully",
1414
+ type: 'text',
1415
+ text: 'Issue link deleted successfully',
1520
1416
  },
1521
1417
  ],
1522
1418
  };
@@ -1525,22 +1421,22 @@ server.tool("delete-issue-link", "Delete a link between issues", {
1525
1421
  return {
1526
1422
  content: [
1527
1423
  {
1528
- type: "text",
1424
+ type: 'text',
1529
1425
  text: `Failed to delete issue link: ${error instanceof Error ? error.message : String(error)}`,
1530
1426
  },
1531
1427
  ],
1532
1428
  };
1533
1429
  }
1534
1430
  });
1535
- server.tool("get-issue-with-links", "Get an issue with all its links", {
1536
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1431
+ server.tool('get-issue-with-links', 'Get an issue with all its links', {
1432
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1537
1433
  }, async ({ issueKey }) => {
1538
1434
  try {
1539
1435
  const result = await jiraService.getIssueWithLinks(issueKey);
1540
1436
  return {
1541
1437
  content: [
1542
1438
  {
1543
- type: "text",
1439
+ type: 'text',
1544
1440
  text: JSON.stringify(result),
1545
1441
  },
1546
1442
  ],
@@ -1550,22 +1446,22 @@ server.tool("get-issue-with-links", "Get an issue with all its links", {
1550
1446
  return {
1551
1447
  content: [
1552
1448
  {
1553
- type: "text",
1449
+ type: 'text',
1554
1450
  text: `Failed to get issue with links: ${error instanceof Error ? error.message : String(error)}`,
1555
1451
  },
1556
1452
  ],
1557
1453
  };
1558
1454
  }
1559
1455
  });
1560
- server.tool("get-issue-watchers", "Get watchers of an issue", {
1561
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1456
+ server.tool('get-issue-watchers', 'Get watchers of an issue', {
1457
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1562
1458
  }, async ({ issueKey }) => {
1563
1459
  try {
1564
1460
  const result = await jiraService.getIssueWatchers(issueKey);
1565
1461
  return {
1566
1462
  content: [
1567
1463
  {
1568
- type: "text",
1464
+ type: 'text',
1569
1465
  text: JSON.stringify(result),
1570
1466
  },
1571
1467
  ],
@@ -1575,24 +1471,24 @@ server.tool("get-issue-watchers", "Get watchers of an issue", {
1575
1471
  return {
1576
1472
  content: [
1577
1473
  {
1578
- type: "text",
1474
+ type: 'text',
1579
1475
  text: `Failed to get issue watchers: ${error instanceof Error ? error.message : String(error)}`,
1580
1476
  },
1581
1477
  ],
1582
1478
  };
1583
1479
  }
1584
1480
  });
1585
- server.tool("add-watcher", "Add a user as watcher to an issue", {
1586
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1587
- accountId: z.string().describe("Account ID of the user to add as watcher"),
1481
+ server.tool('add-watcher', 'Add a user as watcher to an issue', {
1482
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1483
+ accountId: z.string().describe('Account ID of the user to add as watcher'),
1588
1484
  }, async ({ issueKey, accountId }) => {
1589
1485
  try {
1590
1486
  await jiraService.addWatcher(issueKey, accountId);
1591
1487
  return {
1592
1488
  content: [
1593
1489
  {
1594
- type: "text",
1595
- text: "Watcher added successfully",
1490
+ type: 'text',
1491
+ text: 'Watcher added successfully',
1596
1492
  },
1597
1493
  ],
1598
1494
  };
@@ -1601,26 +1497,24 @@ server.tool("add-watcher", "Add a user as watcher to an issue", {
1601
1497
  return {
1602
1498
  content: [
1603
1499
  {
1604
- type: "text",
1500
+ type: 'text',
1605
1501
  text: `Failed to add watcher: ${error instanceof Error ? error.message : String(error)}`,
1606
1502
  },
1607
1503
  ],
1608
1504
  };
1609
1505
  }
1610
1506
  });
1611
- server.tool("remove-watcher", "Remove a user as watcher from an issue", {
1612
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1613
- accountId: z
1614
- .string()
1615
- .describe("Account ID of the user to remove as watcher"),
1507
+ server.tool('remove-watcher', 'Remove a user as watcher from an issue', {
1508
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1509
+ accountId: z.string().describe('Account ID of the user to remove as watcher'),
1616
1510
  }, async ({ issueKey, accountId }) => {
1617
1511
  try {
1618
1512
  await jiraService.removeWatcher(issueKey, accountId);
1619
1513
  return {
1620
1514
  content: [
1621
1515
  {
1622
- type: "text",
1623
- text: "Watcher removed successfully",
1516
+ type: 'text',
1517
+ text: 'Watcher removed successfully',
1624
1518
  },
1625
1519
  ],
1626
1520
  };
@@ -1629,23 +1523,23 @@ server.tool("remove-watcher", "Remove a user as watcher from an issue", {
1629
1523
  return {
1630
1524
  content: [
1631
1525
  {
1632
- type: "text",
1526
+ type: 'text',
1633
1527
  text: `Failed to remove watcher: ${error instanceof Error ? error.message : String(error)}`,
1634
1528
  },
1635
1529
  ],
1636
1530
  };
1637
1531
  }
1638
1532
  });
1639
- server.tool("watch-issue", "Start watching an issue (for current user)", {
1640
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1533
+ server.tool('watch-issue', 'Start watching an issue (for current user)', {
1534
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1641
1535
  }, async ({ issueKey }) => {
1642
1536
  try {
1643
1537
  await jiraService.watchIssue(issueKey);
1644
1538
  return {
1645
1539
  content: [
1646
1540
  {
1647
- type: "text",
1648
- text: "Now watching the issue",
1541
+ type: 'text',
1542
+ text: 'Now watching the issue',
1649
1543
  },
1650
1544
  ],
1651
1545
  };
@@ -1654,23 +1548,23 @@ server.tool("watch-issue", "Start watching an issue (for current user)", {
1654
1548
  return {
1655
1549
  content: [
1656
1550
  {
1657
- type: "text",
1551
+ type: 'text',
1658
1552
  text: `Failed to watch issue: ${error instanceof Error ? error.message : String(error)}`,
1659
1553
  },
1660
1554
  ],
1661
1555
  };
1662
1556
  }
1663
1557
  });
1664
- server.tool("unwatch-issue", "Stop watching an issue (for current user)", {
1665
- issueKey: z.string().describe("Issue key (e.g. PROJ-123)"),
1558
+ server.tool('unwatch-issue', 'Stop watching an issue (for current user)', {
1559
+ issueKey: z.string().describe('Issue key (e.g. PROJ-123)'),
1666
1560
  }, async ({ issueKey }) => {
1667
1561
  try {
1668
1562
  await jiraService.unwatchIssue(issueKey);
1669
1563
  return {
1670
1564
  content: [
1671
1565
  {
1672
- type: "text",
1673
- text: "Stopped watching the issue",
1566
+ type: 'text',
1567
+ text: 'Stopped watching the issue',
1674
1568
  },
1675
1569
  ],
1676
1570
  };
@@ -1679,7 +1573,7 @@ server.tool("unwatch-issue", "Stop watching an issue (for current user)", {
1679
1573
  return {
1680
1574
  content: [
1681
1575
  {
1682
- type: "text",
1576
+ type: 'text',
1683
1577
  text: `Failed to unwatch issue: ${error instanceof Error ? error.message : String(error)}`,
1684
1578
  },
1685
1579
  ],
@@ -1694,9 +1588,9 @@ async function main() {
1694
1588
  * stdout 을 사용하면 stdio server 특성상 문제가 되므로 필요한 출력이 있다면 stderr를 사용한다.
1695
1589
  * @see https://modelcontextprotocol.io/quickstart/server#node
1696
1590
  */
1697
- console.error("Jira MCP Server running on stdio");
1591
+ console.error('Jira MCP Server running on stdio');
1698
1592
  }
1699
1593
  main().catch((error) => {
1700
- console.error("Fatal error in main():", error);
1594
+ console.error('Fatal error in main():', error);
1701
1595
  process.exit(1);
1702
1596
  });