Stdio MCP server that proxies tools from an upstream SonarQube MCP server over streamable HTTP. Tools are forwarded 1:1 with full schema preservation (inputSchema, outputSchema, annotations, title, _meta); CallToolResult is forwarded including isError and structuredContent. - proxy.py: persistent upstream ClientSession, low-level Server with @list_tools and @call_tool(validate_input=False) handlers — the upstream is the sole schema authority. - cli.py: Click-based 'serve' (stdio) and 'check' (probe) commands; logging strictly on stderr (stdout reserved for JSON-RPC). - Targets mcp 1.27.x decorator API (pinned <2 to guard against the unreleased constructor-API rewrite on main). - pytest suite (14 tests) covering env-var resolution, schema passthrough, CallToolResult forwarding, registration, dispatch end-to-end, and CLI success/error paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.6 KiB
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— eineupstream_session()(async context manager) haelt die persistenteClientSessionzum Upstream.build_proxy_server()registriert zwei Handler auf einemmcp.server.lowlevel.Server, die Aufrufe transparent weiterleiten.src/mcp_sonarqube_proxy/cli.py— Click-CLI mitserve(stdio) undcheck(einmaliger Verbindungstest).
Zentrale Architekturentscheidungen
-
Low-Level
Server, nichtFastMCP. FastMCP introspiziert die Handler-Signatur, um eininputSchemazu 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 dasTool-Objekt mit allen Feldern (inputSchema,outputSchema,annotations,title,_meta) unveraendert vom Upstream. -
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, beiserve-Lifetime offenhalten, beim Beenden sauber schliessen. -
validate_input=Falseauf 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. -
server.create_initialization_options()statt manueller Capabilities. Die Helper-Methode liefert die korrektenNotificationOptions()undexperimental_capabilities={}und ueberlebt SDK-Updates besser als ein handgeschriebener Aufruf. -
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
# 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
uv tool install git+https://gitea.gecheckt.de/marcus/mcp-sonarqube-proxy.git
Bekannte offene Punkte
- Reconnect bei Verbindungsabbruch: Wenn der Upstream waehrend
serveweggeht, scheitern nachfolgende Tool-Calls bis zum Neustart des Proxies. Eine Reconnect-Logik mit Retry onanyio.ClosedResourceError/httpx.ReadErrorwaere ein sinnvoller naechster Schritt, ist fuer v0.1 aber bewusst weggelassen. - Concurrent Tool-Calls: Die
ClientSessionkorreliert Antworten ueber Request-IDs und sollte parallele Calls verkraften. Nicht explizit getestet. - SDK-Versionssprung: Auf
mainder python-sdk wurden die Decorators durch Konstruktor-Kwargs ersetzt. Bei Migration auf eine neue Major-Version mussbuild_proxy_server()angepasst werden.