fix(webui): surface MCP runtime connection failures (#5331)

This commit is contained in:
chengyongru
2026-08-11 23:52:02 +08:00
committed by GitHub
parent 1edfd268db
commit d45c893f68
31 changed files with 838 additions and 123 deletions
+51 -2
View File
@@ -1,6 +1,8 @@
from __future__ import annotations
import json
from collections.abc import Callable, Mapping
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import ANY, AsyncMock, MagicMock
from urllib.parse import parse_qs, urlsplit
@@ -10,13 +12,19 @@ from websockets.datastructures import Headers
from nanobot.config.loader import get_config_path
from nanobot.webui.http_utils import http_json_response
from nanobot.webui.mcp_presets_api import custom_mcp_action
from nanobot.webui.settings_routes import WebUISettingsRouter
from nanobot.webui.settings_services import WebUISettingsServices
def _router(*, authorized: bool = True) -> WebUISettingsRouter:
def _router(
*,
authorized: bool = True,
config_path: Path | None = None,
mcp_runtime_status: Callable[[], Mapping[str, str]] | None = None,
) -> WebUISettingsRouter:
return WebUISettingsRouter(
settings=WebUISettingsServices.create(get_config_path()),
settings=WebUISettingsServices.create(config_path or get_config_path()),
bus=SimpleNamespace(),
logger=SimpleNamespace(exception=lambda *_args: None),
check_api_token=lambda _request: authorized,
@@ -28,6 +36,7 @@ def _router(*, authorized: bool = True) -> WebUISettingsRouter:
),
runtime_surface="browser",
runtime_capabilities={},
mcp_runtime_status=mcp_runtime_status,
mcp_oauth_redirect_uri=lambda _request: "https://gateway.example/auth/mcp/callback",
)
@@ -40,6 +49,46 @@ def _mutation_request(path: str, payload: dict[str, object]) -> SimpleNamespace:
return request
@pytest.mark.asyncio
async def test_mcp_list_serializes_local_runtime_failure_snapshot(tmp_path) -> None:
config_path = tmp_path / "config.json"
custom_mcp_action(
"custom",
{
"name": ["team-docs"],
"transport": ["streamableHttp"],
"url": ["https://mcp.example.com/mcp"],
},
config_path=config_path,
)
snapshot_calls = 0
def runtime_snapshot() -> Mapping[str, str]:
nonlocal snapshot_calls
snapshot_calls += 1
return {"team-docs": "failed"}
router = _router(
config_path=config_path,
mcp_runtime_status=runtime_snapshot,
)
request = SimpleNamespace(
path="/api/settings/mcp-presets",
headers=Headers(),
)
response = await router.dispatch(None, request, "/api/settings/mcp-presets")
assert response is not None
assert response.status_code == 200
payload = json.loads(response.body)
row = next(item for item in payload["presets"] if item["name"] == "team-docs")
assert row["status"] == "configured"
assert row["runtime_status"] == "failed"
assert b'"runtime_status": "failed"' in response.body
assert snapshot_calls == 1
@pytest.mark.asyncio
async def test_mcp_oauth_start_uses_gateway_callback_and_requires_api_auth(monkeypatch) -> None:
config = SimpleNamespace(