firewalla-mcp-server
Version:
Model Context Protocol (MCP) server for Firewalla MSP API - Provides real-time network monitoring, security analysis, and firewall management through 28 specialized tools compatible with any MCP client
281 lines • 9.96 kB
JavaScript
import { SecurityManager } from '../config/security';
import { config } from '../config/config';
import { getCurrentTimestamp } from '../utils/timestamp.js';
export class HealthCheckManager {
constructor(firewalla, security) {
this.firewalla = firewalla;
this.startTime = Date.now();
this.security = security || new SecurityManager();
}
async performHealthCheck() {
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,
};
}
async runAllChecks() {
const 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;
}
async checkConfig() {
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,
};
}
}
async checkFirewallaAPI() {
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,
};
}
}
async checkMemoryUsage() {
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,
};
}
}
async checkCacheHealth() {
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,
};
}
}
async checkSecurity() {
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,
};
}
}
determineOverallStatus(checks) {
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() {
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() {
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() {
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',
};
}
}
}
//# sourceMappingURL=endpoints.js.map