/** * MCP Audit — logs and analyzes MCP tool calls per agent. * * Tracks every tool invocation with success/failure, duration, and error detail. * Provides aggregated stats for efficiency dashboards. */ import { getDatabase } from '@/lib/db' export interface McpCallInput { agentName?: string mcpServer?: string toolName?: string success?: boolean durationMs?: number error?: string workspaceId?: number } export interface McpCallStats { totalCalls: number successCount: number failureCount: number successRate: number avgDurationMs: number toolBreakdown: Array<{ toolName: string mcpServer: string calls: number successes: number failures: number avgDurationMs: number }> } export function logMcpCall(input: McpCallInput): number { const db = getDatabase() const result = db.prepare(` INSERT INTO mcp_call_log (agent_name, mcp_server, tool_name, success, duration_ms, error, workspace_id) VALUES (?, ?, ?, ?, ?, ?, ?) `).run( input.agentName ?? null, input.mcpServer ?? null, input.toolName ?? null, input.success !== false ? 1 : 0, input.durationMs ?? null, input.error ?? null, input.workspaceId ?? 1, ) return result.lastInsertRowid as number } export function getMcpCallStats( agentName: string, hours: number = 24, workspaceId: number = 1, ): McpCallStats { const db = getDatabase() const since = Math.floor(Date.now() / 1000) - hours * 3600 const totals = db.prepare(` SELECT COUNT(*) as total, SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successes, SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failures, AVG(duration_ms) as avg_duration FROM mcp_call_log WHERE agent_name = ? AND workspace_id = ? AND created_at > ? `).get(agentName, workspaceId, since) as any const breakdown = db.prepare(` SELECT tool_name, mcp_server, COUNT(*) as calls, SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successes, SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failures, AVG(duration_ms) as avg_duration FROM mcp_call_log WHERE agent_name = ? AND workspace_id = ? AND created_at > ? GROUP BY tool_name, mcp_server ORDER BY calls DESC `).all(agentName, workspaceId, since) as any[] const total = totals?.total ?? 0 const successCount = totals?.successes ?? 0 const failureCount = totals?.failures ?? 0 return { totalCalls: total, successCount, failureCount, successRate: total > 0 ? Math.round((successCount / total) * 10000) / 100 : 100, avgDurationMs: Math.round(totals?.avg_duration ?? 0), toolBreakdown: breakdown.map((row: any) => ({ toolName: row.tool_name ?? 'unknown', mcpServer: row.mcp_server ?? 'unknown', calls: row.calls, successes: row.successes, failures: row.failures, avgDurationMs: Math.round(row.avg_duration ?? 0), })), } }