@mmtr-tech/yandex-tracker-mcp 0.1.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/LICENSE +21 -0
- package/README.md +142 -0
- package/README.ru.md +142 -0
- package/dist/client/tracker-client.d.ts +185 -0
- package/dist/client/tracker-client.js +459 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +39 -0
- package/dist/tools/boards.d.ts +2 -0
- package/dist/tools/boards.js +46 -0
- package/dist/tools/index.d.ts +24 -0
- package/dist/tools/index.js +97 -0
- package/dist/tools/issue-extras.d.ts +2 -0
- package/dist/tools/issue-extras.js +256 -0
- package/dist/tools/issues.d.ts +2 -0
- package/dist/tools/issues.js +437 -0
- package/dist/tools/queues.d.ts +2 -0
- package/dist/tools/queues.js +103 -0
- package/dist/tools/users.d.ts +2 -0
- package/dist/tools/users.js +91 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/truncate.d.ts +20 -0
- package/dist/utils/truncate.js +38 -0
- package/package.json +60 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
const getIssueSchema = z.object({
|
|
4
|
+
issueId: z.string().min(1).describe('Issue key or id (e.g. TEST-1)'),
|
|
5
|
+
expand: z.string().optional()
|
|
6
|
+
.describe('Extra fields: links, comments, transitions, attachments'),
|
|
7
|
+
fields: z.string().optional()
|
|
8
|
+
.describe('Comma-separated field names to return (reduces payload size)'),
|
|
9
|
+
});
|
|
10
|
+
const searchIssuesSchema = z
|
|
11
|
+
.object({
|
|
12
|
+
query: z.string().min(1).optional()
|
|
13
|
+
.describe('Tracker query language filter (preferred for flexible search)'),
|
|
14
|
+
filter: z.record(z.unknown()).optional()
|
|
15
|
+
.describe('Filter object by field values'),
|
|
16
|
+
keys: z.union([z.string().min(1), z.array(z.string().min(1)).min(1)]).optional()
|
|
17
|
+
.describe('Issue key or list of keys'),
|
|
18
|
+
queue: z.string().min(1).optional()
|
|
19
|
+
.describe('Queue key — uses relative pagination; do not combine with query/keys/filter'),
|
|
20
|
+
order: z.string().optional()
|
|
21
|
+
.describe('Sort, e.g. "+updatedAt" or "-updatedAt" (with filter)'),
|
|
22
|
+
perPage: z.coerce.number().int().positive().max(100).optional()
|
|
23
|
+
.describe('Issues per page (default 50)'),
|
|
24
|
+
page: z.coerce.number().int().positive().optional()
|
|
25
|
+
.describe('Page number (page-based pagination for query/filter/keys)'),
|
|
26
|
+
expand: z.string().optional()
|
|
27
|
+
.describe('Extra fields: transitions, attachments, comments'),
|
|
28
|
+
fields: z.string().optional()
|
|
29
|
+
.describe('Comma-separated fields to include in each issue'),
|
|
30
|
+
})
|
|
31
|
+
.superRefine((val, ctx) => {
|
|
32
|
+
const modes = [val.query, val.filter, val.keys, val.queue].filter((v) => v !== undefined);
|
|
33
|
+
if (modes.length === 0) {
|
|
34
|
+
ctx.addIssue({
|
|
35
|
+
code: z.ZodIssueCode.custom,
|
|
36
|
+
message: 'Provide exactly one of: query, filter, keys, or queue',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
else if (modes.length > 1) {
|
|
40
|
+
ctx.addIssue({
|
|
41
|
+
code: z.ZodIssueCode.custom,
|
|
42
|
+
message: 'Use only one of: query, filter, keys, or queue (API rejects combinations)',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const getIssueCommentsSchema = z.object({
|
|
47
|
+
issueId: z.string().min(1).describe('Issue key or id'),
|
|
48
|
+
perPage: z.coerce.number().int().positive().max(100).optional()
|
|
49
|
+
.describe('Comments per page (default 50)'),
|
|
50
|
+
afterId: z.coerce.number().int().positive().optional()
|
|
51
|
+
.describe('Return comments after this comment id (pagination)'),
|
|
52
|
+
expand: z.string().optional()
|
|
53
|
+
.describe('Extra fields: attachments, html, all'),
|
|
54
|
+
});
|
|
55
|
+
const issueIdOnlySchema = z.object({
|
|
56
|
+
issueId: z.string().min(1).describe('Issue key or id (e.g. TEST-1)'),
|
|
57
|
+
});
|
|
58
|
+
const getIssueChangelogSchema = z.object({
|
|
59
|
+
issueId: z.string().min(1).describe('Issue key or id'),
|
|
60
|
+
perPage: z.coerce.number().int().positive().max(100).optional()
|
|
61
|
+
.describe('Changelog entries per page (default 50)'),
|
|
62
|
+
afterId: z.string().min(1).optional()
|
|
63
|
+
.describe('Return entries after this changelog id (pagination)'),
|
|
64
|
+
field: z.string().min(1).optional()
|
|
65
|
+
.describe('Filter by field id, e.g. status or checklistItems'),
|
|
66
|
+
type: z.string().min(1).optional()
|
|
67
|
+
.describe('Filter by change type, e.g. IssueWorkflow, IssueUpdated'),
|
|
68
|
+
});
|
|
69
|
+
const createIssueSchema = z.object({
|
|
70
|
+
queue: z.string().min(1).describe('Queue key or id where the issue will be created'),
|
|
71
|
+
summary: z.string().min(1).describe('Issue title'),
|
|
72
|
+
description: z.string().optional().describe('Issue description'),
|
|
73
|
+
type: z.string().optional().describe('Issue type key or id (e.g. task, bug)'),
|
|
74
|
+
priority: z.string().optional().describe('Priority key or id (e.g. normal, critical)'),
|
|
75
|
+
assignee: z.string().optional().describe('Assignee login or uid'),
|
|
76
|
+
parent: z.string().optional().describe('Parent issue key or id'),
|
|
77
|
+
tags: z.array(z.string()).optional().describe('Tags'),
|
|
78
|
+
markupType: z.string().optional().describe('Set to "md" for YFM markdown in description'),
|
|
79
|
+
fields: z.record(z.unknown()).optional()
|
|
80
|
+
.describe('Extra/custom field map merged into create body (local/global queue fields)'),
|
|
81
|
+
});
|
|
82
|
+
const updateIssueSchema = z
|
|
83
|
+
.object({
|
|
84
|
+
issueId: z.string().min(1).describe('Issue key or id to update'),
|
|
85
|
+
summary: z.string().min(1).optional().describe('New title'),
|
|
86
|
+
description: z.string().optional().describe('New description'),
|
|
87
|
+
type: z.string().optional().describe('Issue type key or id'),
|
|
88
|
+
priority: z.string().optional().describe('Priority key or id'),
|
|
89
|
+
assignee: z.union([z.string().min(1), z.null()]).optional()
|
|
90
|
+
.describe('Assignee login/uid, or null to clear'),
|
|
91
|
+
parent: z.union([z.string().min(1), z.null()]).optional()
|
|
92
|
+
.describe('Parent issue key/id, or null to clear'),
|
|
93
|
+
tags: z.array(z.string()).optional().describe('Replace tags'),
|
|
94
|
+
markupType: z.string().optional().describe('Set to "md" for YFM markdown'),
|
|
95
|
+
version: z.coerce.number().int().positive().optional()
|
|
96
|
+
.describe('Optimistic concurrency version from get_issue'),
|
|
97
|
+
fields: z.record(z.unknown()).optional()
|
|
98
|
+
.describe('Extra/custom fields or Tracker operators (set/add/remove) merged into PATCH body'),
|
|
99
|
+
})
|
|
100
|
+
.superRefine((val, ctx) => {
|
|
101
|
+
const { issueId: _id, version: _v, ...fields } = val;
|
|
102
|
+
if (Object.values(fields).every((v) => v === undefined)) {
|
|
103
|
+
ctx.addIssue({
|
|
104
|
+
code: z.ZodIssueCode.custom,
|
|
105
|
+
message: 'Provide at least one field to update',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const addIssueCommentSchema = z.object({
|
|
110
|
+
issueId: z.string().min(1).describe('Issue key or id'),
|
|
111
|
+
text: z.string().min(1).describe('Comment text'),
|
|
112
|
+
markupType: z.string().optional().describe('Set to "md" for YFM markdown'),
|
|
113
|
+
summonees: z.array(z.string().min(1)).optional()
|
|
114
|
+
.describe('Logins or uids to mention'),
|
|
115
|
+
});
|
|
116
|
+
const executeTransitionSchema = z.object({
|
|
117
|
+
issueId: z.string().min(1).describe('Issue key or id'),
|
|
118
|
+
transitionId: z.string().min(1)
|
|
119
|
+
.describe('Transition id from get_issue_transitions (e.g. close, start_progress)'),
|
|
120
|
+
comment: z.string().optional().describe('Optional comment for the transition'),
|
|
121
|
+
resolution: z.string().optional()
|
|
122
|
+
.describe('Resolution key when required (e.g. fixed, wontFix)'),
|
|
123
|
+
fields: z.record(z.unknown()).optional()
|
|
124
|
+
.describe('Extra field values required by the transition screen'),
|
|
125
|
+
});
|
|
126
|
+
export function registerIssueTools() {
|
|
127
|
+
registerTool({
|
|
128
|
+
zodSchema: getIssueSchema,
|
|
129
|
+
schema: {
|
|
130
|
+
name: 'get_issue',
|
|
131
|
+
description: 'Get a Yandex Tracker issue by key or id (GET /issues/{issueId}). Use expand/fields to control payload size.',
|
|
132
|
+
inputSchema: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
issueId: { type: 'string', description: 'Issue key or id (e.g. TEST-1)' },
|
|
136
|
+
expand: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
description: 'Extra fields: links, comments, transitions, attachments',
|
|
139
|
+
},
|
|
140
|
+
fields: {
|
|
141
|
+
type: 'string',
|
|
142
|
+
description: 'Comma-separated field names to return (reduces payload size)',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
required: ['issueId'],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
execute: async (args, getClient) => {
|
|
149
|
+
return await getClient().getIssue(args);
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
registerTool({
|
|
153
|
+
zodSchema: searchIssuesSchema,
|
|
154
|
+
schema: {
|
|
155
|
+
name: 'search_issues',
|
|
156
|
+
description: 'Search issues (POST /issues/_search). Provide exactly one of query, filter, keys, or queue. Prefer query (Tracker query language). Paginate with perPage/page; default 50 per page. Query examples: "Queue: TEST", "Queue: TEST Assignee: me() Sort by: Updated DESC", "Key: TEST-1", "Queue: TEST Status: open() Resolution: empty()", "Summary: \\"login\\" Queue: TEST".',
|
|
157
|
+
inputSchema: {
|
|
158
|
+
type: 'object',
|
|
159
|
+
properties: {
|
|
160
|
+
query: {
|
|
161
|
+
type: 'string',
|
|
162
|
+
description: 'Tracker query language. Examples: Queue: TEST; Queue: TEST Assignee: me() Sort by: Updated DESC; Key: TEST-1; Queue: TEST Status: open()',
|
|
163
|
+
},
|
|
164
|
+
filter: {
|
|
165
|
+
type: 'object',
|
|
166
|
+
description: 'Filter object by field values',
|
|
167
|
+
additionalProperties: true,
|
|
168
|
+
},
|
|
169
|
+
keys: {
|
|
170
|
+
description: 'Issue key or list of keys',
|
|
171
|
+
oneOf: [
|
|
172
|
+
{ type: 'string' },
|
|
173
|
+
{ type: 'array', items: { type: 'string' } },
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
queue: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
description: 'Queue key (relative pagination; exclusive with other modes)',
|
|
179
|
+
},
|
|
180
|
+
order: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
description: 'Sort, e.g. "+updatedAt" or "-updatedAt"',
|
|
183
|
+
},
|
|
184
|
+
perPage: { type: 'number', description: 'Issues per page (default 50)' },
|
|
185
|
+
page: { type: 'number', description: 'Page number' },
|
|
186
|
+
expand: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
description: 'Extra fields: transitions, attachments, comments',
|
|
189
|
+
},
|
|
190
|
+
fields: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
description: 'Comma-separated fields to include',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
execute: async (args, getClient) => {
|
|
198
|
+
return await getClient().searchIssues(args);
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
registerTool({
|
|
202
|
+
zodSchema: getIssueCommentsSchema,
|
|
203
|
+
schema: {
|
|
204
|
+
name: 'get_issue_comments',
|
|
205
|
+
description: 'List comments on an issue (GET /issues/{issueId}/comments). Paginated; use afterId for next page.',
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
issueId: { type: 'string', description: 'Issue key or id' },
|
|
210
|
+
perPage: { type: 'number', description: 'Comments per page (default 50)' },
|
|
211
|
+
afterId: {
|
|
212
|
+
type: 'number',
|
|
213
|
+
description: 'Return comments after this comment id',
|
|
214
|
+
},
|
|
215
|
+
expand: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
description: 'Extra fields: attachments, html, all',
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
required: ['issueId'],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
execute: async (args, getClient) => {
|
|
224
|
+
return await getClient().getIssueComments(args);
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
registerTool({
|
|
228
|
+
zodSchema: issueIdOnlySchema,
|
|
229
|
+
schema: {
|
|
230
|
+
name: 'get_issue_links',
|
|
231
|
+
description: 'List issue links/relations (GET /issues/{issueId}/links).',
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: 'object',
|
|
234
|
+
properties: {
|
|
235
|
+
issueId: { type: 'string', description: 'Issue key or id (e.g. TEST-1)' },
|
|
236
|
+
},
|
|
237
|
+
required: ['issueId'],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
execute: async (args, getClient) => {
|
|
241
|
+
return await getClient().getIssueLinks(args.issueId);
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
registerTool({
|
|
245
|
+
zodSchema: issueIdOnlySchema,
|
|
246
|
+
schema: {
|
|
247
|
+
name: 'get_issue_transitions',
|
|
248
|
+
description: 'List available status transitions for an issue (GET /issues/{issueId}/transitions). Use transition id with execute_transition.',
|
|
249
|
+
inputSchema: {
|
|
250
|
+
type: 'object',
|
|
251
|
+
properties: {
|
|
252
|
+
issueId: { type: 'string', description: 'Issue key or id (e.g. TEST-1)' },
|
|
253
|
+
},
|
|
254
|
+
required: ['issueId'],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
execute: async (args, getClient) => {
|
|
258
|
+
return await getClient().getIssueTransitions(args.issueId);
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
registerTool({
|
|
262
|
+
zodSchema: getIssueChangelogSchema,
|
|
263
|
+
schema: {
|
|
264
|
+
name: 'get_issue_changelog',
|
|
265
|
+
description: 'Get issue change history (GET /issues/{issueId}/changelog). Paginate with perPage/afterId; filter by field or type (e.g. IssueWorkflow, status).',
|
|
266
|
+
inputSchema: {
|
|
267
|
+
type: 'object',
|
|
268
|
+
properties: {
|
|
269
|
+
issueId: { type: 'string', description: 'Issue key or id' },
|
|
270
|
+
perPage: { type: 'number', description: 'Entries per page (default 50)' },
|
|
271
|
+
afterId: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Return entries after this changelog id',
|
|
274
|
+
},
|
|
275
|
+
field: {
|
|
276
|
+
type: 'string',
|
|
277
|
+
description: 'Filter by field id, e.g. status',
|
|
278
|
+
},
|
|
279
|
+
type: {
|
|
280
|
+
type: 'string',
|
|
281
|
+
description: 'Filter by change type, e.g. IssueWorkflow',
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
required: ['issueId'],
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
execute: async (args, getClient) => {
|
|
288
|
+
return await getClient().getIssueChangelog(args);
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
registerTool({
|
|
292
|
+
zodSchema: issueIdOnlySchema,
|
|
293
|
+
schema: {
|
|
294
|
+
name: 'get_issue_attachments',
|
|
295
|
+
description: 'List issue attachment metadata only (via GET /issues/{issueId}?expand=attachments). Returns id, name, size, mimetype, content URL — does not download file bytes.',
|
|
296
|
+
inputSchema: {
|
|
297
|
+
type: 'object',
|
|
298
|
+
properties: {
|
|
299
|
+
issueId: { type: 'string', description: 'Issue key or id (e.g. TEST-1)' },
|
|
300
|
+
},
|
|
301
|
+
required: ['issueId'],
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
execute: async (args, getClient) => {
|
|
305
|
+
return await getClient().getIssueAttachments(args.issueId);
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
registerTool({
|
|
309
|
+
zodSchema: createIssueSchema,
|
|
310
|
+
schema: {
|
|
311
|
+
name: 'create_issue',
|
|
312
|
+
description: 'CREATE a new issue (POST /issues/). Side effect: writes to Tracker. Requires OAuth tracker:write. Returns the created issue.',
|
|
313
|
+
inputSchema: {
|
|
314
|
+
type: 'object',
|
|
315
|
+
properties: {
|
|
316
|
+
queue: { type: 'string', description: 'Queue key or id' },
|
|
317
|
+
summary: { type: 'string', description: 'Issue title' },
|
|
318
|
+
description: { type: 'string', description: 'Issue description' },
|
|
319
|
+
type: { type: 'string', description: 'Issue type key or id' },
|
|
320
|
+
priority: { type: 'string', description: 'Priority key or id' },
|
|
321
|
+
assignee: { type: 'string', description: 'Assignee login or uid' },
|
|
322
|
+
parent: { type: 'string', description: 'Parent issue key or id' },
|
|
323
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
|
|
324
|
+
markupType: {
|
|
325
|
+
type: 'string',
|
|
326
|
+
description: 'Set to "md" for YFM markdown in description',
|
|
327
|
+
},
|
|
328
|
+
fields: {
|
|
329
|
+
type: 'object',
|
|
330
|
+
additionalProperties: true,
|
|
331
|
+
description: 'Extra/custom fields merged into create body',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
required: ['queue', 'summary'],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
execute: async (args, getClient) => {
|
|
338
|
+
return await getClient().createIssue(args);
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
registerTool({
|
|
342
|
+
zodSchema: updateIssueSchema,
|
|
343
|
+
schema: {
|
|
344
|
+
name: 'update_issue',
|
|
345
|
+
description: 'UPDATE issue fields (PATCH /issues/{issueId}). Side effect: writes to Tracker. Does NOT change status — use execute_transition for that. Use fields for custom fields or Tracker operators (set/add/remove).',
|
|
346
|
+
inputSchema: {
|
|
347
|
+
type: 'object',
|
|
348
|
+
properties: {
|
|
349
|
+
issueId: { type: 'string', description: 'Issue key or id' },
|
|
350
|
+
summary: { type: 'string', description: 'New title' },
|
|
351
|
+
description: { type: 'string', description: 'New description' },
|
|
352
|
+
type: { type: 'string', description: 'Issue type key or id' },
|
|
353
|
+
priority: { type: 'string', description: 'Priority key or id' },
|
|
354
|
+
assignee: {
|
|
355
|
+
description: 'Assignee login/uid, or null to clear',
|
|
356
|
+
oneOf: [{ type: 'string' }, { type: 'null' }],
|
|
357
|
+
},
|
|
358
|
+
parent: {
|
|
359
|
+
description: 'Parent issue key/id, or null to clear',
|
|
360
|
+
oneOf: [{ type: 'string' }, { type: 'null' }],
|
|
361
|
+
},
|
|
362
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Replace tags' },
|
|
363
|
+
markupType: { type: 'string', description: 'Set to "md" for YFM markdown' },
|
|
364
|
+
version: {
|
|
365
|
+
type: 'number',
|
|
366
|
+
description: 'Optimistic concurrency version from get_issue',
|
|
367
|
+
},
|
|
368
|
+
fields: {
|
|
369
|
+
type: 'object',
|
|
370
|
+
additionalProperties: true,
|
|
371
|
+
description: 'Extra/custom fields or operators (set/add/remove)',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
required: ['issueId'],
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
execute: async (args, getClient) => {
|
|
378
|
+
return await getClient().updateIssue(args);
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
registerTool({
|
|
382
|
+
zodSchema: addIssueCommentSchema,
|
|
383
|
+
schema: {
|
|
384
|
+
name: 'add_issue_comment',
|
|
385
|
+
description: 'Add a comment to an issue (POST /issues/{issueId}/comments). Side effect: writes to Tracker.',
|
|
386
|
+
inputSchema: {
|
|
387
|
+
type: 'object',
|
|
388
|
+
properties: {
|
|
389
|
+
issueId: { type: 'string', description: 'Issue key or id' },
|
|
390
|
+
text: { type: 'string', description: 'Comment text' },
|
|
391
|
+
markupType: { type: 'string', description: 'Set to "md" for YFM markdown' },
|
|
392
|
+
summonees: {
|
|
393
|
+
type: 'array',
|
|
394
|
+
items: { type: 'string' },
|
|
395
|
+
description: 'Logins or uids to mention',
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
required: ['issueId', 'text'],
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
execute: async (args, getClient) => {
|
|
402
|
+
return await getClient().addIssueComment(args);
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
registerTool({
|
|
406
|
+
zodSchema: executeTransitionSchema,
|
|
407
|
+
schema: {
|
|
408
|
+
name: 'execute_transition',
|
|
409
|
+
description: 'Execute a status transition (POST /issues/{issueId}/transitions/{transitionId}/_execute). Side effect: changes issue status. Call get_issue_transitions first to get transitionId.',
|
|
410
|
+
inputSchema: {
|
|
411
|
+
type: 'object',
|
|
412
|
+
properties: {
|
|
413
|
+
issueId: { type: 'string', description: 'Issue key or id' },
|
|
414
|
+
transitionId: {
|
|
415
|
+
type: 'string',
|
|
416
|
+
description: 'Transition id from get_issue_transitions',
|
|
417
|
+
},
|
|
418
|
+
comment: { type: 'string', description: 'Optional comment' },
|
|
419
|
+
resolution: {
|
|
420
|
+
type: 'string',
|
|
421
|
+
description: 'Resolution key when required (e.g. fixed)',
|
|
422
|
+
},
|
|
423
|
+
fields: {
|
|
424
|
+
type: 'object',
|
|
425
|
+
additionalProperties: true,
|
|
426
|
+
description: 'Extra field values for the transition screen',
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
required: ['issueId', 'transitionId'],
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
execute: async (args, getClient) => {
|
|
433
|
+
return await getClient().executeTransition(args);
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=issues.js.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
const listQueuesSchema = z.object({
|
|
4
|
+
perPage: z.coerce.number().int().positive().max(100).optional()
|
|
5
|
+
.describe('Queues per page (default 50, max 100)'),
|
|
6
|
+
page: z.coerce.number().int().positive().optional()
|
|
7
|
+
.describe('Page number for pagination'),
|
|
8
|
+
expand: z.string().optional()
|
|
9
|
+
.describe('Extra fields: projects, components, versions, types, team, workflows'),
|
|
10
|
+
});
|
|
11
|
+
const getQueueSchema = z.object({
|
|
12
|
+
queueId: z.string().min(1).describe('Queue key or id (e.g. TEST)'),
|
|
13
|
+
expand: z.string().optional()
|
|
14
|
+
.describe('Extra fields: projects, components, versions, types, team, workflows'),
|
|
15
|
+
});
|
|
16
|
+
export function registerQueueTools() {
|
|
17
|
+
registerTool({
|
|
18
|
+
zodSchema: listQueuesSchema,
|
|
19
|
+
schema: {
|
|
20
|
+
name: 'list_queues',
|
|
21
|
+
description: 'List accessible Yandex Tracker queues (GET /queues/). Paginated; default 50 per page. Prefer small perPage and page through results.',
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
perPage: {
|
|
26
|
+
type: 'number',
|
|
27
|
+
description: 'Queues per page (default 50, max 100)',
|
|
28
|
+
},
|
|
29
|
+
page: {
|
|
30
|
+
type: 'number',
|
|
31
|
+
description: 'Page number for pagination',
|
|
32
|
+
},
|
|
33
|
+
expand: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description: 'Extra fields: projects, components, versions, types, team, workflows',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
execute: async (args, getClient) => {
|
|
41
|
+
return await getClient().listQueues(args);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
registerTool({
|
|
45
|
+
zodSchema: getQueueSchema,
|
|
46
|
+
schema: {
|
|
47
|
+
name: 'get_queue',
|
|
48
|
+
description: 'Get a single queue by key or id (GET /queues/{queueId}).',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
queueId: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Queue key or id (e.g. TEST)',
|
|
55
|
+
},
|
|
56
|
+
expand: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Extra fields: projects, components, versions, types, team, workflows',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
required: ['queueId'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
execute: async (args, getClient) => {
|
|
65
|
+
return await getClient().getQueue(args);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
registerTool({
|
|
69
|
+
zodSchema: getQueueSchema.pick({ queueId: true }),
|
|
70
|
+
schema: {
|
|
71
|
+
name: 'list_queue_versions',
|
|
72
|
+
description: 'List versions of a queue (GET /queues/{queueId}/versions).',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
queueId: { type: 'string', description: 'Queue key or id' },
|
|
77
|
+
},
|
|
78
|
+
required: ['queueId'],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
execute: async (args, getClient) => {
|
|
82
|
+
return await getClient().getQueueVersions(args.queueId);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
registerTool({
|
|
86
|
+
zodSchema: getQueueSchema.pick({ queueId: true }),
|
|
87
|
+
schema: {
|
|
88
|
+
name: 'list_queue_components',
|
|
89
|
+
description: 'List components of a queue (via GET /queues/{queueId}?expand=components). Returns components array only.',
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
queueId: { type: 'string', description: 'Queue key or id' },
|
|
94
|
+
},
|
|
95
|
+
required: ['queueId'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
execute: async (args, getClient) => {
|
|
99
|
+
return await getClient().getQueueComponents(args.queueId);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=queues.js.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { registerTool } from './index.js';
|
|
3
|
+
const getMyselfSchema = z.object({});
|
|
4
|
+
const getUserSchema = z.object({
|
|
5
|
+
userId: z.string().min(1)
|
|
6
|
+
.describe('User login or uid. If login is digits-only, use login:<digits>'),
|
|
7
|
+
expand: z.string().optional()
|
|
8
|
+
.describe('Extra fields: groups'),
|
|
9
|
+
});
|
|
10
|
+
const listUsersSchema = z.object({
|
|
11
|
+
perPage: z.coerce.number().int().min(1).max(100).optional()
|
|
12
|
+
.describe('Users per page (1–100, default 50)'),
|
|
13
|
+
id: z.coerce.number().int().positive().optional()
|
|
14
|
+
.describe('Start listing after this user uid (pagination cursor)'),
|
|
15
|
+
email: z.string().email().optional()
|
|
16
|
+
.describe('Exact email filter — returns matching user(s)'),
|
|
17
|
+
expand: z.string().optional()
|
|
18
|
+
.describe('Extra fields: groups'),
|
|
19
|
+
});
|
|
20
|
+
export function registerUserTools() {
|
|
21
|
+
registerTool({
|
|
22
|
+
zodSchema: getMyselfSchema,
|
|
23
|
+
schema: {
|
|
24
|
+
name: 'get_myself',
|
|
25
|
+
description: 'Get the current Yandex Tracker user (GET /myself). Use to verify OAuth access and learn who the API acts as.',
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
execute: async (_args, getClient) => {
|
|
32
|
+
return await getClient().getMyself();
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
registerTool({
|
|
36
|
+
zodSchema: getUserSchema,
|
|
37
|
+
schema: {
|
|
38
|
+
name: 'get_user',
|
|
39
|
+
description: 'Get a Tracker user by login or uid (GET /users/{userId}). If the login is digits-only, pass login:<digits>. Optional expand=groups.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
userId: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'User login or uid. Digits-only login: login:<digits>',
|
|
46
|
+
},
|
|
47
|
+
expand: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Extra fields: groups',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
required: ['userId'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
execute: async (args, getClient) => {
|
|
56
|
+
return await getClient().getUser(args);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
registerTool({
|
|
60
|
+
zodSchema: listUsersSchema,
|
|
61
|
+
schema: {
|
|
62
|
+
name: 'list_users',
|
|
63
|
+
description: 'List organization users (GET /users). Paginate with perPage (max 100) and id cursor. Filter by exact email when known.',
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
perPage: {
|
|
68
|
+
type: 'number',
|
|
69
|
+
description: 'Users per page (1–100, default 50)',
|
|
70
|
+
},
|
|
71
|
+
id: {
|
|
72
|
+
type: 'number',
|
|
73
|
+
description: 'Start listing after this user uid',
|
|
74
|
+
},
|
|
75
|
+
email: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Exact email filter',
|
|
78
|
+
},
|
|
79
|
+
expand: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Extra fields: groups',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
execute: async (args, getClient) => {
|
|
87
|
+
return await getClient().listUsers(args);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=users.js.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Re-export client types for convenience. */
|
|
2
|
+
export type { TrackerClientConfig, ListQueuesParams, GetQueueParams, GetIssueParams, SearchIssuesParams, ListCommentsParams, CreateIssueParams, UpdateIssueParams, AddCommentParams, ExecuteTransitionParams, GetIssueChangelogParams, GetUserParams, ListUsersParams, } from '../client/tracker-client.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Default cap for large tool payloads returned to the MCP client. */
|
|
2
|
+
export declare const DEFAULT_MAX_CHARS = 80000;
|
|
3
|
+
export interface TruncatedText {
|
|
4
|
+
text: string;
|
|
5
|
+
truncated: boolean;
|
|
6
|
+
original_length: number;
|
|
7
|
+
max_chars: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function truncateText(text: string, maxChars?: number): TruncatedText;
|
|
10
|
+
export interface TruncationMeta {
|
|
11
|
+
truncated: boolean;
|
|
12
|
+
original_length: number;
|
|
13
|
+
max_chars: number;
|
|
14
|
+
note?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Truncate a JSON-serializable value so stringify(result) stays under maxChars. */
|
|
17
|
+
export declare function truncatePayload<T>(value: T, maxChars?: number): T & {
|
|
18
|
+
_truncation?: TruncationMeta;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=truncate.d.ts.map
|