a6fd188c14
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>
72 lines
2.0 KiB
Python
72 lines
2.0 KiB
Python
"""Tests for the Click CLI: serve startup errors, check success/failure."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from click.testing import CliRunner
|
|
from mcp import types
|
|
|
|
from mcp_sonarqube_proxy import cli
|
|
|
|
|
|
def test_check_success_lists_tools(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
fake_tools = [
|
|
types.Tool(
|
|
name="search",
|
|
description="Search issues.",
|
|
inputSchema={"type": "object"},
|
|
),
|
|
types.Tool(
|
|
name="get_metric",
|
|
title="Project Metric",
|
|
description=None,
|
|
inputSchema={"type": "object"},
|
|
),
|
|
]
|
|
|
|
async def fake_run_check() -> list[types.Tool]:
|
|
return fake_tools
|
|
|
|
monkeypatch.setattr(cli, "_run_check", fake_run_check)
|
|
|
|
result = CliRunner().invoke(cli.main, ["check"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "2 Tools" in result.output
|
|
assert "search" in result.output
|
|
assert "Project Metric" in result.output
|
|
|
|
|
|
def test_check_failure_exits_one_with_stderr(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
async def fake_run_check() -> list[types.Tool]:
|
|
raise ConnectionError("connection refused")
|
|
|
|
monkeypatch.setattr(cli, "_run_check", fake_run_check)
|
|
|
|
result = CliRunner().invoke(cli.main, ["check"])
|
|
|
|
assert result.exit_code == 1
|
|
assert "Upstream nicht erreichbar" in result.stderr
|
|
assert "connection refused" in result.stderr
|
|
|
|
|
|
def test_serve_startup_error_exits_one(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
async def fake_run_serve() -> None:
|
|
raise RuntimeError("upstream initialize failed")
|
|
|
|
monkeypatch.setattr(cli, "_run_serve", fake_run_serve)
|
|
|
|
result = CliRunner().invoke(cli.main, ["serve"])
|
|
|
|
assert result.exit_code == 1
|
|
assert "fatal" in result.stderr
|
|
assert "upstream initialize failed" in result.stderr
|
|
|
|
|
|
def test_version_flag() -> None:
|
|
from mcp_sonarqube_proxy import __version__
|
|
|
|
result = CliRunner().invoke(cli.main, ["--version"])
|
|
assert result.exit_code == 0
|
|
assert __version__ in result.output
|