@dpesch/mantisbt-mcp-server 1.14.1 → 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
146
159
 
147
- **Tool:** `get_issue_enums`
160
+ Returns the full list of projects accessible with your API key.
161
+
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
@@ -1386,7 +1647,7 @@ Only one server process syncs the shared index at a time. If another process (fo
1386
1647
 
1387
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.
1388
1649
 
1389
- **Tool:** `get_search_index_status`
1650
+ **Tool:** `get_metadata`
1390
1651
 
1391
1652
  **Parameters:** _(none)_
1392
1653
 
@@ -1396,18 +1657,27 @@ Returns the number of indexed issues, total issue count, and the timestamp of th
1396
1657
  {}
1397
1658
  ```
1398
1659
 
1399
- **Response:**
1660
+ **Response (relevant excerpt):**
1400
1661
 
1401
1662
  ```json
1402
1663
  {
1403
- "summary": "312/312 (100 %)",
1404
- "indexed": 312,
1405
- "total": 312,
1406
- "percent": 100,
1407
- "last_synced_at": "2024-11-05T14:00:00+01:00"
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
+ }
1408
1676
  }
1409
1677
  ```
1410
1678
 
1679
+ > **Deprecated:** `get_search_index_status` will be removed in 2.0.0 — use `get_metadata` (field `search_index`) as shown above.
1680
+
1411
1681
  ---
1412
1682
 
1413
1683
  ### Search by meaning
@@ -1542,68 +1812,159 @@ Shows which part of an issue matched the search query. Each result that has keyw
1542
1812
 
1543
1813
  ## Projects & Categories
1544
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
+
1545
1892
  ### List project categories
1546
1893
 
1547
1894
  Returns all categories available for a MantisBT project. Use the returned names directly when creating issues.
1548
1895
 
1549
- **Tool:** `get_project_categories`
1896
+ **Tool:** `get_project`
1550
1897
 
1551
1898
  **Parameters:**
1552
1899
  - `project_id` — numeric project ID
1900
+ - `include` — `["categories"]`
1553
1901
 
1554
1902
  **Request:**
1555
1903
 
1556
1904
  ```json
1557
1905
  {
1558
- "project_id": 3
1906
+ "project_id": 3,
1907
+ "include": ["categories"]
1559
1908
  }
1560
1909
  ```
1561
1910
 
1562
1911
  **Response:**
1563
1912
 
1564
1913
  ```json
1565
- [
1566
- { "id": 1, "name": "General" },
1567
- { "id": 2, "name": "UI" },
1568
- { "id": 3, "name": "Backend" }
1569
- ]
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
+ }
1570
1925
  ```
1571
1926
 
1572
1927
  > **Note:** Category names prefixed with `[All Projects]` (inherited from the global project) have the prefix automatically stripped in the response.
1573
1928
 
1929
+ > **Deprecated:** `get_project_categories` will be removed in 2.0.0 — use `get_project` with `include: ["categories"]` as shown above.
1930
+
1574
1931
  ---
1575
1932
 
1576
1933
  ### Find a project member
1577
1934
 
1578
- 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`.
1579
1936
 
1580
- **Tool:** `find_project_member`
1937
+ **Tool:** `get_project`
1581
1938
 
1582
1939
  **Parameters:**
1583
1940
  - `project_id` — numeric project ID
1584
- - `query` — _(optional)_ substring to match against `name`, `real_name`, or `email`
1585
- - `limit` — _(optional)_ maximum number of results, default 10, max 100
1941
+ - `member_query` — substring to match against `name`, `real_name`, or `email`
1586
1942
 
1587
1943
  **Request:**
1588
1944
 
1589
1945
  ```json
1590
1946
  {
1591
1947
  "project_id": 3,
1592
- "query": "smith",
1593
- "limit": 5
1948
+ "member_query": "smith"
1594
1949
  }
1595
1950
  ```
1596
1951
 
1597
1952
  **Response:**
1598
1953
 
