// frontend/components/AdminTabs/mcp/ServerCard.jsx // One installed MCP server. Collapsed shows summary + actions; expanded // reveals the per-tool list with risk badges and individual toggles. import React, { useState } from "react"; import ToolRow from "./ToolRow.jsx"; const RISK_PALETTE = { low: { bg: "#0f3a26", border: "#1f5a3e", text: "#86efac" }, medium: { bg: "#3a2e0f", border: "#5a4a1f", text: "#fcd34d" }, high: { bg: "#3a0f0f", border: "#5a1f1f", text: "#fca5a5" }, }; export default function ServerCard({ server, onEnable, onDisable, onUninstall, onTest, onToggleTool, onForget, }) { const [expanded, setExpanded] = useState(false); const [testResult, setTestResult] = useState(null); const [testing, setTesting] = useState(false); const handleTest = async () => { setTesting(true); try { const result = await onTest(); setTestResult(result); } finally { setTesting(false); } }; const statusDot = server.enabled ? "#10b981" : "#6b7280"; const statusLabel = server.enabled ? "Enabled" : "Disabled"; // Risk roll-up shown next to the tool count. const riskCounts = server.tools?.reduce( (acc, t) => ({ ...acc, [t.risk]: (acc[t.risk] || 0) + 1 }), {} ) || {}; return (
{server.id} {statusLabel} {!server.is_known && ( custom )} {server.orphan && ( orphan )} {server.source === "forge-sync" && !server.orphan && ( via sync )}
{server.description || "—"}
{server.endpoint || "—"}
{(server.tags || []).map((t) => ( {t} ))}
{server.enabled ? ( Disable ) : ( Enable )} {testing ? "Testing…" : "Test"} {onForget ? ( Forget ) : ( Uninstall )}
{server.tool_count} tool{server.tool_count === 1 ? "" : "s"} {Object.entries(riskCounts).map(([risk, count]) => ( {count} {risk} ))}
{testResult && (
{testResult.ok ? "Healthy. Inspector confirmed the server is reachable and advertises its expected tools." : `Failed: ${testResult.reason || testResult.error || "unknown error"}`}
)}
{expanded && (
{server.tools?.length ? ( server.tools.map((t) => ( onToggleTool(t.name, enabled)} /> )) ) : (
No tools advertised by this server.
)}
)}
); } function Btn({ children, variant = "default", ...props }) { const palettes = { default: { bg: "#252634", color: "#e0e0e7", border: "#3a3b4a" }, primary: { bg: "#3B82F6", color: "#fff", border: "#3B82F6" }, ghost: { bg: "transparent", color: "#cdd0d8", border: "#3a3b4a" }, danger: { bg: "transparent", color: "#fca5a5", border: "#5a1f1f" }, }; const p = palettes[variant]; return ( ); }