Files
mcp-sonarqube-proxy/CLAUDE.md
T
marcus a6fd188c14 feat: initial v0.1.0 of mcp-sonarqube-proxy
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>
2026-05-06 20:26:38 +02:00

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 — 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

# 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 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.