@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/config.js +4 -4
- package/dist/index.js +426 -532
- package/dist/libs/base-client.js +13 -13
- package/dist/libs/error-handler.js +4 -4
- package/dist/libs/jira-client.js +53 -53
- package/package.json +3 -4
package/dist/index.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { McpServer } from
|
|
3
|
-
import { StdioServerTransport } from
|
|
4
|
-
import { z } from
|
|
5
|
-
import { JiraService } from
|
|
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:
|
|
9
|
-
version:
|
|
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(
|
|
15
|
-
issueKey: z.string().describe(
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
'renderedFields',
|
|
19
|
+
'names',
|
|
20
|
+
'schema',
|
|
21
|
+
'transitions',
|
|
22
|
+
'editmeta',
|
|
23
|
+
'changelog',
|
|
24
|
+
'versionedRepresentations',
|
|
25
25
|
])
|
|
26
26
|
.array()
|
|
27
27
|
.optional()
|
|
28
|
-
.describe(
|
|
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:
|
|
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:
|
|
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(
|
|
53
|
-
jql: z.string().describe(
|
|
54
|
-
fields: z
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
'renderedFields',
|
|
71
|
+
'names',
|
|
72
|
+
'schema',
|
|
73
|
+
'transitions',
|
|
74
|
+
'editmeta',
|
|
75
|
+
'changelog',
|
|
76
|
+
'versionedRepresentations',
|
|
66
77
|
])
|
|
67
78
|
.array()
|
|
68
79
|
.optional()
|
|
69
|
-
.describe(
|
|
70
|
-
properties: z
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
108
|
-
issueKey: z.string().describe(
|
|
109
|
-
startAt: z
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
142
|
-
startAt: z
|
|
143
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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(
|
|
157
|
-
id: z.array(z.number().int()).max(50).optional().describe(
|
|
158
|
-
keys: z.array(z.string()).max(50).optional().describe(
|
|
159
|
-
query: z.string().optional().describe(
|
|
160
|
-
typeKey: z
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
228
|
-
projectIdOrKey: z
|
|
229
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
256
|
-
type: z
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
306
|
-
query: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
335
|
-
projectKey: z.string().describe(
|
|
336
|
-
summary: z.string().describe(
|
|
337
|
-
issueTypeId: z.string().optional().describe(
|
|
338
|
-
issueTypeName: z.string().optional().describe(
|
|
339
|
-
description: z
|
|
340
|
-
|
|
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(
|
|
351
|
-
priorityId: z.string().optional().describe(
|
|
352
|
-
labels: z.array(z.string()).optional().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
392
|
-
issueKey: z.string().describe(
|
|
393
|
-
assigneeAccountId: z
|
|
394
|
-
|
|
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:
|
|
413
|
-
text:
|
|
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:
|
|
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(
|
|
430
|
-
issueKey: z.string().describe(
|
|
431
|
-
summary: z.string().optional().describe(
|
|
432
|
-
description: z.string().optional().describe(
|
|
433
|
-
assigneeAccountId: z
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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:
|
|
462
|
-
text:
|
|
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:
|
|
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(
|
|
479
|
-
query: z.string().optional().describe(
|
|
480
|
-
accountId: z.string().optional().describe(
|
|
481
|
-
startAt: z
|
|
482
|
-
|
|
483
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
526
|
-
query: z.string().describe(
|
|
527
|
-
maxResults: z
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
579
|
-
projectKeys: z
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
628
|
-
permissions: z
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
653
|
+
server.tool('get-myself', 'Get current user information', {
|
|
686
654
|
expand: z
|
|
687
|
-
.array(z.enum([
|
|
655
|
+
.array(z.enum(['groups', 'applicationRoles']))
|
|
688
656
|
.optional()
|
|
689
|
-
.describe(
|
|
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:
|
|
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:
|
|
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(
|
|
714
|
-
projectKey: z
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
776
|
-
emailAddress: z.string().email().optional().describe(
|
|
777
|
-
displayName: z.string().optional().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
812
|
-
key: z.string().optional().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
837
|
-
key: z.string().describe(
|
|
838
|
-
value: z.any().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
934
|
-
issueKey: z.string().describe(
|
|
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([
|
|
880
|
+
.array(z.enum(['transitions.fields', 'fields']))
|
|
937
881
|
.optional()
|
|
938
|
-
.describe(
|
|
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:
|
|
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:
|
|
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(
|
|
963
|
-
issueKey: z.string().describe(
|
|
964
|
-
transitionId: z.string().describe(
|
|
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(
|
|
911
|
+
body: z.string().describe('Comment text'),
|
|
968
912
|
visibility: z
|
|
969
913
|
.object({
|
|
970
|
-
type: z.enum([
|
|
971
|
-
value: z.string().describe(
|
|
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(
|
|
918
|
+
.describe('Comment visibility restrictions'),
|
|
975
919
|
})
|
|
976
920
|
.optional()
|
|
977
|
-
.describe(
|
|
978
|
-
fields: z
|
|
979
|
-
|
|
980
|
-
|
|
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(
|
|
990
|
-
value: z.any().describe(
|
|
927
|
+
key: z.string().describe('Property key'),
|
|
928
|
+
value: z.any().describe('Property value'),
|
|
991
929
|
}))
|
|
992
930
|
.optional()
|
|
993
|
-
.describe(
|
|
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:
|
|
1008
|
-
text:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
1048
|
-
idOrName: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1073
|
-
startAt: z
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
1123
|
-
id: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1148
|
-
startAt: z
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
1203
|
-
issueKey: z.string().describe(
|
|
1204
|
-
body: z.string().describe(
|
|
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([
|
|
1208
|
-
value: z.string().describe(
|
|
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(
|
|
1116
|
+
.describe('Comment visibility restrictions'),
|
|
1212
1117
|
properties: z
|
|
1213
1118
|
.array(z.object({
|
|
1214
|
-
key: z.string().describe(
|
|
1215
|
-
value: z.any().describe(
|
|
1119
|
+
key: z.string().describe('Property key'),
|
|
1120
|
+
value: z.any().describe('Property value'),
|
|
1216
1121
|
}))
|
|
1217
1122
|
.optional()
|
|
1218
|
-
.describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1247
|
-
issueKey: z.string().describe(
|
|
1248
|
-
commentId: z.string().describe(
|
|
1249
|
-
body: z.string().describe(
|
|
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([
|
|
1253
|
-
value: z.string().describe(
|
|
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(
|
|
1161
|
+
.describe('Comment visibility restrictions'),
|
|
1257
1162
|
properties: z
|
|
1258
1163
|
.array(z.object({
|
|
1259
|
-
key: z.string().describe(
|
|
1260
|
-
value: z.any().describe(
|
|
1164
|
+
key: z.string().describe('Property key'),
|
|
1165
|
+
value: z.any().describe('Property value'),
|
|
1261
1166
|
}))
|
|
1262
1167
|
.optional()
|
|
1263
|
-
.describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1292
|
-
issueKey: z.string().describe(
|
|
1293
|
-
commentId: z.string().describe(
|
|
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:
|
|
1301
|
-
text:
|
|
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:
|
|
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(
|
|
1318
|
-
issueKey: z.string().describe(
|
|
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:
|
|
1330
|
-
text:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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(
|
|
1370
|
-
issueLinkTypeId: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1395
|
-
linkTypeId: z
|
|
1396
|
-
|
|
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(
|
|
1302
|
+
.describe('Inward issue ID (either this or inwardIssueKey must be provided)'),
|
|
1407
1303
|
inwardIssueKey: z
|
|
1408
1304
|
.string()
|
|
1409
1305
|
.optional()
|
|
1410
|
-
.describe(
|
|
1306
|
+
.describe('Inward issue key (either this or inwardIssueId must be provided)'),
|
|
1411
1307
|
outwardIssueId: z
|
|
1412
1308
|
.string()
|
|
1413
1309
|
.optional()
|
|
1414
|
-
.describe(
|
|
1310
|
+
.describe('Outward issue ID (either this or outwardIssueKey must be provided)'),
|
|
1415
1311
|
outwardIssueKey: z
|
|
1416
1312
|
.string()
|
|
1417
1313
|
.optional()
|
|
1418
|
-
.describe(
|
|
1314
|
+
.describe('Outward issue key (either this or outwardIssueId must be provided)'),
|
|
1419
1315
|
comment: z
|
|
1420
1316
|
.object({
|
|
1421
|
-
body: z.string().describe(
|
|
1317
|
+
body: z.string().describe('Comment text'),
|
|
1422
1318
|
visibility: z
|
|
1423
1319
|
.object({
|
|
1424
|
-
type: z.enum([
|
|
1425
|
-
value: z.string().describe(
|
|
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(
|
|
1324
|
+
.describe('Comment visibility restrictions'),
|
|
1429
1325
|
})
|
|
1430
1326
|
.optional()
|
|
1431
|
-
.describe(
|
|
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(
|
|
1332
|
+
throw new Error('Either linkTypeId or linkTypeName must be provided');
|
|
1437
1333
|
}
|
|
1438
1334
|
if (!inwardIssueId && !inwardIssueKey) {
|
|
1439
|
-
throw new Error(
|
|
1335
|
+
throw new Error('Either inwardIssueId or inwardIssueKey must be provided');
|
|
1440
1336
|
}
|
|
1441
1337
|
if (!outwardIssueId && !outwardIssueKey) {
|
|
1442
|
-
throw new Error(
|
|
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:
|
|
1469
|
-
text:
|
|
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:
|
|
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(
|
|
1486
|
-
linkId: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1511
|
-
linkId: z.string().describe(
|
|
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:
|
|
1519
|
-
text:
|
|
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:
|
|
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(
|
|
1536
|
-
issueKey: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1561
|
-
issueKey: z.string().describe(
|
|
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:
|
|
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:
|
|
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(
|
|
1586
|
-
issueKey: z.string().describe(
|
|
1587
|
-
accountId: z.string().describe(
|
|
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:
|
|
1595
|
-
text:
|
|
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:
|
|
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(
|
|
1612
|
-
issueKey: z.string().describe(
|
|
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:
|
|
1623
|
-
text:
|
|
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:
|
|
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(
|
|
1640
|
-
issueKey: z.string().describe(
|
|
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:
|
|
1648
|
-
text:
|
|
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:
|
|
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(
|
|
1665
|
-
issueKey: z.string().describe(
|
|
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:
|
|
1673
|
-
text:
|
|
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:
|
|
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(
|
|
1591
|
+
console.error('Jira MCP Server running on stdio');
|
|
1698
1592
|
}
|
|
1699
1593
|
main().catch((error) => {
|
|
1700
|
-
console.error(
|
|
1594
|
+
console.error('Fatal error in main():', error);
|
|
1701
1595
|
process.exit(1);
|
|
1702
1596
|
});
|