Skip to main content
Glama
amittell

firewalla-mcp-server

get_alarm_trends

Analyze historical alarm trend data to track daily alarm frequency for Firewalla MSP firewall integration, aiding in network security monitoring and analysis.

Instructions

Get historical alarm trend data (alarms generated per day)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
groupNoGet trends for a specific box group

Implementation Reference

  • The GetAlarmTrendsHandler class implements the core tool logic. It validates the optional 'period' parameter (default '24h'), calls firewalla.getAlarmTrends(), processes the trends data with validation and normalization, computes summary statistics (total alarms, average, peak, frequency), and returns a structured ToolResponse.
    export class GetAlarmTrendsHandler extends BaseToolHandler { name = 'get_alarm_trends'; description = 'Get historical alarm data trends over time with configurable periods. Optional period parameter. Data cached for 1 hour for performance.'; category = 'analytics' as const; constructor() { super({ enableGeoEnrichment: false, // No IP fields in alarm trends enableFieldNormalization: true, additionalMeta: { data_source: 'alarm_trends', entity_type: 'historical_alarm_data', supports_geographic_enrichment: false, supports_field_normalization: true, standardization_version: '2.0.0', }, }); } async execute( _args: ToolArgs, firewalla: FirewallaClient ): Promise<ToolResponse> { try { const periodValidation = ParameterValidator.validateEnum( _args?.period, 'period', ['1h', '24h', '7d', '30d'], false, '24h' ); if (!periodValidation.isValid) { return this.createErrorResponse( 'Parameter validation failed', ErrorType.VALIDATION_ERROR, undefined, periodValidation.errors ); } const period = periodValidation.sanitizedValue!; const trends = await withToolTimeout( async () => firewalla.getAlarmTrends(period as '1h' | '24h' | '7d' | '30d'), this.name ); // Defensive programming: validate trends response structure if ( !trends || !SafeAccess.getNestedValue(trends, 'results') || !Array.isArray(trends.results) ) { return this.createSuccessResponse({ period, data_points: 0, trends: [], summary: { total_alarms: 0, avg_alarms_per_interval: 0, peak_alarm_count: 0, intervals_with_alarms: 0, alarm_frequency: 0, }, error: 'Invalid alarm trends data received', }); } // Validate individual trend entries const validTrends = SafeAccess.safeArrayFilter( trends.results, (trend: any) => trend && typeof SafeAccess.getNestedValue(trend, 'ts') === 'number' && typeof SafeAccess.getNestedValue(trend, 'value') === 'number' && (SafeAccess.getNestedValue(trend, 'ts', 0) as number) > 0 && (SafeAccess.getNestedValue(trend, 'value', 0) as number) >= 0 ); const startTime = Date.now(); const unifiedResponseData = { period, data_points: validTrends.length, trends: SafeAccess.safeArrayMap(validTrends, (trend: any) => ({ timestamp: SafeAccess.getNestedValue(trend, 'ts', 0), timestamp_iso: unixToISOString( SafeAccess.getNestedValue(trend, 'ts', 0) as number ), alarm_count: SafeAccess.getNestedValue(trend, 'value', 0), })), summary: { total_alarms: validTrends.reduce( (sum: number, t: any) => sum + (SafeAccess.getNestedValue(t, 'value', 0) as number), 0 ), avg_alarms_per_interval: validTrends.length > 0 ? Math.round( (validTrends.reduce( (sum: number, t: any) => sum + (SafeAccess.getNestedValue(t, 'value', 0) as number), 0 ) / validTrends.length) * 100 ) / 100 : 0, // Performance Buffer Strategy: Same defensive slicing as flow trends // to prevent call stack overflow with large alarm trend datasets peak_alarm_count: validTrends.length > 0 ? Math.max( ...validTrends .slice(0, 1000) // Defensive limit to prevent call stack overflow .map( (t: any) => SafeAccess.getNestedValue(t, 'value', 0) as number ) ) : 0, intervals_with_alarms: SafeAccess.safeArrayFilter( validTrends, (t: any) => (SafeAccess.getNestedValue(t, 'value', 0) as number) > 0 ).length, alarm_frequency: validTrends.length > 0 ? Math.round( (SafeAccess.safeArrayFilter( validTrends, (t: any) => (SafeAccess.getNestedValue(t, 'value', 0) as number) > 0 ).length / validTrends.length) * 100 ) : 0, }, }; const executionTime = Date.now() - startTime; return this.createUnifiedResponse(unifiedResponseData, { executionTimeMs: executionTime, }); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return this.createErrorResponse( `Failed to get alarm trends: ${errorMessage}`, ErrorType.API_ERROR ); } } }
  • MCP tool schema definition in ListTools response, specifying the tool name, description, and input schema (optional 'group' parameter). Note: handler also supports 'period' parameter not listed here.
    name: 'get_alarm_trends', description: 'Get historical alarm trend data (alarms generated per day)', inputSchema: { type: 'object', properties: { group: { type: 'string', description: 'Get trends for a specific box group', }, }, required: [], }, },
  • Registration of the GetAlarmTrendsHandler in the central ToolRegistry during construction.
    this.register(new GetAlarmTrendsHandler());

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