devto-mcp 0.5.0 → 0.5.1
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/cli.js +86 -44
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +18 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +577 -22
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +37 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +599 -15
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -64,24 +64,76 @@ DevTo connects to the developer's project tracker (Jira, Linear, etc.) and manag
|
|
|
64
64
|
## Behavior
|
|
65
65
|
- When the user asks about tasks, status, or work items, use the DevTo tools — do not confuse with Claude Code's built-in task system.
|
|
66
66
|
- Never write to the project tracker without explicit developer confirmation. Show what you intend to do and wait for a yes.
|
|
67
|
-
- When the developer asks to add a comment to
|
|
67
|
+
- IMPORTANT: When the developer asks to add a comment to ANY ticket, ALWAYS use update_task with the comment parameter. You do NOT need to change status — just pass the comment parameter alone. This is NOT optional — update_task IS the comment tool. Do not tell the user you cannot add comments.
|
|
68
68
|
- When the developer asks to read comments on a ticket, use get_comments.
|
|
69
69
|
|
|
70
70
|
## Tools
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
### Project Overview
|
|
73
|
+
- get_project_summary — Lightweight snapshot of all active work with epic progress. Call at session start.
|
|
74
|
+
- get_status — Aggregate project metrics (task counts, sprint info).
|
|
75
|
+
- list_epics — List all epics with progress bars (done/in-progress/todo counts).
|
|
76
|
+
- get_epic — Deep dive into a single epic: all child tasks + recent comments.
|
|
77
|
+
|
|
78
|
+
### Planning
|
|
72
79
|
- create_plan — AI-powered plan generation (epic + stories + subtasks). Returns preview only.
|
|
73
80
|
- confirm_plan — Execute a previously previewed plan.
|
|
81
|
+
|
|
82
|
+
### Issue Management
|
|
74
83
|
- create_epic — Create a single epic.
|
|
75
|
-
- create_task — Create a story/task, optionally linked to an epic.
|
|
84
|
+
- create_task — Create a story/task, optionally linked to an epic via epic_key.
|
|
76
85
|
- create_subtask — Create a subtask under a parent issue.
|
|
86
|
+
- update_task — Update ANY field on a task: status, title, description, assignee, priority, labels, epic_key (link to epic), or add a comment. All fields optional except issue_key. Accepts natural language references.
|
|
87
|
+
- update_epic — Update an epic's status, title, description, or add a comment.
|
|
88
|
+
- delete_issue — Permanently delete any ticket. Cannot be undone.
|
|
77
89
|
- get_tasks — Fetch open tasks. Optionally filter by epic.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
|
|
91
|
+
### Comments
|
|
92
|
+
- add_comment — Add a comment to any ticket. This is the simplest way to comment on a task, epic, or any issue.
|
|
93
|
+
- get_comments — Read recent comments on a ticket (20 most recent).
|
|
94
|
+
- delete_comment — Delete a comment by ID.
|
|
95
|
+
|
|
96
|
+
### Sprint Management
|
|
97
|
+
- list_sprints — See active and upcoming sprints.
|
|
98
|
+
- create_sprint — Create a new sprint with optional start/end dates.
|
|
99
|
+
- move_to_sprint — Move one or more issues into a sprint. Resolves sprint by name.
|
|
100
|
+
- manage_sprint — Start or close a sprint.
|
|
101
|
+
|
|
102
|
+
### Search
|
|
103
|
+
- search_issues — Search for issues using JQL (Jira Query Language). Supports any valid JQL query.
|
|
104
|
+
|
|
105
|
+
### Custom Fields
|
|
106
|
+
- get_custom_fields — List available custom fields and their IDs. Use when setting custom_fields on create_task or update_task.
|
|
107
|
+
|
|
108
|
+
### Issue Linking
|
|
109
|
+
- link_issues — Link two issues together (e.g. blocks, duplicates, relates to). Use get_link_types to see available types.
|
|
110
|
+
- get_issue_links — Get all links for an issue (blocks, duplicates, relates to, etc.).
|
|
111
|
+
- get_link_types — List available issue link types with inward/outward descriptions.
|
|
112
|
+
|
|
113
|
+
### Time Tracking
|
|
114
|
+
- log_work — Log time spent on an issue. Time format: '2h', '30m', '1d', '2h 30m'.
|
|
115
|
+
- get_worklog — Get work log entries for an issue. Shows who logged what time and when.
|
|
116
|
+
- set_estimate — Set the time estimate for an issue. Format: '4h', '1d', '2w'.
|
|
117
|
+
|
|
118
|
+
### Versions/Releases
|
|
119
|
+
- list_versions — List all versions/releases for the project.
|
|
120
|
+
- create_version — Create a new version/release.
|
|
121
|
+
- release_version — Mark a version as released. Resolves by name.
|
|
122
|
+
|
|
123
|
+
### Backlog
|
|
124
|
+
- get_backlog — Get issues in the backlog (not assigned to any sprint).
|
|
125
|
+
- move_to_backlog — Move issues from a sprint back to the backlog.
|
|
126
|
+
|
|
127
|
+
### Bulk Operations
|
|
128
|
+
- bulk_create_tasks — Create multiple tasks at once. Each task gets a title, description, optional type and epic_key.
|
|
129
|
+
- bulk_update_tasks — Update multiple tasks at once. Useful for batch status changes.
|
|
130
|
+
|
|
131
|
+
### Attachments
|
|
132
|
+
- attach_file — Attach a local file to an issue. Reads from your filesystem.
|
|
133
|
+
- list_attachments — List all attachments on an issue.
|
|
134
|
+
|
|
135
|
+
### Watchers
|
|
136
|
+
- manage_watchers — List, add, or remove watchers on an issue.`;
|
|
85
137
|
const server = new index_js_1.Server({
|
|
86
138
|
name: "devto",
|
|
87
139
|
version: config_1.VERSION,
|
|
@@ -145,15 +197,19 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
145
197
|
},
|
|
146
198
|
{
|
|
147
199
|
name: "create_task",
|
|
148
|
-
description: "Create a
|
|
200
|
+
description: "Create a work item (Story, Bug, Task, or any type available in the project), optionally linked to an epic.",
|
|
149
201
|
inputSchema: {
|
|
150
202
|
type: "object",
|
|
151
203
|
properties: {
|
|
152
|
-
title: { type: "string", description: "
|
|
153
|
-
description: { type: "string", description: "
|
|
204
|
+
title: { type: "string", description: "Title" },
|
|
205
|
+
description: { type: "string", description: "Description" },
|
|
154
206
|
epic_key: {
|
|
155
207
|
type: "string",
|
|
156
|
-
description: "Optional epic key
|
|
208
|
+
description: "Optional epic key or description to link this task to",
|
|
209
|
+
},
|
|
210
|
+
type: {
|
|
211
|
+
type: "string",
|
|
212
|
+
description: "Issue type name (e.g. 'Story', 'Bug', 'Task'). Defaults to Story. Use get_status to see available types for this project.",
|
|
157
213
|
},
|
|
158
214
|
},
|
|
159
215
|
required: ["title", "description"],
|
|
@@ -191,7 +247,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
191
247
|
},
|
|
192
248
|
{
|
|
193
249
|
name: "update_task",
|
|
194
|
-
description: "Update a task
|
|
250
|
+
description: "Update any field on a task: status, title, description, assignee, priority, labels, epic_key, or add a comment. This is also the PRIMARY way to add comments — just pass comment alone. Accepts natural language references (e.g. 'the auth task'). At least one field is required.",
|
|
195
251
|
inputSchema: {
|
|
196
252
|
type: "object",
|
|
197
253
|
properties: {
|
|
@@ -201,12 +257,36 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
201
257
|
},
|
|
202
258
|
status: {
|
|
203
259
|
type: "string",
|
|
204
|
-
|
|
205
|
-
|
|
260
|
+
description: "New status: 'todo', 'in_progress', 'in_review', 'done', or any custom Jira status name (e.g. 'QA', 'Blocked'). Optional.",
|
|
261
|
+
},
|
|
262
|
+
title: {
|
|
263
|
+
type: "string",
|
|
264
|
+
description: "New title/summary for the ticket. Use this to rename or fix typos.",
|
|
265
|
+
},
|
|
266
|
+
description: {
|
|
267
|
+
type: "string",
|
|
268
|
+
description: "New description for the ticket. Replaces the existing description.",
|
|
206
269
|
},
|
|
207
270
|
comment: {
|
|
208
271
|
type: "string",
|
|
209
|
-
description: "Comment to add to the ticket.
|
|
272
|
+
description: "Comment to add to the ticket. You can pass comment alone without status — this is the primary way to add comments.",
|
|
273
|
+
},
|
|
274
|
+
assignee: {
|
|
275
|
+
type: "string",
|
|
276
|
+
description: "Assign to a person by name (e.g. 'John Doe'). DevTo will look up their Jira account.",
|
|
277
|
+
},
|
|
278
|
+
priority: {
|
|
279
|
+
type: "string",
|
|
280
|
+
description: "Set priority (e.g. 'High', 'Medium', 'Low', 'Critical').",
|
|
281
|
+
},
|
|
282
|
+
labels: {
|
|
283
|
+
type: "array",
|
|
284
|
+
items: { type: "string" },
|
|
285
|
+
description: "Set labels/tags on the ticket (replaces existing labels).",
|
|
286
|
+
},
|
|
287
|
+
epic_key: {
|
|
288
|
+
type: "string",
|
|
289
|
+
description: "Link this task to an epic by key (e.g. 'PROJ-2') or natural language description. Moves the task under the specified epic.",
|
|
210
290
|
},
|
|
211
291
|
},
|
|
212
292
|
required: ["issue_key"],
|
|
@@ -247,8 +327,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
247
327
|
},
|
|
248
328
|
status: {
|
|
249
329
|
type: "string",
|
|
250
|
-
|
|
251
|
-
description: "New status for the epic",
|
|
330
|
+
description: "New status: 'todo', 'in_progress', 'in_review', 'done', or any custom Jira status name (e.g. 'QA', 'Blocked').",
|
|
252
331
|
},
|
|
253
332
|
title: {
|
|
254
333
|
type: "string",
|
|
@@ -298,6 +377,98 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
298
377
|
required: ["issue_key", "comment_id"],
|
|
299
378
|
},
|
|
300
379
|
},
|
|
380
|
+
{
|
|
381
|
+
name: "add_comment",
|
|
382
|
+
description: "Add a comment to any ticket (task, epic, story, subtask). This is the simplest way to comment. Use this whenever the developer asks to add a comment.",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {
|
|
386
|
+
issue_key: {
|
|
387
|
+
type: "string",
|
|
388
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
389
|
+
},
|
|
390
|
+
comment: {
|
|
391
|
+
type: "string",
|
|
392
|
+
description: "The comment text to add",
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
required: ["issue_key", "comment"],
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "delete_issue",
|
|
400
|
+
description: "Permanently delete a ticket from your project. This cannot be undone. Use this when the developer asks to remove or delete a task, epic, story, or subtask.",
|
|
401
|
+
inputSchema: {
|
|
402
|
+
type: "object",
|
|
403
|
+
properties: {
|
|
404
|
+
issue_key: {
|
|
405
|
+
type: "string",
|
|
406
|
+
description: "Issue key (e.g. PROJ-5) or natural language description of the issue to delete",
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
required: ["issue_key"],
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "list_sprints",
|
|
414
|
+
description: "List active and upcoming sprints for the project. Shows sprint name, state, and date range.",
|
|
415
|
+
inputSchema: {
|
|
416
|
+
type: "object",
|
|
417
|
+
properties: {},
|
|
418
|
+
required: [],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: "create_sprint",
|
|
423
|
+
description: "Create a new sprint. Dates are optional — you can start the sprint later.",
|
|
424
|
+
inputSchema: {
|
|
425
|
+
type: "object",
|
|
426
|
+
properties: {
|
|
427
|
+
name: { type: "string", description: "Sprint name (e.g. 'Sprint 5')" },
|
|
428
|
+
start_date: { type: "string", description: "Start date (ISO 8601, e.g. '2026-03-24'). Optional." },
|
|
429
|
+
end_date: { type: "string", description: "End date (ISO 8601, e.g. '2026-04-07'). Optional." },
|
|
430
|
+
},
|
|
431
|
+
required: ["name"],
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "move_to_sprint",
|
|
436
|
+
description: "Move one or more issues into a sprint. You can reference the sprint by name or ID, and issues by key or natural language.",
|
|
437
|
+
inputSchema: {
|
|
438
|
+
type: "object",
|
|
439
|
+
properties: {
|
|
440
|
+
sprint: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "Sprint name (e.g. 'Sprint 5') or sprint ID number",
|
|
443
|
+
},
|
|
444
|
+
issue_keys: {
|
|
445
|
+
type: "array",
|
|
446
|
+
items: { type: "string" },
|
|
447
|
+
description: "Issue keys to move (e.g. ['PROJ-1', 'PROJ-2'])",
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
required: ["sprint", "issue_keys"],
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "manage_sprint",
|
|
455
|
+
description: "Start or close a sprint. Use 'start' to activate a future sprint, or 'close' to complete an active sprint.",
|
|
456
|
+
inputSchema: {
|
|
457
|
+
type: "object",
|
|
458
|
+
properties: {
|
|
459
|
+
sprint: {
|
|
460
|
+
type: "string",
|
|
461
|
+
description: "Sprint name or ID",
|
|
462
|
+
},
|
|
463
|
+
action: {
|
|
464
|
+
type: "string",
|
|
465
|
+
enum: ["start", "close"],
|
|
466
|
+
description: "Action to perform: 'start' or 'close'",
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
required: ["sprint", "action"],
|
|
470
|
+
},
|
|
471
|
+
},
|
|
301
472
|
{
|
|
302
473
|
name: "get_status",
|
|
303
474
|
description: "Get a summary of your project: task counts and current sprint",
|
|
@@ -307,6 +478,305 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
307
478
|
required: [],
|
|
308
479
|
},
|
|
309
480
|
},
|
|
481
|
+
{
|
|
482
|
+
name: "search_issues",
|
|
483
|
+
description: "Search for issues using JQL (Jira Query Language). Examples: 'assignee = currentUser()', 'status = \"In Progress\"', 'labels = bug AND priority = High'.",
|
|
484
|
+
inputSchema: {
|
|
485
|
+
type: "object",
|
|
486
|
+
properties: {
|
|
487
|
+
jql: {
|
|
488
|
+
type: "string",
|
|
489
|
+
description: "JQL query string",
|
|
490
|
+
},
|
|
491
|
+
max_results: {
|
|
492
|
+
type: "number",
|
|
493
|
+
description: "Maximum number of results to return (default 50)",
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
required: ["jql"],
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: "get_custom_fields",
|
|
501
|
+
description: "List all custom fields available in the project. Shows field IDs needed when setting custom_fields on create_task or update_task.",
|
|
502
|
+
inputSchema: {
|
|
503
|
+
type: "object",
|
|
504
|
+
properties: {},
|
|
505
|
+
required: [],
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
name: "link_issues",
|
|
510
|
+
description: "Link two issues together (e.g. blocks, duplicates, relates to). Use get_link_types to see available link types.",
|
|
511
|
+
inputSchema: {
|
|
512
|
+
type: "object",
|
|
513
|
+
properties: {
|
|
514
|
+
issue_key_1: {
|
|
515
|
+
type: "string",
|
|
516
|
+
description: "First issue key or natural language description",
|
|
517
|
+
},
|
|
518
|
+
issue_key_2: {
|
|
519
|
+
type: "string",
|
|
520
|
+
description: "Second issue key or natural language description",
|
|
521
|
+
},
|
|
522
|
+
link_type: {
|
|
523
|
+
type: "string",
|
|
524
|
+
description: "Link type name (e.g. 'Blocks', 'Duplicate', 'Relates')",
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
required: ["issue_key_1", "issue_key_2", "link_type"],
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
name: "get_issue_links",
|
|
532
|
+
description: "Get all links for an issue (blocks, duplicates, relates to, etc.).",
|
|
533
|
+
inputSchema: {
|
|
534
|
+
type: "object",
|
|
535
|
+
properties: {
|
|
536
|
+
issue_key: {
|
|
537
|
+
type: "string",
|
|
538
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
539
|
+
},
|
|
540
|
+
},
|
|
541
|
+
required: ["issue_key"],
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
name: "get_link_types",
|
|
546
|
+
description: "List available issue link types (e.g. Blocks, Duplicate, Relates).",
|
|
547
|
+
inputSchema: {
|
|
548
|
+
type: "object",
|
|
549
|
+
properties: {},
|
|
550
|
+
required: [],
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: "log_work",
|
|
555
|
+
description: "Log time spent on an issue. Time format: '2h', '30m', '1d', '2h 30m'.",
|
|
556
|
+
inputSchema: {
|
|
557
|
+
type: "object",
|
|
558
|
+
properties: {
|
|
559
|
+
issue_key: {
|
|
560
|
+
type: "string",
|
|
561
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
562
|
+
},
|
|
563
|
+
time_spent: {
|
|
564
|
+
type: "string",
|
|
565
|
+
description: "Time spent (e.g. '2h', '30m', '1d', '2h 30m')",
|
|
566
|
+
},
|
|
567
|
+
comment: {
|
|
568
|
+
type: "string",
|
|
569
|
+
description: "Optional comment describing the work done",
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
required: ["issue_key", "time_spent"],
|
|
573
|
+
},
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
name: "get_worklog",
|
|
577
|
+
description: "Get work log entries for an issue. Shows who logged what time and when.",
|
|
578
|
+
inputSchema: {
|
|
579
|
+
type: "object",
|
|
580
|
+
properties: {
|
|
581
|
+
issue_key: {
|
|
582
|
+
type: "string",
|
|
583
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
required: ["issue_key"],
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
name: "set_estimate",
|
|
591
|
+
description: "Set the time estimate for an issue. Format: '4h', '1d', '2w'.",
|
|
592
|
+
inputSchema: {
|
|
593
|
+
type: "object",
|
|
594
|
+
properties: {
|
|
595
|
+
issue_key: {
|
|
596
|
+
type: "string",
|
|
597
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
598
|
+
},
|
|
599
|
+
estimate: {
|
|
600
|
+
type: "string",
|
|
601
|
+
description: "Time estimate (e.g. '4h', '1d', '2w')",
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
required: ["issue_key", "estimate"],
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
name: "list_versions",
|
|
609
|
+
description: "List all versions/releases for the project.",
|
|
610
|
+
inputSchema: {
|
|
611
|
+
type: "object",
|
|
612
|
+
properties: {},
|
|
613
|
+
required: [],
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
name: "create_version",
|
|
618
|
+
description: "Create a new version/release for the project.",
|
|
619
|
+
inputSchema: {
|
|
620
|
+
type: "object",
|
|
621
|
+
properties: {
|
|
622
|
+
name: {
|
|
623
|
+
type: "string",
|
|
624
|
+
description: "Version name (e.g. 'v1.0.0')",
|
|
625
|
+
},
|
|
626
|
+
description: {
|
|
627
|
+
type: "string",
|
|
628
|
+
description: "Version description. Optional.",
|
|
629
|
+
},
|
|
630
|
+
release_date: {
|
|
631
|
+
type: "string",
|
|
632
|
+
description: "Planned release date (ISO 8601, e.g. '2026-04-01'). Optional.",
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
required: ["name"],
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
name: "release_version",
|
|
640
|
+
description: "Mark a version as released. Resolves by name.",
|
|
641
|
+
inputSchema: {
|
|
642
|
+
type: "object",
|
|
643
|
+
properties: {
|
|
644
|
+
version: {
|
|
645
|
+
type: "string",
|
|
646
|
+
description: "Version name (e.g. 'v1.0.0') or ID",
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
required: ["version"],
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
name: "get_backlog",
|
|
654
|
+
description: "Get issues in the backlog (not assigned to any sprint).",
|
|
655
|
+
inputSchema: {
|
|
656
|
+
type: "object",
|
|
657
|
+
properties: {},
|
|
658
|
+
required: [],
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
name: "move_to_backlog",
|
|
663
|
+
description: "Move issues from a sprint back to the backlog.",
|
|
664
|
+
inputSchema: {
|
|
665
|
+
type: "object",
|
|
666
|
+
properties: {
|
|
667
|
+
issue_keys: {
|
|
668
|
+
type: "array",
|
|
669
|
+
items: { type: "string" },
|
|
670
|
+
description: "Issue keys to move to backlog (e.g. ['PROJ-1', 'PROJ-2'])",
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
required: ["issue_keys"],
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
name: "bulk_create_tasks",
|
|
678
|
+
description: "Create multiple tasks at once. Each task gets a title, description, optional type and epic_key.",
|
|
679
|
+
inputSchema: {
|
|
680
|
+
type: "object",
|
|
681
|
+
properties: {
|
|
682
|
+
tasks: {
|
|
683
|
+
type: "array",
|
|
684
|
+
items: {
|
|
685
|
+
type: "object",
|
|
686
|
+
properties: {
|
|
687
|
+
title: { type: "string", description: "Task title" },
|
|
688
|
+
description: { type: "string", description: "Task description" },
|
|
689
|
+
type: { type: "string", description: "Issue type (e.g. 'Story', 'Bug', 'Task'). Optional." },
|
|
690
|
+
epic_key: { type: "string", description: "Epic key to link to. Optional." },
|
|
691
|
+
},
|
|
692
|
+
required: ["title", "description"],
|
|
693
|
+
},
|
|
694
|
+
description: "Array of tasks to create",
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
required: ["tasks"],
|
|
698
|
+
},
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
name: "bulk_update_tasks",
|
|
702
|
+
description: "Update multiple tasks at once. Useful for batch status changes.",
|
|
703
|
+
inputSchema: {
|
|
704
|
+
type: "object",
|
|
705
|
+
properties: {
|
|
706
|
+
updates: {
|
|
707
|
+
type: "array",
|
|
708
|
+
items: {
|
|
709
|
+
type: "object",
|
|
710
|
+
properties: {
|
|
711
|
+
issue_key: { type: "string", description: "Issue key or natural language description" },
|
|
712
|
+
status: { type: "string", description: "New status. Optional." },
|
|
713
|
+
comment: { type: "string", description: "Comment to add. Optional." },
|
|
714
|
+
assignee: { type: "string", description: "Assignee name. Optional." },
|
|
715
|
+
priority: { type: "string", description: "Priority level. Optional." },
|
|
716
|
+
},
|
|
717
|
+
required: ["issue_key"],
|
|
718
|
+
},
|
|
719
|
+
description: "Array of updates to apply",
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
required: ["updates"],
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
name: "attach_file",
|
|
727
|
+
description: "Attach a file from your local machine to a Jira issue. Provide the full file path.",
|
|
728
|
+
inputSchema: {
|
|
729
|
+
type: "object",
|
|
730
|
+
properties: {
|
|
731
|
+
issue_key: {
|
|
732
|
+
type: "string",
|
|
733
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
734
|
+
},
|
|
735
|
+
file_path: {
|
|
736
|
+
type: "string",
|
|
737
|
+
description: "Absolute path to the file on your local machine",
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
required: ["issue_key", "file_path"],
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
name: "list_attachments",
|
|
745
|
+
description: "List all attachments on an issue.",
|
|
746
|
+
inputSchema: {
|
|
747
|
+
type: "object",
|
|
748
|
+
properties: {
|
|
749
|
+
issue_key: {
|
|
750
|
+
type: "string",
|
|
751
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
752
|
+
},
|
|
753
|
+
},
|
|
754
|
+
required: ["issue_key"],
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
name: "manage_watchers",
|
|
759
|
+
description: "Manage watchers on an issue: list, add, or remove.",
|
|
760
|
+
inputSchema: {
|
|
761
|
+
type: "object",
|
|
762
|
+
properties: {
|
|
763
|
+
issue_key: {
|
|
764
|
+
type: "string",
|
|
765
|
+
description: "Issue key (e.g. PROJ-5) or natural language description",
|
|
766
|
+
},
|
|
767
|
+
action: {
|
|
768
|
+
type: "string",
|
|
769
|
+
enum: ["list", "add", "remove"],
|
|
770
|
+
description: "Action to perform: 'list', 'add', or 'remove'",
|
|
771
|
+
},
|
|
772
|
+
user_name: {
|
|
773
|
+
type: "string",
|
|
774
|
+
description: "Display name of the user (required for 'add' and 'remove' actions)",
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
required: ["issue_key", "action"],
|
|
778
|
+
},
|
|
779
|
+
},
|
|
310
780
|
],
|
|
311
781
|
}));
|
|
312
782
|
// ─── Tool handler ────────────────────────────────────────────────────────────
|
|
@@ -340,6 +810,19 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
340
810
|
}
|
|
341
811
|
try {
|
|
342
812
|
let result;
|
|
813
|
+
// Read-only mode: block all write operations
|
|
814
|
+
const READ_ONLY_TOOLS = new Set([
|
|
815
|
+
"get_project_summary", "get_status", "get_tasks", "get_comments", "list_epics",
|
|
816
|
+
"get_epic", "list_sprints", "search_issues", "get_custom_fields", "get_issue_links",
|
|
817
|
+
"get_link_types", "get_worklog", "list_versions", "get_backlog", "list_attachments",
|
|
818
|
+
// manage_watchers excluded — has write actions (add/remove)
|
|
819
|
+
]);
|
|
820
|
+
if ((0, config_1.isReadOnly)() && !READ_ONLY_TOOLS.has(name)) {
|
|
821
|
+
return {
|
|
822
|
+
content: [{ type: "text", text: "DevTo is in **read-only mode** (DEVTO_READ_ONLY=true). Write operations are disabled. Remove the DEVTO_READ_ONLY environment variable to enable writes." }],
|
|
823
|
+
isError: true,
|
|
824
|
+
};
|
|
825
|
+
}
|
|
343
826
|
switch (name) {
|
|
344
827
|
case "get_project_summary":
|
|
345
828
|
result = await (0, tools_1.getProjectSummary)();
|
|
@@ -354,7 +837,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
354
837
|
result = await (0, tools_1.createEpic)(args?.title, args?.description);
|
|
355
838
|
break;
|
|
356
839
|
case "create_task":
|
|
357
|
-
result = await (0, tools_1.createTask)(args?.title, args?.description, args?.epic_key);
|
|
840
|
+
result = await (0, tools_1.createTask)(args?.title, args?.description, args?.epic_key, args?.type);
|
|
358
841
|
break;
|
|
359
842
|
case "create_subtask":
|
|
360
843
|
result = await (0, tools_1.createSubtask)(args?.title, args?.description, args?.parent_key);
|
|
@@ -363,7 +846,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
363
846
|
result = await (0, tools_1.getTasks)(args?.epic_key);
|
|
364
847
|
break;
|
|
365
848
|
case "update_task":
|
|
366
|
-
result = await (0, tools_1.updateTask)(args?.issue_key, args?.status, args?.comment);
|
|
849
|
+
result = await (0, tools_1.updateTask)(args?.issue_key, args?.status, args?.comment, args?.assignee, args?.priority, args?.labels, args?.epic_key, args?.title, args?.description);
|
|
367
850
|
break;
|
|
368
851
|
case "get_comments":
|
|
369
852
|
result = await (0, tools_1.getComments)(args?.issue_key);
|
|
@@ -380,9 +863,81 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
380
863
|
case "delete_comment":
|
|
381
864
|
result = await (0, tools_1.deleteComment)(args?.issue_key, args?.comment_id);
|
|
382
865
|
break;
|
|
866
|
+
case "add_comment":
|
|
867
|
+
result = await (0, tools_1.addCommentTool)(args?.issue_key, args?.comment);
|
|
868
|
+
break;
|
|
869
|
+
case "delete_issue":
|
|
870
|
+
result = await (0, tools_1.deleteIssueTool)(args?.issue_key);
|
|
871
|
+
break;
|
|
872
|
+
case "list_sprints":
|
|
873
|
+
result = await (0, tools_1.listSprints)();
|
|
874
|
+
break;
|
|
875
|
+
case "create_sprint":
|
|
876
|
+
result = await (0, tools_1.createSprintTool)(args?.name, args?.start_date, args?.end_date);
|
|
877
|
+
break;
|
|
878
|
+
case "move_to_sprint":
|
|
879
|
+
result = await (0, tools_1.moveToSprintTool)(args?.sprint, args?.issue_keys);
|
|
880
|
+
break;
|
|
881
|
+
case "manage_sprint":
|
|
882
|
+
result = await (0, tools_1.manageSprintTool)(args?.sprint, args?.action);
|
|
883
|
+
break;
|
|
383
884
|
case "get_status":
|
|
384
885
|
result = await (0, tools_1.getStatus)();
|
|
385
886
|
break;
|
|
887
|
+
case "search_issues":
|
|
888
|
+
result = await (0, tools_1.searchIssues)(args?.jql, args?.max_results);
|
|
889
|
+
break;
|
|
890
|
+
case "get_custom_fields":
|
|
891
|
+
result = await (0, tools_1.getCustomFields)();
|
|
892
|
+
break;
|
|
893
|
+
case "link_issues":
|
|
894
|
+
result = await (0, tools_1.linkIssues)(args?.issue_key_1, args?.issue_key_2, args?.link_type);
|
|
895
|
+
break;
|
|
896
|
+
case "get_issue_links":
|
|
897
|
+
result = await (0, tools_1.getIssueLinks)(args?.issue_key);
|
|
898
|
+
break;
|
|
899
|
+
case "get_link_types":
|
|
900
|
+
result = await (0, tools_1.getLinkTypes)();
|
|
901
|
+
break;
|
|
902
|
+
case "log_work":
|
|
903
|
+
result = await (0, tools_1.logWork)(args?.issue_key, args?.time_spent, args?.comment);
|
|
904
|
+
break;
|
|
905
|
+
case "get_worklog":
|
|
906
|
+
result = await (0, tools_1.getWorklog)(args?.issue_key);
|
|
907
|
+
break;
|
|
908
|
+
case "set_estimate":
|
|
909
|
+
result = await (0, tools_1.setEstimate)(args?.issue_key, args?.estimate);
|
|
910
|
+
break;
|
|
911
|
+
case "list_versions":
|
|
912
|
+
result = await (0, tools_1.listVersions)();
|
|
913
|
+
break;
|
|
914
|
+
case "create_version":
|
|
915
|
+
result = await (0, tools_1.createVersion)(args?.name, args?.description, args?.release_date);
|
|
916
|
+
break;
|
|
917
|
+
case "release_version":
|
|
918
|
+
result = await (0, tools_1.releaseVersion)(args?.version);
|
|
919
|
+
break;
|
|
920
|
+
case "get_backlog":
|
|
921
|
+
result = await (0, tools_1.getBacklog)();
|
|
922
|
+
break;
|
|
923
|
+
case "move_to_backlog":
|
|
924
|
+
result = await (0, tools_1.moveToBacklog)(args?.issue_keys);
|
|
925
|
+
break;
|
|
926
|
+
case "bulk_create_tasks":
|
|
927
|
+
result = await (0, tools_1.bulkCreateTasks)(args?.tasks);
|
|
928
|
+
break;
|
|
929
|
+
case "bulk_update_tasks":
|
|
930
|
+
result = await (0, tools_1.bulkUpdateTasks)(args?.updates);
|
|
931
|
+
break;
|
|
932
|
+
case "attach_file":
|
|
933
|
+
result = await (0, tools_1.attachFile)(args?.issue_key, args?.file_path);
|
|
934
|
+
break;
|
|
935
|
+
case "list_attachments":
|
|
936
|
+
result = await (0, tools_1.listAttachments)(args?.issue_key);
|
|
937
|
+
break;
|
|
938
|
+
case "manage_watchers":
|
|
939
|
+
result = await (0, tools_1.manageWatchers)(args?.issue_key, args?.action, args?.user_name);
|
|
940
|
+
break;
|
|
386
941
|
default:
|
|
387
942
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
388
943
|
}
|