MCP telemetry: per-call logging, aggregation route, and admin dashboard
Gadoes adds end-to-end observability for MCP tool calls: a 17-line `mcp_events` migration, telemetry logging inside `McpClientManager.callTool()`, a `GET /admin/mcp-telemetry` aggregation endpoint, and a Next.js admin page that auto-refreshes every 60 seconds.
Schema (migration 005). mcp_events stores user_id, source, tool, latency_ms, cache_hit, success, error_type, and created_at. Two indexes: one on created_at, one on source. The table is intentionally lightweight - no FK to chat_messages, no payload storage.
Logging. McpClientManager.callTool() gains an optional { userId, db } options argument. When provided, it inserts a row after each call with latency and success/error outcome. The chatTools.ts call site is updated to pass those values through. A source_unavailable SSE event is also emitted when the circuit is open, so the frontend can surface a per-source degradation message without waiting for a timeout.
Aggregation route. GET /admin/mcp-telemetry at routes/admin.ts (71 lines) queries mcp_events and returns per-source aggregates: total_calls, success_rate, avg_latency_ms, cache_hit_rate, errors_24h. Gated by the is_admin column added in Chunk 6.
Dashboard. The Next.js page at /admin/mcp-telemetry renders a table of those aggregates and re-fetches every 60 seconds via setInterval. Sample data in the test shows courtlistener at 340ms average latency and EUR-Lex at 820ms.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?