1599
1954
  ```json
1600
- [
1601
- { "id": 4, "name": "jsmith", "real_name": "John Smith", "email": "jsmith@example.com", "access_level": { "id": 55, "name": "developer" } },
1602
- { "id": 11, "name": "asmith", "real_name": "Alice Smith", "email": "asmith@example.com", "access_level": { "id": 40, "name": "reporter" } }
1603
- ]
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
+ }
1604
1965
  ```
1605
1966
 
1606
- > **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.
1607
1968
 
1608
1969
  ---
1609
1970
 
@@ -1658,12 +2019,13 @@ Updates an existing version of a MantisBT project. Only the fields you pass are
1658
2019
 
1659
2020
  **Parameters:**
1660
2021
  - `project_id` — numeric project ID
1661
- - `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)
1662
2023
  - `name` — _(optional)_ new version name (must be unique within the project)
1663
2024
  - `description` — _(optional)_ new version description
1664
2025
  - `released` — _(optional)_ released flag
1665
2026
  - `obsolete` — _(optional)_ obsolete flag
1666
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
1667
2029
 
1668
2030
  **Request:** _(mark a version as obsolete)_
1669
2031
 
@@ -1687,9 +2049,46 @@ Updates an existing version of a MantisBT project. Only the fields you pass are
1687
2049
  }
1688
2050
  ```
1689
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
+
1690
2087
  ---
1691
2088
 
1692
- ### 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.
1693
2092
 
1694
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`.
1695
2094
 
@@ -1735,7 +2134,7 @@ Marks a version as released (setting its date) and creates a follow-up version p
1735
2134
  }
1736
2135
  ```
1737
2136
 
1738
- > **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.
1739
2138
 
1740
2139
  ---
1741
2140
 
@@ -1776,9 +2175,11 @@ Returns a compact overview of all cached metadata: total project and tag counts,
1776
2175
 
1777
2176
  **Tool:** `get_metadata`
1778
2177
 
1779
- **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`
1780
2181
 
1781
- **Request:**
2182
+ **Request:** _(summary, from cache)_
1782
2183
 
1783
2184
  ```json
1784
2185
  {}
@@ -1799,36 +2200,75 @@ Returns a compact overview of all cached metadata: total project and tag counts,
1799
2200
  }
1800
2201
  ```
1801
2202
 
1802
- > **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.
1803
2242
 
1804
2243
  ---
1805
2244
 
1806
2245
  ### Get the full metadata cache
1807
2246
 
1808
- 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 }`.
1809
2248
 
1810
- **Tool:** `get_metadata_full`
2249
+ **Tool:** `get_metadata`
1811
2250
 
1812
- **Parameters:** _(none)_
2251
+ **Parameters:**
2252
+ - `detail` — `"full"`
1813
2253
 
1814
2254
  **Request:**
1815
2255
 
1816
2256
  ```json
1817
- {}
2257
+ { "detail": "full" }
1818
2258
  ```
1819
2259
 
1820
2260
  **Response:**
1821
2261
 
1822
2262
  ```json
1823
2263
  {
2264
+ "timestamp": 1743066000000,
1824
2265
  "projects": [
1825
- {
1826
- "id": 3,
1827
- "name": "Webshop",
1828
- "status": { "id": 10, "name": "development" },
1829
- "enabled": true,
2266
+ { "id": 3, "name": "Webshop", "status": { "id": 10, "name": "development" }, "enabled": true }
2267
+ ],
2268
+ "byProject": {
2269
+ "3": {
1830
2270
  "users": [
1831
- { "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" }
1832
2272
  ],
1833
2273
  "versions": [
1834
2274
  { "id": 21, "name": "2.4.0", "released": false, "obsolete": false }
@@ -1838,81 +2278,57 @@ Returns the complete raw metadata cache as minified JSON. Contains all projects
1838
2278
  { "id": 2, "name": "UI" }
1839
2279
  ]
1840
2280
  }
1841
- ],
2281
+ },
1842
2282
  "tags": [
1843
2283
  { "id": 1, "name": "regression" },
1844
2284
  { "id": 2, "name": "hotfix" }
1845
- ],
1846
- "cached_at": "2026-03-27T09:00:00.000Z"
2285
+ ]
1847
2286
  }
1848
2287
  ```
