@dpesch/mantisbt-mcp-server 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/cookbook.md CHANGED
@@ -6,10 +6,10 @@ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly
6
6
 
7
7
  - [Connection setup](#connection-setup)
8
8
  - [Connect to an installation without URL rewriting](#connect-to-an-installation-without-url-rewriting)
9
+ - [Offer only some tool groups](#offer-only-some-tool-groups)
9
10
  - [Discovering your instance](#discovering-your-instance)
10
11
  - [Get all projects](#get-all-projects)
11
- - [Discover valid enum values (severity, status, priority)](#discover-valid-enum-values-severity-status-priority)
12
- - [Discover valid field names for `select`](#discover-valid-field-names-for-select)
12
+ - [Valid select fields and enum values](#valid-select-fields-and-enum-values)
13
13
  - [Issues](#issues)
14
14
  - [Fetch a single issue](#fetch-a-single-issue)
15
15
  - [Fetch multiple issues in one call](#fetch-multiple-issues-in-one-call)
@@ -18,6 +18,7 @@ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly
18
18
  - [Filter by status](#filter-by-status)
19
19
  - [Filter by assignee or reporter](#filter-by-assignee-or-reporter)
20
20
  - [Apply a saved filter](#apply-a-saved-filter)
21
+ - [Count issues per status, handler, priority or category](#count-issues-per-status-handler-priority-or-category)
21
22
  - [Create an issue](#create-an-issue)
22
23
  - [Close an issue (status + resolution)](#close-an-issue-status--resolution)
23
24
  - [Resolve an issue with a reason note (single call)](#resolve-an-issue-with-a-reason-note-single-call)
@@ -25,9 +26,11 @@ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly
25
26
  - [Reassign an issue](#reassign-an-issue)
26
27
  - [Set fix version](#set-fix-version)
27
28
  - [Notes](#notes)
29
+ - [Get notes for an issue](#get-notes-for-an-issue)
28
30
  - [Add a public note](#add-a-public-note)
29
31
  - [Add a private note](#add-a-private-note)
30
32
  - [Delete a note](#delete-a-note)
33
+ - [Edit a note](#edit-a-note)
31
34
  - [File Attachments](#file-attachments)
32
35
  - [Upload a local file](#upload-a-local-file)
33
36
  - [Upload file content (base64)](#upload-file-content-base64)
@@ -41,8 +44,9 @@ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly
41
44
  - [Attach tags by name](#attach-tags-by-name)
42
45
  - [Detach a tag](#detach-a-tag)
43
46
  - [Monitors (Watchers)](#monitors-watchers)
44
- - [Add a watcher](#add-a-watcher)
45
- - [Remove a watcher](#remove-a-watcher)
47
+ - [Change watchers via update_issue](#change-watchers-via-update_issue)
48
+ - [Add a watcher (deprecated)](#add-a-watcher-deprecated)
49
+ - [Remove a watcher (deprecated)](#remove-a-watcher-deprecated)
46
50
  - [Semantic Search](#semantic-search)
47
51
  - [Build the initial index](#build-the-initial-index)
48
52
  - [Incremental index update](#incremental-index-update)
@@ -50,18 +54,19 @@ Tool-oriented recipes for the MantisBT MCP server — each recipe shows exactly
50
54
  - [Search by meaning](#search-by-meaning)
51
55
  - [Search with field enrichment](#search-with-field-enrichment)
52
56
  - [Projects & Categories](#projects--categories)
57
+ - [Get a project with categories, users and versions](#get-a-project-with-categories-users-and-versions)
53
58
  - [List project categories](#list-project-categories)
54
59
  - [Find a project member](#find-a-project-member)
55
60
  - [Create a project version](#create-a-project-version)
56
61
  - [Update a project version](#update-a-project-version)
57
- - [Release a version and create the next bugfix placeholder](#release-a-version-and-create-the-next-bugfix-placeholder)
62
+ - [Release a version and create the next bugfix placeholder (deprecated)](#release-a-version-and-create-the-next-bugfix-placeholder-deprecated)
58
63
  - [Delete a project version](#delete-a-project-version)
59
64
  - [Metadata](#metadata)
60
65
  - [Get a metadata summary](#get-a-metadata-summary)
66
+ - [Refresh the metadata cache](#refresh-the-metadata-cache)
61
67
  - [Get the full metadata cache](#get-the-full-metadata-cache)
62
68
  - [Version & Diagnostics](#version--diagnostics)
63
- - [Get MCP server version](#get-mcp-server-version)
64
- - [Get MantisBT version](#get-mantis-version)
69
+ - [Get versions (MCP server and MantisBT)](#get-versions-mcp-server-and-mantisbt)
65
70
  - [Get the current user](#get-the-current-user)
66
71
  - [Resources](#resources)
67
72
  - [Read the current user profile](#read-the-current-user-profile)
@@ -109,42 +114,52 @@ Some MantisBT installations serve the REST API only through its front controller
109
114
 
110
115
  When `MANTIS_BASE_URL` ends with `/api/rest/index.php`, index.php routing is enabled automatically. An explicitly set `MANTIS_USE_INDEX_PHP` always wins over the detection — setting it to `false` alongside such a URL forces plain `/api/rest/` routing and logs a warning on stderr.
111
116
 
112
- **Verify:** call `get_mantis_version`. A successful response means the routing is correct.
117
+ **Verify:** call `get_version`. A successful response means the routing is correct.
113
118
 
114
119
  ---
115
120
 
116
- ## Discovering your instance
117
-
118
- ### Get all projects
121
+ ### Offer only some tool groups
119
122
 
120
- Returns the full list of projects accessible with your API key.
123
+ By default all 41 tools are active (search off). Restrict them with `MANTIS_TOOLSETS` to keep the model's context shorter and load only what is needed for the task. Use `MANTIS_DISABLE_DESTRUCTIVE=true` to hide every destructive tool regardless of the active groups.
121
124
 
122
- **Tool:** `list_projects`
123
-
124
- **Parameters:** _(none)_
125
+ Valid group names: `issues`, `notes`, `links`, `files`, `projects`, `versions`, `meta`, `search`. An unknown name stops the server at startup with a message listing the valid ones. Deprecated tools always belong to the same group as their replacement. For the complete group-to-tool mapping see [Limit the offered tools in the README](../README.md#limit-the-offered-tools).
125
126
 
126
- **Request:**
127
+ **Example A — triage setup** (`issues`, `notes`, `meta`; no destructive operations):
127
128
 
128
129
  ```json
129
- {}
130
+ {
131
+ "env": {
132
+ "MANTIS_BASE_URL": "https://mantis.example.com",
133
+ "MANTIS_API_KEY": "your-api-token",
134
+ "MANTIS_TOOLSETS": "issues,notes,meta",
135
+ "MANTIS_DISABLE_DESTRUCTIVE": "true"
136
+ }
137
+ }
130
138
  ```
131
139
 
132
- **Response:**
140
+ **Example B — all groups, delete-protection only** (36 of the 41 default tools):
133
141
 
134
142
  ```json
135
- [
136
- { "id": 3, "name": "Webshop", "status": { "id": 10, "name": "development" }, "enabled": true },
137
- { "id": 5, "name": "Backend API", "status": { "id": 10, "name": "development" }, "enabled": true }
138
- ]
143
+ {
144
+ "env": {
145
+ "MANTIS_BASE_URL": "https://mantis.example.com",
146
+ "MANTIS_API_KEY": "your-api-token",
147
+ "MANTIS_DISABLE_DESTRUCTIVE": "true"
148
+ }
149
+ }
139
150
  ```
140
151
 
152
+ The `search` group additionally requires `MANTIS_SEARCH_ENABLED=true`. Without the `search` group in `MANTIS_TOOLSETS`, the search module — index, embedding model, background sync — is not started at all, even if `MANTIS_SEARCH_ENABLED=true` is set.
153
+
141
154
  ---
142
155
 
143
- ### Discover valid enum values (severity, status, priority)
156
+ ## Discovering your instance
144
157
 
145
- Returns the enum values configured on your specific MantisBT instance. Use this before creating or updating issues to know which values are valid.
158
+ ### Get all projects
159
+
160
+ Returns the full list of projects accessible with your API key.
146
161
 
147
- **Tool:** `get_issue_enums`
162
+ **Tool:** `list_projects`
148
163
 
149
164
  **Parameters:** _(none)_
150
165
 
@@ -157,57 +172,27 @@ Returns the enum values configured on your specific MantisBT instance. Use this
157
172
  **Response:**
158
173
 
159
174
  ```json
160
- {
161
- "priorities": [
162
- { "id": 10, "name": "none" },
163
- { "id": 20, "name": "low" },
164
- { "id": 30, "name": "normal" },
165
- { "id": 40, "name": "high" },
166
- { "id": 50, "name": "urgent" },
167
- { "id": 60, "name": "immediate" }
168
- ],
169
- "severities": [
170
- { "id": 10, "name": "feature" },
171
- { "id": 20, "name": "trivial" },
172
- { "id": 50, "name": "major" },
173
- { "id": 60, "name": "crash" }
174
- // ...
175
- ],
176
- "statuses": [
177
- { "id": 10, "name": "new" },
178
- { "id": 50, "name": "assigned" },
179
- { "id": 80, "name": "resolved" },
180
- { "id": 90, "name": "closed" }
181
- // ...
182
- ],
183
- "resolutions": [
184
- { "id": 10, "name": "open" },
185
- { "id": 20, "name": "fixed" },
186
- { "id": 60, "name": "duplicate" }
187
- // ...
188
- ]
189
- }
175
+ [
176
+ { "id": 3, "name": "Webshop", "status": { "id": 10, "name": "development" }, "enabled": true },
177
+ { "id": 5, "name": "Backend API", "status": { "id": 10, "name": "development" }, "enabled": true }
178
+ ]
190
179
  ```
191
180
 
192
- > **Note:** On localized installations, `get_issue_enums()` returns a `name` in the local language and an optional `canonical_name` with the English original. `create_issue` accepts **both** — pass either the canonical English name (e.g. `minor`) or the localized name (e.g. `Unschönheit`). The server resolves the value automatically.
193
-
194
181
  ---
195
182
 
196
- ### Discover valid field names for `select`
183
+ ### Valid select fields and enum values
197
184
 
198
- Returns all field names that can be passed to the `select` parameter of `list_issues`.
185
+ Returns the valid `select` field names and the enum values (severity, status, priority, resolution, reproducibility) for this MantisBT server in one call. Use this before building a `select` string or before setting enum fields on `create_issue` / `update_issue`.
199
186
 
200
- **Tool:** `get_issue_fields`
187
+ **Tool:** `get_issue_schema`
201
188
 
202
189
  **Parameters:**
203
- - `project_id` — _(optional)_ restrict to fields available for a specific project
190
+ - `project_id` — _(optional)_ restrict the field discovery sample to a specific project
204
191
 
205
192
  **Request:**
206
193
 
207
194
  ```json
208
- {
209
- "project_id": 3
210
- }
195
+ {}
211
196
  ```
212
197
 
213
198
  **Response:**
@@ -221,10 +206,46 @@ Returns all field names that can be passed to the `select` parameter of `list_is
221
206
  "severity", "status", "summary", "tags", "target_version",
222
207
  "updated_at", "version", "view_state"
223
208
  ],
224
- "source": "live"
209
+ "fields_source": "live",
210
+ "enums": {
211
+ "severity": [
212
+ { "id": 10, "name": "feature" },
213
+ { "id": 20, "name": "trivial" },
214
+ { "id": 50, "name": "major" },
215
+ { "id": 60, "name": "crash" }
216
+ ],
217
+ "status": [
218
+ { "id": 10, "name": "new" },
219
+ { "id": 50, "name": "assigned" },
220
+ { "id": 80, "name": "resolved" },
221
+ { "id": 90, "name": "closed" }
222
+ ],
223
+ "priority": [
224
+ { "id": 10, "name": "none" },
225
+ { "id": 20, "name": "low" },
226
+ { "id": 30, "name": "normal" },
227
+ { "id": 40, "name": "high" },
228
+ { "id": 50, "name": "urgent" },
229
+ { "id": 60, "name": "immediate" }
230
+ ],
231
+ "resolution": [
232
+ { "id": 10, "name": "open" },
233
+ { "id": 20, "name": "fixed" },
234
+ { "id": 60, "name": "duplicate" }
235
+ ],
236
+ "reproducibility": [
237
+ { "id": 10, "name": "always" },
238
+ { "id": 30, "name": "sometimes" },
239
+ { "id": 70, "name": "have not tried" }
240
+ ]
241
+ }
225
242
  }
226
243
  ```
227
244
 
245
+ `fields_source` is `"cache"`, `"live"`, or `"static"`. On localized installations each enum entry may include a `label` (localized) and a `canonical_name` (standard English). `create_issue` accepts both — pass the canonical English name (e.g. `minor`) or the localized name; the server resolves it automatically.
246
+
247
+ > **Deprecated:** `get_issue_fields` (fields only) and `get_issue_enums` (enums only) are superseded by `get_issue_schema` — they will be removed in 2.0.0. The resource `mantis://enums` stays.
248
+
228
249
  ---
229
250
 
230
251
  ## Issues
@@ -287,10 +308,11 @@ Compact variant (only the fields you need):
287
308
 
288
309
  Fetches up to 50 issues in a single MCP call. Requests run in parallel (max 5 concurrent). Missing or inaccessible IDs return `null` at their position — the call never fails due to individual missing IDs.
289
310
 
290
- **Tool:** `get_issues`
311
+ **Tool:** `get_issue`
291
312
 
292
313
  **Parameters:**
293
314
  - `ids` — array of numeric issue IDs (1–50)
315
+ - `select` — _(optional)_ comma-separated field list
294
316
 
295
317
  **Request:**
296
318
 
@@ -327,6 +349,8 @@ Fetches up to 50 issues in a single MCP call. Requests run in parallel (max 5 co
327
349
 
328
350
  > **Note:** `null` entries indicate IDs that were not found or could not be accessed. Check `failed` to see how many IDs could not be retrieved.
329
351
 
352
+ > **Deprecated:** `get_issues` provides the same functionality but is deprecated — use `get_issue` with `ids` as shown above; `get_issues` will be removed in 2.0.0.
353
+
330
354
  ---
331
355
 
332
356
  ### List issues (paginated)
@@ -412,7 +436,7 @@ Pass a comma-separated list of field names to receive only the fields you need.
412
436
  }
413
437
  ```
414
438
 
415
- > **Note:** Use `get_issue_fields()` to see all available field names.
439
+ > **Note:** Use `get_issue_schema()` to see all available field names.
416
440
 
417
441
  > **Note:** `view_url` is always present in all issue responses — it is injected by the MCP server and is not affected by the `select` parameter.
418
442
 
@@ -553,6 +577,71 @@ Use a pre-saved MantisBT filter by its ID. This is the recommended approach for
553
577
 
554
578
  ---
555
579
 
580
+ ### Count issues per status, handler, priority or category
581
+
582
+ Returns the number of matching issues grouped by a single field instead of listing individual issues — far fewer tokens than reading all pages.
583
+
584
+ **Tool:** `list_issues`
585
+
586
+ **Parameters:**
587
+ - `project_id` — _(optional)_ numeric project ID
588
+ - `group_by` — `"status"`, `"handler"`, `"priority"`, or `"category"`
589
+ - `status`, `assigned_to`, `reporter_id`, date filters — _(optional)_ all filters still apply; `page`, `page_size`, and `select` are ignored
590
+
591
+ **Request:**
592
+
593
+ ```json
594
+ {
595
+ "project_id": 3,
596
+ "group_by": "status"
597
+ }
598
+ ```
599
+
600
+ **Response:**
601
+
602
+ ```json
603
+ {
604
+ "group_by": "status",
605
+ "total": 604,
606
+ "groups": [
607
+ { "id": 80, "name": "resolved", "label": "resolved", "count": 412 },
608
+ { "id": 50, "name": "assigned", "label": "assigned", "count": 98 },
609
+ { "id": 40, "name": "confirmed", "label": "confirmed", "count": 57 },
610
+ { "id": 20, "name": "feedback", "label": "feedback", "count": 37 }
611
+ ]
612
+ }
613
+ ```
614
+
615
+ Groups are sorted by count descending, then by name ascending. The `label` field contains the localized display name and is omitted for groups that have no label (e.g. handler).
616
+
617
+ **Request (handler, open issues only):**
618
+
619
+ ```json
620
+ {
621
+ "project_id": 3,
622
+ "group_by": "handler",
623
+ "status": "open"
624
+ }
625
+ ```
626
+
627
+ **Response:**
628
+
629
+ ```json
630
+ {
631
+ "group_by": "handler",
632
+ "total": 185,
633
+ "groups": [
634
+ { "id": 7, "name": "jdoe", "count": 72 },
635
+ { "id": 4, "name": "jsmith", "count": 68 },
636
+ { "id": null, "name": "(unassigned)", "count": 45 }
637
+ ]
638
+ }
639
+ ```
640
+
641
+ > **Note:** The server scans all matching issues up to a limit of 50,000. If the limit is reached, the response contains `"truncated": true` and the counts are incomplete. This is a much larger scan than the 500-issue limit of client-side filters in `list_issues`.
642
+
643
+ ---
644
+
556
645
  ### Create an issue
557
646
 
558
647
  Creates a new issue in MantisBT.
@@ -564,8 +653,8 @@ Creates a new issue in MantisBT.
564
653
  - `project_id` — numeric project ID
565
654
  - `category` — category name string
566
655
  - `description` — _(optional)_ detailed description
567
- - `priority` — _(optional)_ priority: canonical English name (`none`, `low`, `normal`, `high`, `urgent`, `immediate`) or localized label. Default: `"normal"`. Use `get_issue_enums()` to see all available values.
568
- - `severity` — _(optional)_ severity: canonical English name (`feature`, `trivial`, `text`, `tweak`, `minor`, `major`, `crash`, `block`) or localized label. Default: `"minor"`. Use `get_issue_enums()` to see all available values.
656
+ - `priority` — _(optional)_ priority: canonical English name (`none`, `low`, `normal`, `high`, `urgent`, `immediate`) or localized label. Default: `"normal"`. Use `get_issue_schema()` to see all available values.
657
+ - `severity` — _(optional)_ severity: canonical English name (`feature`, `trivial`, `text`, `tweak`, `minor`, `major`, `crash`, `block`) or localized label. Default: `"minor"`. Use `get_issue_schema()` to see all available values.
569
658
  - `handler` — _(optional)_ assignee username (resolved to ID automatically)
570
659
  - `handler_id` — _(optional)_ assignee numeric user ID (alternative to `handler`)
571
660
 
@@ -609,11 +698,11 @@ Creates a new issue in MantisBT.
609
698
 
610
699
  **Error: unknown severity or priority**
611
700
 
612
- The server first checks canonical English names, then falls back to a live `get_issue_enums` lookup. An error is only returned if the value matches neither:
701
+ The server first checks canonical English names, then falls back to a live enum lookup. An error is only returned if the value matches neither:
613
702
 
614
- > Error: Invalid severity "xyz". Valid canonical names: feature, trivial, text, tweak, minor, major, crash, block. Call get_issue_enums to see localized labels.
703
+ > Error: Invalid severity "xyz". Valid canonical names: feature, trivial, text, tweak, minor, major, crash, block. Call get_issue_schema to see localized labels.
615
704
 
616
- Use `get_issue_enums` to discover all accepted values — both canonical and localized names work.
705
+ Use `get_issue_schema` to discover all accepted values — both canonical and localized names work.
617
706
 
618
707
  ---
619
708
 
@@ -655,7 +744,7 @@ Resolves and closes an issue. Always set **both** `status` and `resolution` —
655
744
  }
656
745
  ```
657
746
 
658
- > **Note:** Resolution ID 20 is "fixed" in a default MantisBT installation. Use `get_issue_enums()` to confirm the correct ID for your instance.
747
+ > **Note:** Resolution ID 20 is "fixed" in a default MantisBT installation. Use `get_issue_schema()` to confirm the correct ID for your instance.
659
748
 
660
749
  ---
661
750
 
@@ -710,7 +799,7 @@ Writes custom field values on create or update. The same `custom_fields` format
710
799
  }
711
800
  ```
712
801
 
713
- > **Note:** Only the listed custom fields are changed — others stay untouched. Use `get_issue_fields()` or `get_metadata()` to discover available custom fields per project. Values are always strings.
802
+ > **Note:** Only the listed custom fields are changed — others stay untouched. Use `get_issue_schema()` or `get_metadata()` to discover available custom fields per project. Values are always strings.
714
803
 
715
804
  ---
716
805
 
@@ -783,12 +872,54 @@ Sets the `fixed_in_version` field on an issue.
783
872
  }
784
873
  ```
785
874
 
786
- > **Note:** Use `get_project_versions(project_id)` to list valid version names for a project.
875
+ > **Note:** Use `get_project` with `include: ["versions"]` to list valid version names for a project.
787
876
 
788
877
  ---
789
878
 
790
879
  ## Notes
791
880
 
881
+ ### Get notes for an issue
882
+
883
+ Retrieves only the notes of an issue using server-side field projection. This is the preferred alternative to the deprecated `list_notes` tool.
884
+
885
+ **Tool:** `get_issue`
886
+
887
+ **Parameters:**
888
+ - `id` — numeric issue ID
889
+ - `select` — `"id,notes"` (include `id` so `view_url` is always set even when the projection omits it)
890
+
891
+ **Request:**
892
+
893
+ ```json
894
+ {
895
+ "id": 1042,
896
+ "select": "id,notes"
897
+ }
898
+ ```
899
+
900
+ **Response:**
901
+
902
+ ```json
903
+ {
904
+ "id": 1042,
905
+ "notes": [
906
+ {
907
+ "id": 88,
908
+ "reporter": { "id": 7, "name": "jdoe" },
909
+ "text": "Reproduced on version 2.0.3. Root cause identified in the auth middleware.",
910
+ "view_state": { "id": 10, "name": "public" },
911
+ "created_at": "2024-11-05T14:02:11+00:00",
912
+ "view_url": "https://mantis.example.com/view.php?id=1042#bugnote88"
913
+ }
914
+ ],
915
+ "view_url": "https://mantis.example.com/view.php?id=1042"
916
+ }
917
+ ```
918
+
919
+ > **Deprecated:** `list_notes` will be removed in 2.0.0 — use `get_issue` with `select: "id,notes"` as shown above.
920
+
921
+ ---
922
+
792
923
  ### Add a public note
793
924
 
794
925
  Adds a publicly visible note to an issue.
@@ -868,7 +999,7 @@ Permanently removes a note from an issue.
868
999
 
869
1000
  **Parameters:**
870
1001
  - `issue_id` — numeric issue ID
871
- - `note_id` — numeric note ID (from `list_notes` or `get_issue`)
1002
+ - `note_id` — numeric note ID (from `get_issue`)
872
1003
 
873
1004
  **Request:**
874
1005
 
@@ -889,6 +1020,51 @@ Permanently removes a note from an issue.
889
1020
 
890
1021
  ---
891
1022
 
1023
+ ### Edit a note
1024
+
1025
+ Edits the text and/or visibility of an existing note via `update_issue`. The note ID comes from `get_issue`. At least one of `text` or `view_state` must be given. Multiple notes can be edited in a single call.
1026
+
1027
+ **Tool:** `update_issue`
1028
+
1029
+ **Parameters:**
1030
+ - `id` — numeric issue ID
1031
+ - `fields.notes` — array of note edits: `{ id, text?, view_state? }`; omitting `view_state` keeps the note's current visibility
1032
+
1033
+ **Request:** _(text-only edit)_
1034
+
1035
+ ```json
1036
+ {
1037
+ "id": 1042,
1038
+ "fields": {
1039
+ "notes": [
1040
+ { "id": 88, "text": "Reproduced on version 2.0.4 — auth middleware is missing a null check." }
1041
+ ]
1042
+ }
1043
+ }
1044
+ ```
1045
+
1046
+ **Response:**
1047
+
1048
+ ```json
1049
+ {
1050
+ "id": 1042,
1051
+ "summary": "Login button unresponsive on mobile Safari",
1052
+ "notes": [
1053
+ {
1054
+ "id": 88,
1055
+ "text": "Reproduced on version 2.0.4 — auth middleware is missing a null check.",
1056
+ "view_state": { "id": 10, "name": "public" },
1057
+ "updated_at": "2024-11-06T12:00:00+00:00"
1058
+ }
1059
+ ],
1060
+ "view_url": "https://mantis.example.com/view.php?id=1042"
1061
+ }
1062
+ ```
1063
+
1064
+ > **Note:** Unknown note IDs are rejected before any write. If MantisBT did not apply an edit, the response contains `notes_error` with the details instead of failing the call — only when the note edit was the only requested change does the call return an error. To add a new note use the `note` parameter or `add_note`.
1065
+
1066
+ ---
1067
+
892
1068
  ## File Attachments
893
1069
 
894
1070
  ### Upload a local file
@@ -969,36 +1145,45 @@ Attaches a file by passing its base64-encoded content directly. Use this **only*
969
1145
 
970
1146
  ### List attachments
971
1147
 
972
- Returns all file attachments for an issue.
1148
+ Returns all file attachments for an issue using server-side field projection. Each attachment includes a `download_url` built from the MantisBT file download endpoint.
973
1149
 
974
- **Tool:** `list_issue_files`
1150
+ **Tool:** `get_issue`
975
1151
 
976
1152
  **Parameters:**
977
- - `issue_id` — numeric issue ID
1153
+ - `id` — numeric issue ID
1154
+ - `select` — `"id,attachments"`
978
1155
 
979
1156
  **Request:**
980
1157
 
981
1158
  ```json
982
1159
  {
983
- "issue_id": 1042
1160
+ "id": 1042,
1161
+ "select": "id,attachments"
984
1162
  }
985
1163
  ```
986
1164
 
987
1165
  **Response:**
988
1166
 
989
1167
  ```json
990
- [
991
- {
992
- "id": 23,
993
- "filename": "login-error.png",
994
- "size": 42318,
995
- "content_type": "image/png",
996
- "description": "Login error on mobile Safari",
997
- "created_at": "2024-11-05T15:30:00+00:00"
998
- }
999
- ]
1168
+ {
1169
+ "id": 1042,
1170
+ "attachments": [
1171
+ {
1172
+ "id": 23,
1173
+ "filename": "login-error.png",
1174
+ "size": 42318,
1175
+ "content_type": "image/png",
1176
+ "created_at": "2024-11-05T15:30:00+00:00",
1177
+ "reporter": { "id": 4, "name": "jsmith" },
1178
+ "download_url": "https://mantis.example.com/file_download.php?file_id=23&type=bug"
1179
+ }
1180
+ ],
1181
+ "view_url": "https://mantis.example.com/view.php?id=1042"
1182
+ }
1000
1183
  ```
1001
1184
 
1185
+ > **Deprecated:** `list_issue_files` will be removed in 2.0.0 — use `get_issue` with `select: "id,attachments"` as shown above.
1186
+
1002
1187
  ---
1003
1188
 
1004
1189
  ## Relationships
@@ -1261,7 +1446,70 @@ Read `tags[].id` from the response.
1261
1446
 
1262
1447
  ## Monitors (Watchers)
1263
1448
 
1264
- ### Add a watcher
1449
+ ### Change watchers via update_issue
1450
+
1451
+ Adds and/or removes watchers (monitors) of an issue in a single `update_issue` call. `fields` may be omitted — only `add_monitors`, `remove_monitors`, or both are required. Names are matched case-insensitively.
1452
+
1453
+ **Tool:** `update_issue`
1454
+
1455
+ **Parameters:**
1456
+ - `id` — numeric issue ID
1457
+ - `add_monitors` — _(optional)_ array of MantisBT login names to add as watchers
1458
+ - `remove_monitors` — _(optional)_ array of MantisBT login names to remove from watchers; names not currently watching are silently skipped
1459
+ - A user listed in both arrays is rejected.
1460
+
1461
+ **Request:** _(add one watcher)_
1462
+
1463
+ ```json
1464
+ {
1465
+ "id": 1042,
1466
+ "add_monitors": ["jsmith"]
1467
+ }
1468
+ ```
1469
+
1470
+ **Response:**
1471
+
1472
+ ```json
1473
+ {
1474
+ "id": 1042,
1475
+ "view_url": "https://mantis.example.com/view.php?id=1042",
1476
+ "monitors": {
1477
+ "added": ["jsmith"],
1478
+ "current": ["asmith", "jsmith"]
1479
+ }
1480
+ }
1481
+ ```
1482
+
1483
+ **Request:** _(remove one watcher)_
1484
+
1485
+ ```json
1486
+ {
1487
+ "id": 1042,
1488
+ "remove_monitors": ["jsmith"]
1489
+ }
1490
+ ```
1491
+
1492
+ **Response:**
1493
+
1494
+ ```json
1495
+ {
1496
+ "id": 1042,
1497
+ "view_url": "https://mantis.example.com/view.php?id=1042",
1498
+ "monitors": {
1499
+ "removed": ["jsmith"],
1500
+ "not_monitoring": [],
1501
+ "current": ["asmith"]
1502
+ }
1503
+ }
1504
+ ```
1505
+
1506
+ `monitors.current` always lists all remaining watchers. `monitors.added` lists names successfully added; `monitors.removed` lists names successfully removed; `monitors.not_monitoring` lists names that were not watching and were therefore skipped. Adding or removing other users requires the `monitor_add_others_bug_threshold` / `monitor_delete_others_bug_threshold` access level. The steps run in order — `fields`, monitors, `note`. Once one of them succeeded, a later failure is reported inline as `monitors_error` or `note_error` (nothing is rolled back); only when every requested step failed does the call return an error.
1507
+
1508
+ ---
1509
+
1510
+ ### Add a watcher (deprecated)
1511
+
1512
+ > **Deprecated:** use `update_issue` with `add_monitors` instead — `add_monitor` will be removed in 2.0.0.
1265
1513
 
1266
1514
  Subscribes a user to notifications for an issue.
1267
1515
 
@@ -1269,7 +1517,7 @@ Subscribes a user to notifications for an issue.
1269
1517
 
1270
1518
  **Parameters:**
1271
1519
  - `issue_id` — numeric issue ID
1272
- - `username` — username string
1520
+ - `username` — MantisBT login name
1273
1521
 
1274
1522
  **Request:**
1275
1523
 
@@ -1283,12 +1531,19 @@ Subscribes a user to notifications for an issue.
1283
1531
  **Response:**
1284
1532
 
1285
1533
  ```json
1286
- { "success": true }
1534
+ {
1535
+ "success": true,
1536
+ "monitors": ["asmith", "jsmith"]
1537
+ }
1287
1538
  ```
1288
1539
 
1540
+ `monitors` lists all users now watching the issue. Adding a user who already watches it changes nothing and still succeeds. Adding another user requires the `monitor_add_others_bug_threshold` access level.
1541
+
1289
1542
  ---
1290
1543
 
1291
- ### Remove a watcher
1544
+ ### Remove a watcher (deprecated)
1545
+
1546
+ > **Deprecated:** use `update_issue` with `remove_monitors` instead — `remove_monitor` will be removed in 2.0.0.
1292
1547
 
1293
1548
  Unsubscribes a user from notifications for an issue.
1294
1549
 
@@ -1296,7 +1551,7 @@ Unsubscribes a user from notifications for an issue.
1296
1551
 
1297
1552
  **Parameters:**
1298
1553
  - `issue_id` — numeric issue ID
1299
- - `username` — username string
1554
+ - `username` — MantisBT login name (case-insensitive)
1300
1555
 
1301
1556
  **Request:**
1302
1557
 
@@ -1310,9 +1565,15 @@ Unsubscribes a user from notifications for an issue.
1310
1565
  **Response:**
1311
1566
 
1312
1567
  ```json
1313
- { "success": true }
1568
+ {
1569
+ "success": true,
1570
+ "removed": true,
1571
+ "monitors": ["asmith"]
1572
+ }
1314
1573
  ```
1315
1574
 
1575
+ `monitors` lists the users still watching the issue. If `jsmith` was not a monitor, nothing is changed and the response contains `"removed": false` plus a `message`. Removing another user requires the `monitor_delete_others_bug_threshold` access level; without it the tool returns an error.
1576
+
1316
1577
  ---
1317
1578
 
1318
1579
  ## Semantic Search
@@ -1351,7 +1612,9 @@ Builds the full vector search index from scratch. Run this once after enabling s
1351
1612
 
1352
1613
  ### Incremental index update
1353
1614
 
1354
- Updates the index with issues added or changed since the last build. Faster than a full rebuild.
1615
+ Updates the index with issues added or changed since the last sync. Faster than a full rebuild: only issues changed since then are fetched and re-embedded.
1616
+
1617
+ Only one server process syncs the shared index at a time. If another process (for example another client session) is already syncing, the tool returns an error ("A search index sync is already running") — try again once that sync has finished. A sync limited to `project_id` does not advance `last_synced_at`, so changes in other projects are still picked up by the next sync.
1355
1618
 
1356
1619
  **Tool:** `rebuild_search_index`
1357
1620
 
@@ -1372,7 +1635,7 @@ Updates the index with issues added or changed since the last build. Faster than
1372
1635
  ```json
1373
1636
  {
1374
1637
  "indexed": 14,
1375
- "skipped": 298,
1638
+ "skipped": 0,
1376
1639
  "total": 312,
1377
1640
  "duration_ms": 2104
1378
1641
  }
@@ -1382,9 +1645,9 @@ Updates the index with issues added or changed since the last build. Faster than
1382
1645
 
1383
1646
  ### Check index status
1384
1647
 
1385
- Returns the number of indexed issues, total issue count, and the timestamp of the last sync.
1648
+ Returns the number of indexed issues, total issue count, and the timestamp of the last sync. `last_synced_at` is the newest `updated_at` the MantisBT server reported at that sync (server time), so it can lie before the actual time of the sync.
1386
1649
 
1387
- **Tool:** `get_search_index_status`
1650
+ **Tool:** `get_metadata`
1388
1651
 
1389
1652
  **Parameters:** _(none)_
1390
1653
 
@@ -1394,18 +1657,27 @@ Returns the number of indexed issues, total issue count, and the timestamp of th
1394
1657
  {}
1395
1658
  ```
1396
1659
 
1397
- **Response:**
1660
+ **Response (relevant excerpt):**
1398
1661
 
1399
1662
  ```json
1400
1663
  {
1401
- "summary": "312/312 (100 %)",
1402
- "indexed": 312,
1403
- "total": 312,
1404
- "percent": 100,
1405
- "last_synced_at": "2024-11-05T14:00:00.000Z"
1664
+ "projects": 24,
1665
+ "tags": 15,
1666
+ "byProject": { "3": { "name": "Webshop", "users": 8, "versions": 12, "categories": 4 } },
1667
+ "cached_at": "2026-03-27T09:00:00.000Z",
1668
+ "ttl_seconds": 82800,
1669
+ "search_index": {
1670
+ "summary": "312/312 (100 %)",
1671
+ "indexed": 312,
1672
+ "total": 312,
1673
+ "percent": 100,
1674
+ "last_synced_at": "2024-11-05T14:00:00+01:00"
1675
+ }
1406
1676
  }
1407
1677
  ```
1408
1678
 
1679
+ > **Deprecated:** `get_search_index_status` will be removed in 2.0.0 — use `get_metadata` (field `search_index`) as shown above.
1680
+
1409
1681
  ---
1410
1682
 
1411
1683
  ### Search by meaning
@@ -1540,68 +1812,159 @@ Shows which part of an issue matched the search query. Each result that has keyw
1540
1812
 
1541
1813
  ## Projects & Categories
1542
1814
 
1815
+ ### Get a project with categories, users and versions
1816
+
1817
+ Retrieves a project's master data plus any combination of its categories, users and versions in one call. Categories come without the `[All Projects]` prefix — ready for use in `create_issue`. `member_query` filters users by a case-insensitive substring in login name, real name or email, and returns all matches.
1818
+
1819
+ **Tool:** `get_project`
1820
+
1821
+ **Parameters:**
1822
+ - `project_id` — numeric project ID (use `list_projects` to discover)
1823
+ - `include` — _(optional)_ array of `"categories"`, `"users"`, `"versions"` (any combination)
1824
+ - `access_level` — _(optional)_ only users at or above this level (10=viewer, 25=reporter, 40=updater, 55=developer, 70=manager, 90=administrator); implies `"users"`
1825
+ - `member_query` — _(optional)_ case-insensitive substring; implies `"users"`, returns all matches
1826
+ - `obsolete` — _(optional)_ include obsolete versions; implies `"versions"`
1827
+ - `inherit` — _(optional)_ include versions inherited from parent projects; implies `"versions"`
1828
+
1829
+ **Request:** _(master data + categories + users + versions)_
1830
+
1831
+ ```json
1832
+ {
1833
+ "project_id": 3,
1834
+ "include": ["categories", "users", "versions"]
1835
+ }
1836
+ ```
1837
+
1838
+ **Response:**
1839
+
1840
+ ```json
1841
+ {
1842
+ "id": 3,
1843
+ "name": "Webshop",
1844
+ "description": "Main customer-facing storefront",
1845
+ "status": { "id": 10, "name": "development" },
1846
+ "enabled": true,
1847
+ "view_state": { "id": 10, "name": "public" },
1848
+ "categories": [
1849
+ { "id": 1, "name": "General" },
1850
+ { "id": 2, "name": "UI" },
1851
+ { "id": 3, "name": "Backend" }
1852
+ ],
1853
+ "users": [
1854
+ { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } },
1855
+ { "id": 7, "name": "jdoe", "real_name": "Jane Doe", "email": "jdoe@example.com", "access_level": { "id": 70, "name": "manager" } }
1856
+ ],
1857
+ "versions": [
1858
+ { "id": 42, "name": "1.2.0", "released": false, "obsolete": false, "timestamp": "2026-10-31T00:00:00+00:00" },
1859
+ { "id": 43, "name": "1.2.1", "released": false, "obsolete": false, "timestamp": "2026-10-31T00:00:00+00:00" }
1860
+ ]
1861
+ }
1862
+ ```
1863
+
1864
+ **Request:** _(member search)_
1865
+
1866
+ ```json
1867
+ {
1868
+ "project_id": 3,
1869
+ "member_query": "smith"
1870
+ }
1871
+ ```
1872
+
1873
+ **Response:**
1874
+
1875
+ ```json
1876
+ {
1877
+ "id": 3,
1878
+ "name": "Webshop",
1879
+ "status": { "id": 10, "name": "development" },
1880
+ "enabled": true,
1881
+ "users": [
1882
+ { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } },
1883
+ { "id": 11, "name": "asmith", "real_name": "Alice Smith", "email": "asmith@example.com", "access_level": { "id": 40, "name": "updater" } }
1884
+ ]
1885
+ }
1886
+ ```
1887
+
1888
+ > **Note:** `get_project_categories`, `get_project_users`, `get_project_versions`, and `find_project_member` are deprecated in favour of `get_project` with `include` / `member_query` and will be removed in 2.0.0.
1889
+
1890
+ ---
1891
+
1543
1892
  ### List project categories
1544
1893
 
1545
1894
  Returns all categories available for a MantisBT project. Use the returned names directly when creating issues.
1546
1895
 
1547
- **Tool:** `get_project_categories`
1896
+ **Tool:** `get_project`
1548
1897
 
1549
1898
  **Parameters:**
1550
1899
  - `project_id` — numeric project ID
1900
+ - `include` — `["categories"]`
1551
1901
 
1552
1902
  **Request:**
1553
1903
 
1554
1904
  ```json
1555
1905
  {
1556
- "project_id": 3
1906
+ "project_id": 3,
1907
+ "include": ["categories"]
1557
1908
  }
1558
1909
  ```
1559
1910
 
1560
1911
  **Response:**
1561
1912
 
1562
1913
  ```json
1563
- [
1564
- { "id": 1, "name": "General" },
1565
- { "id": 2, "name": "UI" },
1566
- { "id": 3, "name": "Backend" }
1567
- ]
1914
+ {
1915
+ "id": 3,
1916
+ "name": "Webshop",
1917
+ "status": { "id": 10, "name": "development" },
1918
+ "enabled": true,
1919
+ "categories": [
1920
+ { "id": 1, "name": "General" },
1921
+ { "id": 2, "name": "UI" },
1922
+ { "id": 3, "name": "Backend" }
1923
+ ]
1924
+ }
1568
1925
  ```
1569
1926
 
1570
1927
  > **Note:** Category names prefixed with `[All Projects]` (inherited from the global project) have the prefix automatically stripped in the response.
1571
1928
 
1929
+ > **Deprecated:** `get_project_categories` will be removed in 2.0.0 — use `get_project` with `include: ["categories"]` as shown above.
1930
+
1572
1931
  ---
1573
1932
 
1574
1933
  ### Find a project member
1575
1934
 
1576
- Searches project members by name, real name, or email. The search is case-insensitive and matches any substring. Results are served from the metadata cache when available; falls back to a live API call on a cold cache.
1935
+ Searches project members by name, real name, or email. The search is case-insensitive and matches any substring. All matching users are returned — there is no `limit`.
1577
1936
 
1578
- **Tool:** `find_project_member`
1937
+ **Tool:** `get_project`
1579
1938
 
1580
1939
  **Parameters:**
1581
1940
  - `project_id` — numeric project ID
1582
- - `query` — _(optional)_ substring to match against `name`, `real_name`, or `email`
1583
- - `limit` — _(optional)_ maximum number of results, default 10, max 100
1941
+ - `member_query` — substring to match against `name`, `real_name`, or `email`
1584
1942
 
1585
1943
  **Request:**
1586
1944
 
1587
1945
  ```json
1588
1946
  {
1589
1947
  "project_id": 3,
1590
- "query": "smith",
1591
- "limit": 5
1948
+ "member_query": "smith"
1592
1949
  }
1593
1950
  ```
1594
1951
 
1595
1952
  **Response:**
1596
1953
 
1597
1954
  ```json
1598
- [
1599
- { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } },
1600
- { "id": 11, "name": "asmith", "real_name": "Alice Smith", "email": "asmith@example.com", "access_level": { "id": 40, "name": "reporter" } }
1601
- ]
1955
+ {
1956
+ "id": 3,
1957
+ "name": "Webshop",
1958
+ "status": { "id": 10, "name": "development" },
1959
+ "enabled": true,
1960
+ "users": [
1961
+ { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } },
1962
+ { "id": 11, "name": "asmith", "real_name": "Alice Smith", "email": "asmith@example.com", "access_level": { "id": 40, "name": "updater" } }
1963
+ ]
1964
+ }
1602
1965
  ```
1603
1966
 
1604
- > **Tip:** Omit `query` to list all members of the project (up to `limit`).
1967
+ > **Deprecated:** `find_project_member` will be removed in 2.0.0 — use `get_project` with `member_query` as shown above. Unlike `find_project_member`, `get_project` has no `limit` and returns all matching users.
1605
1968
 
1606
1969
  ---
1607
1970
 
@@ -1656,12 +2019,13 @@ Updates an existing version of a MantisBT project. Only the fields you pass are
1656
2019
 
1657
2020
  **Parameters:**
1658
2021
  - `project_id` — numeric project ID
1659
- - `version_id` — numeric version ID (use `get_project_versions` to discover)
2022
+ - `version_id` — numeric version ID (use `get_project` with `include: ["versions"]` to discover)
1660
2023
  - `name` — _(optional)_ new version name (must be unique within the project)
1661
2024
  - `description` — _(optional)_ new version description
1662
2025
  - `released` — _(optional)_ released flag
1663
2026
  - `obsolete` — _(optional)_ obsolete flag
1664
2027
  - `timestamp` — _(optional)_ version date as ISO 8601 string
2028
+ - `next_version` — _(optional, only with `released: true`)_ name of a follow-up version to create as an unreleased placeholder, e.g. `"1.2.1"`; used as-is — no automatic numbering
1665
2029
 
1666
2030
  **Request:** _(mark a version as obsolete)_
1667
2031
 
@@ -1685,9 +2049,46 @@ Updates an existing version of a MantisBT project. Only the fields you pass are
1685
2049
  }
1686
2050
  ```
1687
2051
 
2052
+ **Request:** _(release a version and create a follow-up placeholder)_
2053
+
2054
+ ```json
2055
+ {
2056
+ "project_id": 3,
2057
+ "version_id": 42,
2058
+ "released": true,
2059
+ "timestamp": "2026-10-31",
2060
+ "next_version": "1.2.1"
2061
+ }
2062
+ ```
2063
+
2064
+ **Response:**
2065
+
2066
+ ```json
2067
+ {
2068
+ "version": {
2069
+ "id": 42,
2070
+ "name": "1.2.0",
2071
+ "released": true,
2072
+ "obsolete": false,
2073
+ "timestamp": "2026-10-31T00:00:00+00:00"
2074
+ },
2075
+ "next_version": {
2076
+ "id": 43,
2077
+ "name": "1.2.1",
2078
+ "released": false,
2079
+ "obsolete": false,
2080
+ "timestamp": "2026-10-31T00:00:00+00:00"
2081
+ }
2082
+ }
2083
+ ```
2084
+
2085
+ Setting `released=true` does not change the version date — always pass `timestamp` with the release date. If creating the follow-up version fails, the update itself stays in effect and the error is reported as `next_version_error` in the response.
2086
+
1688
2087
  ---
1689
2088
 
1690
- ### Release a version and create the next bugfix placeholder
2089
+ ### Release a version and create the next bugfix placeholder (deprecated)
2090
+
2091
+ > **Deprecated:** use `update_version` with `released: true`, `timestamp`, and optionally `next_version` instead — `release_version` will be removed in 2.0.0. See [Update a project version](#update-a-project-version) for the replacement recipe.
1691
2092
 
1692
2093
  Marks a version as released (setting its date) and creates a follow-up version placeholder in the same call. The follow-up version name is used as-is — no automatic numbering. If the follow-up creation fails, the release stays in effect and the error is reported in `next_version_error`.
1693
2094
 
@@ -1733,7 +2134,7 @@ Marks a version as released (setting its date) and creates a follow-up version p
1733
2134
  }
1734
2135
  ```
1735
2136
 
1736
- > **Note:** Setting `released=true` via `update_version` does not change the version date — use `release_version` when you want to set both in one step.
2137
+ > **Note:** Setting `released=true` via `update_version` does not change the version date — always pass `timestamp` for the release date. Use `next_version` to create a follow-up version in the same call.
1737
2138
 
1738
2139
  ---
1739
2140
 
@@ -1774,9 +2175,11 @@ Returns a compact overview of all cached metadata: total project and tag counts,
1774
2175
 
1775
2176
  **Tool:** `get_metadata`
1776
2177
 
1777
- **Parameters:** _(none)_
2178
+ **Parameters:**
2179
+ - `detail` — _(optional)_ `"summary"` (default) for counts only; `"full"` for the complete raw cache
2180
+ - `refresh` — _(optional)_ `true` to re-fetch all metadata from MantisBT before answering; default `false`
1778
2181
 
1779
- **Request:**
2182
+ **Request:** _(summary, from cache)_
1780
2183
 
1781
2184
  ```json
1782
2185
  {}
@@ -1797,36 +2200,75 @@ Returns a compact overview of all cached metadata: total project and tag counts,
1797
2200
  }
1798
2201
  ```
1799
2202
 
1800
- > **Note:** For full lists use `list_projects`, `get_project_users`, `get_project_versions`, `get_project_categories`, `list_tags`, or `get_metadata_full`.
2203
+ With `MANTIS_SEARCH_ENABLED=true` the response also contains a `search_index` block:
2204
+
2205
+ ```json
2206
+ {
2207
+ "projects": 24,
2208
+ "tags": 15,
2209
+ "byProject": { "3": { "name": "Webshop", "users": 8, "versions": 12, "categories": 4 } },
2210
+ "cached_at": "2026-03-27T09:00:00.000Z",
2211
+ "ttl_seconds": 82800,
2212
+ "search_index": {
2213
+ "summary": "312/312 (100 %)",
2214
+ "indexed": 312,
2215
+ "total": 312,
2216
+ "percent": 100,
2217
+ "last_synced_at": "2026-03-27T08:55:00+01:00"
2218
+ }
2219
+ }
2220
+ ```
2221
+
2222
+ > **Note:** For full lists use `list_projects`, `get_project` (with `include`), or `list_tags`.
2223
+
2224
+ ---
2225
+
2226
+ ### Refresh the metadata cache
2227
+
2228
+ Forces a fresh fetch of all metadata from MantisBT before returning the summary.
2229
+
2230
+ **Tool:** `get_metadata`
2231
+
2232
+ **Parameters:**
2233
+ - `refresh` — `true`
2234
+
2235
+ **Request:**
2236
+
2237
+ ```json
2238
+ { "refresh": true }
2239
+ ```
2240
+
2241
+ **Response:** same shape as the summary above, with `cached_at` updated to now.
1801
2242
 
1802
2243
  ---
1803
2244
 
1804
2245
  ### Get the full metadata cache
1805
2246
 
1806
- Returns the complete raw metadata cache as minified JSON. Contains all projects with their full field set, plus users, versions, and categories per project, and all tags. Use this when you need the complete data in a single call.
2247
+ Returns the complete raw metadata cache as minified JSON. The cache structure is `{ timestamp, projects, byProject: {"<id>": { users, versions, categories }}, tags }`.
1807
2248
 
1808
- **Tool:** `get_metadata_full`
2249
+ **Tool:** `get_metadata`
1809
2250
 
1810
- **Parameters:** _(none)_
2251
+ **Parameters:**
2252
+ - `detail` — `"full"`
1811
2253
 
1812
2254
  **Request:**
1813
2255
 
1814
2256
  ```json
1815
- {}
2257
+ { "detail": "full" }
1816
2258
  ```
1817
2259
 
1818
2260
  **Response:**
1819
2261
 
1820
2262
  ```json
1821
2263
  {
2264
+ "timestamp": 1743066000000,
1822
2265
  "projects": [
1823
- {
1824
- "id": 3,
1825
- "name": "Webshop",
1826
- "status": { "id": 10, "name": "development" },
1827
- "enabled": true,
2266
+ { "id": 3, "name": "Webshop", "status": { "id": 10, "name": "development" }, "enabled": true }
2267
+ ],
2268
+ "byProject": {
2269
+ "3": {
1828
2270
  "users": [
1829
- { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } }
2271
+ { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com" }
1830
2272
  ],
1831
2273
  "versions": [
1832
2274
  { "id": 21, "name": "2.4.0", "released": false, "obsolete": false }
@@ -1836,81 +2278,57 @@ Returns the complete raw metadata cache as minified JSON. Contains all projects
1836
2278
  { "id": 2, "name": "UI" }
1837
2279
  ]
1838
2280
  }
1839
- ],
2281
+ },
1840
2282
  "tags": [
1841
2283
  { "id": 1, "name": "regression" },
1842
2284
  { "id": 2, "name": "hotfix" }
1843
- ],
1844
- "cached_at": "2026-03-27T09:00:00.000Z"
2285
+ ]
1845
2286
  }
1846
2287
  ```
1847
2288
 
1848
- > **Tip:** `get_metadata` provides the same data as a compact summary (counts only). Use `get_metadata_full` when you need the actual arrays.
2289
+ > **Deprecated:** `get_metadata_full` will be removed in 2.0.0 — use `get_metadata` with `detail: "full"` as shown above.
1849
2290
 
1850
2291
  ---
1851
2292
 
1852
2293
  ## Version & Diagnostics
1853
2294
 
1854
- ### Get MCP server version
1855
-
1856
- Returns the version of this mantisbt-mcp-server instance.
1857
-
1858
- **Tool:** `get_mcp_version`
1859
-
1860
- **Parameters:** _(none)_
1861
-
1862
- **Request:**
2295
+ ### Get versions (MCP server and MantisBT)
1863
2296
 
1864
- ```json
1865
- {}
1866
- ```
2297
+ Returns the version of this mantisbt-mcp-server and of the connected MantisBT installation in one response. With `check_latest: true` (default) the MantisBT version is compared against the latest release on GitHub (outbound HTTPS, up to 5 s). If MantisBT cannot be reached, `mantis` holds an `error` and the MCP server version is still returned.
1867
2298
 
1868
- **Response:**
1869
-
1870
- ```json
1871
- {
1872
- "version": "1.5.8"
1873
- }
1874
- ```
1875
-
1876
- ---
1877
-
1878
- ### Get MantisBT version
1879
-
1880
- Returns the version of the connected MantisBT installation and optionally compares it against the latest official release on GitHub.
1881
-
1882
- **Tool:** `get_mantis_version`
2299
+ **Tool:** `get_version`
1883
2300
 
1884
2301
  **Parameters:**
1885
- - `check_latest` — _(optional)_ whether to compare against the latest GitHub release; default `true`
2302
+ - `check_latest` — _(optional)_ compare MantisBT against the latest GitHub release; default `true`
1886
2303
 
1887
2304
  **Request:**
1888
2305
 
1889
2306
  ```json
1890
- {
1891
- "check_latest": true
1892
- }
2307
+ {}
1893
2308
  ```
1894
2309
 
1895
2310
  **Response:**
1896
2311
 
1897
2312
  ```json
1898
2313
  {
1899
- "installed_version": "2.27.0",
1900
- "latest_version": "2.27.1",
1901
- "status": "update-available"
2314
+ "mcp_server": { "version": "1.15.0" },
2315
+ "mantis": {
2316
+ "installed_version": "2.27.0",
2317
+ "latest_version": "2.27.1",
2318
+ "status": "update-available"
2319
+ }
1902
2320
  }
1903
2321
  ```
1904
2322
 
1905
- Possible values for `status`: `up-to-date`, `update-available`, `newer-than-release`, `unknown`.
2323
+ Possible values for `status`: `up-to-date`, `update-available`, `newer-than-release`, `unknown`. Set `check_latest: false` to skip the GitHub comparison.
1906
2324
 
1907
- > **Note:** The GitHub comparison requires an outbound HTTPS request. Set `check_latest` to `false` to skip it.
2325
+ > **Deprecated:** `get_mcp_version` and `get_mantis_version` will be removed in 2.0.0 — use `get_version` as shown above.
1908
2326
 
1909
2327
  ---
1910
2328
 
1911
2329
  ### Get the current user
1912
2330
 
1913
- Returns the profile of the user associated with the configured API key. Useful to verify the connection and confirm which account is being used.
2331
+ Returns the profile of the user associated with the configured API key. Useful to verify the connection and confirm which account is being used. The `language` field tells you which MantisBT language is configured for this user — use it as a hint for the language to write issue texts and notes in, and expect localized enum labels in that language.
1914
2332
 
1915
2333
  **Tool:** `get_current_user`
1916
2334
 
@@ -1930,6 +2348,7 @@ Returns the profile of the user associated with the configured API key. Useful t
1930
2348
  "name": "jsmith",
1931
2349
  "real_name": "John Smith",
1932
2350
  "email": "jsmith@example.com",
2351
+ "language": "english",
1933
2352
  "access_level": { "id": 55, "name": "developer" }
1934
2353
  }
1935
2354
  ```
@@ -1972,7 +2391,7 @@ Returns all MantisBT projects accessible with the configured API key.
1972
2391
 
1973
2392
  **Resource URI:** `mantis://projects`
1974
2393
 
1975
- **Fetch behaviour:** Served from the MetadataCache (default TTL 24 h). Falls back to a live API call when the cache is empty. Run `sync_metadata` to force a refresh.
2394
+ **Fetch behaviour:** Served from the MetadataCache (default TTL 24 h). Falls back to a live API call when the cache is empty. Run `get_metadata` with `refresh: true` to force a refresh.
1976
2395
 
1977
2396
  **Response:**
1978
2397
 
@@ -2062,7 +2481,7 @@ Returns valid ID/name pairs for all issue enum fields (severity, priority, statu
2062
2481
  }
2063
2482
  ```
2064
2483
 
2065
- > **Tip:** The `get_issue_enums` tool provides the same data for clients that do not support Resources.
2484
+ > **Tip:** The `get_issue_schema` tool provides enum values for clients that do not support Resources (and also returns the valid `select` fields).
2066
2485
 
2067
2486
  ---
2068
2487
 
@@ -2088,7 +2507,7 @@ Collects structured bug data and calls `create_issue`.
2088
2507
  - `actual` — actual (observed) behavior
2089
2508
  - `environment` — environment details (OS, browser, version, etc.)
2090
2509
 
2091
- **What happens:** The prompt returns a message that instructs the LLM to call `get_issue_enums` (to resolve valid severity/priority values) and then `create_issue` with the provided data.
2510
+ **What happens:** The prompt returns a message that instructs the LLM to call `get_issue_schema` (to resolve valid severity/priority values) and then `create_issue` with the provided data.
2092
2511
 
2093
2512
  **Example call:**
2094
2513
 
@@ -2182,6 +2601,8 @@ Lists all issues for a project and generates a status report grouped by severity
2182
2601
 
2183
2602
  ## Destructive Operations
2184
2603
 
2604
+ > To hide all destructive tools at once — e.g. for a session that should never delete anything — set `MANTIS_DISABLE_DESTRUCTIVE=true`; see [Offer only some tool groups](#offer-only-some-tool-groups).
2605
+
2185
2606
  ### Delete an issue
2186
2607
 
2187
2608
  Permanently deletes a MantisBT issue. This action cannot be undone.