devto-mcp 0.4.3 → 0.4.5
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.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 +558 -19
- 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 +569 -13
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -68,20 +68,72 @@ DevTo connects to the developer's project tracker (Jira, Linear, etc.) and manag
|
|
|
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,7 +257,15 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
201
257
|
},
|
|
202
258
|
status: {
|
|
203
259
|
type: "string",
|
|
204
|
-
description: "New status: 'todo', 'in_progress', 'in_review', 'done', or any custom Jira status name (e.g. 'QA', 'Blocked'). Optional
|
|
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.",
|
|
205
269
|
},
|
|
206
270
|
comment: {
|
|
207
271
|
type: "string",
|
|
@@ -263,8 +327,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
263
327
|
},
|
|
264
328
|
status: {
|
|
265
329
|
type: "string",
|
|
266
|
-
|
|
267
|
-
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').",
|
|
268
331
|
},
|
|
269
332
|
title: {
|
|
270
333
|
type: "string",
|
|
@@ -314,6 +377,98 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
314
377
|
required: ["issue_key", "comment_id"],
|
|
315
378
|
},
|
|
316
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
|
+
},
|
|
317
472
|
{
|
|
318
473
|
name: "get_status",
|
|
319
474
|
description: "Get a summary of your project: task counts and current sprint",
|
|
@@ -323,6 +478,305 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
|
323
478
|
required: [],
|
|
324
479
|
},
|
|
325
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
|
+
},
|
|
326
780
|
],
|
|
327
781
|
}));
|
|
328
782
|
// ─── Tool handler ────────────────────────────────────────────────────────────
|
|
@@ -356,6 +810,19 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
356
810
|
}
|
|
357
811
|
try {
|
|
358
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
|
+
}
|
|
359
826
|
switch (name) {
|
|
360
827
|
case "get_project_summary":
|
|
361
828
|
result = await (0, tools_1.getProjectSummary)();
|
|
@@ -370,7 +837,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
370
837
|
result = await (0, tools_1.createEpic)(args?.title, args?.description);
|
|
371
838
|
break;
|
|
372
839
|
case "create_task":
|
|
373
|
-
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);
|
|
374
841
|
break;
|
|
375
842
|
case "create_subtask":
|
|
376
843
|
result = await (0, tools_1.createSubtask)(args?.title, args?.description, args?.parent_key);
|
|
@@ -379,7 +846,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
379
846
|
result = await (0, tools_1.getTasks)(args?.epic_key);
|
|
380
847
|
break;
|
|
381
848
|
case "update_task":
|
|
382
|
-
result = await (0, tools_1.updateTask)(args?.issue_key, args?.status, args?.comment, args?.assignee, args?.priority, args?.labels, args?.epic_key);
|
|
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);
|
|
383
850
|
break;
|
|
384
851
|
case "get_comments":
|
|
385
852
|
result = await (0, tools_1.getComments)(args?.issue_key);
|
|
@@ -396,9 +863,81 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
396
863
|
case "delete_comment":
|
|
397
864
|
result = await (0, tools_1.deleteComment)(args?.issue_key, args?.comment_id);
|
|
398
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;
|
|
399
884
|
case "get_status":
|
|
400
885
|
result = await (0, tools_1.getStatus)();
|
|
401
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;
|
|
402
941
|
default:
|
|
403
942
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
404
943
|
}
|