Files
mcp-sonarqube-proxy/README.md
T
marcus d76c16d9a7 feat(auth): forward SONARQUBE_TOKEN to upstream as Bearer header
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>
2026-05-06 20:42:51 +02:00

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`