1849
2288
 
1850
- > **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.
1851
2290
 
1852
2291
  ---
1853
2292
 
1854
2293
  ## Version & Diagnostics
1855
2294
 
1856
- ### Get MCP server version
1857
-
1858
- Returns the version of this mantisbt-mcp-server instance.
1859
-
1860
- **Tool:** `get_mcp_version`
1861
-
1862
- **Parameters:** _(none)_
1863
-
1864
- **Request:**
1865
-
1866
- ```json
1867
- {}
1868
- ```
1869
-
1870
- **Response:**
1871
-
1872
- ```json
1873
- {
1874
- "version": "1.5.8"
1875
- }
1876
- ```
1877
-
1878
- ---
2295
+ ### Get versions (MCP server and MantisBT)
1879
2296
 
1880
- ### Get MantisBT version
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.
1881
2298
 
1882
- Returns the version of the connected MantisBT installation and optionally compares it against the latest official release on GitHub.
1883
-
1884
- **Tool:** `get_mantis_version`
2299
+ **Tool:** `get_version`
1885
2300
 
1886
2301
  **Parameters:**
1887
- - `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`
1888
2303
 
1889
2304
  **Request:**
1890
2305
 
1891
2306
  ```json
1892
- {
1893
- "check_latest": true
1894
- }
2307
+ {}
1895
2308
  ```
1896
2309
 
1897
2310
  **Response:**
1898
2311
 
1899
2312
  ```json
1900
2313
  {
1901
- "installed_version": "2.27.0",
1902
- "latest_version": "2.27.1",
1903
- "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
+ }
1904
2320
  }
1905
2321
  ```
1906
2322
 
1907
- 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.
1908
2324
 
1909
- > **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.
1910
2326
 
1911
2327
  ---
1912
2328
 
1913
2329
  ### Get the current user
1914
2330
 
1915
- 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.
1916
2332
 
1917
2333
  **Tool:** `get_current_user`
1918
2334
 
@@ -1932,6 +2348,7 @@ Returns the profile of the user associated with the configured API key. Useful t
1932
2348
  "name": "jsmith",
1933
2349
  "real_name": "John Smith",
1934
2350
  "email": "jsmith@example.com",
2351
+ "language": "english",
1935
2352
  "access_level": { "id": 55, "name": "developer" }
1936
2353
  }
1937
2354
  ```
@@ -1974,7 +2391,7 @@ Returns all MantisBT projects accessible with the configured API key.
1974
2391
 
1975
2392
  **Resource URI:** `mantis://projects`
1976
2393
 
1977
- **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.
1978
2395
 
1979
2396
  **Response:**
1980
2397
 
@@ -2064,7 +2481,7 @@ Returns valid ID/name pairs for all issue enum fields (severity, priority, statu
2064
2481
  }
2065
2482
  ```
2066
2483
 
2067
- > **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).
2068
2485
 
2069
2486
  ---
2070
2487
 
@@ -2090,7 +2507,7 @@ Collects structured bug data and calls `create_issue`.
2090
2507
  - `actual` — actual (observed) behavior
2091
2508
  - `environment` — environment details (OS, browser, version, etc.)
2092
2509
 
2093
- **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.
2094
2511
 
2095
2512
  **Example call:**
2096
2513
 
@@ -2184,6 +2601,8 @@ Lists all issues for a project and generates a status report grouped by severity
2184
2601
 
2185
2602
  ## Destructive Operations
2186
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
+
2187
2606
  ### Delete an issue
2188
2607
 
2189
2608
  Permanently deletes a MantisBT issue. This action cannot be undone.