309 lines
11 KiB
Markdown
309 lines
11 KiB
Markdown
# dependencyTrack-MCP
|
|
|
|
MCP-Server fuer [OWASP Dependency-Track](https://dependencytrack.org/), in Rust.
|
|
Ueberwiegend lesender Zugriff (Projekte, Findings, Metriken, VEX/SBOM u.a.) plus
|
|
eine geschuetzte Schreib-Operation: Finding-Suppression/Analyse.
|
|
|
|
Zwei Frontends, eine gemeinsame Tool-Logik:
|
|
|
|
| Modus | Binary | Einsatz |
|
|
|---|---|---|
|
|
| **stdio** | `dtrack-stdio` | Lokal/Arbeitsrechner: von Claude Desktop gestartet (`docker run -i` oder native `.exe`) |
|
|
| **HTTP** | `dtrack-http` | Server: StreamableHTTP `/mcp`, Multi-Client, Bearer-Auth/RBAC, Admin-UI |
|
|
|
|
> **Status: Stage 3** -- HTTP-Frontend, Bearer-Auth, persistente Config,
|
|
> Admin-UI und RBAC-Enforcement stehen. Tool-Sichtbarkeit pro Client (Stufe 2)
|
|
> und SSO folgen (siehe Roadmap).
|
|
|
|
## Architektur
|
|
|
|
```
|
|
crates/dtrack-config Config (TOML laden/speichern, Secret-Masking, Persistenz)
|
|
crates/dtrack-perms RBAC-Policy (Rollen/Clients, Deny-overrides-Allow)
|
|
crates/dtrack-core DT-REST-Client (reqwest+rustls)
|
|
crates/dtrack-tools rmcp-Server (die Tools) -- transport-unabhaengig, geteilt
|
|
crates/dtrack-stdio Bin: stdio-Frontend
|
|
crates/dtrack-http Bin: HTTP-Frontend (axum + StreamableHTTP + Admin-UI)
|
|
```
|
|
|
|
## Tools
|
|
|
|
Lesend:
|
|
|
|
| Tool | Argument | DT-Endpoint |
|
|
|---|---|---|
|
|
| `list_projects` | -- | `GET /project` |
|
|
| `lookup_project` | `name`, `version?` | `GET /project/lookup` |
|
|
| `project_components` | `uuid` | `GET /component/project/{uuid}` |
|
|
| `project_findings` | `uuid` | `GET /finding/project/{uuid}` |
|
|
| `project_metrics` | `uuid` | `GET /metrics/project/{uuid}/current` |
|
|
| `project_violations` | `uuid` | `GET /violation/project/{uuid}` (braucht `VIEW_POLICY_VIOLATION`) |
|
|
| `project_vex` | `uuid` | `GET /vex/cyclonedx/project/{uuid}` |
|
|
| `project_bom` | `uuid` | `GET /bom/cyclonedx/project/{uuid}` |
|
|
|
|
Schreibend (braucht das DT-Recht `VULNERABILITY_ANALYSIS`):
|
|
|
|
| Tool | Argument | DT-Endpoint |
|
|
|---|---|---|
|
|
| `suppress_finding` | `project`, `component`, `vulnerability`, `suppressed?`, `state?`, `justification?`, `comment?` | `PUT /analysis` |
|
|
|
|
> `suppress_finding` ist die einzige schreibende Operation. Die drei UUIDs
|
|
> (project/component/vulnerability) stammen aus der `project_findings`-Antwort.
|
|
> `suppressed` ist standardmaessig `true` (`false` hebt die Unterdrueckung auf).
|
|
> Wer nur lesen soll, bekommt einen Key **ohne** `VULNERABILITY_ANALYSIS` --
|
|
> dann scheitert der Write serverseitig mit HTTP 403. Im HTTP-Modus zusaetzlich
|
|
> per RBAC eingrenzbar (eigene Rolle / `deny`).
|
|
|
|
## Konfiguration (Umgebungsvariablen)
|
|
|
|
| Var | Pflicht | Bedeutung |
|
|
|---|---|---|
|
|
| `DTRACK_URL` | ja* | Basis-URL der DT-Instanz (ohne `/api/v1`, wird angehaengt) |
|
|
| `DTRACK_API_KEY` | ja* | API-Key eines Teams. Lesen: `VIEW_PORTFOLIO` + `VIEW_VULNERABILITY` (Policy-Verstoesse: `VIEW_POLICY_VIOLATION`); fuer `suppress_finding`: `VULNERABILITY_ANALYSIS` |
|
|
| `DTRACK_INSECURE` | nein | `1`/`true` -> TLS-Pruefung aus (Notbehelf bei internem CA-Cert) |
|
|
| `DTRACK_CONFIG` | nein | Pfad zu einer TOML-Config; einmal aus env gebootstrappt, danach massgeblich |
|
|
| `DTRACK_PERMISSIONS` | nein | (nur HTTP) Pfad zur RBAC-Policy; gesetzt -> RBAC statt flacher Token-Liste |
|
|
| `DTRACK_HTTP_TOKENS` | nein | (nur HTTP) kommagetrennte erlaubte Bearer-Tokens; leer = ungeschuetzt |
|
|
| `DTRACK_HTTP_ADDR` | nein | (nur HTTP) Bind-Adresse, Default `0.0.0.0:8080` |
|
|
| `DTRACK_ADMIN_USER` | nein | (nur HTTP) Basic-Auth-User der Admin-UI; leer = UI deaktiviert |
|
|
| `DTRACK_ADMIN_PASSWORD` | nein | (nur HTTP) Basic-Auth-Passwort der Admin-UI |
|
|
|
|
\* oder ueber `DTRACK_CONFIG`-Datei.
|
|
|
|
---
|
|
|
|
## Schnellstart: lokal testen (Mac/Linux mit Docker)
|
|
|
|
> Beispiele mit `docker`; `podman` funktioniert identisch.
|
|
|
|
### Variante A -- aus dem Quellcode bauen (baut nativ fuer deine Architektur)
|
|
|
|
```sh
|
|
cp .env.example .env # DTRACK_URL / DTRACK_API_KEY ausfuellen
|
|
docker compose up --build
|
|
```
|
|
|
|
### Variante B -- vorgebautes Release-Image laden
|
|
|
|
Am Release haengen pro Architektur Tarballs. Passenden waehlen
|
|
(**arm64** = Apple Silicon, **amd64** = Intel / "nicht Mac"):
|
|
|
|
```sh
|
|
docker load -i dtrack-http-0.1.0-arm64.tar.gz
|
|
|
|
docker run --rm -p 8080:8080 \
|
|
-e DTRACK_URL=http://host.docker.internal:8081 \
|
|
-e DTRACK_API_KEY=odt_dein_key \
|
|
-e DTRACK_ADMIN_USER=admin -e DTRACK_ADMIN_PASSWORD=geheim \
|
|
dtrack-http:0.1.0-arm64
|
|
```
|
|
|
|
Pruefen:
|
|
- `curl http://localhost:8080/health` -> `OK`
|
|
- `http://localhost:8080/admin` -> Admin-UI (Basic-Auth)
|
|
|
|
> Der Server bootet auch ohne erreichbare DT -- nur die Tool-Calls brauchen eine
|
|
> echte Instanz. Tipp fuer Persistenz: `-v ~/dtrack-data:/data -e DTRACK_CONFIG=/data/config.toml`
|
|
> ergaenzen, dann ueberleben Admin-Aenderungen den Neustart.
|
|
|
|
### (optional) Dummy-DependencyTrack zum Testen
|
|
|
|
`docker-compose.yml` in einem eigenen Ordner:
|
|
|
|
```yaml
|
|
services:
|
|
dtrack-apiserver:
|
|
image: dependencytrack/apiserver
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 4608m
|
|
ports:
|
|
- "8081:8080" # API -> Host-Port 8081
|
|
volumes:
|
|
- dtrack-data:/data
|
|
dtrack-frontend:
|
|
image: dependencytrack/frontend
|
|
environment:
|
|
- API_BASE_URL=http://localhost:8081
|
|
ports:
|
|
- "8082:8080" # Web-UI -> Host-Port 8082
|
|
volumes:
|
|
dtrack-data: {}
|
|
```
|
|
|
|
`docker compose up -d` (apiserver braucht ~4 GB RAM + ein paar Minuten beim
|
|
Erststart). Dann `http://localhost:8082` (Login `admin`/`admin`), unter
|
|
**Administration -> Access Management -> Teams** einen API-Key mit
|
|
`VIEW_PORTFOLIO` + `VIEW_VULNERABILITY` erzeugen (fuer den Suppression-Test
|
|
zusaetzlich `VULNERABILITY_ANALYSIS`) und ein Projekt anlegen.
|
|
Aus dem MCP-Container ist die DT unter `http://host.docker.internal:8081`
|
|
erreichbar (nicht `localhost`).
|
|
|
|
---
|
|
|
|
## Mit Claude Desktop verbinden
|
|
|
|
> **Wichtig:** Der UI-Weg *"Add custom connector"* (URL eingeben) funktioniert
|
|
> fuer einen **lokalen** Server **nicht** -- Claude verbindet sich dabei aus
|
|
> Anthropics Cloud, die deinen `localhost` nicht erreicht. Fuer lokal geht der
|
|
> Weg ueber die `claude_desktop_config.json`.
|
|
|
|
Config-Datei (macOS): `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
(oder in Desktop: **Settings -> Developer -> Edit Config**). Den `mcpServers`-Block
|
|
neben `preferences` einfuegen, danach Desktop **komplett neu starten** (Cmd+Q).
|
|
|
|
### Empfohlen lokal: stdio
|
|
|
|
stdio hat keinen HTTP-Session-Handshake -> zuverlaessig. Den HTTP-Container
|
|
braucht man dafuer nicht (nur eine laufende DT).
|
|
|
|
```sh
|
|
docker load -i dtrack-stdio-0.1.0-amd64.tar.gz
|
|
```
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"dependency-track": {
|
|
"command": "docker",
|
|
"args": ["run","-i","--rm",
|
|
"-e","DTRACK_URL","-e","DTRACK_API_KEY",
|
|
"dtrack-stdio:0.1.0-amd64"],
|
|
"env": {
|
|
"DTRACK_URL": "http://host.docker.internal:8081",
|
|
"DTRACK_API_KEY": "odt_dein_key"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
> Findet Desktop `docker` nicht (eingeschraenkter PATH), `which docker` ausfuehren
|
|
> und den vollen Pfad als `command` setzen (z.B. `/usr/local/bin/docker`).
|
|
> Das stdio-Release-Image ist amd64 -> laeuft auf Apple Silicon emuliert (ok zum Testen).
|
|
|
|
### Windows (Arbeitsrechner): native `.exe` -- empfohlen hinter Firmen-VPN
|
|
|
|
Auf Windows ist die native `.exe` der zuverlaessigste Weg: sie laeuft im
|
|
Netz-Kontext des Windows-Hosts, also greift die **VPN-Route zur Firmen-DT
|
|
direkt**. Container (Docker/Podman Desktop) laufen dagegen in einer WSL2-VM --
|
|
`--network=host` bindet dort an die VM, und die DT ueber die Host-VPN ist von da
|
|
drin oft nicht erreichbar.
|
|
|
|
**1. `.exe` bauen** -- Cross-Compile von CachyOS aus. reqwest nutzt rustls (kein
|
|
OpenSSL), darum keine nativen TLS-Libs noetig, nur der MinGW-Linker:
|
|
|
|
```sh
|
|
rustup target add x86_64-pc-windows-gnu
|
|
sudo pacman -S --needed mingw-w64-gcc
|
|
cargo build --release --target x86_64-pc-windows-gnu --bin dtrack-stdio
|
|
# -> target/x86_64-pc-windows-gnu/release/dtrack-stdio.exe
|
|
```
|
|
|
|
Findet cargo den Linker nicht, in `.cargo/config.toml`:
|
|
|
|
```toml
|
|
[target.x86_64-pc-windows-gnu]
|
|
linker = "x86_64-w64-mingw32-gcc"
|
|
```
|
|
|
|
> **Fallback**, falls der rustls-Crypto-Provider beim `windows-gnu`-Cross zickt:
|
|
> direkt auf dem Windows-Rechner mit rustup/MSVC bauen --
|
|
> `cargo build --release --bin dtrack-stdio` erzeugt dieselbe `.exe`.
|
|
|
|
Die `dtrack-stdio.exe` dann auf den Arbeitsrechner ziehen, z.B. nach
|
|
`C:\Tools\dtrack-mcp\dtrack-stdio.exe`.
|
|
|
|
**2. Claude Desktop einbinden** -- Config-Datei unter Windows:
|
|
`%APPDATA%\Claude\claude_desktop_config.json`
|
|
(oder **Settings -> Developer -> Edit Config**):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"dependency-track": {
|
|
"command": "C:\\Tools\\dtrack-mcp\\dtrack-stdio.exe",
|
|
"env": {
|
|
"DTRACK_URL": "https://dtrack.firma.intern",
|
|
"DTRACK_API_KEY": "odt_...",
|
|
"DTRACK_INSECURE": "0"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Pfad mit doppelten Backslashes (oder Forward-Slashes). Bei internem CA-Cert
|
|
`DTRACK_INSECURE` auf `"1"` setzen. Danach Desktop **komplett neu starten**.
|
|
|
|
**3. Testen** -- VPN verbinden, im Chat z.B. *"liste die DT-Projekte"* ->
|
|
`list_projects` muss Treffer liefern. Kommt nichts: `DTRACK_URL`/Key pruefen,
|
|
bei TLS-Fehler `DTRACK_INSECURE=1`, VPN-Verbindung pruefen. Logs:
|
|
`%APPDATA%\Claude\logs\mcp*.log`.
|
|
|
|
### HTTP als echter Remote-Connector
|
|
|
|
Der HTTP-Modus ist fuer den Betrieb als **oeffentlich erreichbarer** Remote-MCP
|
|
gedacht (Custom Connector ueber eine echte URL, z.B. hinter Reverse-Proxy/Tunnel).
|
|
Der Bridge-Versuch `npx mcp-remote http://localhost:8080/mcp` fuer lokal scheitert
|
|
aktuell am rmcp-StreamableHTTP-Handshake (`tools/list` vor `initialized`) -- darum
|
|
lokal stdio nutzen.
|
|
|
|
Logs bei Problemen: `~/Library/Logs/Claude/mcp*.log`.
|
|
|
|
---
|
|
|
|
## RBAC (optional, nur HTTP)
|
|
|
|
Standardmaessig regelt `DTRACK_HTTP_TOKENS` den Zugang (flache Token-Liste,
|
|
leer = offen). Fuer feinere Rechte `permissions.toml.example` nach
|
|
`./data/permissions.toml` kopieren, Tokens/Rollen eintragen und
|
|
`DTRACK_PERMISSIONS=/data/permissions.toml` setzen.
|
|
|
|
Modell: benannte Rollen mit `allow`/`deny` (`"*"` = alle Tools, **deny schlaegt
|
|
allow**), Clients ordnen einen Bearer-Token einer Rolle zu. Ein nicht erlaubter
|
|
`tools/call` wird mit **403** abgewiesen. Tipp: das schreibende `suppress_finding`
|
|
gezielt nur Auditor-Rollen erlauben (oder breit per `deny` ausschliessen).
|
|
|
|
```toml
|
|
[[roles]]
|
|
name = "read-only"
|
|
allow = ["*"]
|
|
deny = ["suppress_finding"]
|
|
|
|
[[roles]]
|
|
name = "auditor"
|
|
allow = ["*"]
|
|
|
|
[[clients]]
|
|
name = "dashboard-bot"
|
|
token = "GEHEIM"
|
|
role = "read-only"
|
|
```
|
|
|
|
## Admin-UI
|
|
|
|
Unter `/admin` (Basic-Auth via `DTRACK_ADMIN_USER`/`_PASSWORD`): zeigt URL +
|
|
maskierten API-Key, erlaubt Aendern (Client wird **live** neu gebaut) und
|
|
persistiert bei gesetztem `DTRACK_CONFIG`. Aktuell bewusst minimal -- Styling
|
|
und Client-/Rollen-Verwaltung folgen.
|
|
|
|
## Release bauen (Maintainer)
|
|
|
|
In Gitea einen Release veroeffentlichen (oder **Actions -> Release Images ->
|
|
Run workflow** mit Tag). Der Workflow baut via buildx Multi-Arch und haengt an:
|
|
`dtrack-stdio-<tag>-amd64`, `dtrack-http-<tag>-amd64`, `dtrack-http-<tag>-arm64`
|
|
(je `.tar.gz`). Auth laeuft ueber das automatische `gitea.token`.
|
|
|
|
## Roadmap
|
|
|
|
| Stage | Inhalt | Status |
|
|
|---|---|---|
|
|
| 0 | stdio, read-only, 3 Tools, CI, Container | ✅ |
|
|
| 1 | Config-Layer + geteiltes Tool-Crate | ✅ |
|
|
| 2 | HTTP-Frontend + Bearer-Auth | ✅ |
|
|
| 3 | Admin-UI + Persistenz + RBAC-Enforcement | ✅ |
|
|
| 3.2 | Tool-Sichtbarkeit pro Client (`tools/list` filtern) | … |
|
|
| 4 | SSO (Gitea-OIDC) | … |
|