# CLAUDE.md Entwicklungshinweise fuer `mcp-sonarqube-proxy`. ## Projekt Stdio-MCP-Server, der beim Start eine Streamable-HTTP-Verbindung zum Upstream SonarQube-MCP-Server oeffnet, dessen Tools 1:1 weiterreicht und Aufrufe an diesen weiterleitet. Claude Desktop / Claude App spawnt diesen Prozess via stdio. ## Architektur - `src/mcp_sonarqube_proxy/proxy.py` — eine `upstream_session()` (async context manager) haelt die persistente `ClientSession` zum Upstream. `build_proxy_server()` registriert zwei Handler auf einem `mcp.server.lowlevel.Server`, die Aufrufe transparent weiterleiten. - `src/mcp_sonarqube_proxy/cli.py` — Click-CLI mit `serve` (stdio) und `check` (einmaliger Verbindungstest). ### Zentrale Architekturentscheidungen 1. **Low-Level `Server`, nicht `FastMCP`.** FastMCP introspiziert die Handler-Signatur, um ein `inputSchema` zu generieren. Bei einem generischen `**kwargs`-Handler ist das Schema leer und der Client weiss nicht, wie er das Tool aufrufen soll. Der Low-Level-Server uebernimmt dagegen das `Tool`-Objekt mit allen Feldern (`inputSchema`, `outputSchema`, `annotations`, `title`, `_meta`) unveraendert vom Upstream. 2. **Eine persistente Upstream-Session, kein Per-Call-Reconnect.** Die fruehere Variante hat fuer jeden Tool-Call eine neue HTTP-Session geoeffnet. Das bricht die Streamable-HTTP-Session-Id, multipliziert die Latenz und macht `initialize()` zur teuersten Operation im Hot Path. Jetzt: einmal beim Start verbinden, bei `serve`-Lifetime offenhalten, beim Beenden sauber schliessen. 3. **`validate_input=False` auf dem `@call_tool`-Decorator.** Der Upstream ist die einzige Wahrheit ueber Schemata. Lokale Validierung wuerde nur duplizieren und koennte bei Schema-Drift zu falschen Ablehnungen fuehren. 4. **`server.create_initialization_options()` statt manueller Capabilities.** Die Helper-Methode liefert die korrekten `NotificationOptions()` und `experimental_capabilities={}` und ueberlebt SDK-Updates besser als ein handgeschriebener Aufruf. 5. **Stateless Tool-Liste — kein Caching.** Jeder `tools/list`-Request re-fetcht den Upstream. Weniger Code, immer aktuell, kein Cache-Coherency- Problem. ### Logging und stdout/stderr `stdout` ist fuer JSON-RPC reserviert. Jegliche Ausgabe (Logging, Startmeldungen, Fehlermeldungen) muss auf `stderr`. `_configure_logging` setzt das fuer das Logging-Modul, `_stderr()` ist der Helper fuer direkte Meldungen. ## Lokale Entwicklung ```bash # Editable install + Dev-Group uv sync # Upstream-Verbindung testen SONARQUBE_MCP_URL=http://192.168.0.2:8765/mcp uv run mcp-sonarqube-proxy check # Server lokal starten (stdio — z.B. via MCP Inspector) SONARQUBE_MCP_URL=http://192.168.0.2:8765/mcp uv run mcp-sonarqube-proxy serve # Tests uv run pytest # Lint / Format uv run ruff check . uv run ruff format . ``` ## Installation als Tool ```bash uv tool install git+https://gitea.gecheckt.de/marcus/mcp-sonarqube-proxy.git ``` ## Bekannte offene Punkte - **Reconnect bei Verbindungsabbruch:** Wenn der Upstream waehrend `serve` weggeht, scheitern nachfolgende Tool-Calls bis zum Neustart des Proxies. Eine Reconnect-Logik mit Retry on `anyio.ClosedResourceError`/`httpx.ReadError` waere ein sinnvoller naechster Schritt, ist fuer v0.1 aber bewusst weggelassen. - **Concurrent Tool-Calls:** Die `ClientSession` korreliert Antworten ueber Request-IDs und sollte parallele Calls verkraften. Nicht explizit getestet. - **SDK-Versionssprung:** Auf `main` der python-sdk wurden die Decorators durch Konstruktor-Kwargs ersetzt. Bei Migration auf eine neue Major-Version muss `build_proxy_server()` angepasst werden.