Skip to content

feat(api+dash): wire MCP page to real backend (closes #206)#304

Merged
thinmintdev merged 1 commit into
mainfrom
feat/wire-mcp-page-206
May 24, 2026
Merged

feat(api+dash): wire MCP page to real backend (closes #206)#304
thinmintdev merged 1 commit into
mainfrom
feat/wire-mcp-page-206

Conversation

@thinmintdev
Copy link
Copy Markdown
Contributor

Summary

Replaces the v3 dashboard's HAL0_DATA-driven /agents/mcp page with live queries against new /api/mcp/* routes. Closes #206.

Backend (new — src/hal0/api/routes/mcp.py)

  • GET /api/mcp/servers — introspects app.state.mcp_servers (FastMCP instances) for tool/resource/prompt counts; returns connect_url + audit-derived activity.rpm and connected clients
  • GET /api/mcp/clients — derives connected clients from the hal0.mcp.audit journald stream (grouped by client_id, with role heuristic)
  • GET /api/mcp/catalog — static module-level installable list (ADR-0013 will swap to live registry)
  • GET /api/mcp/stream — SSE tail of mcp.tool.* audit events; backfills last 60 s on subscribe
  • GET /api/mcp/{id}/logs — per-server audit rows for the LogsDrawer
  • POST /api/mcp/install + DELETE /api/mcp/{id} + POST /api/mcp/{id}/{action} + PATCH /api/mcp/{id}/configSTUB 501 with code mcp.not_implemented pending ADR-0013 mcp_client.py work

mcp_mount.py now stashes the live FastMCP instances on app.state.mcp_servers so the introspection route can call server.list_tools() etc. without re-importing the builders. This is the only new export from the existing MCP infrastructure.

Frontend (new — ui/src/api/hooks/useMcp.ts)

  • useMcpServers / useMcpClients / useMcpCatalog — TanStack Query hooks with 404 → mock fallback
  • useMcpCallStream — EventSource against /api/mcp/stream, returns {calls, now} matching the existing useLiveCallStream shape so the LiveTimeline render is unchanged
  • useMcpInstall / useMcpUninstall / useMcpRestart / useMcpConfigPatch / useMcpServerLogs — mutations that catch 501 and surface the ADR-0013 toast

Page wiring (mcp.jsx + mcp-modals.jsx)

  • McpView reads useMcpServers / useMcpClients; falls back to HAL0_DATA mock when live returns empty so the prototype demo + skip-marked specs keep rendering
  • LiveTimeline driven by useMcpCallStream (the local random stream is only used against the HAL0_DATA mock)
  • InstallDrawer catalog reads useMcpCatalog; Install button fires useMcpInstall mutation (501 → toast)
  • LogsDrawer reads useMcpServerLogs; sample lines remain as a fresh-install fallback
  • EditConfigModal Save fires useMcpConfigPatch (501 → toast)

Sidebar (chrome.jsx)

  • Adds the MCP nav item so the page is reachable without typing the URL fragment

STUB list (pending ADR-0013 mcp_client.py)

  • POST /api/mcp/install
  • DELETE /api/mcp/{id}
  • POST /api/mcp/{id}/{action} (start/stop/restart)
  • PATCH /api/mcp/{id}/config

All return 501 with envelope {error: {code: "mcp.not_implemented", message: "... pending ADR-0013 follow-up (#206)"}}. Follow-up issue will track the actual lifecycle work.

Test plan

  • uv run pytest tests/api/test_mcp_routes.py -v — 11 pass
  • uv run pytest tests/api/ --tb=short — 338 pass, 3 pre-existing skips
  • uv run ruff format --check && uv run ruff check — clean
  • npx tsc --noEmit — clean
  • npm run build — clean
  • npx playwright test — 38 pass, 15 pre-existing skips
  • npx playwright test specs/mcp-v3-wired.spec.ts — 5/5 pass (new spec)

🤖 Generated with Claude Code

…on + audit-log SSE (closes #206)

Replaces the v3 dashboard's HAL0_DATA-driven /agents/mcp page with live
queries against new /api/mcp/* routes.

Backend (src/hal0/api/routes/mcp.py + mcp_mount.py)
  - GET /api/mcp/servers — introspects app.state.mcp_servers
    (FastMCP instances) for tool/resource/prompt counts
  - GET /api/mcp/clients — derives connected clients from the
    hal0.mcp.audit journald stream
  - GET /api/mcp/catalog — static module-level installable list
  - GET /api/mcp/stream — SSE tail of mcp.tool.* audit events
  - GET /api/mcp/{id}/logs — per-server audit rows
  - POST /api/mcp/install + DELETE /api/mcp/{id} + POST
    /api/mcp/{id}/{action} + PATCH /api/mcp/{id}/config — STUB 501
    with code mcp.not_implemented pending ADR-0013 mcp_client.py work

mcp_mount.py exports the live FastMCP instances on
app.state.mcp_servers so the introspection route can call
server.list_tools() etc. without re-importing the builders.

Frontend (ui/src/api/hooks/useMcp.ts)
  - useMcpServers / useMcpClients / useMcpCatalog — TanStack Query
    hooks with mock fallback on 404 (matches useAgentMcpClients
    pattern)
  - useMcpCallStream — EventSource against /api/mcp/stream, returns
    {calls, now} matching the existing useLiveCallStream shape so
    LiveTimeline render is unchanged
  - useMcpInstall / useMcpUninstall / useMcpRestart /
    useMcpConfigPatch / useMcpServerLogs — mutations that catch 501
    and surface the ADR-0013 toast

mcp.jsx + mcp-modals.jsx
  - McpView reads useMcpServers / useMcpClients; falls back to
    HAL0_DATA mock when live returns empty so prototype demo + skip-
    marked specs keep rendering
  - LiveTimeline driven by useMcpCallStream (local random stream only
    used against HAL0_DATA mock)
  - InstallDrawer catalog reads useMcpCatalog; Install button fires
    useMcpInstall mutation (501 → toast)
  - LogsDrawer reads useMcpServerLogs; falls back to sample lines
    against fresh install
  - EditConfigModal Save fires useMcpConfigPatch (501 → toast)

Sidebar nav (chrome.jsx)
  - Adds MCP item to the sidebar so the page is reachable without
    typing the URL fragment

Tests
  - tests/api/test_mcp_routes.py — 11 tests covering the 4 GET
    endpoints + 4 stub 501s (all pass)
  - ui/tests/e2e/specs/mcp-v3-wired.spec.ts — 5 specs covering
    server list, clients ribbon, KPI count, catalog drawer, and the
    501-stub toast path (all pass)

Follow-up: separate issue tracks the install/uninstall/config
lifecycle (ADR-0013's mcp_client.py work).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thinmintdev thinmintdev merged commit d510ceb into main May 24, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v3: wire MCP page (/agents/mcp) to real backend

1 participant