This commit is contained in:
Danilo Reyes
2026-01-30 23:17:02 -06:00
parent 527fad8da0
commit 97053901c0
17 changed files with 646 additions and 26 deletions

View File

@@ -0,0 +1,12 @@
"""Test configuration for MCP server tests."""
from __future__ import annotations
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
SRC = PROJECT_ROOT / "src"
for path in (PROJECT_ROOT, SRC):
if str(path) not in sys.path:
sys.path.insert(0, str(path))

View File

@@ -0,0 +1,13 @@
"""Docs sync tests."""
from __future__ import annotations
from mcp_server.docs_sync import check_catalog_parity
def test_docs_sync_runs() -> None:
"""Docs sync returns structured result."""
result = check_catalog_parity()
assert "status" in result
assert "missingInDocs" in result
assert isinstance(result["missingInDocs"], list)

View File

@@ -0,0 +1,25 @@
"""Performance tests for MCP server handlers."""
from __future__ import annotations
import time
from mcp_server.server import handle_request
MAX_LATENCY_SECONDS = 2
def test_list_tools_is_fast() -> None:
"""ListTools responds under the latency target."""
start = time.perf_counter()
handle_request({"method": "listTools", "params": {}})
duration = time.perf_counter() - start
assert duration < MAX_LATENCY_SECONDS
def test_invoke_tool_is_fast() -> None:
"""InvokeTool responds under the latency target."""
start = time.perf_counter()
handle_request({"method": "invokeTool", "params": {"name": "show-constitution", "args": {}}})
duration = time.perf_counter() - start
assert duration < MAX_LATENCY_SECONDS

View File

@@ -0,0 +1,56 @@
"""Server dispatch tests."""
from __future__ import annotations
from mcp_server import server as server_module
from mcp_server.server import handle_request
METHOD_NOT_FOUND = -32601
def test_list_tools_round_trip() -> None:
"""ListTools returns catalog entries."""
response = handle_request({"method": "listTools", "params": {}})
tools = response["result"]["tools"]
assert isinstance(tools, list)
assert any(entry["name"] == "show-constitution" for entry in tools)
def test_invoke_tool_round_trip() -> None:
"""InvokeTool returns standard shape."""
response = handle_request(
{"method": "invokeTool", "params": {"name": "show-constitution", "args": {}}}
)
result = response["result"]
assert result["status"] in {"ok", "unsupported", "invalid_input"}
assert "output" in result
def test_sync_docs_response_shape() -> None:
"""SyncDocs returns expected fields."""
response = handle_request({"method": "syncDocs", "params": {}})
result = response["result"]
assert "status" in result
assert "missingInDocs" in result
def test_invalid_method() -> None:
"""Unknown method yields error."""
response = handle_request({"method": "unknown", "params": {}})
assert "error" in response
assert response["error"]["code"] == METHOD_NOT_FOUND
def test_unavailable_service_returns_actions(monkeypatch) -> None:
"""Invoke tool failure returns guidance."""
def boom(*_: object, **__: object) -> dict:
raise RuntimeError("boom")
monkeypatch.setattr(server_module, "invoke_tool", boom)
response = handle_request(
{"method": "invokeTool", "params": {"name": "list-mcp-tasks", "args": {}}}
)
assert "result" in response
assert response["result"]["status"] == "failed"
assert "actions" in response["result"]

View File

@@ -0,0 +1,31 @@
"""Tool registry tests."""
from __future__ import annotations
from mcp_server import tools
MIN_TOOLS = 5
def test_tool_catalog_has_minimum_tools() -> None:
"""Catalog includes baseline tools."""
catalog = tools.tool_catalog()
assert len(catalog) >= MIN_TOOLS
names = {tool.name for tool in catalog}
assert "show-constitution" in names
assert "list-playbooks" in names
assert "show-reference" in names
def test_invoke_tool_handles_unknown() -> None:
"""Unknown tool returns unsupported guidance."""
result = tools.invoke_tool("missing-tool", {})
assert result["status"] == "unsupported"
assert "listTools" in result["actions"][0]
def test_list_tools_payload_shape() -> None:
"""Payload includes tools key."""
payload = tools.list_tools_payload()
assert "tools" in payload
assert all("name" in entry for entry in payload["tools"])