@dpesch/mantisbt-mcp-server 1.5.8 → 1.6.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/CHANGELOG.md +34 -0
- package/README.de.md +28 -12
- package/README.md +28 -12
- package/dist/client.js +37 -23
- package/dist/config.js +41 -50
- package/dist/constants.js +12 -0
- package/dist/index.js +23 -13
- package/dist/prompts/index.js +112 -0
- package/dist/resources/index.js +29 -0
- package/dist/tools/config.js +44 -40
- package/dist/tools/issues.js +22 -6
- package/docs/cookbook.de.md +1664 -0
- package/docs/cookbook.md +1664 -0
- package/docs/examples.de.md +200 -0
- package/docs/examples.md +200 -0
- package/package.json +6 -2
- package/server.json +2 -2
- package/tests/client.test.ts +70 -0
- package/tests/config.test.ts +47 -37
- package/tests/helpers/mock-server.ts +61 -0
- package/tests/prompts/prompts.test.ts +242 -0
- package/tests/resources/resources.test.ts +192 -0
- package/tests/tools/issues.test.ts +26 -10
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Anwendungsbeispiele
|
|
2
|
+
|
|
3
|
+
Praktische Beispiele für die Interaktion mit MantisBT über Claude, sobald der MCP-Server verbunden ist. Einfach in natürlicher Sprache fragen — keine Tool-Namen oder Parameter erforderlich. Für exakte Tool-Aufrufe und Parameter siehe das [Cookbook](cookbook.de.md).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Alltägliche Anwendungsfälle
|
|
8
|
+
|
|
9
|
+
### Issues durchsuchen und filtern
|
|
10
|
+
|
|
11
|
+
> »Zeige mir alle offenen Issues im Projekt Webshop.«
|
|
12
|
+
|
|
13
|
+
> »Welche Bugs sind mir aktuell zugewiesen?«
|
|
14
|
+
|
|
15
|
+
> »Liste alle ungelösten Issues mit Priorität 'dringend' im Backend-Projekt.«
|
|
16
|
+
|
|
17
|
+
> »Was ist der Status von Issue #1042?«
|
|
18
|
+
|
|
19
|
+
> »Zeige mir alle Issues, die jsmith diesen Monat gemeldet hat.«
|
|
20
|
+
|
|
21
|
+
> »Welche Issues im Webshop-Projekt blockieren das Release 2.4.0?«
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### Issues erstellen
|
|
26
|
+
|
|
27
|
+
> »Erstelle einen Bug-Report: Auf der Checkout-Seite wird die Bestellung doppelt abgeschickt, wenn man zweimal auf 'Bestellen' klickt. Kategorie: Shop, Schweregrad: schwerwiegend.«
|
|
28
|
+
|
|
29
|
+
> »Öffne ein neues Issue im API-Projekt — der Token-Refresh-Endpoint gibt 500 zurück, wenn das Refresh-Token abgelaufen ist. Dem Backend-Team zuweisen.«
|
|
30
|
+
|
|
31
|
+
> »Erstelle einen Feature-Request im Frontend-Projekt für einen Dunkelmodus in den Benutzereinstellungen. Niedrige Priorität, kein Fälligkeitsdatum.«
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### Issues aktualisieren
|
|
36
|
+
|
|
37
|
+
> »Markiere Issue #1042 als gelöst.«
|
|
38
|
+
|
|
39
|
+
> »Weise Issue #887 an jdoe neu zu.«
|
|
40
|
+
|
|
41
|
+
> »Ändere den Schweregrad von #1099 auf 'schwerwiegend' und füge eine Notiz hinzu: auf Produktion reproduziert.«
|
|
42
|
+
|
|
43
|
+
> »Setze die Fix-Version von Issues #901 und #902 auf 2.4.1.«
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### Notizen und Kommentare
|
|
48
|
+
|
|
49
|
+
> »Füge einen Kommentar zu #1042 hinzu: Fix auf Staging ausgerollt, warte auf QA-Freigabe.«
|
|
50
|
+
|
|
51
|
+
> »Zeige mir alle Notizen zu Issue #774.«
|
|
52
|
+
|
|
53
|
+
> »Füge eine private Notiz zu #512 hinzu: Kundenreferenz AC-2291, nicht weitergeben.«
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### Anhänge
|
|
58
|
+
|
|
59
|
+
> »Hänge die Datei /tmp/error.log an Issue #1042 an.«
|
|
60
|
+
|
|
61
|
+
> »Welche Dateien sind an Issue #930 angehängt?«
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### Beziehungen
|
|
66
|
+
|
|
67
|
+
> »Markiere Issue #1044 als Duplikat von #1042.«
|
|
68
|
+
|
|
69
|
+
> »Verknüpfe #901 und #902 als verwandte Issues.«
|
|
70
|
+
|
|
71
|
+
> »Issue #1100 blockiert #1101 — bitte diese Beziehung anlegen.«
|
|
72
|
+
> *(Richtung ist entscheidend: #1100 ist das blockierende Issue)*
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Tags
|
|
77
|
+
|
|
78
|
+
> »Versehe Issue #1042 mit den Tags 'regression' und 'hotfix'.«
|
|
79
|
+
|
|
80
|
+
> »Entferne den Tag 'wontfix' von Issue #887.«
|
|
81
|
+
|
|
82
|
+
> »Welche Tags gibt es in dieser MantisBT-Instanz?«
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Projektmetadaten
|
|
87
|
+
|
|
88
|
+
> »Auf welche Projekte habe ich Zugriff?«
|
|
89
|
+
|
|
90
|
+
> »Welche Versionen sind im Webshop-Projekt definiert?«
|
|
91
|
+
|
|
92
|
+
> »Liste alle Kategorien im Backend-Projekt.«
|
|
93
|
+
|
|
94
|
+
> »Wer sind die Mitglieder des API-Projekts?«
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Triage und Auswertung
|
|
99
|
+
|
|
100
|
+
> »Gib mir einen Überblick über alle kritischen und dringenden offenen Issues in allen Projekten.«
|
|
101
|
+
|
|
102
|
+
> »Welche Issues im Backend-Projekt sind seit mehr als 30 Tagen ohne Aktivität offen?«
|
|
103
|
+
|
|
104
|
+
> »Was sind die häufigsten Bug-Typen der letzten sechs Monate?«
|
|
105
|
+
|
|
106
|
+
> »Fasse die Notizen zu Issue #774 zusammen und schlage einen nächsten Schritt vor.«
|
|
107
|
+
|
|
108
|
+
> »Liste alle Issues mit dem Tag 'regression' und fasse zusammen, was schiefgelaufen ist.«
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Geführte Prompt-Workflows
|
|
113
|
+
|
|
114
|
+
Der Server enthält Prompt-Templates, die Claude durch strukturierte Arbeitsabläufe führen — Tool-Namen oder Parameter müssen nicht manuell angegeben werden. Die Prompts werden aus einem MCP-fähigen Client beim Namen aufgerufen.
|
|
115
|
+
|
|
116
|
+
### Issues über Prompt-Templates anlegen
|
|
117
|
+
|
|
118
|
+
> »Verwende den Prompt `create-bug-report` für das Safari-Login-Issue: Projekt 3, Kategorie UI, Titel 'Login-Button reagiert auf Mobile Safari nicht', Beschreibung 'Ein Tipp auf den Login-Button auf iPhone 14 / Safari 17 bewirkt nichts', Schritte: Login-Seite öffnen → Anmelden antippen → nichts passiert, Erwartet: Weiterleitung zum Dashboard, Tatsächlich: Formular bleibt geöffnet.«
|
|
119
|
+
|
|
120
|
+
> »Nutze `create-feature-request` für Projekt 5, Kategorie UX: Dunkelmodus-Schalter auf der Einstellungsseite hinzufügen.«
|
|
121
|
+
|
|
122
|
+
### Zusammenfassen und Berichten
|
|
123
|
+
|
|
124
|
+
> »Führe den Prompt `summarize-issue` für Issue #1042 aus.«
|
|
125
|
+
|
|
126
|
+
> »Verwende den Prompt `project-status` für Projekt 3, um einen Überblick über offene Issues nach Schweregrad zu erhalten.«
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Semantische Suche
|
|
131
|
+
|
|
132
|
+
Die semantische Suche versteht die *Bedeutung* deiner Frage — nicht nur einzelne Schlüsselwörter. Sie findet konzeptionell verwandte Issues, auch wenn die genaue Formulierung abweicht. Aktivierung mit `MANTIS_SEARCH_ENABLED=true`.
|
|
133
|
+
|
|
134
|
+
### Duplikaterkennung vor dem Anlegen
|
|
135
|
+
|
|
136
|
+
> »Bevor ich ein neues Issue anlege: Hat jemand schon ein Problem mit dem Login-Formular nach einem Passwort-Reset gemeldet?«
|
|
137
|
+
|
|
138
|
+
> »Gibt es bereits ein Ticket wegen langsamer PDF-Generierung bei großen Rechnungen?«
|
|
139
|
+
|
|
140
|
+
> »Suche nach Issues ähnlich wie: 'Die Benutzersitzung geht verloren, wenn man den Browser-Tab wechselt'.«
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Thematische Übersichten
|
|
145
|
+
|
|
146
|
+
> »Zeig mir relevante Issues rund um die Zahlungsabwicklung — projektübergreifend.«
|
|
147
|
+
|
|
148
|
+
> »Zeig mir Beispiele für gemeldete E-Mail-Zustellungsfehler.«
|
|
149
|
+
|
|
150
|
+
> »Welche Issues erwähnen Performance-Probleme auf Mobilgeräten?«
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### Unscharfe / terminologieunabhängige Suche
|
|
155
|
+
|
|
156
|
+
> »Finde Issues zu 'doppelten Einträgen' — sie könnten auch als 'zweimal angezeigt', 'doppelte Datensätze' oder 'Phantom-Zeilen' beschrieben sein.«
|
|
157
|
+
|
|
158
|
+
> »Suche nach authentifizierungsbezogenen Issues — die Berichte verwenden möglicherweise 'Login', 'Anmeldung', 'Token', 'Session' oder 'Auth'.«
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Projektübergreifende Recherche
|
|
163
|
+
|
|
164
|
+
> »Wurde der Bild-Upload-Bug, den wir im Webshop behoben haben, auch im Mobile-Projekt gemeldet?«
|
|
165
|
+
|
|
166
|
+
> »Welche Projekte haben offene Issues zu DSGVO oder Datenexport?«
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Einarbeitung und Wissenstransfer
|
|
171
|
+
|
|
172
|
+
> »Zeig mir Tickets, die erklären warum der Authentifizierungsfluss so gebaut wurde wie er ist.«
|
|
173
|
+
|
|
174
|
+
> »Gibt es bekannte Fallstricke beim Einrichten der Deployment-Pipeline?«
|
|
175
|
+
|
|
176
|
+
> »Welche Issues beschreiben Probleme, die beim ersten Einrichten der Entwicklungsumgebung auftreten?«
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Ressourcen
|
|
181
|
+
|
|
182
|
+
MCP-Ressourcen sind URI-adressierbare, schreibgeschützte Daten, die Clients direkt per URI abrufen können — kein Tool-Aufruf nötig. Die Ressourcen-Unterstützung variiert je nach Client; wenn der verwendete Client keine Ressourcen unterstützt, das entsprechende Tool als Alternative verwenden.
|
|
183
|
+
|
|
184
|
+
### Server-Zustand über Ressourcen abrufen
|
|
185
|
+
|
|
186
|
+
> »Lese `mantis://me`, um zu sehen, welches Konto der MCP-Server verwendet.«
|
|
187
|
+
|
|
188
|
+
> »Rufe `mantis://projects` ab, um die Liste der verfügbaren Projekte zu erhalten.«
|
|
189
|
+
|
|
190
|
+
> »Lade `mantis://enums`, um die gültigen Severity- und Priority-Werte einzusehen, bevor ein Issue erstellt wird.«
|
|
191
|
+
|
|
192
|
+
### Alternative Tools für Clients ohne Ressourcen-Unterstützung
|
|
193
|
+
|
|
194
|
+
Wenn der Client keine Ressourcen unterstützt, Claude einfach das entsprechende Tool verwenden lassen:
|
|
195
|
+
|
|
196
|
+
> »Zeig mir mein Benutzerprofil.« *(verwendet `get_current_user`)*
|
|
197
|
+
|
|
198
|
+
> »Welche Projekte sind verfügbar?« *(verwendet `list_projects`)*
|
|
199
|
+
|
|
200
|
+
> »Welche Prioritätswerte sind gültig?« *(verwendet `get_issue_enums`)*
|
package/docs/examples.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Usage Examples
|
|
2
|
+
|
|
3
|
+
Practical examples of how to interact with MantisBT through Claude once the MCP server is connected. Just ask in natural language — no tool names or parameters required. For exact tool calls and parameters, see the [Cookbook](cookbook.md).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Everyday Use Cases
|
|
8
|
+
|
|
9
|
+
### Browsing and searching issues
|
|
10
|
+
|
|
11
|
+
> "Show me all open issues in the Webshop project."
|
|
12
|
+
|
|
13
|
+
> "What bugs are currently assigned to me?"
|
|
14
|
+
|
|
15
|
+
> "List the unresolved issues with priority 'urgent' in the Backend project."
|
|
16
|
+
|
|
17
|
+
> "What's the status of issue #1042?"
|
|
18
|
+
|
|
19
|
+
> "Show me all issues reported by jsmith this month."
|
|
20
|
+
|
|
21
|
+
> "Which issues in the Webshop project are blocking the 2.4.0 release?"
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### Creating issues
|
|
26
|
+
|
|
27
|
+
> "Create a bug report: on the checkout page, clicking 'Place order' twice submits the order twice. Category: Shop, severity: major."
|
|
28
|
+
|
|
29
|
+
> "Open a new issue in the API project — the token refresh endpoint returns 500 when the refresh token has expired. Assign it to the backend team."
|
|
30
|
+
|
|
31
|
+
> "Create a feature request in the Frontend project for a dark mode in the user settings. Low priority, no due date."
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### Updating issues
|
|
36
|
+
|
|
37
|
+
> "Mark issue #1042 as resolved."
|
|
38
|
+
|
|
39
|
+
> "Reassign issue #887 to jdoe."
|
|
40
|
+
|
|
41
|
+
> "Change the severity of #1099 to 'major' and add a note: reproduced on production."
|
|
42
|
+
|
|
43
|
+
> "Set the fix version of issues #901 and #902 to 2.4.1."
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### Notes and comments
|
|
48
|
+
|
|
49
|
+
> "Add a comment to #1042: fix deployed to staging, awaiting QA sign-off."
|
|
50
|
+
|
|
51
|
+
> "Show me all notes on issue #774."
|
|
52
|
+
|
|
53
|
+
> "Add a private note to #512: customer reference AC-2291, do not disclose."
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### Attachments
|
|
58
|
+
|
|
59
|
+
> "Attach the file /tmp/error.log to issue #1042."
|
|
60
|
+
|
|
61
|
+
> "What files are attached to issue #930?"
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### Relationships
|
|
66
|
+
|
|
67
|
+
> "Mark issue #1044 as a duplicate of #1042."
|
|
68
|
+
|
|
69
|
+
> "Link #901 and #902 as related issues."
|
|
70
|
+
|
|
71
|
+
> "Issue #1100 blocks #1101 — please create that relationship."
|
|
72
|
+
> *(direction matters: #1100 is the blocking issue)*
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Tags
|
|
77
|
+
|
|
78
|
+
> "Tag issue #1042 with 'regression' and 'hotfix'."
|
|
79
|
+
|
|
80
|
+
> "Remove the 'wontfix' tag from issue #887."
|
|
81
|
+
|
|
82
|
+
> "Which tags are available in this MantisBT instance?"
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Project metadata
|
|
87
|
+
|
|
88
|
+
> "Which projects do I have access to?"
|
|
89
|
+
|
|
90
|
+
> "What versions are defined in the Webshop project?"
|
|
91
|
+
|
|
92
|
+
> "List all categories in the Backend project."
|
|
93
|
+
|
|
94
|
+
> "Who are the members of the API project?"
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### Triage and reporting
|
|
99
|
+
|
|
100
|
+
> "Give me an overview of all critical and urgent open issues across all projects."
|
|
101
|
+
|
|
102
|
+
> "Which issues in the Backend project have been open for more than 30 days without any activity?"
|
|
103
|
+
|
|
104
|
+
> "What are the most common types of bugs reported in the last six months?"
|
|
105
|
+
|
|
106
|
+
> "Summarise the notes on issue #774 and suggest a next step."
|
|
107
|
+
|
|
108
|
+
> "List all issues tagged 'regression' and summarise what went wrong."
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Guided Prompt Workflows
|
|
113
|
+
|
|
114
|
+
The server ships with prompt templates that guide Claude through structured workflows — no need to specify tool names or parameters manually. Invoke them by name from a MCP-capable client.
|
|
115
|
+
|
|
116
|
+
### Creating issues from a prompt template
|
|
117
|
+
|
|
118
|
+
> "Use the `create-bug-report` prompt to file the Safari login issue: project 3, category UI, summary 'Login button unresponsive on mobile Safari', description 'Tapping login on iPhone 14 / Safari 17 does nothing', steps: open login page → tap Login → nothing happens, expected: redirect to dashboard, actual: form stays open."
|
|
119
|
+
|
|
120
|
+
> "Use `create-feature-request` for project 5, category UX: add a dark mode toggle to the settings page."
|
|
121
|
+
|
|
122
|
+
### Summarizing and reporting
|
|
123
|
+
|
|
124
|
+
> "Run the `summarize-issue` prompt for issue #1042."
|
|
125
|
+
|
|
126
|
+
> "Use the `project-status` prompt for project 3 to get an overview of open issues grouped by severity."
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Semantic Search
|
|
131
|
+
|
|
132
|
+
Semantic search understands the *meaning* of your question — not just keywords. It finds conceptually related issues even when the exact wording differs. Enable it with `MANTIS_SEARCH_ENABLED=true`.
|
|
133
|
+
|
|
134
|
+
### Duplicate detection before filing a report
|
|
135
|
+
|
|
136
|
+
> "Before I create a new issue: has anyone reported a problem with the login form after a password reset?"
|
|
137
|
+
|
|
138
|
+
> "Is there already a ticket about slow PDF generation for large invoices?"
|
|
139
|
+
|
|
140
|
+
> "Search for issues similar to: 'user session is lost when switching browser tabs'."
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Thematic overviews
|
|
145
|
+
|
|
146
|
+
> "Show me relevant issues related to payment processing — across all projects."
|
|
147
|
+
|
|
148
|
+
> "Show me examples of reported email delivery failures."
|
|
149
|
+
|
|
150
|
+
> "Which issues mention performance problems on mobile devices?"
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### Fuzzy / terminology-independent search
|
|
155
|
+
|
|
156
|
+
> "Find issues about 'duplicate entries' — they might also be described as 'shown twice', 'double records', or 'phantom rows'."
|
|
157
|
+
|
|
158
|
+
> "Search for authentication-related issues — the reports might use 'login', 'sign-in', 'token', 'session', or 'auth'."
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Cross-project research
|
|
163
|
+
|
|
164
|
+
> "Is the image upload bug we fixed in the Webshop also reported in the Mobile project?"
|
|
165
|
+
|
|
166
|
+
> "Which projects have open issues related to GDPR or data export?"
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Onboarding and knowledge transfer
|
|
171
|
+
|
|
172
|
+
> "Show me tickets that explain why the authentication flow was built this way."
|
|
173
|
+
|
|
174
|
+
> "Are there any known pitfalls when setting up the deployment pipeline?"
|
|
175
|
+
|
|
176
|
+
> "Which issues describe problems that occur during initial environment setup?"
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Resources
|
|
181
|
+
|
|
182
|
+
MCP Resources are URI-addressable, read-only data that clients can fetch directly by URI — no tool invocation required. Resource support varies by client; if your client does not support Resources, use the equivalent tool instead.
|
|
183
|
+
|
|
184
|
+
### Reading server state via resources
|
|
185
|
+
|
|
186
|
+
> "Read `mantis://me` to see which account the MCP server is using."
|
|
187
|
+
|
|
188
|
+
> "Fetch `mantis://projects` to get the list of available projects."
|
|
189
|
+
|
|
190
|
+
> "Load `mantis://enums` to see valid severity and priority values before creating an issue."
|
|
191
|
+
|
|
192
|
+
### Equivalent tool fallbacks
|
|
193
|
+
|
|
194
|
+
If your client does not support Resources, ask Claude to use the corresponding tool:
|
|
195
|
+
|
|
196
|
+
> "Show me my user profile." *(uses `get_current_user`)*
|
|
197
|
+
|
|
198
|
+
> "Which projects are available?" *(uses `list_projects`)*
|
|
199
|
+
|
|
200
|
+
> "What are the valid priority values?" *(uses `get_issue_enums`)*
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dpesch/mantisbt-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"mcpName": "io.github.dpesch/mantisbt-mcp-server",
|
|
5
5
|
"description": "MCP server for MantisBT REST API – read and manage bug tracker issues",
|
|
6
6
|
"author": "Dominik Pesch",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"homepage": "https://codeberg.org/dpesch/mantisbt-mcp-server",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://codeberg.org/dpesch/mantisbt-mcp-server/issues"
|
|
11
|
+
},
|
|
8
12
|
"repository": {
|
|
9
13
|
"type": "git",
|
|
10
14
|
"url": "https://codeberg.org/dpesch/mantisbt-mcp-server"
|
|
11
15
|
},
|
|
12
|
-
"keywords": ["mcp", "mantisbt", "bugtracker", "mantis", "model-context-protocol"],
|
|
16
|
+
"keywords": ["mcp", "mcp-server", "mantisbt", "bugtracker", "mantis", "model-context-protocol"],
|
|
13
17
|
"main": "dist/index.js",
|
|
14
18
|
"bin": {
|
|
15
19
|
"mantisbt-mcp-server": "dist/index.js"
|
package/server.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"name": "io.github.dpesch/mantisbt-mcp-server",
|
|
4
4
|
"title": "MantisBT MCP Server",
|
|
5
5
|
"description": "MantisBT MCP server – manage issues, notes, files, tags, and relationships. With semantic search.",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.6.0",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"identifier": "@dpesch/mantisbt-mcp-server",
|
|
11
|
-
"version": "1.
|
|
11
|
+
"version": "1.6.0",
|
|
12
12
|
"runtimeHint": "npx",
|
|
13
13
|
"transport": {
|
|
14
14
|
"type": "stdio"
|
package/tests/client.test.ts
CHANGED
|
@@ -209,6 +209,76 @@ describe('MantisClient – HTTP methods', () => {
|
|
|
209
209
|
});
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// Credential factory (lazy constructor)
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
describe('MantisClient – credential factory', () => {
|
|
217
|
+
it('does not call the factory until the first API method', async () => {
|
|
218
|
+
const factory = vi.fn().mockResolvedValue({
|
|
219
|
+
baseUrl: 'https://lazy.example.com',
|
|
220
|
+
apiKey: 'lazy-key',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
new MantisClient(factory);
|
|
224
|
+
|
|
225
|
+
expect(factory).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('calls the factory on first API method and uses the returned credentials', async () => {
|
|
229
|
+
const fetchMock = vi.fn().mockResolvedValue(makeResponse(200, '{}'));
|
|
230
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
231
|
+
|
|
232
|
+
const factory = vi.fn().mockResolvedValue({
|
|
233
|
+
baseUrl: 'https://lazy.example.com',
|
|
234
|
+
apiKey: 'lazy-key',
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const client = new MantisClient(factory);
|
|
238
|
+
await client.get('issues');
|
|
239
|
+
|
|
240
|
+
expect(factory).toHaveBeenCalledOnce();
|
|
241
|
+
const calledUrl: string = fetchMock.mock.calls[0][0] as string;
|
|
242
|
+
expect(calledUrl).toBe('https://lazy.example.com/api/rest/issues');
|
|
243
|
+
const options = fetchMock.mock.calls[0][1] as RequestInit;
|
|
244
|
+
expect((options.headers as Record<string, string>)['Authorization']).toBe('lazy-key');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('caches credentials after the first call and does not call the factory again', async () => {
|
|
248
|
+
const fetchMock = vi.fn().mockResolvedValue(makeResponse(200, '{}'));
|
|
249
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
250
|
+
|
|
251
|
+
const factory = vi.fn().mockResolvedValue({
|
|
252
|
+
baseUrl: 'https://lazy.example.com',
|
|
253
|
+
apiKey: 'lazy-key',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const client = new MantisClient(factory);
|
|
257
|
+
await client.get('issues');
|
|
258
|
+
await client.get('projects');
|
|
259
|
+
|
|
260
|
+
expect(factory).toHaveBeenCalledOnce();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('forwards the responseObserver when using factory constructor', async () => {
|
|
264
|
+
const observer = vi.fn();
|
|
265
|
+
const fakeResponse = makeResponse(200, '{}');
|
|
266
|
+
const fetchMock = vi.fn().mockResolvedValue(fakeResponse);
|
|
267
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
268
|
+
|
|
269
|
+
const factory = vi.fn().mockResolvedValue({
|
|
270
|
+
baseUrl: 'https://lazy.example.com',
|
|
271
|
+
apiKey: 'lazy-key',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const client = new MantisClient(factory, observer);
|
|
275
|
+
await client.get('issues');
|
|
276
|
+
|
|
277
|
+
expect(observer).toHaveBeenCalledOnce();
|
|
278
|
+
expect(observer).toHaveBeenCalledWith(fakeResponse);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
212
282
|
// ---------------------------------------------------------------------------
|
|
213
283
|
// responseObserver
|
|
214
284
|
// ---------------------------------------------------------------------------
|
package/tests/config.test.ts
CHANGED
|
@@ -19,6 +19,12 @@ async function freshGetConfig(): Promise<(typeof import('../src/config.js'))['ge
|
|
|
19
19
|
return mod.getConfig;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
async function freshGetStartupConfig(): Promise<(typeof import('../src/config.js'))['getStartupConfig']> {
|
|
23
|
+
vi.resetModules();
|
|
24
|
+
const mod = await import('../src/config.js');
|
|
25
|
+
return mod.getStartupConfig;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
// ---------------------------------------------------------------------------
|
|
23
29
|
// Setup
|
|
24
30
|
// ---------------------------------------------------------------------------
|
|
@@ -87,60 +93,26 @@ describe('getConfig() – ENV variables', () => {
|
|
|
87
93
|
});
|
|
88
94
|
});
|
|
89
95
|
|
|
90
|
-
// ---------------------------------------------------------------------------
|
|
91
|
-
// JSON fallback
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
|
|
94
|
-
describe('getConfig() – mantis.json fallback', () => {
|
|
95
|
-
it('falls back to ~/.claude/mantis.json when ENV vars are missing', async () => {
|
|
96
|
-
const json = JSON.stringify({ base_url: 'https://from-json.example.com', api_key: 'json-key' });
|
|
97
|
-
vi.mocked(readFile).mockResolvedValue(json as any);
|
|
98
|
-
|
|
99
|
-
const getConfig = await freshGetConfig();
|
|
100
|
-
const config = await getConfig();
|
|
101
|
-
|
|
102
|
-
expect(config.baseUrl).toBe('https://from-json.example.com');
|
|
103
|
-
expect(config.apiKey).toBe('json-key');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('prefers ENV vars over mantis.json values', async () => {
|
|
107
|
-
vi.stubEnv('MANTIS_BASE_URL', 'https://from-env.example.com');
|
|
108
|
-
vi.stubEnv('MANTIS_API_KEY', 'env-key');
|
|
109
|
-
const json = JSON.stringify({ base_url: 'https://from-json.example.com', api_key: 'json-key' });
|
|
110
|
-
vi.mocked(readFile).mockResolvedValue(json as any);
|
|
111
|
-
|
|
112
|
-
const getConfig = await freshGetConfig();
|
|
113
|
-
const config = await getConfig();
|
|
114
|
-
|
|
115
|
-
expect(config.baseUrl).toBe('https://from-env.example.com');
|
|
116
|
-
expect(config.apiKey).toBe('env-key');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
96
|
// ---------------------------------------------------------------------------
|
|
121
97
|
// Error cases
|
|
122
98
|
// ---------------------------------------------------------------------------
|
|
123
99
|
|
|
124
100
|
describe('getConfig() – errors', () => {
|
|
125
|
-
it('throws when
|
|
101
|
+
it('throws when MANTIS_BASE_URL is not set', async () => {
|
|
126
102
|
vi.stubEnv('MANTIS_API_KEY', 'some-key');
|
|
127
|
-
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
128
103
|
|
|
129
104
|
const getConfig = await freshGetConfig();
|
|
130
105
|
await expect(getConfig()).rejects.toThrow('MANTIS_BASE_URL');
|
|
131
106
|
});
|
|
132
107
|
|
|
133
|
-
it('throws when
|
|
108
|
+
it('throws when MANTIS_API_KEY is not set', async () => {
|
|
134
109
|
vi.stubEnv('MANTIS_BASE_URL', 'https://mantis.example.com');
|
|
135
|
-
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
136
110
|
|
|
137
111
|
const getConfig = await freshGetConfig();
|
|
138
112
|
await expect(getConfig()).rejects.toThrow('MANTIS_API_KEY');
|
|
139
113
|
});
|
|
140
114
|
|
|
141
|
-
it('throws when no configuration is
|
|
142
|
-
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
143
|
-
|
|
115
|
+
it('throws when no configuration is provided at all', async () => {
|
|
144
116
|
const getConfig = await freshGetConfig();
|
|
145
117
|
await expect(getConfig()).rejects.toThrow('Missing required MantisBT configuration');
|
|
146
118
|
});
|
|
@@ -215,6 +187,44 @@ describe('getConfig() – HTTP transport', () => {
|
|
|
215
187
|
});
|
|
216
188
|
});
|
|
217
189
|
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// getStartupConfig — never throws without credentials
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
describe('getStartupConfig()', () => {
|
|
195
|
+
it('succeeds without MANTIS_BASE_URL and MANTIS_API_KEY', async () => {
|
|
196
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
197
|
+
|
|
198
|
+
const getStartupConfig = await freshGetStartupConfig();
|
|
199
|
+
const config = await getStartupConfig();
|
|
200
|
+
|
|
201
|
+
expect(config).toBeDefined();
|
|
202
|
+
expect(config.cacheTtl).toBe(3600);
|
|
203
|
+
expect(config.httpHost).toBe('127.0.0.1');
|
|
204
|
+
expect(config.httpPort).toBe(3000);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('does not include baseUrl or apiKey', async () => {
|
|
208
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
209
|
+
|
|
210
|
+
const getStartupConfig = await freshGetStartupConfig();
|
|
211
|
+
const config = await getStartupConfig();
|
|
212
|
+
|
|
213
|
+
expect(config).not.toHaveProperty('baseUrl');
|
|
214
|
+
expect(config).not.toHaveProperty('apiKey');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('reads MANTIS_CACHE_DIR from environment', async () => {
|
|
218
|
+
vi.stubEnv('MANTIS_CACHE_DIR', '/tmp/test-cache');
|
|
219
|
+
vi.mocked(readFile).mockRejectedValue(new Error('ENOENT'));
|
|
220
|
+
|
|
221
|
+
const getStartupConfig = await freshGetStartupConfig();
|
|
222
|
+
const config = await getStartupConfig();
|
|
223
|
+
|
|
224
|
+
expect(config.cacheDir).toBe('/tmp/test-cache');
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
218
228
|
// ---------------------------------------------------------------------------
|
|
219
229
|
// Singleton caching
|
|
220
230
|
// ---------------------------------------------------------------------------
|