Skip to main content
Glama

firewalla-mcp-server

endpoints.ts9.39 kB
import type { FirewallaClient } from '../firewalla/client'; import { SecurityManager } from '../config/security'; import { config } from '../config/config'; import { getCurrentTimestamp } from '../utils/timestamp.js'; export interface HealthStatus { status: 'healthy' | 'degraded' | 'unhealthy'; timestamp: string; version: string; uptime: number; checks: Record< string, { status: 'pass' | 'fail' | 'warn'; message?: string; responseTime?: number; details?: Record<string, unknown>; } >; } export class HealthCheckManager { private startTime: number; private security: SecurityManager; constructor( private firewalla: FirewallaClient, security?: SecurityManager ) { this.startTime = Date.now(); this.security = security || new SecurityManager(); } async performHealthCheck(): Promise<HealthStatus> { const checks = await this.runAllChecks(); const overallStatus = this.determineOverallStatus(checks); return { status: overallStatus, timestamp: getCurrentTimestamp(), version: '1.0.0', uptime: Math.floor((Date.now() - this.startTime) / 1000), checks, }; } private async runAllChecks(): Promise<HealthStatus['checks']> { const checks: HealthStatus['checks'] = {}; // Run checks in parallel for better performance const checkPromises = [ this.checkConfig().then(result => ({ key: 'configuration', result })), this.checkFirewallaAPI().then(result => ({ key: 'firewalla_api', result, })), this.checkMemoryUsage().then(result => ({ key: 'memory', result })), this.checkCacheHealth().then(result => ({ key: 'cache', result })), this.checkSecurity().then(result => ({ key: 'security', result })), ]; const results = await Promise.allSettled(checkPromises); results.forEach((result, index) => { if (result.status === 'fulfilled' && result.value) { checks[result.value.key] = result.value.result; } else { const checkNames = [ 'configuration', 'firewalla_api', 'memory', 'cache', 'security', ]; checks[checkNames[index] || 'unknown'] = { status: 'fail', message: 'Health check failed to execute', }; } }); return checks; } private async checkConfig(): Promise<HealthStatus['checks'][string]> { const startTime = Date.now(); try { const validation = this.security.validateEnvironmentVars(); const responseTime = Date.now() - startTime; if (!validation.valid) { return { status: 'fail', message: 'Configuration validation failed', responseTime, details: { errors: validation.errors }, }; } return { status: 'pass', message: 'Configuration is valid', responseTime, }; } catch (error) { return { status: 'fail', message: error instanceof Error ? error.message : 'Configuration check failed', responseTime: Date.now() - startTime, }; } } private async checkFirewallaAPI(): Promise<HealthStatus['checks'][string]> { const startTime = Date.now(); try { // Try a lightweight API call to check connectivity await this.firewalla.getFirewallSummary(); const responseTime = Date.now() - startTime; if (responseTime > 5000) { return { status: 'warn', message: 'API response time is slow', responseTime, }; } return { status: 'pass', message: 'Firewalla API is responsive', responseTime, }; } catch (error) { return { status: 'fail', message: error instanceof Error ? error.message : 'API connection failed', responseTime: Date.now() - startTime, }; } } private async checkMemoryUsage(): Promise<HealthStatus['checks'][string]> { const startTime = Date.now(); try { const memUsage = process.memoryUsage(); const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024); const heapTotalMB = Math.round(memUsage.heapTotal / 1024 / 1024); const heapUsagePercent = Math.round( (memUsage.heapUsed / memUsage.heapTotal) * 100 ); const responseTime = Date.now() - startTime; if (heapUsedMB > 512) { return { status: 'warn', message: 'High memory usage detected', responseTime, details: { heapUsedMB, heapTotalMB, heapUsagePercent, }, }; } return { status: 'pass', message: 'Memory usage is normal', responseTime, details: { heapUsedMB, heapTotalMB, heapUsagePercent, }, }; } catch { return { status: 'fail', message: 'Memory check failed', responseTime: Date.now() - startTime, }; } } private async checkCacheHealth(): Promise<HealthStatus['checks'][string]> { const startTime = Date.now(); try { const cacheStats = this.firewalla.getCacheStats(); const responseTime = Date.now() - startTime; if (cacheStats.size > 1000) { return { status: 'warn', message: 'Cache size is large', responseTime, details: { cacheSize: cacheStats.size, cacheKeys: cacheStats.keys.length, }, }; } return { status: 'pass', message: 'Cache is healthy', responseTime, details: { cacheSize: cacheStats.size, cacheKeys: cacheStats.keys.length, }, }; } catch { return { status: 'fail', message: 'Cache check failed', responseTime: Date.now() - startTime, }; } } private async checkSecurity(): Promise<HealthStatus['checks'][string]> { const startTime = Date.now(); try { // Check rate limiting functionality const testClientId = 'health-check-test'; const rateLimitWorking = this.security.checkRateLimit(testClientId); // Check input validation const validationWorking = this.security.validateInput('test input'); const responseTime = Date.now() - startTime; if (!rateLimitWorking || !validationWorking) { return { status: 'fail', message: 'Security checks failed', responseTime, details: { rateLimitWorking, validationWorking, }, }; } return { status: 'pass', message: 'Security systems are operational', responseTime, }; } catch { return { status: 'fail', message: 'Security check failed', responseTime: Date.now() - startTime, }; } } private determineOverallStatus( checks: HealthStatus['checks'] ): HealthStatus['status'] { const statuses = Object.values(checks).map(check => check.status); if (statuses.includes('fail')) { return 'unhealthy'; } if (statuses.includes('warn')) { return 'degraded'; } return 'healthy'; } async getDetailedStatus(): Promise<{ health: HealthStatus; metrics: { firewalla_cache_size: number; memory_heap_used_mb: number; uptime_seconds: number; last_api_response_time_ms?: number; }; }> { const health = await this.performHealthCheck(); const memUsage = process.memoryUsage(); const cacheStats = this.firewalla.getCacheStats(); return { health, metrics: { firewalla_cache_size: cacheStats.size, memory_heap_used_mb: Math.round(memUsage.heapUsed / 1024 / 1024), uptime_seconds: Math.floor((Date.now() - this.startTime) / 1000), ...(health.checks.firewalla_api?.responseTime && { last_api_response_time_ms: health.checks.firewalla_api.responseTime, }), }, }; } getReadinessStatus(): { ready: boolean; reason?: string } { try { // Check if essential services are configured if (!config.mspToken || !config.boxId) { return { ready: false, reason: 'Missing required configuration' }; } // Check if we can validate environment const validation = this.security.validateEnvironmentVars(); if (!validation.valid) { return { ready: false, reason: 'Invalid environment configuration' }; } return { ready: true }; } catch (error) { return { ready: false, reason: error instanceof Error ? error.message : 'Readiness check failed', }; } } getLivenessStatus(): { alive: boolean; reason?: string } { try { // Basic liveness checks const memUsage = process.memoryUsage(); const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024); // Check if memory usage is reasonable (less than 1GB) if (heapUsedMB > 1024) { return { alive: false, reason: 'Memory usage too high' }; } return { alive: true }; } catch (error) { return { alive: false, reason: error instanceof Error ? error.message : 'Liveness check failed', }; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/amittell/firewalla-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server