feat(api+dash): wire MCP page to real backend (closes #206)#304
Merged
Conversation
…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>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the v3 dashboard's HAL0_DATA-driven
/agents/mcppage with live queries against new/api/mcp/*routes. Closes #206.Backend (new —
src/hal0/api/routes/mcp.py)GET /api/mcp/servers— introspectsapp.state.mcp_servers(FastMCP instances) for tool/resource/prompt counts; returns connect_url + audit-derivedactivity.rpmandconnectedclientsGET /api/mcp/clients— derives connected clients from thehal0.mcp.auditjournald stream (grouped byclient_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 ofmcp.tool.*audit events; backfills last 60 s on subscribeGET /api/mcp/{id}/logs— per-server audit rows for the LogsDrawerPOST /api/mcp/install+DELETE /api/mcp/{id}+POST /api/mcp/{id}/{action}+PATCH /api/mcp/{id}/config— STUB 501 with codemcp.not_implementedpending ADR-0013mcp_client.pyworkmcp_mount.pynow stashes the live FastMCP instances onapp.state.mcp_serversso the introspection route can callserver.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 fallbackuseMcpCallStream— EventSource against/api/mcp/stream, returns{calls, now}matching the existinguseLiveCallStreamshape so the LiveTimeline render is unchangeduseMcpInstall/useMcpUninstall/useMcpRestart/useMcpConfigPatch/useMcpServerLogs— mutations that catch 501 and surface the ADR-0013 toastPage wiring (
mcp.jsx+mcp-modals.jsx)McpViewreadsuseMcpServers/useMcpClients; falls back toHAL0_DATAmock when live returns empty so the prototype demo + skip-marked specs keep renderinguseMcpCallStream(the local random stream is only used against theHAL0_DATAmock)InstallDrawercatalog readsuseMcpCatalog; Install button firesuseMcpInstallmutation (501 → toast)LogsDrawerreadsuseMcpServerLogs; sample lines remain as a fresh-install fallbackEditConfigModalSave firesuseMcpConfigPatch(501 → toast)Sidebar (
chrome.jsx)STUB list (pending ADR-0013 mcp_client.py)
POST /api/mcp/installDELETE /api/mcp/{id}POST /api/mcp/{id}/{action}(start/stop/restart)PATCH /api/mcp/{id}/configAll return
501with 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 passuv run pytest tests/api/ --tb=short— 338 pass, 3 pre-existing skipsuv run ruff format --check && uv run ruff check— cleannpx tsc --noEmit— cleannpm run build— cleannpx playwright test— 38 pass, 15 pre-existing skipsnpx playwright test specs/mcp-v3-wired.spec.ts— 5/5 pass (new spec)🤖 Generated with Claude Code