@dpesch/mantisbt-mcp-server 1.5.7 → 1.5.9

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.
@@ -0,0 +1,1446 @@
1
+ # Cookbook
2
+
3
+ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly which tool to call and with which parameters. For natural language prompt examples, see [examples.md](examples.md).
4
+
5
+ ---
6
+
7
+ - [Discovering your instance](#discovering-your-instance)
8
+ - [Get all projects](#get-all-projects)
9
+ - [Discover valid enum values (severity, status, priority)](#discover-valid-enum-values-severity-status-priority)
10
+ - [Discover valid field names for `select`](#discover-valid-field-names-for-select)
11
+ - [Issues](#issues)
12
+ - [Fetch a single issue](#fetch-a-single-issue)
13
+ - [List issues (paginated)](#list-issues-paginated)
14
+ - [Reduce response size with `select`](#reduce-response-size-with-select)
15
+ - [Filter by status](#filter-by-status)
16
+ - [Filter by assignee or reporter](#filter-by-assignee-or-reporter)
17
+ - [Apply a saved filter](#apply-a-saved-filter)
18
+ - [Create an issue](#create-an-issue)
19
+ - [Close an issue (status + resolution)](#close-an-issue-status--resolution)
20
+ - [Reassign an issue](#reassign-an-issue)
21
+ - [Set fix version](#set-fix-version)
22
+ - [Notes](#notes)
23
+ - [Add a public note](#add-a-public-note)
24
+ - [Add a private note](#add-a-private-note)
25
+ - [Delete a note](#delete-a-note)
26
+ - [File Attachments](#file-attachments)
27
+ - [Upload a local file](#upload-a-local-file)
28
+ - [Upload file content (base64)](#upload-file-content-base64)
29
+ - [List attachments](#list-attachments)
30
+ - [Relationships](#relationships)
31
+ - [Mark as duplicate](#mark-as-duplicate)
32
+ - [Link as related](#link-as-related)
33
+ - [Set a blocking relationship](#set-a-blocking-relationship)
34
+ - [Remove a relationship](#remove-a-relationship)
35
+ - [Tags](#tags)
36
+ - [Attach tags by name](#attach-tags-by-name)
37
+ - [Detach a tag](#detach-a-tag)
38
+ - [Monitors (Watchers)](#monitors-watchers)
39
+ - [Add a watcher](#add-a-watcher)
40
+ - [Remove a watcher](#remove-a-watcher)
41
+ - [Semantic Search](#semantic-search)
42
+ - [Build the initial index](#build-the-initial-index)
43
+ - [Incremental index update](#incremental-index-update)
44
+ - [Check index status](#check-index-status)
45
+ - [Search by meaning](#search-by-meaning)
46
+ - [Search with field enrichment](#search-with-field-enrichment)
47
+ - [Projects & Categories](#projects--categories)
48
+ - [List project categories](#list-project-categories)
49
+ - [Version & Diagnostics](#version--diagnostics)
50
+ - [Get MCP server version](#get-mcp-server-version)
51
+ - [Get MantisBT version](#get-mantis-version)
52
+ - [Get the current user](#get-the-current-user)
53
+ - [Destructive Operations](#destructive-operations)
54
+ - [Delete an issue](#delete-an-issue)
55
+
56
+ ---
57
+
58
+ ## Discovering your instance
59
+
60
+ ### Get all projects
61
+
62
+ Returns the full list of projects accessible with your API key.
63
+
64
+ **Tool:** `list_projects`
65
+
66
+ **Parameters:** _(none)_
67
+
68
+ **Request:**
69
+
70
+ ```json
71
+ {}
72
+ ```
73
+
74
+ **Response:**
75
+
76
+ ```json
77
+ [
78
+ { "id": 3, "name": "Webshop", "status": { "id": 10, "name": "development" }, "enabled": true },
79
+ { "id": 5, "name": "Backend API", "status": { "id": 10, "name": "development" }, "enabled": true }
80
+ ]
81
+ ```
82
+
83
+ ---
84
+
85
+ ### Discover valid enum values (severity, status, priority)
86
+
87
+ Returns the enum values configured on your specific MantisBT instance. Use this before creating or updating issues to know which values are valid.
88
+
89
+ **Tool:** `get_issue_enums`
90
+
91
+ **Parameters:** _(none)_
92
+
93
+ **Request:**
94
+
95
+ ```json
96
+ {}
97
+ ```
98
+
99
+ **Response:**
100
+
101
+ ```json
102
+ {
103
+ "priorities": [
104
+ { "id": 10, "name": "none" },
105
+ { "id": 20, "name": "low" },
106
+ { "id": 30, "name": "normal" },
107
+ { "id": 40, "name": "high" },
108
+ { "id": 50, "name": "urgent" },
109
+ { "id": 60, "name": "immediate" }
110
+ ],
111
+ "severities": [
112
+ { "id": 10, "name": "feature" },
113
+ { "id": 20, "name": "trivial" },
114
+ { "id": 50, "name": "major" },
115
+ { "id": 60, "name": "crash" }
116
+ // ...
117
+ ],
118
+ "statuses": [
119
+ { "id": 10, "name": "new" },
120
+ { "id": 50, "name": "assigned" },
121
+ { "id": 80, "name": "resolved" },
122
+ { "id": 90, "name": "closed" }
123
+ // ...
124
+ ],
125
+ "resolutions": [
126
+ { "id": 10, "name": "open" },
127
+ { "id": 20, "name": "fixed" },
128
+ { "id": 60, "name": "duplicate" }
129
+ // ...
130
+ ]
131
+ }
132
+ ```
133
+
134
+ > **Note:** The names returned by `get_issue_enums()` may be localized. `create_issue` and `update_issue` require **canonical English names** for `severity` and `priority` (e.g. `minor`, `major`, `normal`) — look at the `canonical_name` field in the response if you are unsure.
135
+
136
+ ---
137
+
138
+ ### Discover valid field names for `select`
139
+
140
+ Returns all field names that can be passed to the `select` parameter of `list_issues`.
141
+
142
+ **Tool:** `get_issue_fields`
143
+
144
+ **Parameters:**
145
+ - `project_id` — _(optional)_ restrict to fields available for a specific project
146
+
147
+ **Request:**
148
+
149
+ ```json
150
+ {
151
+ "project_id": 3
152
+ }
153
+ ```
154
+
155
+ **Response:**
156
+
157
+ ```json
158
+ {
159
+ "fields": [
160
+ "additional_information", "attachments", "category", "created_at",
161
+ "description", "fixed_in_version", "handler", "id", "notes",
162
+ "priority", "project", "relationships", "reporter", "resolution",
163
+ "severity", "status", "summary", "tags", "target_version",
164
+ "updated_at", "version", "view_state"
165
+ ],
166
+ "source": "live"
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Issues
173
+
174
+ ### Fetch a single issue
175
+
176
+ Retrieves a single issue by its numeric ID including notes, attachments, tags, and relationships.
177
+
178
+ **Tool:** `get_issue`
179
+
180
+ **Parameters:**
181
+ - `id` — numeric issue ID
182
+
183
+ **Request:**
184
+
185
+ ```json
186
+ {
187
+ "id": 1042
188
+ }
189
+ ```
190
+
191
+ **Response:**
192
+
193
+ ```json
194
+ {
195
+ "id": 1042,
196
+ "summary": "Login button unresponsive on mobile Safari",
197
+ "description": "Tapping the login button on iPhone 14 / Safari 17 does nothing.",
198
+ "project": { "id": 3, "name": "Webshop" },
199
+ "category": { "id": 1, "name": "UI" },
200
+ "status": { "id": 50, "name": "assigned" },
201
+ "resolution": { "id": 10, "name": "open" },
202
+ "priority": { "id": 30, "name": "normal" },
203
+ "severity": { "id": 50, "name": "major" },
204
+ "reporter": { "id": 4, "name": "jsmith" },
205
+ "handler": { "id": 7, "name": "jdoe" },
206
+ "created_at": "2024-11-03T09:14:22+00:00",
207
+ "updated_at": "2024-11-05T14:02:11+00:00",
208
+ "tags": [],
209
+ "notes": [],
210
+ "attachments": [],
211
+ "relationships": []
212
+ }
213
+ ```
214
+
215
+ ---
216
+
217
+ ### List issues (paginated)
218
+
219
+ Returns a paginated list of issues, optionally scoped to a project.
220
+
221
+ **Tool:** `list_issues`
222
+
223
+ **Parameters:**
224
+ - `project_id` — _(optional)_ numeric project ID
225
+ - `page` — _(optional)_ page number, default 1
226
+ - `page_size` — _(optional)_ issues per page, default 50
227
+
228
+ **Request:**
229
+
230
+ ```json
231
+ {
232
+ "project_id": 3,
233
+ "page": 1,
234
+ "page_size": 25
235
+ }
236
+ ```
237
+
238
+ **Response:**
239
+
240
+ ```json
241
+ {
242
+ "issues": [
243
+ {
244
+ "id": 1042,
245
+ "summary": "Login button unresponsive on mobile Safari",
246
+ "status": { "id": 50, "name": "assigned" },
247
+ "handler": { "id": 7, "name": "jdoe" }
248
+ },
249
+ {
250
+ "id": 1041,
251
+ "summary": "Checkout total rounds incorrectly",
252
+ "status": { "id": 40, "name": "confirmed" },
253
+ "handler": { "id": 4, "name": "jsmith" }
254
+ }
255
+ // ...
256
+ ]
257
+ }
258
+ ```
259
+
260
+ ---
261
+
262
+ ### Reduce response size with `select`
263
+
264
+ Pass a comma-separated list of field names to receive only the fields you need. Significantly reduces payload size for large lists.
265
+
266
+ **Tool:** `list_issues`
267
+
268
+ **Parameters:**
269
+ - `project_id` — _(optional)_ numeric project ID
270
+ - `select` — comma-separated field names
271
+
272
+ **Request:**
273
+
274
+ ```json
275
+ {
276
+ "project_id": 3,
277
+ "select": "id,summary,status,handler"
278
+ }
279
+ ```
280
+
281
+ **Response:**
282
+
283
+ ```json
284
+ {
285
+ "issues": [
286
+ {
287
+ "id": 1042,
288
+ "summary": "Login button unresponsive on mobile Safari",
289
+ "status": { "id": 50, "name": "assigned" },
290
+ "handler": { "id": 7, "name": "jdoe" }
291
+ }
292
+ // ...
293
+ ]
294
+ }
295
+ ```
296
+
297
+ > **Note:** Use `get_issue_fields()` to see all available field names.
298
+
299
+ ---
300
+
301
+ ### Filter by status
302
+
303
+ Returns only issues with a specific status. The filter is applied client-side — the tool scans up to 500 issues internally.
304
+
305
+ **Tool:** `list_issues`
306
+
307
+ **Parameters:**
308
+ - `project_id` — _(optional)_ numeric project ID
309
+ - `status` — status name string (e.g. `"new"`, `"assigned"`, `"resolved"`)
310
+
311
+ **Request:**
312
+
313
+ ```json
314
+ {
315
+ "project_id": 3,
316
+ "status": "assigned"
317
+ }
318
+ ```
319
+
320
+ **Response:**
321
+
322
+ ```json
323
+ {
324
+ "issues": [
325
+ {
326
+ "id": 1042,
327
+ "summary": "Login button unresponsive on mobile Safari",
328
+ "status": { "id": 50, "name": "assigned" },
329
+ "handler": { "id": 7, "name": "jdoe" }
330
+ }
331
+ // ...
332
+ ]
333
+ }
334
+ ```
335
+
336
+ > **Note:** For large projects with many issues, use a pre-saved MantisBT filter via `filter_id` instead — client-side filtering only scans the first 500 issues (10 pages × 50).
337
+
338
+ ---
339
+
340
+ ### Filter by assignee or reporter
341
+
342
+ Returns issues filtered by the assigned user or reporter. Both filters are applied client-side.
343
+
344
+ **Tool:** `list_issues`
345
+
346
+ **Parameters:**
347
+ - `project_id` — _(optional)_ numeric project ID
348
+ - `assigned_to` — _(optional)_ numeric user ID of the assignee
349
+ - `reporter_id` — _(optional)_ numeric user ID of the reporter
350
+
351
+ **Request:**
352
+
353
+ ```json
354
+ {
355
+ "project_id": 3,
356
+ "assigned_to": 7
357
+ }
358
+ ```
359
+
360
+ **Response:**
361
+
362
+ ```json
363
+ {
364
+ "issues": [
365
+ {
366
+ "id": 1042,
367
+ "summary": "Login button unresponsive on mobile Safari",
368
+ "status": { "id": 50, "name": "assigned" },
369
+ "handler": { "id": 7, "name": "jdoe" }
370
+ }
371
+ // ...
372
+ ]
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ### Apply a saved filter
379
+
380
+ Use a pre-saved MantisBT filter by its ID. This is the recommended approach for large datasets.
381
+
382
+ **Step 1 — List available filters:**
383
+
384
+ **Tool:** `list_filters`
385
+
386
+ **Request:**
387
+
388
+ ```json
389
+ {}
390
+ ```
391
+
392
+ **Response:**
393
+
394
+ ```json
395
+ [
396
+ { "id": 12, "name": "My open issues", "owner": { "id": 4, "name": "jsmith" } },
397
+ { "id": 15, "name": "Critical bugs", "owner": { "id": 4, "name": "jsmith" } }
398
+ ]
399
+ ```
400
+
401
+ **Step 2 — Fetch issues using the filter ID:**
402
+
403
+ **Tool:** `list_issues`
404
+
405
+ **Parameters:**
406
+ - `filter_id` — numeric filter ID from step 1
407
+
408
+ **Request:**
409
+
410
+ ```json
411
+ {
412
+ "filter_id": 12
413
+ }
414
+ ```
415
+
416
+ **Response:**
417
+
418
+ ```json
419
+ {
420
+ "issues": [
421
+ {
422
+ "id": 1042,
423
+ "summary": "Login button unresponsive on mobile Safari",
424
+ "status": { "id": 50, "name": "assigned" },
425
+ "handler": { "id": 7, "name": "jdoe" }
426
+ }
427
+ // ...
428
+ ]
429
+ }
430
+ ```
431
+
432
+ ---
433
+
434
+ ### Create an issue
435
+
436
+ Creates a new issue in MantisBT.
437
+
438
+ **Tool:** `create_issue`
439
+
440
+ **Parameters:**
441
+ - `summary` — issue title
442
+ - `project_id` — numeric project ID
443
+ - `category` — category name string
444
+ - `description` — _(optional)_ detailed description
445
+ - `priority` — _(optional)_ canonical English priority name: `none`, `low`, `normal`, `high`, `urgent`, `immediate` — call `get_issue_enums()` to see localized labels
446
+ - `severity` — _(optional)_ canonical English severity name: `feature`, `trivial`, `text`, `tweak`, `minor`, `major`, `crash`, `block`; default is `"minor"` — call `get_issue_enums()` to see localized labels
447
+ - `handler` — _(optional)_ assignee username (resolved to ID automatically)
448
+ - `handler_id` — _(optional)_ assignee numeric user ID (alternative to `handler`)
449
+
450
+ **Request:**
451
+
452
+ ```json
453
+ {
454
+ "summary": "Login button unresponsive on mobile Safari",
455
+ "project_id": 3,
456
+ "category": "UI",
457
+ "description": "Tapping the login button on iPhone 14 / Safari 17 does nothing.",
458
+ "severity": "major",
459
+ "handler": "jsmith"
460
+ }
461
+ ```
462
+
463
+ **Response:**
464
+
465
+ ```json
466
+ {
467
+ "id": 1042,
468
+ "summary": "Login button unresponsive on mobile Safari",
469
+ "description": "Tapping the login button on iPhone 14 / Safari 17 does nothing.",
470
+ "project": { "id": 3, "name": "Webshop" },
471
+ "category": { "id": 1, "name": "UI" },
472
+ "status": { "id": 10, "name": "new" },
473
+ "resolution": { "id": 10, "name": "open" },
474
+ "priority": { "id": 30, "name": "normal" },
475
+ "severity": { "id": 50, "name": "major" },
476
+ "reporter": { "id": 4, "name": "jsmith" },
477
+ "handler": { "id": 4, "name": "jsmith" },
478
+ "created_at": "2024-11-03T09:14:22+00:00",
479
+ "updated_at": "2024-11-03T09:14:22+00:00",
480
+ "tags": [],
481
+ "notes": [],
482
+ "attachments": [],
483
+ "relationships": []
484
+ }
485
+ ```
486
+
487
+ **Error: unknown severity or priority**
488
+
489
+ If an unrecognized name is passed for `severity` or `priority`, the server returns an error listing valid values:
490
+
491
+ > Error: Invalid severity "schwerer Fehler". Valid canonical names: feature, trivial, text, tweak, minor, major, crash, block. Call get_issue_enums to see localized labels.
492
+
493
+ Use `get_issue_enums` to discover the canonical names accepted by `create_issue`.
494
+
495
+ ---
496
+
497
+ ### Close an issue (status + resolution)
498
+
499
+ Resolves and closes an issue. Always set **both** `status` and `resolution` — setting only status leaves resolution as "open".
500
+
501
+ **Tool:** `update_issue`
502
+
503
+ **Parameters:**
504
+ - `id` — numeric issue ID
505
+ - `fields.status` — status object with name
506
+ - `fields.resolution` — resolution object with id
507
+
508
+ **Request:**
509
+
510
+ ```json
511
+ {
512
+ "id": 1042,
513
+ "fields": {
514
+ "status": { "name": "resolved" },
515
+ "resolution": { "id": 20 }
516
+ }
517
+ }
518
+ ```
519
+
520
+ **Response:**
521
+
522
+ ```json
523
+ {
524
+ "id": 1042,
525
+ "summary": "Login button unresponsive on mobile Safari",
526
+ "status": { "id": 80, "name": "resolved" },
527
+ "resolution": { "id": 20, "name": "fixed" },
528
+ "updated_at": "2024-11-06T10:30:00+00:00"
529
+ }
530
+ ```
531
+
532
+ > **Note:** Resolution ID 20 is "fixed" in a default MantisBT installation. Use `get_issue_enums()` to confirm the correct ID for your instance.
533
+
534
+ ---
535
+
536
+ ### Reassign an issue
537
+
538
+ Changes the handler (assignee) of an existing issue.
539
+
540
+ **Tool:** `update_issue`
541
+
542
+ **Parameters:**
543
+ - `id` — numeric issue ID
544
+ - `fields.handler` — username string (resolved to ID automatically)
545
+
546
+ **Request:**
547
+
548
+ ```json
549
+ {
550
+ "id": 1042,
551
+ "fields": {
552
+ "handler": "jdoe"
553
+ }
554
+ }
555
+ ```
556
+
557
+ **Response:**
558
+
559
+ ```json
560
+ {
561
+ "id": 1042,
562
+ "summary": "Login button unresponsive on mobile Safari",
563
+ "status": { "id": 50, "name": "assigned" },
564
+ "handler": { "id": 7, "name": "jdoe" },
565
+ "updated_at": "2024-11-06T11:00:00+00:00"
566
+ }
567
+ ```
568
+
569
+ ---
570
+
571
+ ### Set fix version
572
+
573
+ Sets the `fixed_in_version` field on an issue.
574
+
575
+ **Tool:** `update_issue`
576
+
577
+ **Parameters:**
578
+ - `id` — numeric issue ID
579
+ - `fields.fixed_in_version` — version name string
580
+
581
+ **Request:**
582
+
583
+ ```json
584
+ {
585
+ "id": 1042,
586
+ "fields": {
587
+ "fixed_in_version": "2.1.0"
588
+ }
589
+ }
590
+ ```
591
+
592
+ **Response:**
593
+
594
+ ```json
595
+ {
596
+ "id": 1042,
597
+ "summary": "Login button unresponsive on mobile Safari",
598
+ "fixed_in_version": { "name": "2.1.0" },
599
+ "updated_at": "2024-11-06T11:15:00+00:00"
600
+ }
601
+ ```
602
+
603
+ > **Note:** Use `get_project_versions(project_id)` to list valid version names for a project.
604
+
605
+ ---
606
+
607
+ ## Notes
608
+
609
+ ### Add a public note
610
+
611
+ Adds a publicly visible note to an issue.
612
+
613
+ **Tool:** `add_note`
614
+
615
+ **Parameters:**
616
+ - `issue_id` — numeric issue ID
617
+ - `text` — note content
618
+ - `view_state` — _(optional)_ `"public"` (default) or `"private"`
619
+
620
+ **Request:**
621
+
622
+ ```json
623
+ {
624
+ "issue_id": 1042,
625
+ "text": "Reproduced on version 2.0.3. Root cause identified in the auth middleware."
626
+ }
627
+ ```
628
+
629
+ **Response:**
630
+
631
+ ```json
632
+ {
633
+ "id": 88,
634
+ "reporter": { "id": 7, "name": "jdoe" },
635
+ "text": "Reproduced on version 2.0.3. Root cause identified in the auth middleware.",
636
+ "view_state": { "id": 10, "name": "public" },
637
+ "created_at": "2024-11-05T14:02:11+00:00"
638
+ }
639
+ ```
640
+
641
+ ---
642
+
643
+ ### Add a private note
644
+
645
+ Adds a note visible only to developers and managers.
646
+
647
+ **Tool:** `add_note`
648
+
649
+ **Parameters:**
650
+ - `issue_id` — numeric issue ID
651
+ - `text` — note content
652
+ - `view_state` — `"private"`
653
+
654
+ **Request:**
655
+
656
+ ```json
657
+ {
658
+ "issue_id": 1042,
659
+ "text": "Internal: this is caused by the session token not being refreshed.",
660
+ "view_state": "private"
661
+ }
662
+ ```
663
+
664
+ **Response:**
665
+
666
+ ```json
667
+ {
668
+ "id": 89,
669
+ "reporter": { "id": 7, "name": "jdoe" },
670
+ "text": "Internal: this is caused by the session token not being refreshed.",
671
+ "view_state": { "id": 50, "name": "private" },
672
+ "created_at": "2024-11-05T14:05:00+00:00"
673
+ }
674
+ ```
675
+
676
+ ---
677
+
678
+ ### Delete a note
679
+
680
+ Permanently removes a note from an issue.
681
+
682
+ **Tool:** `delete_note`
683
+
684
+ **Parameters:**
685
+ - `issue_id` — numeric issue ID
686
+ - `note_id` — numeric note ID (from `list_notes` or `get_issue`)
687
+
688
+ **Request:**
689
+
690
+ ```json
691
+ {
692
+ "issue_id": 1042,
693
+ "note_id": 88
694
+ }
695
+ ```
696
+
697
+ **Response:**
698
+
699
+ ```
700
+ "Note #88 deleted from issue #1042."
701
+ ```
702
+
703
+ > **Note:** This action is permanent and cannot be undone.
704
+
705
+ ---
706
+
707
+ ## File Attachments
708
+
709
+ ### Upload a local file
710
+
711
+ Attaches a file from the local filesystem to an issue.
712
+
713
+ **Tool:** `upload_file`
714
+
715
+ **Parameters:**
716
+ - `issue_id` — numeric issue ID
717
+ - `file_path` — absolute path to the file
718
+
719
+ **Request:**
720
+
721
+ ```json
722
+ {
723
+ "issue_id": 1042,
724
+ "file_path": "/home/user/screenshots/login-error.png"
725
+ }
726
+ ```
727
+
728
+ **Response:**
729
+
730
+ ```json
731
+ {
732
+ "id": 101,
733
+ "file_name": "login-error.png",
734
+ "size": 14523,
735
+ "content_type": "image/png"
736
+ }
737
+ ```
738
+
739
+ > **Note:** If the MantisBT instance does not return file metadata, the response is `{ "success": true }`.
740
+
741
+ > **Note:** If `MANTIS_UPLOAD_DIR` is set, `file_path` must point to a file inside that directory. Paths outside the directory or path traversal attempts (`../`) are rejected with an error.
742
+
743
+ ---
744
+
745
+ ### Upload file content (base64)
746
+
747
+ Attaches a file by passing its base64-encoded content directly. Use this when the file is not on a local filesystem accessible to the server.
748
+
749
+ **Tool:** `upload_file`
750
+
751
+ **Parameters:**
752
+ - `issue_id` — numeric issue ID
753
+ - `content` — base64-encoded file content
754
+ - `filename` — filename including extension (required when using `content`)
755
+ - `content_type` — _(optional)_ MIME type
756
+ - `description` — _(optional)_ attachment description
757
+
758
+ **Request:**
759
+
760
+ ```json
761
+ {
762
+ "issue_id": 1042,
763
+ "content": "iVBORw0KGgoAAAANSUhEUgAA...",
764
+ "filename": "screenshot.png",
765
+ "content_type": "image/png",
766
+ "description": "Login error on mobile Safari"
767
+ }
768
+ ```
769
+
770
+ **Response:**
771
+
772
+ ```json
773
+ {
774
+ "id": 101,
775
+ "file_name": "screenshot.png",
776
+ "size": 14523,
777
+ "content_type": "image/png"
778
+ }
779
+ ```
780
+
781
+ > **Note:** If the MantisBT instance does not return file metadata, the response is `{ "success": true }`.
782
+
783
+ ---
784
+
785
+ ### List attachments
786
+
787
+ Returns all file attachments for an issue.
788
+
789
+ **Tool:** `list_issue_files`
790
+
791
+ **Parameters:**
792
+ - `issue_id` — numeric issue ID
793
+
794
+ **Request:**
795
+
796
+ ```json
797
+ {
798
+ "issue_id": 1042
799
+ }
800
+ ```
801
+
802
+ **Response:**
803
+
804
+ ```json
805
+ [
806
+ {
807
+ "id": 23,
808
+ "filename": "login-error.png",
809
+ "size": 42318,
810
+ "content_type": "image/png",
811
+ "description": "Login error on mobile Safari",
812
+ "created_at": "2024-11-05T15:30:00+00:00"
813
+ }
814
+ ]
815
+ ```
816
+
817
+ ---
818
+
819
+ ## Relationships
820
+
821
+ ### Mark as duplicate
822
+
823
+ Links issue A as a duplicate of issue B.
824
+
825
+ **Tool:** `add_relationship`
826
+
827
+ **Parameters:**
828
+ - `issue_id` — ID of the duplicate issue (A)
829
+ - `target_id` — ID of the original issue (B)
830
+ - `type_name` — `"duplicate_of"`
831
+
832
+ **Request:**
833
+
834
+ ```json
835
+ {
836
+ "issue_id": 1055,
837
+ "target_id": 1042,
838
+ "type_name": "duplicate_of"
839
+ }
840
+ ```
841
+
842
+ **Response:**
843
+
844
+ ```json
845
+ {
846
+ "id": 5,
847
+ "issue": { "id": 1055 },
848
+ "type": { "id": 0, "name": "duplicate of" }
849
+ }
850
+ ```
851
+
852
+ ---
853
+
854
+ ### Link as related
855
+
856
+ Creates a non-directional "related to" link between two issues.
857
+
858
+ **Tool:** `add_relationship`
859
+
860
+ **Parameters:**
861
+ - `issue_id` — numeric issue ID
862
+ - `target_id` — numeric ID of the related issue
863
+ - `type_name` — `"related_to"`
864
+
865
+ **Request:**
866
+
867
+ ```json
868
+ {
869
+ "issue_id": 1042,
870
+ "target_id": 1038,
871
+ "type_name": "related_to"
872
+ }
873
+ ```
874
+
875
+ **Response:**
876
+
877
+ ```json
878
+ {
879
+ "id": 6,
880
+ "issue": { "id": 1042 },
881
+ "type": { "id": 1, "name": "related to" }
882
+ }
883
+ ```
884
+
885
+ ---
886
+
887
+ ### Set a blocking relationship
888
+
889
+ Marks issue A as blocking issue B (B cannot proceed until A is done). The direction matters — read carefully.
890
+
891
+ **Tool:** `add_relationship`
892
+
893
+ **Parameters:**
894
+ - `issue_id` — ID of the blocking issue (A)
895
+ - `target_id` — ID of the blocked issue (B)
896
+ - `type_name` — `"parent_of"` (A blocks B) or `"child_of"` (A is blocked by B)
897
+
898
+ **Example — A blocks B:**
899
+
900
+ **Request:**
901
+
902
+ ```json
903
+ {
904
+ "issue_id": 1038,
905
+ "target_id": 1042,
906
+ "type_name": "parent_of"
907
+ }
908
+ ```
909
+
910
+ **Response:**
911
+
912
+ ```json
913
+ {
914
+ "id": 7,
915
+ "issue": { "id": 1038 },
916
+ "type": { "id": 2, "name": "parent of" }
917
+ }
918
+ ```
919
+
920
+ Accepted values for `type_name`:
921
+ - `duplicate_of` / `has_duplicate`
922
+ - `related_to` / `related-to`
923
+ - `parent_of` / `parent-of` / `depends_on`
924
+ - `child_of` / `child-of` / `blocks`
925
+
926
+ > **Note:** "A `child_of` B" means A is blocked by B (A depends on B). "A `parent_of` B" means A blocks B. Aliases `depends_on` (→ `parent_of`) and `blocks` (→ `child_of`) are also accepted. Dash variants (e.g. `related-to`, `parent-of`) work as well. Getting the direction wrong inverts the dependency.
927
+
928
+ ---
929
+
930
+ ### Remove a relationship
931
+
932
+ Removes a relationship from an issue.
933
+
934
+ **Step 1 — Get the relationship ID:**
935
+
936
+ **Tool:** `get_issue`
937
+
938
+ **Request:**
939
+
940
+ ```json
941
+ {
942
+ "id": 1042
943
+ }
944
+ ```
945
+
946
+ **Response:**
947
+
948
+ ```json
949
+ {
950
+ "id": 1042,
951
+ "summary": "Login button unresponsive on mobile Safari",
952
+ "relationships": [
953
+ { "id": 5, "type": { "id": 0, "name": "duplicate of" }, "issue": { "id": 1055 } }
954
+ ]
955
+ }
956
+ ```
957
+
958
+ Read `relationships[].id` from the response.
959
+
960
+ **Step 2 — Remove the relationship:**
961
+
962
+ **Tool:** `remove_relationship`
963
+
964
+ **Parameters:**
965
+ - `issue_id` — numeric issue ID
966
+ - `relationship_id` — numeric relationship ID from step 1
967
+
968
+ **Request:**
969
+
970
+ ```json
971
+ {
972
+ "issue_id": 1042,
973
+ "relationship_id": 5
974
+ }
975
+ ```
976
+
977
+ **Response:**
978
+
979
+ ```json
980
+ { "success": true }
981
+ ```
982
+
983
+ > **Note:** `relationship_id` is the ID of the relationship record itself, not the type ID or the target issue ID.
984
+
985
+ ---
986
+
987
+ ## Tags
988
+
989
+ ### Attach tags by name
990
+
991
+ Attaches one or more tags to an issue by name. Unknown tag names are automatically created.
992
+
993
+ **Tool:** `attach_tags`
994
+
995
+ **Parameters:**
996
+ - `issue_id` — numeric issue ID
997
+ - `tags` — array of tag objects; use `{name: "..."}` to reference by name or `{id: N}` to reference by ID
998
+
999
+ **Request:**
1000
+
1001
+ ```json
1002
+ {
1003
+ "issue_id": 1042,
1004
+ "tags": [
1005
+ { "name": "needs-review" },
1006
+ { "name": "regression" }
1007
+ ]
1008
+ }
1009
+ ```
1010
+
1011
+ **Response:**
1012
+
1013
+ ```
1014
+ "Tags successfully attached to issue #1042."
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ### Detach a tag
1020
+
1021
+ Removes a tag from an issue. Requires the numeric tag ID.
1022
+
1023
+ **Step 1 — Get the tag ID:**
1024
+
1025
+ **Tool:** `get_issue`
1026
+
1027
+ **Request:**
1028
+
1029
+ ```json
1030
+ {
1031
+ "id": 1042
1032
+ }
1033
+ ```
1034
+
1035
+ **Response:**
1036
+
1037
+ ```json
1038
+ {
1039
+ "id": 1042,
1040
+ "summary": "Login button unresponsive on mobile Safari",
1041
+ "tags": [
1042
+ { "id": 14, "name": "needs-review" },
1043
+ { "id": 17, "name": "regression" }
1044
+ ]
1045
+ }
1046
+ ```
1047
+
1048
+ Read `tags[].id` from the response.
1049
+
1050
+ **Step 2 — Detach the tag:**
1051
+
1052
+ **Tool:** `detach_tag`
1053
+
1054
+ **Parameters:**
1055
+ - `issue_id` — numeric issue ID
1056
+ - `tag_id` — numeric tag ID from step 1
1057
+
1058
+ **Request:**
1059
+
1060
+ ```json
1061
+ {
1062
+ "issue_id": 1042,
1063
+ "tag_id": 14
1064
+ }
1065
+ ```
1066
+
1067
+ **Response:**
1068
+
1069
+ ```
1070
+ "Tag #14 successfully removed from issue #1042."
1071
+ ```
1072
+
1073
+ > **Note:** `detach_tag` requires a numeric ID, not the tag name. There is no lookup by name — always retrieve the ID first via `get_issue` or `get_metadata`.
1074
+
1075
+ ---
1076
+
1077
+ ## Monitors (Watchers)
1078
+
1079
+ ### Add a watcher
1080
+
1081
+ Subscribes a user to notifications for an issue.
1082
+
1083
+ **Tool:** `add_monitor`
1084
+
1085
+ **Parameters:**
1086
+ - `issue_id` — numeric issue ID
1087
+ - `username` — username string
1088
+
1089
+ **Request:**
1090
+
1091
+ ```json
1092
+ {
1093
+ "issue_id": 1042,
1094
+ "username": "jsmith"
1095
+ }
1096
+ ```
1097
+
1098
+ **Response:**
1099
+
1100
+ ```json
1101
+ { "success": true }
1102
+ ```
1103
+
1104
+ ---
1105
+
1106
+ ### Remove a watcher
1107
+
1108
+ Unsubscribes a user from notifications for an issue.
1109
+
1110
+ **Tool:** `remove_monitor`
1111
+
1112
+ **Parameters:**
1113
+ - `issue_id` — numeric issue ID
1114
+ - `username` — username string
1115
+
1116
+ **Request:**
1117
+
1118
+ ```json
1119
+ {
1120
+ "issue_id": 1042,
1121
+ "username": "jsmith"
1122
+ }
1123
+ ```
1124
+
1125
+ **Response:**
1126
+
1127
+ ```json
1128
+ { "success": true }
1129
+ ```
1130
+
1131
+ ---
1132
+
1133
+ ## Semantic Search
1134
+
1135
+ > **Note:** All tools in this section require `MANTIS_SEARCH_ENABLED=true` in the server configuration.
1136
+
1137
+ ### Build the initial index
1138
+
1139
+ Builds the full vector search index from scratch. Run this once after enabling semantic search.
1140
+
1141
+ **Tool:** `rebuild_search_index`
1142
+
1143
+ **Parameters:**
1144
+ - `full` — set to `true` to clear the existing index before rebuilding
1145
+
1146
+ **Request:**
1147
+
1148
+ ```json
1149
+ {
1150
+ "full": true
1151
+ }
1152
+ ```
1153
+
1154
+ **Response:**
1155
+
1156
+ ```json
1157
+ {
1158
+ "indexed": 312,
1159
+ "skipped": 0,
1160
+ "total": 312,
1161
+ "duration_ms": 48203
1162
+ }
1163
+ ```
1164
+
1165
+ ---
1166
+
1167
+ ### Incremental index update
1168
+
1169
+ Updates the index with issues added or changed since the last build. Faster than a full rebuild.
1170
+
1171
+ **Tool:** `rebuild_search_index`
1172
+
1173
+ **Parameters:**
1174
+ - `project_id` — _(optional)_ limit to a single project
1175
+ - `full` — omit or set to `false` for incremental mode
1176
+
1177
+ **Request:**
1178
+
1179
+ ```json
1180
+ {
1181
+ "project_id": 3
1182
+ }
1183
+ ```
1184
+
1185
+ **Response:**
1186
+
1187
+ ```json
1188
+ {
1189
+ "indexed": 14,
1190
+ "skipped": 298,
1191
+ "total": 312,
1192
+ "duration_ms": 2104
1193
+ }
1194
+ ```
1195
+
1196
+ ---
1197
+
1198
+ ### Check index status
1199
+
1200
+ Returns the number of indexed issues, total issue count, and the timestamp of the last sync.
1201
+
1202
+ **Tool:** `get_search_index_status`
1203
+
1204
+ **Parameters:** _(none)_
1205
+
1206
+ **Request:**
1207
+
1208
+ ```json
1209
+ {}
1210
+ ```
1211
+
1212
+ **Response:**
1213
+
1214
+ ```json
1215
+ {
1216
+ "summary": "312/312 (100 %)",
1217
+ "indexed": 312,
1218
+ "total": 312,
1219
+ "percent": 100,
1220
+ "last_synced_at": "2024-11-05T14:00:00.000Z"
1221
+ }
1222
+ ```
1223
+
1224
+ ---
1225
+
1226
+ ### Search by meaning
1227
+
1228
+ Finds issues semantically similar to a natural language query. Returns issue IDs and relevance scores.
1229
+
1230
+ **Tool:** `search_issues`
1231
+
1232
+ **Parameters:**
1233
+ - `query` — natural language search query
1234
+ - `top_n` — _(optional)_ number of results to return; default 10
1235
+
1236
+ **Request:**
1237
+
1238
+ ```json
1239
+ {
1240
+ "query": "authentication fails after password reset",
1241
+ "top_n": 5
1242
+ }
1243
+ ```
1244
+
1245
+ **Response:**
1246
+
1247
+ ```json
1248
+ [
1249
+ { "id": 1042, "score": 0.91 },
1250
+ { "id": 987, "score": 0.84 },
1251
+ { "id": 1015, "score": 0.79 }
1252
+ ]
1253
+ ```
1254
+
1255
+ > **Note:** Semantic search returns the top-N most similar issues — it does not guarantee exhaustive recall. It is not suitable for "find all issues about X" census queries.
1256
+
1257
+ ---
1258
+
1259
+ ### Search with field enrichment
1260
+
1261
+ Enriches search results with specific fields fetched from MantisBT. Without `select`, only `id` and score are returned.
1262
+
1263
+ **Tool:** `search_issues`
1264
+
1265
+ **Parameters:**
1266
+ - `query` — natural language search query
1267
+ - `top_n` — _(optional)_ number of results
1268
+ - `select` — comma-separated field names to fetch for each result
1269
+
1270
+ **Request:**
1271
+
1272
+ ```json
1273
+ {
1274
+ "query": "authentication fails after password reset",
1275
+ "top_n": 10,
1276
+ "select": "id,summary,status,handler"
1277
+ }
1278
+ ```
1279
+
1280
+ **Response:**
1281
+
1282
+ ```json
1283
+ [
1284
+ {
1285
+ "id": 1042,
1286
+ "score": 0.91,
1287
+ "summary": "Login button unresponsive on mobile Safari",
1288
+ "status": { "id": 50, "name": "assigned" },
1289
+ "handler": { "id": 7, "name": "jdoe" }
1290
+ }
1291
+ // ...
1292
+ ]
1293
+ ```
1294
+
1295
+ > **Note:** Using `select` triggers additional API calls to MantisBT for each result. Keep `top_n` small when using enrichment to avoid excessive requests.
1296
+
1297
+ ---
1298
+
1299
+ ## Projects & Categories
1300
+
1301
+ ### List project categories
1302
+
1303
+ Returns all categories available for a MantisBT project. Use the returned names directly when creating issues.
1304
+
1305
+ **Tool:** `get_project_categories`
1306
+
1307
+ **Parameters:**
1308
+ - `project_id` — numeric project ID
1309
+
1310
+ **Request:**
1311
+
1312
+ ```json
1313
+ {
1314
+ "project_id": 3
1315
+ }
1316
+ ```
1317
+
1318
+ **Response:**
1319
+
1320
+ ```json
1321
+ [
1322
+ { "id": 1, "name": "General" },
1323
+ { "id": 2, "name": "UI" },
1324
+ { "id": 3, "name": "Backend" }
1325
+ ]
1326
+ ```
1327
+
1328
+ > **Note:** Category names prefixed with `[All Projects]` (inherited from the global project) have the prefix automatically stripped in the response.
1329
+
1330
+ ---
1331
+
1332
+ ## Version & Diagnostics
1333
+
1334
+ ### Get MCP server version
1335
+
1336
+ Returns the version of this mantisbt-mcp-server instance.
1337
+
1338
+ **Tool:** `get_mcp_version`
1339
+
1340
+ **Parameters:** _(none)_
1341
+
1342
+ **Request:**
1343
+
1344
+ ```json
1345
+ {}
1346
+ ```
1347
+
1348
+ **Response:**
1349
+
1350
+ ```json
1351
+ {
1352
+ "version": "1.5.8"
1353
+ }
1354
+ ```
1355
+
1356
+ ---
1357
+
1358
+ ### Get MantisBT version
1359
+
1360
+ Returns the version of the connected MantisBT installation and optionally compares it against the latest official release on GitHub.
1361
+
1362
+ **Tool:** `get_mantis_version`
1363
+
1364
+ **Parameters:**
1365
+ - `check_latest` — _(optional)_ whether to compare against the latest GitHub release; default `true`
1366
+
1367
+ **Request:**
1368
+
1369
+ ```json
1370
+ {
1371
+ "check_latest": true
1372
+ }
1373
+ ```
1374
+
1375
+ **Response:**
1376
+
1377
+ ```json
1378
+ {
1379
+ "installed_version": "2.27.0",
1380
+ "latest_version": "2.27.1",
1381
+ "status": "update-available"
1382
+ }
1383
+ ```
1384
+
1385
+ Possible values for `status`: `up-to-date`, `update-available`, `newer-than-release`, `unknown`.
1386
+
1387
+ > **Note:** The GitHub comparison requires an outbound HTTPS request. Set `check_latest` to `false` to skip it.
1388
+
1389
+ ---
1390
+
1391
+ ### Get the current user
1392
+
1393
+ Returns the profile of the user associated with the configured API key. Useful to verify the connection and confirm which account is being used.
1394
+
1395
+ **Tool:** `get_current_user`
1396
+
1397
+ **Parameters:** _(none)_
1398
+
1399
+ **Request:**
1400
+
1401
+ ```json
1402
+ {}
1403
+ ```
1404
+
1405
+ **Response:**
1406
+
1407
+ ```json
1408
+ {
1409
+ "id": 4,
1410
+ "name": "jsmith",
1411
+ "real_name": "John Smith",
1412
+ "email": "jsmith@example.com",
1413
+ "access_level": { "id": 55, "name": "developer" }
1414
+ }
1415
+ ```
1416
+
1417
+ ---
1418
+
1419
+ ## Destructive Operations
1420
+
1421
+ ### Delete an issue
1422
+
1423
+ Permanently deletes a MantisBT issue. This action cannot be undone.
1424
+
1425
+ **Tool:** `delete_issue`
1426
+
1427
+ **Parameters:**
1428
+ - `id` — numeric issue ID
1429
+
1430
+ **Request:**
1431
+
1432
+ ```json
1433
+ {
1434
+ "id": 42
1435
+ }
1436
+ ```
1437
+
1438
+ **Response:**
1439
+
1440
+ ```
1441
+ "Issue #42 deleted successfully."
1442
+ ```
1443
+
1444
+ > **Warning:** This action is permanent and cannot be undone.
1445
+
1446
+ ---