Read-mostly MCP server for Dependency-Track with version lifecycle, single-call triage, duplicate-filtering ergonomics, strict input validation, broadcast triage, cross-project vulnerability search, and transient-failure retry
dtrack-mcp demonstrates solid tool design with comprehensive parameter schemas, clear descriptions, and thoughtful domain modeling. All 7 tools have explicit descriptions (194 - 450 chars, well above the 10 - 1024 baseline). Input schemas are complete with typed parameters and descriptions. Tool names follow verb_noun convention (list_*, resolve_*, find_*, search_*, group_*, get_*). However, output schemas are not formally documented in the source, responses are inferred from docstrings and code logic rather than explicit JSON Schema declarations. Error handling is minimal; no recovery guidance or actionable error messages visible. No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite all tools being read-only. Parameter descriptions are strong but could benefit from explicit format/constraint examples (e.g., UUID format, enum values for analysis_states).
Fetch the full detail record of a vulnerability. When ``source`` is given (e.g. "NVD", "GITHUB"), fetches directly. When omitted, probes candidate sources based on the id prefix (CVE-* → NVD, GHSA-* → GITHUB, etc.) and returns the first hit, or null if nothing matches. Read-only. Returns title, description, CVSS v2/v3/v4 scores and vectors, CWEs, EPSS score and percentile, KEV flag, references, and alias list.
Fetch the analysis record for one finding. Returns the analysis state, justification, response, details, suppressed flag, and the full comment history. If DT has no analysis row yet, returns an empty-analysis default (state ``NOT_SET``, no comments) — callers never get null. Read-only.
Group findings by alias (transitive closure) — dedup CVE/GHSA/OSV. Vulnerabilities reported under different ids (e.g. CVE-2024-X and GHSA-Y-Z) often refer to the same issue and are linked via DT's aliases. This tool runs union-find over that alias graph and returns one cluster per real issue. Each cluster carries a canonical id (CVE first, then GHSA, then OSV, then SNYK, then INTERNAL, then alphabetical), the full alias list, a ``merge_reason`` trace of the edges that joined the cluster, and every finding in the project belonging to it. Same filters as list_findings. Pagination applies to groups, not to the findings inside them — a group always ships with all its findings intact. Sorted by highest CVSS score (v3 or v4) descending. Read-only. ``include_details=True`` (v0.3) embeds title/description/references in every finding's vulnerability summary. The same description text repeats on each finding inside a group — acceptable tradeoff for a single-call triage flow.
Output schemas not formally documented. Responses inferred from docstrings and code; no explicit JSON Schema declarations for return types. LLMs cannot reliably predict response structure for downstream tool chaining.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). All 7 tools are read-only but lack explicit readOnlyHint annotation. Agents cannot infer safety/idempotency without annotations.
Error handling lacks recovery guidance. No visible error classification (retryable vs user-fixable vs fatal) or actionable error messages. Stack traces or bare error codes provide no guidance to LLM agents.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | <=2025-11-25 | v2 |
List vulnerability findings for a project with optional filters. Returns normalized findings — each one bundles the vulnerability (severity, CVSS v3/v4, CWE, EPSS, aliases), the affected component (name, version, purl, latest known version), and the analysis state. All filters are applied client-side before pagination, so ``total`` reflects the post-filter count. Read-only. When ``include_details=True``, every finding's vulnerability summary also carries ``title``, ``description``, and ``references`` so an LLM can draft a verdict without a separate ``get_vulnerability`` call. Off by default because descriptions can be 2–4 KB each — set it to ``true`` only for focused batches (20–30 findings), not project-wide scans.
List Dependency-Track projects. List projects in the Dependency-Track instance, optionally filtered by a substring of the project name. Returns normalized projects with per-severity vulnerability counts. Read-only.
Resolve a project by UUID or by exact (name, version). Two lookup paths — use whichever you have: * ``project_uuid`` — direct UUID lookup (e.g. copied from the DT UI URL or returned by another tool). * ``name`` + ``version`` — exact-match lookup by project name and version string. When ``project_uuid`` is provided it takes precedence; ``name`` and ``version`` are ignored. Returns a normalized project, or null if nothing matches. Read-only.
Search which projects are affected by a vulnerability. Given a vulnerability id (e.g. "CVE-2024-1234"), resolves it, then finds every DT project that contains a finding for this vulnerability (or any of its aliases). For each project returns the analysis state per affected component. Use this to answer "which products are affected by CVE-X and what's been decided?" without manually iterating over projects. Read-only.
Parameter constraints not fully explicit. analysis_states and severities accept arrays but valid enum values not declared in schema. LLMs may hallucinate invalid state names (e.g., 'PENDING' instead of 'IN_TRIAGE').
No pagination guidance in descriptions. list_projects, list_findings, group_findings_by_alias support pagination but descriptions do not explain when/why to use page/page_size or what happens when total > page_size.