d76c16d9a7
The upstream MCP container requires a SonarQube user token in the Authorization header. Without one, every call returns 401. - proxy: read SONARQUBE_TOKEN via sonarqube_token() at session-open time; raise TokenMissingError when unset/blank. upstream_session() attaches the token as "Authorization: Bearer <token>" via streamablehttp_client(headers=...). - cli: fail fast in serve and check with a clear stderr message and exit 1 when the token is missing, before any network attempt. All exception text written to stderr passes through _redact() so an accidentally-leaked token from a third-party exception is replaced with [REDACTED] before display. - The token is never stored on any object, never logged, and the TokenMissingError message contains no token material (it only describes how to generate one in SonarQube). - Tests: header forwarding via mocked streamablehttp_client, missing- token exit code, redaction in CLI error paths, whitespace stripping on the token. Total: 25 tests. - Docs: README/CLAUDE updated with the new env-var, Claude Desktop config snippet, and the security guarantees. CHANGELOG added. Bumps version to 0.2.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
99 lines
3.7 KiB
Markdown
99 lines
3.7 KiB
Markdown
# mcp-sonarqube-proxy
|
|
|
|
Stdio-MCP-Server, der einen Upstream-SonarQube-MCP-Server (Streamable HTTP)
|
|
in Claude Desktop / Claude App einbindet. Der Proxy wird via stdio gespawnt,
|
|
verbindet sich beim Start mit dem Upstream und reicht alle Tools 1:1 weiter —
|
|
inklusive `inputSchema`, `outputSchema` und `annotations`, sodass Claude die
|
|
Tools korrekt aufrufen kann.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
uv tool install git+https://gitea.gecheckt.de/marcus/mcp-sonarqube-proxy.git
|
|
```
|
|
|
|
## SonarQube-Token
|
|
|
|
Der Upstream-Container verlangt einen SonarQube-User-Token. Token erzeugen
|
|
in SonarQube unter **My Account → Security → Generate Tokens**, dann in
|
|
`SONARQUBE_TOKEN` setzen. Ohne Token brechen `serve` und `check` mit Exit-Code 1
|
|
und einer klaren Meldung auf stderr ab. Der Token wird ausschliesslich als
|
|
`Authorization: Bearer <token>` an den Upstream weitergereicht und nirgends
|
|
geloggt; Fehlermeldungen, die den Token versehentlich enthalten, werden vor der
|
|
Ausgabe maskiert (`[REDACTED]`).
|
|
|
|
## Verwendung
|
|
|
|
### Verbindung pruefen
|
|
|
|
```bash
|
|
SONARQUBE_MCP_URL=http://192.168.0.2:8765/mcp \
|
|
SONARQUBE_TOKEN=<your-sonarqube-token> \
|
|
mcp-sonarqube-proxy check
|
|
```
|
|
|
|
Listet alle Tools auf, die der Upstream bereitstellt. Exit-Code 0 bei Erfolg,
|
|
1 wenn der Token fehlt oder der Upstream nicht erreichbar ist.
|
|
|
|
### Claude Desktop / Claude App Konfiguration
|
|
|
|
In `claude_desktop_config.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"sonarqube": {
|
|
"command": "mcp-sonarqube-proxy",
|
|
"args": ["serve"],
|
|
"env": {
|
|
"SONARQUBE_MCP_URL": "http://192.168.0.2:8765/mcp",
|
|
"SONARQUBE_TOKEN": "<your-sonarqube-token>"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Auf Windows ist `command` typischerweise der absolute Pfad zur per
|
|
`uv tool install` installierten EXE, z.B.
|
|
`%USERPROFILE%\.local\bin\mcp-sonarqube-proxy.exe`.
|
|
|
|
## Umgebungsvariablen
|
|
|
|
| Variable | Pflicht | Default | Beschreibung |
|
|
|----------------------|---------|----------------------------------|---------------------------------------------|
|
|
| `SONARQUBE_TOKEN` | ja | — | SonarQube-User-Token (My Account → Security)|
|
|
| `SONARQUBE_MCP_URL` | nein | `http://192.168.0.2:8765/mcp` | Upstream-MCP-Endpoint (Streamable HTTP) |
|
|
|
|
## Kommandos
|
|
|
|
| Kommando | Beschreibung |
|
|
|--------------------------------|----------------------------------------------------|
|
|
| `mcp-sonarqube-proxy serve` | Startet den MCP-Server auf stdio. |
|
|
| `mcp-sonarqube-proxy check` | Testet Upstream-Verbindung und listet Tools. |
|
|
| `mcp-sonarqube-proxy --version`| Gibt die Proxy-Version aus. |
|
|
|
|
## Funktionsweise
|
|
|
|
1. Beim Start liest `serve` `SONARQUBE_TOKEN` und oeffnet eine Streamable-HTTP-
|
|
Session zum Upstream mit `Authorization: Bearer <token>`. Anschliessend wird
|
|
`initialize()` ausgefuehrt. Schlaegt eines davon fehl, beendet sich der
|
|
Prozess mit Exit-Code 1 und schreibt die Fehlermeldung auf stderr.
|
|
2. Diese Session bleibt fuer die Lebensdauer des Proxies offen.
|
|
3. `tools/list`-Requests vom Client werden 1:1 an den Upstream weitergeleitet —
|
|
die `Tool`-Objekte (mit allen Schemata und Annotations) kommen unveraendert
|
|
beim Client an.
|
|
4. `tools/call`-Requests werden ebenfalls weitergeleitet. Das vollstaendige
|
|
`CallToolResult` (inklusive `isError`, `structuredContent` und allen
|
|
Content-Bloecken) wird an den Client zurueckgegeben.
|
|
5. `stdout` ist ausschliesslich fuer JSON-RPC reserviert. Logging und
|
|
Statusmeldungen gehen auf `stderr`.
|
|
|
|
Der Proxy validiert Tool-Argumente bewusst nicht lokal — der Upstream ist die
|
|
einzige Schema-Autoritaet und uebernimmt die Validierung.
|
|
|
|
## Anforderungen
|
|
|
|
- Python `>= 3.12`
|
|
- `mcp >= 1.27, < 2`
|