defectdojo-mcp-server 0.1.0__tar.gz

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.
Files changed (38) hide show
  1. defectdojo_mcp_server-0.1.0/.gitignore +13 -0
  2. defectdojo_mcp_server-0.1.0/CHANGELOG.md +23 -0
  3. defectdojo_mcp_server-0.1.0/LICENSE +11 -0
  4. defectdojo_mcp_server-0.1.0/PKG-INFO +288 -0
  5. defectdojo_mcp_server-0.1.0/README.md +253 -0
  6. defectdojo_mcp_server-0.1.0/pyproject.toml +106 -0
  7. defectdojo_mcp_server-0.1.0/server.json +101 -0
  8. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/__init__.py +10 -0
  9. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/__main__.py +4 -0
  10. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/app.py +165 -0
  11. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/cli.py +200 -0
  12. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/client.py +290 -0
  13. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/config.py +138 -0
  14. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/http_auth.py +68 -0
  15. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/prompts.py +58 -0
  16. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/server.py +66 -0
  17. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/shaping.py +379 -0
  18. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/tools/__init__.py +6 -0
  19. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/tools/common.py +44 -0
  20. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/tools/read.py +667 -0
  21. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/tools/write.py +510 -0
  22. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/untrusted.py +204 -0
  23. defectdojo_mcp_server-0.1.0/src/defectdojo_mcp/uploads.py +179 -0
  24. defectdojo_mcp_server-0.1.0/tests/__init__.py +0 -0
  25. defectdojo_mcp_server-0.1.0/tests/conftest.py +108 -0
  26. defectdojo_mcp_server-0.1.0/tests/data/live-scan-v1.json +43 -0
  27. defectdojo_mcp_server-0.1.0/tests/data/live-scan-v2.json +56 -0
  28. defectdojo_mcp_server-0.1.0/tests/test_cli.py +173 -0
  29. defectdojo_mcp_server-0.1.0/tests/test_client.py +204 -0
  30. defectdojo_mcp_server-0.1.0/tests/test_config.py +102 -0
  31. defectdojo_mcp_server-0.1.0/tests/test_http.py +141 -0
  32. defectdojo_mcp_server-0.1.0/tests/test_live.py +286 -0
  33. defectdojo_mcp_server-0.1.0/tests/test_prompts.py +38 -0
  34. defectdojo_mcp_server-0.1.0/tests/test_read_tools.py +680 -0
  35. defectdojo_mcp_server-0.1.0/tests/test_shaping.py +266 -0
  36. defectdojo_mcp_server-0.1.0/tests/test_untrusted.py +228 -0
  37. defectdojo_mcp_server-0.1.0/tests/test_uploads.py +168 -0
  38. defectdojo_mcp_server-0.1.0/tests/test_write_tools.py +653 -0
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ .env
13
+ .DS_Store
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
4
+
5
+ ## [0.1.0] - Unreleased
6
+
7
+ ### Added
8
+
9
+ - First release of the open-source DefectDojo MCP server, built on the MCP Python SDK 2.x. Published to PyPI as `defectdojo-mcp-server` (run it with `uvx defectdojo-mcp-server`), to `ghcr.io/defectdojo/defectdojo-mcp`, and to the MCP registry as `io.github.DefectDojo/defectdojo-mcp`. The `defectdojo-mcp` command is installed too.
10
+ - Read tools: `get_instance_info`, `list_findings`, `get_finding`, `get_finding_stats`, `list_finding_notes`, `list_products`, `get_product`, `list_product_types`, `list_engagements`, `get_engagement`, `list_tests`, `get_test`, `list_scan_types`, `list_test_imports`, `get_current_user`, `list_locations`.
11
+ - Write tools, registered only when `DEFECTDOJO_ALLOW_WRITES=true`: `import_scan`, `reimport_scan`, `add_finding_note`, `update_finding_status`, `risk_accept_findings`, `create_product`, `create_engagement`.
12
+ - Prompts: `triage_critical_findings` and `summarize_import_changes`.
13
+ - stdio transport, plus streamable HTTP with bearer token or per-request DefectDojo key pass-through.
14
+ - Untrusted-content markers with a random suffix per value (`<untrusted-data-XXXX>`), look-alike and bidi escaping, and truncation for all free text returned from DefectDojo.
15
+ - File path imports fail closed: they need DEFECTDOJO_IMPORT_DIRS, refuse the home folder, its parents and the filesystem root, never read hidden or hard-linked files, and open files without following symlinks swapped in after the check.
16
+ - Write errors say when a change may already have been applied, and `update_finding_status` reports partial success.
17
+ - Best-effort DefectDojo Pro detection with a pointer to Pro's built-in MCP server.
18
+
19
+ ### Security
20
+
21
+ - Locked certifi 2026.10.19 and upgrade `ca-certificates` in its own Docker layer, so the compromised eMudhra root is no longer trusted (Mozilla bug 2083449). `certifi>=2026.10.19` is now a direct runtime dependency, so `uvx` and `pip` installs, which ignore `uv.lock`, get the fixed bundle too.
22
+
23
+ [0.1.0]: https://github.com/DefectDojo/defectdojo-mcp/releases/tag/v0.1.0
@@ -0,0 +1,11 @@
1
+ Copyright (c) 2026 DefectDojo Inc and contributors. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,288 @@
1
+ Metadata-Version: 2.5
2
+ Name: defectdojo-mcp-server
3
+ Version: 0.1.0
4
+ Summary: Official open-source MCP server for DefectDojo. Connect Claude, Cursor, VS Code and other MCP clients to DefectDojo.
5
+ Project-URL: Homepage, https://github.com/DefectDojo/defectdojo-mcp
6
+ Project-URL: Repository, https://github.com/DefectDojo/defectdojo-mcp
7
+ Project-URL: Issues, https://github.com/DefectDojo/defectdojo-mcp/issues
8
+ Project-URL: Changelog, https://github.com/DefectDojo/defectdojo-mcp/blob/main/CHANGELOG.md
9
+ Project-URL: DefectDojo, https://github.com/DefectDojo/django-DefectDojo
10
+ Author: DefectDojo Inc
11
+ License-Expression: BSD-3-Clause
12
+ License-File: LICENSE
13
+ Keywords: appsec,defectdojo,mcp,model-context-protocol,security,vulnerability-management
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: Information Technology
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Security
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: anyio>=4.9
28
+ Requires-Dist: certifi>=2026.10.19
29
+ Requires-Dist: httpx<1,>=0.28
30
+ Requires-Dist: mcp<3,>=2.3
31
+ Requires-Dist: pydantic>=2.12
32
+ Requires-Dist: starlette>=0.48
33
+ Requires-Dist: uvicorn>=0.31
34
+ Description-Content-Type: text/markdown
35
+
36
+ # DefectDojo MCP Server
37
+
38
+ The official open-source [Model Context Protocol](https://modelcontextprotocol.io) server for [DefectDojo](https://github.com/DefectDojo/django-DefectDojo).
39
+
40
+ It lets Claude, Cursor, VS Code and other MCP clients work with your DefectDojo instance through the DefectDojo REST API v2. Ask an assistant to find the open critical findings in a product, explain a finding, compare two imports, or (when you turn writes on) import a scan and update finding status.
41
+
42
+ - Works with open-source DefectDojo 2.x and 3.x, and with DefectDojo Pro.
43
+ - Read-only by default. Write tools only exist when you enable them.
44
+ - Text from DefectDojo is marked as untrusted, because scanner output can carry prompt injection.
45
+ - Runs locally over stdio, or as a streamable HTTP server with authentication.
46
+ - No telemetry of any kind.
47
+
48
+ <!-- mcp-name: io.github.DefectDojo/defectdojo-mcp -->
49
+
50
+ ## Quick start
51
+
52
+ You need:
53
+
54
+ 1. [uv](https://docs.astral.sh/uv/getting-started/installation/), which provides the `uvx` command.
55
+ 2. The URL of your DefectDojo instance.
56
+ 3. A DefectDojo API v2 key. In DefectDojo, open the user menu and choose **API v2 Key**. Use a dedicated account with only the permissions the assistant needs (see [Security](#security)).
57
+
58
+ Check that it starts:
59
+
60
+ ```sh
61
+ DEFECTDOJO_URL=https://defectdojo.example.com DEFECTDOJO_API_KEY=your-key uvx defectdojo-mcp-server --help
62
+ ```
63
+
64
+ The package on PyPI is `defectdojo-mcp-server`. A package named `defectdojo-mcp` also exists on PyPI, but it is an unrelated project, not this server.
65
+
66
+ ### Claude Desktop
67
+
68
+ Open **Settings > Developer > Edit Config** and add the server to `claude_desktop_config.json`:
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "defectdojo": {
74
+ "command": "uvx",
75
+ "args": ["defectdojo-mcp-server"],
76
+ "env": {
77
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
78
+ "DEFECTDOJO_API_KEY": "your-api-key"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ Restart Claude Desktop after saving.
86
+
87
+ ### Claude Code
88
+
89
+ ```sh
90
+ claude mcp add defectdojo \
91
+ --env DEFECTDOJO_URL=https://defectdojo.example.com \
92
+ --env DEFECTDOJO_API_KEY=your-api-key \
93
+ -- uvx defectdojo-mcp-server
94
+ ```
95
+
96
+ ### Cursor
97
+
98
+ Add this to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project):
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "defectdojo": {
104
+ "command": "uvx",
105
+ "args": ["defectdojo-mcp-server"],
106
+ "env": {
107
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
108
+ "DEFECTDOJO_API_KEY": "your-api-key"
109
+ }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ ### VS Code
116
+
117
+ Add this to `.vscode/mcp.json`. VS Code asks for the API key once and stores it securely, so the key stays out of the file:
118
+
119
+ ```json
120
+ {
121
+ "inputs": [
122
+ {
123
+ "type": "promptString",
124
+ "id": "defectdojo-api-key",
125
+ "description": "DefectDojo API v2 key",
126
+ "password": true
127
+ }
128
+ ],
129
+ "servers": {
130
+ "defectdojo": {
131
+ "type": "stdio",
132
+ "command": "uvx",
133
+ "args": ["defectdojo-mcp-server"],
134
+ "env": {
135
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
136
+ "DEFECTDOJO_API_KEY": "${input:defectdojo-api-key}"
137
+ }
138
+ }
139
+ }
140
+ }
141
+ ```
142
+
143
+ ### Docker
144
+
145
+ ```sh
146
+ docker run -i --rm \
147
+ -e DEFECTDOJO_URL=https://defectdojo.example.com \
148
+ -e DEFECTDOJO_API_KEY=your-api-key \
149
+ ghcr.io/defectdojo/defectdojo-mcp
150
+ ```
151
+
152
+ To build the image yourself instead, run `docker build -t defectdojo-mcp .` in a clone and use `defectdojo-mcp` as the image name.
153
+
154
+ Use `"command": "docker"` with these arguments in any client config above to run it in a container. For HTTP mode inside a container, bind all interfaces in the container (`--host 0.0.0.0`), publish the port to loopback only (`-p 127.0.0.1:8000:8000`), and set `DEFECTDOJO_MCP_ALLOWED_HOSTS`.
155
+
156
+ ## Configuration
157
+
158
+ All settings come from environment variables.
159
+
160
+ | Variable | Default | Description |
161
+ | --- | --- | --- |
162
+ | `DEFECTDOJO_URL` | required | Base URL of the instance, for example `https://defectdojo.example.com`. A trailing `/api/v2` is accepted and removed. |
163
+ | `DEFECTDOJO_API_KEY` | required | API v2 key. Not needed in HTTP pass-through mode. Never logged. |
164
+ | `DEFECTDOJO_VERIFY_SSL` | `true` | `true`, `false`, or the path to a CA bundle for private certificate authorities. |
165
+ | `DEFECTDOJO_TIMEOUT` | `30` | Request timeout in seconds. |
166
+ | `DEFECTDOJO_ALLOW_WRITES` | `false` | Set to `true` to register the write tools. |
167
+ | `DEFECTDOJO_IMPORT_DIRS` | none | Folders that `import_scan` and `reimport_scan` may read report files from. Separate several with `:` (`;` on Windows). While unset, imports by file path are refused and only base64 uploads work. The home folder itself and the filesystem root are never accepted. |
168
+ | `DEFECTDOJO_MAX_UPLOAD_MB` | `25` | Largest scan report the server will upload. |
169
+ | `DEFECTDOJO_MCP_AUTH_TOKEN` | none | Bearer token that HTTP clients must send in token mode. |
170
+ | `DEFECTDOJO_MCP_ALLOWED_HOSTS` | none | Comma-separated host names accepted in the `Host` header when serving HTTP on a non-loopback address. |
171
+
172
+ ## Tools
173
+
174
+ Every tool returns JSON. List tools are paged with `limit` and `offset`, and each page reports `count` and `next_offset`.
175
+
176
+ ### Read tools (always available)
177
+
178
+ | Tool | What it does |
179
+ | --- | --- |
180
+ | `get_instance_info` | Instance URL, DefectDojo version, edition (open source or Pro, best effort), current user, and whether writes are on. |
181
+ | `list_findings` | Search findings by product, engagement, test, product type, severity, active, verified, duplicate, false positive, risk accepted, mitigated, out of scope, CVE or other vulnerability id, CWE, title text, component, file path, tags and dates. Sortable. |
182
+ | `get_finding` | One finding with full text fields, vulnerability ids, CWE, file path, component, notes, affected endpoints or locations, and its test, engagement and product. |
183
+ | `get_finding_stats` | Exact counts by severity and by status for a product, engagement, test, product type or the whole instance. |
184
+ | `list_finding_notes` | Notes on a finding. |
185
+ | `list_products`, `get_product` | Products. Newer releases call them assets. |
186
+ | `list_product_types` | Product types. Newer releases call them organizations. |
187
+ | `list_engagements`, `get_engagement` | Engagements. |
188
+ | `list_tests`, `get_test` | Tests, meaning individual scan imports or manual tests. |
189
+ | `list_scan_types` | Scan types the instance can import, for use as `scan_type`. |
190
+ | `list_test_imports` | Import and reimport history for a test, with the findings each run created, closed, reactivated or left untouched. |
191
+ | `get_current_user` | The user the API key belongs to. |
192
+ | `list_locations` | Hosts, URLs and other locations. Uses the locations API on newer releases and the endpoints API on older ones. |
193
+
194
+ ### Write tools (only with `DEFECTDOJO_ALLOW_WRITES=true`)
195
+
196
+ | Tool | What it does |
197
+ | --- | --- |
198
+ | `import_scan` | Upload a scan report as a new test. Target an engagement id, or name a product and engagement and let DefectDojo create them with `auto_create_context`. Supports `close_old_findings`, `minimum_severity`, tags, scan date, version and CI metadata. |
199
+ | `reimport_scan` | Upload a newer report into an existing test so DefectDojo closes fixed findings and adds new ones. |
200
+ | `add_finding_note` | Add a note to a finding. |
201
+ | `update_finding_status` | Set active, verified, false positive, out of scope, or mitigated (with an optional date and note). |
202
+ | `risk_accept_findings` | Risk accept, or revoke acceptance for, up to 50 findings with DefectDojo's simple risk acceptance. |
203
+ | `create_product` | Create a product in a product type. |
204
+ | `create_engagement` | Create an engagement in a product. |
205
+
206
+ Scan reports reach the server in one of two ways. Over stdio, pass `file_path` pointing at a file inside one of the `DEFECTDOJO_IMPORT_DIRS` folders. Over stdio or HTTP, pass the report as `file_content_base64` with a `file_name`.
207
+
208
+ File path imports fail closed. With no `DEFECTDOJO_IMPORT_DIRS` set, the server refuses them instead of falling back to its working directory. It also refuses the home folder and the filesystem root as import folders, resolves symlinks before checking that a file is inside an allowed folder, rejects hidden files and anything inside a hidden folder (any path part that starts with a dot, before or after following symlinks), enforces the size limit, and never includes file contents in error messages. Point `DEFECTDOJO_IMPORT_DIRS` at a dedicated reports folder, not at a home folder or a whole repository.
209
+
210
+ ### Prompts
211
+
212
+ | Prompt | What it does |
213
+ | --- | --- |
214
+ | `triage_critical_findings` | Walks through the open critical and high findings of a product and suggests a verdict for each. |
215
+ | `summarize_import_changes` | Summarizes what the latest import of a test created, closed and reactivated. |
216
+
217
+ ## Read-only by default
218
+
219
+ Without `DEFECTDOJO_ALLOW_WRITES=true` the write tools are not registered at all, so an assistant cannot call them even by mistake. The prompts and server instructions also tell the assistant whether changes are possible.
220
+
221
+ To enable writes, add `"DEFECTDOJO_ALLOW_WRITES": "true"` to the `env` block of your client config. Most clients still ask you to approve each tool call, and the write tools carry MCP annotations that mark them as state-changing.
222
+
223
+ ## Security
224
+
225
+ ### Prompt injection
226
+
227
+ Finding titles, descriptions, notes, file paths, component names and similar fields usually come straight from scanner output. Anyone who controls something that gets scanned can put text there, including instructions aimed at an AI assistant.
228
+
229
+ This server wraps every free-text value from DefectDojo in a pair of tags with a random 16-character hex suffix chosen for that value, for example `<untrusted-data-3f9c0a7b1e2d4c58>...</untrusted-data-3f9c0a7b1e2d4c58>`. A client or model recognizes the data by the matching suffix on the opening and closing tag. Text inside cannot close the wrapper early because it cannot guess the suffix. As a second layer, look-alike tags inside the text are escaped, bidirectional control characters are shown as code points such as `[U+202E]`, and long fields are truncated. Tool descriptions and the server instructions tell the model to treat tagged text as data only. This lowers the risk but cannot remove it, so keep a person in the loop for write actions and review what the assistant proposes.
230
+
231
+ ### Local files
232
+
233
+ A prompt-injected assistant could try to upload local files, such as keys or dotfiles, to DefectDojo through `import_scan`. That is why file path imports are off until you name the folders in `DEFECTDOJO_IMPORT_DIRS`, and why hidden files are always refused. Keep scan reports in their own folder.
234
+
235
+ ### API key scope
236
+
237
+ The server can do anything the API key's user can do. Create a dedicated DefectDojo user for the assistant, give it access only to the products it needs, and keep writes off unless you need them. The key is sent only to `DEFECTDOJO_URL`, redirects are never followed, and the key is redacted from logs and error messages.
238
+
239
+ ### HTTP mode
240
+
241
+ Over stdio the server is only reachable by the client that started it. HTTP mode is for shared or remote setups:
242
+
243
+ ```sh
244
+ export DEFECTDOJO_URL=https://defectdojo.example.com
245
+ export DEFECTDOJO_API_KEY=your-api-key
246
+ export DEFECTDOJO_MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
247
+ defectdojo-mcp --transport http --host 127.0.0.1 --port 8000
248
+ ```
249
+
250
+ The endpoint is `http://127.0.0.1:8000/mcp`, and `/healthz` answers without authentication for health checks. The server refuses to start in HTTP mode without one of these authentication modes:
251
+
252
+ - **Token mode** (`--http-auth token`, the default). Every request must send `Authorization: Bearer <DEFECTDOJO_MCP_AUTH_TOKEN>`. All callers share the server's DefectDojo key, so give that key the narrowest permissions that work for everyone.
253
+ - **Pass-through mode** (`--http-auth passthrough`). Every request carries the caller's own DefectDojo key in `X-DefectDojo-Api-Key` or `Authorization: Token <key>`. The server holds no key of its own and DefectDojo enforces each caller's permissions.
254
+
255
+ The server binds to `127.0.0.1` by default and checks the `Host` and `Origin` headers to block DNS rebinding. To serve other machines, bind a non-loopback address, set `DEFECTDOJO_MCP_ALLOWED_HOSTS` to the public host name, and put a TLS-terminating reverse proxy in front. Keys and tokens travel in headers, so plain HTTP across a network exposes them.
256
+
257
+ Report security problems as described in [SECURITY.md](SECURITY.md).
258
+
259
+ ## Compatibility
260
+
261
+ - **Open-source DefectDojo 2.x and 3.x.** The server uses long-standing API v2 endpoints and skips fields a version does not return. On older releases, filters that the instance does not know are ignored by DefectDojo, so the date filters on `list_findings` need a release from late 2024 or newer. `list_locations` uses the locations API in 3.x and falls back to endpoints on older releases.
262
+ - **DefectDojo Pro.** Everything here works against Pro through the same API. Pro also includes its own built-in MCP server at `https://<your-instance>/mcp` with more capabilities, and `get_instance_info` mentions it when it detects Pro.
263
+ - **MCP.** Built on the official [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) 2.x and protocol version 2026-07-28, with fallback to earlier protocol versions for older clients.
264
+ - **Python** 3.11 or newer.
265
+
266
+ ## Development
267
+
268
+ ```sh
269
+ git clone https://github.com/DefectDojo/defectdojo-mcp
270
+ cd defectdojo-mcp
271
+ uv sync
272
+ uv run pytest # unit tests with mocked HTTP
273
+ uv run ruff check .
274
+ uv run ruff format --check .
275
+ uv run mypy
276
+ ```
277
+
278
+ The live test suite runs every tool against a real DefectDojo instance over stdio. Point it at a disposable instance, since it creates products, engagements and findings:
279
+
280
+ ```sh
281
+ DEFECTDOJO_LIVE_URL=http://127.0.0.1:8080 DEFECTDOJO_LIVE_API_KEY=your-key uv run pytest -m live
282
+ ```
283
+
284
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more.
285
+
286
+ ## License
287
+
288
+ BSD 3-Clause. See [LICENSE](LICENSE).
@@ -0,0 +1,253 @@
1
+ # DefectDojo MCP Server
2
+
3
+ The official open-source [Model Context Protocol](https://modelcontextprotocol.io) server for [DefectDojo](https://github.com/DefectDojo/django-DefectDojo).
4
+
5
+ It lets Claude, Cursor, VS Code and other MCP clients work with your DefectDojo instance through the DefectDojo REST API v2. Ask an assistant to find the open critical findings in a product, explain a finding, compare two imports, or (when you turn writes on) import a scan and update finding status.
6
+
7
+ - Works with open-source DefectDojo 2.x and 3.x, and with DefectDojo Pro.
8
+ - Read-only by default. Write tools only exist when you enable them.
9
+ - Text from DefectDojo is marked as untrusted, because scanner output can carry prompt injection.
10
+ - Runs locally over stdio, or as a streamable HTTP server with authentication.
11
+ - No telemetry of any kind.
12
+
13
+ <!-- mcp-name: io.github.DefectDojo/defectdojo-mcp -->
14
+
15
+ ## Quick start
16
+
17
+ You need:
18
+
19
+ 1. [uv](https://docs.astral.sh/uv/getting-started/installation/), which provides the `uvx` command.
20
+ 2. The URL of your DefectDojo instance.
21
+ 3. A DefectDojo API v2 key. In DefectDojo, open the user menu and choose **API v2 Key**. Use a dedicated account with only the permissions the assistant needs (see [Security](#security)).
22
+
23
+ Check that it starts:
24
+
25
+ ```sh
26
+ DEFECTDOJO_URL=https://defectdojo.example.com DEFECTDOJO_API_KEY=your-key uvx defectdojo-mcp-server --help
27
+ ```
28
+
29
+ The package on PyPI is `defectdojo-mcp-server`. A package named `defectdojo-mcp` also exists on PyPI, but it is an unrelated project, not this server.
30
+
31
+ ### Claude Desktop
32
+
33
+ Open **Settings > Developer > Edit Config** and add the server to `claude_desktop_config.json`:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "defectdojo": {
39
+ "command": "uvx",
40
+ "args": ["defectdojo-mcp-server"],
41
+ "env": {
42
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
43
+ "DEFECTDOJO_API_KEY": "your-api-key"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ Restart Claude Desktop after saving.
51
+
52
+ ### Claude Code
53
+
54
+ ```sh
55
+ claude mcp add defectdojo \
56
+ --env DEFECTDOJO_URL=https://defectdojo.example.com \
57
+ --env DEFECTDOJO_API_KEY=your-api-key \
58
+ -- uvx defectdojo-mcp-server
59
+ ```
60
+
61
+ ### Cursor
62
+
63
+ Add this to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project):
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "defectdojo": {
69
+ "command": "uvx",
70
+ "args": ["defectdojo-mcp-server"],
71
+ "env": {
72
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
73
+ "DEFECTDOJO_API_KEY": "your-api-key"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ ### VS Code
81
+
82
+ Add this to `.vscode/mcp.json`. VS Code asks for the API key once and stores it securely, so the key stays out of the file:
83
+
84
+ ```json
85
+ {
86
+ "inputs": [
87
+ {
88
+ "type": "promptString",
89
+ "id": "defectdojo-api-key",
90
+ "description": "DefectDojo API v2 key",
91
+ "password": true
92
+ }
93
+ ],
94
+ "servers": {
95
+ "defectdojo": {
96
+ "type": "stdio",
97
+ "command": "uvx",
98
+ "args": ["defectdojo-mcp-server"],
99
+ "env": {
100
+ "DEFECTDOJO_URL": "https://defectdojo.example.com",
101
+ "DEFECTDOJO_API_KEY": "${input:defectdojo-api-key}"
102
+ }
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### Docker
109
+
110
+ ```sh
111
+ docker run -i --rm \
112
+ -e DEFECTDOJO_URL=https://defectdojo.example.com \
113
+ -e DEFECTDOJO_API_KEY=your-api-key \
114
+ ghcr.io/defectdojo/defectdojo-mcp
115
+ ```
116
+
117
+ To build the image yourself instead, run `docker build -t defectdojo-mcp .` in a clone and use `defectdojo-mcp` as the image name.
118
+
119
+ Use `"command": "docker"` with these arguments in any client config above to run it in a container. For HTTP mode inside a container, bind all interfaces in the container (`--host 0.0.0.0`), publish the port to loopback only (`-p 127.0.0.1:8000:8000`), and set `DEFECTDOJO_MCP_ALLOWED_HOSTS`.
120
+
121
+ ## Configuration
122
+
123
+ All settings come from environment variables.
124
+
125
+ | Variable | Default | Description |
126
+ | --- | --- | --- |
127
+ | `DEFECTDOJO_URL` | required | Base URL of the instance, for example `https://defectdojo.example.com`. A trailing `/api/v2` is accepted and removed. |
128
+ | `DEFECTDOJO_API_KEY` | required | API v2 key. Not needed in HTTP pass-through mode. Never logged. |
129
+ | `DEFECTDOJO_VERIFY_SSL` | `true` | `true`, `false`, or the path to a CA bundle for private certificate authorities. |
130
+ | `DEFECTDOJO_TIMEOUT` | `30` | Request timeout in seconds. |
131
+ | `DEFECTDOJO_ALLOW_WRITES` | `false` | Set to `true` to register the write tools. |
132
+ | `DEFECTDOJO_IMPORT_DIRS` | none | Folders that `import_scan` and `reimport_scan` may read report files from. Separate several with `:` (`;` on Windows). While unset, imports by file path are refused and only base64 uploads work. The home folder itself and the filesystem root are never accepted. |
133
+ | `DEFECTDOJO_MAX_UPLOAD_MB` | `25` | Largest scan report the server will upload. |
134
+ | `DEFECTDOJO_MCP_AUTH_TOKEN` | none | Bearer token that HTTP clients must send in token mode. |
135
+ | `DEFECTDOJO_MCP_ALLOWED_HOSTS` | none | Comma-separated host names accepted in the `Host` header when serving HTTP on a non-loopback address. |
136
+
137
+ ## Tools
138
+
139
+ Every tool returns JSON. List tools are paged with `limit` and `offset`, and each page reports `count` and `next_offset`.
140
+
141
+ ### Read tools (always available)
142
+
143
+ | Tool | What it does |
144
+ | --- | --- |
145
+ | `get_instance_info` | Instance URL, DefectDojo version, edition (open source or Pro, best effort), current user, and whether writes are on. |
146
+ | `list_findings` | Search findings by product, engagement, test, product type, severity, active, verified, duplicate, false positive, risk accepted, mitigated, out of scope, CVE or other vulnerability id, CWE, title text, component, file path, tags and dates. Sortable. |
147
+ | `get_finding` | One finding with full text fields, vulnerability ids, CWE, file path, component, notes, affected endpoints or locations, and its test, engagement and product. |
148
+ | `get_finding_stats` | Exact counts by severity and by status for a product, engagement, test, product type or the whole instance. |
149
+ | `list_finding_notes` | Notes on a finding. |
150
+ | `list_products`, `get_product` | Products. Newer releases call them assets. |
151
+ | `list_product_types` | Product types. Newer releases call them organizations. |
152
+ | `list_engagements`, `get_engagement` | Engagements. |
153
+ | `list_tests`, `get_test` | Tests, meaning individual scan imports or manual tests. |
154
+ | `list_scan_types` | Scan types the instance can import, for use as `scan_type`. |
155
+ | `list_test_imports` | Import and reimport history for a test, with the findings each run created, closed, reactivated or left untouched. |
156
+ | `get_current_user` | The user the API key belongs to. |
157
+ | `list_locations` | Hosts, URLs and other locations. Uses the locations API on newer releases and the endpoints API on older ones. |
158
+
159
+ ### Write tools (only with `DEFECTDOJO_ALLOW_WRITES=true`)
160
+
161
+ | Tool | What it does |
162
+ | --- | --- |
163
+ | `import_scan` | Upload a scan report as a new test. Target an engagement id, or name a product and engagement and let DefectDojo create them with `auto_create_context`. Supports `close_old_findings`, `minimum_severity`, tags, scan date, version and CI metadata. |
164
+ | `reimport_scan` | Upload a newer report into an existing test so DefectDojo closes fixed findings and adds new ones. |
165
+ | `add_finding_note` | Add a note to a finding. |
166
+ | `update_finding_status` | Set active, verified, false positive, out of scope, or mitigated (with an optional date and note). |
167
+ | `risk_accept_findings` | Risk accept, or revoke acceptance for, up to 50 findings with DefectDojo's simple risk acceptance. |
168
+ | `create_product` | Create a product in a product type. |
169
+ | `create_engagement` | Create an engagement in a product. |
170
+
171
+ Scan reports reach the server in one of two ways. Over stdio, pass `file_path` pointing at a file inside one of the `DEFECTDOJO_IMPORT_DIRS` folders. Over stdio or HTTP, pass the report as `file_content_base64` with a `file_name`.
172
+
173
+ File path imports fail closed. With no `DEFECTDOJO_IMPORT_DIRS` set, the server refuses them instead of falling back to its working directory. It also refuses the home folder and the filesystem root as import folders, resolves symlinks before checking that a file is inside an allowed folder, rejects hidden files and anything inside a hidden folder (any path part that starts with a dot, before or after following symlinks), enforces the size limit, and never includes file contents in error messages. Point `DEFECTDOJO_IMPORT_DIRS` at a dedicated reports folder, not at a home folder or a whole repository.
174
+
175
+ ### Prompts
176
+
177
+ | Prompt | What it does |
178
+ | --- | --- |
179
+ | `triage_critical_findings` | Walks through the open critical and high findings of a product and suggests a verdict for each. |
180
+ | `summarize_import_changes` | Summarizes what the latest import of a test created, closed and reactivated. |
181
+
182
+ ## Read-only by default
183
+
184
+ Without `DEFECTDOJO_ALLOW_WRITES=true` the write tools are not registered at all, so an assistant cannot call them even by mistake. The prompts and server instructions also tell the assistant whether changes are possible.
185
+
186
+ To enable writes, add `"DEFECTDOJO_ALLOW_WRITES": "true"` to the `env` block of your client config. Most clients still ask you to approve each tool call, and the write tools carry MCP annotations that mark them as state-changing.
187
+
188
+ ## Security
189
+
190
+ ### Prompt injection
191
+
192
+ Finding titles, descriptions, notes, file paths, component names and similar fields usually come straight from scanner output. Anyone who controls something that gets scanned can put text there, including instructions aimed at an AI assistant.
193
+
194
+ This server wraps every free-text value from DefectDojo in a pair of tags with a random 16-character hex suffix chosen for that value, for example `<untrusted-data-3f9c0a7b1e2d4c58>...</untrusted-data-3f9c0a7b1e2d4c58>`. A client or model recognizes the data by the matching suffix on the opening and closing tag. Text inside cannot close the wrapper early because it cannot guess the suffix. As a second layer, look-alike tags inside the text are escaped, bidirectional control characters are shown as code points such as `[U+202E]`, and long fields are truncated. Tool descriptions and the server instructions tell the model to treat tagged text as data only. This lowers the risk but cannot remove it, so keep a person in the loop for write actions and review what the assistant proposes.
195
+
196
+ ### Local files
197
+
198
+ A prompt-injected assistant could try to upload local files, such as keys or dotfiles, to DefectDojo through `import_scan`. That is why file path imports are off until you name the folders in `DEFECTDOJO_IMPORT_DIRS`, and why hidden files are always refused. Keep scan reports in their own folder.
199
+
200
+ ### API key scope
201
+
202
+ The server can do anything the API key's user can do. Create a dedicated DefectDojo user for the assistant, give it access only to the products it needs, and keep writes off unless you need them. The key is sent only to `DEFECTDOJO_URL`, redirects are never followed, and the key is redacted from logs and error messages.
203
+
204
+ ### HTTP mode
205
+
206
+ Over stdio the server is only reachable by the client that started it. HTTP mode is for shared or remote setups:
207
+
208
+ ```sh
209
+ export DEFECTDOJO_URL=https://defectdojo.example.com
210
+ export DEFECTDOJO_API_KEY=your-api-key
211
+ export DEFECTDOJO_MCP_AUTH_TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
212
+ defectdojo-mcp --transport http --host 127.0.0.1 --port 8000
213
+ ```
214
+
215
+ The endpoint is `http://127.0.0.1:8000/mcp`, and `/healthz` answers without authentication for health checks. The server refuses to start in HTTP mode without one of these authentication modes:
216
+
217
+ - **Token mode** (`--http-auth token`, the default). Every request must send `Authorization: Bearer <DEFECTDOJO_MCP_AUTH_TOKEN>`. All callers share the server's DefectDojo key, so give that key the narrowest permissions that work for everyone.
218
+ - **Pass-through mode** (`--http-auth passthrough`). Every request carries the caller's own DefectDojo key in `X-DefectDojo-Api-Key` or `Authorization: Token <key>`. The server holds no key of its own and DefectDojo enforces each caller's permissions.
219
+
220
+ The server binds to `127.0.0.1` by default and checks the `Host` and `Origin` headers to block DNS rebinding. To serve other machines, bind a non-loopback address, set `DEFECTDOJO_MCP_ALLOWED_HOSTS` to the public host name, and put a TLS-terminating reverse proxy in front. Keys and tokens travel in headers, so plain HTTP across a network exposes them.
221
+
222
+ Report security problems as described in [SECURITY.md](SECURITY.md).
223
+
224
+ ## Compatibility
225
+
226
+ - **Open-source DefectDojo 2.x and 3.x.** The server uses long-standing API v2 endpoints and skips fields a version does not return. On older releases, filters that the instance does not know are ignored by DefectDojo, so the date filters on `list_findings` need a release from late 2024 or newer. `list_locations` uses the locations API in 3.x and falls back to endpoints on older releases.
227
+ - **DefectDojo Pro.** Everything here works against Pro through the same API. Pro also includes its own built-in MCP server at `https://<your-instance>/mcp` with more capabilities, and `get_instance_info` mentions it when it detects Pro.
228
+ - **MCP.** Built on the official [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) 2.x and protocol version 2026-07-28, with fallback to earlier protocol versions for older clients.
229
+ - **Python** 3.11 or newer.
230
+
231
+ ## Development
232
+
233
+ ```sh
234
+ git clone https://github.com/DefectDojo/defectdojo-mcp
235
+ cd defectdojo-mcp
236
+ uv sync
237
+ uv run pytest # unit tests with mocked HTTP
238
+ uv run ruff check .
239
+ uv run ruff format --check .
240
+ uv run mypy
241
+ ```
242
+
243
+ The live test suite runs every tool against a real DefectDojo instance over stdio. Point it at a disposable instance, since it creates products, engagements and findings:
244
+
245
+ ```sh
246
+ DEFECTDOJO_LIVE_URL=http://127.0.0.1:8080 DEFECTDOJO_LIVE_API_KEY=your-key uv run pytest -m live
247
+ ```
248
+
249
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more.
250
+
251
+ ## License
252
+
253
+ BSD 3-Clause. See [LICENSE](LICENSE).