import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { Server, Activity, CheckCircle, XCircle, AlertTriangle } from 'lucide-react'
import { format } from 'date-fns'
const fetchHealth = async () => {
const response = await fetch('/health')
if (!response.ok) throw new Error('Failed to fetch health')
return response.json()
}
export default function ServerHealth() {
const { data: health, isLoading, isError } = useQuery({
queryKey: ['health'],
queryFn: fetchHealth,
refetchInterval: 5000
})
if (isLoading) {
return (
<div className="px-4 sm:px-6 lg:px-8">
<div className="animate-pulse">
<div className="h-8 bg-gray-300 dark:bg-gray-700 rounded w-1/4 mb-4"></div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{[...Array(6)].map((_, i) => (
<div key={i} className="h-32 bg-gray-300 dark:bg-gray-700 rounded"></div>
))}
</div>
</div>
</div>
)
}
const getStatusIcon = (status: string) => {
switch (status) {
case 'ok':
return <CheckCircle className="w-5 h-5 text-green-600" />
case 'degraded':
return <AlertTriangle className="w-5 h-5 text-yellow-600" />
case 'down':
return <XCircle className="w-5 h-5 text-red-600" />
default:
return <Activity className="w-5 h-5 text-gray-400" />
}
}
const getStatusColor = (status: string) => {
switch (status) {
case 'ok':
return 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-300'
case 'degraded':
return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-300'
case 'down':
return 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-300'
default:
return 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'
}
}
return (
<div className="px-4 sm:px-6 lg:px-8">
<div className="sm:flex sm:items-center">
<div className="sm:flex-auto">
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white">Server Health</h1>
<p className="mt-2 text-sm text-gray-700 dark:text-gray-300">
Monitor the health and performance of your MCP server.
</p>
</div>
</div>
{isError ? (
<div className="mt-8 bg-red-50 dark:bg-red-900/10 border border-red-200 dark:border-red-800 rounded-lg p-6">
<div className="flex items-center">
<XCircle className="w-6 h-6 text-red-600 mr-3" />
<div>
<h3 className="text-lg font-medium text-red-800 dark:text-red-200">
Server Unreachable
</h3>
<p className="mt-1 text-sm text-red-600 dark:text-red-300">
Unable to connect to the MCP server. Please check if the server is running.
</p>
</div>
</div>
</div>
) : (
<>
{/* Overall Status */}
<div className="mt-8">
<div className="bg-white dark:bg-gray-800 shadow rounded-lg border dark:border-gray-700 p-6">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="w-12 h-12 rounded-full bg-indigo-100 dark:bg-indigo-900/20 flex items-center justify-center">
<Server className="w-6 h-6 text-indigo-600" />
</div>
<div>
<h3 className="text-lg font-medium text-gray-900 dark:text-white">
MCP Fullstack Server
</h3>
<div className="flex items-center mt-1">
{getStatusIcon(health?.status || 'unknown')}
<span className={`ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(health?.status || 'unknown')}`}>
{health?.status?.toUpperCase() || 'UNKNOWN'}
</span>
</div>
</div>
</div>
<div className="text-right text-sm text-gray-500 dark:text-gray-400">
<div>Uptime: {Math.floor((health?.server?.uptime || 0) / 3600)}h {Math.floor(((health?.server?.uptime || 0) % 3600) / 60)}m</div>
<div>Running: {health?.server?.running ? 'Yes' : 'No'}</div>
</div>
</div>
</div>
</div>
{/* Registry Stats */}
<div className="mt-8 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
<div className="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg border dark:border-gray-700">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<Activity className="w-6 h-6 text-blue-600" />
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
Total Tools
</dt>
<dd className="text-lg font-semibold text-gray-900 dark:text-white">
{health?.registry?.total_tools || 0}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg border dark:border-gray-700">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<CheckCircle className="w-6 h-6 text-green-600" />
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
Static Tools
</dt>
<dd className="text-lg font-semibold text-gray-900 dark:text-white">
{health?.registry?.static_tools || 0}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg border dark:border-gray-700">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<Activity className="w-6 h-6 text-purple-600" />
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
Session Tools
</dt>
<dd className="text-lg font-semibold text-gray-900 dark:text-white">
{health?.registry?.session_tools || 0}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg border dark:border-gray-700">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<Server className="w-6 h-6 text-orange-600" />
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">
Active Sessions
</dt>
<dd className="text-lg font-semibold text-gray-900 dark:text-white">
{health?.registry?.active_sessions || 0}
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
{/* Environment Status */}
<div className="mt-8">
<div className="bg-white dark:bg-gray-800 shadow rounded-lg border dark:border-gray-700">
<div className="px-6 py-4 border-b dark:border-gray-700">
<h3 className="text-lg font-medium text-gray-900 dark:text-white">
Environment Configuration
</h3>
</div>
<div className="p-6">
<div className="text-sm text-gray-500 dark:text-gray-400 mb-4">
Configuration status for external service integrations
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">WebDriver</span>
<CheckCircle className="w-4 h-4 text-green-500" />
</div>
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">Supabase</span>
<XCircle className="w-4 h-4 text-gray-400" />
</div>
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">Render</span>
<XCircle className="w-4 h-4 text-gray-400" />
</div>
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">Vercel</span>
<XCircle className="w-4 h-4 text-gray-400" />
</div>
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">PostHog</span>
<XCircle className="w-4 h-4 text-gray-400" />
</div>
<div className="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded">
<span className="text-sm font-medium">Gemini</span>
<XCircle className="w-4 h-4 text-gray-400" />
</div>
</div>
</div>
</div>
</div>
</>
)}
</div>
)
}