Skip to main content
Glama

firewalla-mcp-server

boolean-field-translator.ts9.79 kB
/** * Boolean Field Translator for Firewalla MCP Server * * Translates boolean field queries to backend-compatible format. * * The Firewalla API backend has limitations with boolean syntax: * - "blocked:true" fails with "Bad Request: Invalid parameters" * - "protocol:tcp" works fine * * This utility translates boolean field patterns to formats the backend accepts. */ /** * Configuration for boolean field translation */ interface BooleanFieldConfig { /** Fields that should be translated from boolean syntax */ booleanFields: string[]; /** Translation mapping: true/false to backend values */ translations: { true: string; false: string; }; } /** * Entity-specific boolean field configurations */ const BOOLEAN_FIELD_CONFIGS: Record<string, BooleanFieldConfig> = { flows: { booleanFields: ['blocked', 'allowed', 'encrypted', 'compressed'], translations: { true: '1', false: '0', }, }, alarms: { booleanFields: ['resolved', 'acknowledged', 'dismissed', 'active'], translations: { true: '1', false: '0', }, }, rules: { booleanFields: ['active', 'enabled', 'disabled', 'paused'], translations: { true: '1', false: '0', }, }, devices: { booleanFields: ['online', 'monitored', 'blocked', 'trusted'], translations: { true: '1', false: '0', }, }, }; /** * Alternative translation formats to try if primary format fails */ const ALTERNATIVE_FORMATS = [ { true: 'true', false: 'false' }, // Lowercase boolean strings { true: 'True', false: 'False' }, // Capitalized boolean strings { true: 'yes', false: 'no' }, // Yes/no format { true: 'on', false: 'off' }, // On/off format ]; /** * Boolean field translator utility class */ export class BooleanFieldTranslator { /** * Translate boolean field queries to backend-compatible format * * @param query - Original query string (e.g., "blocked:true AND protocol:tcp") * @param entityType - Entity type for field configuration * @returns Translated query string */ static translateQuery(query: string, entityType: string): string { if (!query || typeof query !== 'string') { return query; } const config = BOOLEAN_FIELD_CONFIGS[entityType]; if (!config) { // No translation needed for unknown entity types return query; } let translatedQuery = query; // First pass: Convert "field=true/false" syntax to "field:true/false" for standardization for (const field of config.booleanFields) { const equalsPattern = new RegExp(`\\b${field}=(true|false)\\b`, 'gi'); translatedQuery = translatedQuery.replace( equalsPattern, (_match, boolValue) => { return `${field}:${boolValue}`; } ); } // Second pass: Process each boolean field for this entity type (now all use colon syntax) for (const field of config.booleanFields) { // Match patterns like "field:true" or "field:false" (case insensitive) const booleanPattern = new RegExp(`\\b${field}:(true|false)\\b`, 'gi'); translatedQuery = translatedQuery.replace( booleanPattern, (_match, boolValue) => { const lowerBoolValue = boolValue.toLowerCase() as 'true' | 'false'; const translatedValue = config.translations[lowerBoolValue]; return `${field}:${translatedValue}`; } ); } // Third pass: Handle standalone boolean fields (e.g., "blocked" means "blocked:true") for (const field of config.booleanFields) { // Match standalone field names that aren't already part of a field:value pair // Use negative lookbehind and lookahead to avoid matching fields that are already qualified const standalonePattern = new RegExp(`\\b${field}\\b(?!\\s*[:=])`, 'gi'); translatedQuery = translatedQuery.replace(standalonePattern, _match => { const trueValue = config.translations.true; return `${field}:${trueValue}`; }); } return translatedQuery; } /** * Check if a query contains boolean field syntax that needs translation * * @param query - Query string to check * @param entityType - Entity type for field configuration * @returns True if translation is needed */ static needsTranslation(query: string, entityType: string): boolean { if (!query || typeof query !== 'string') { return false; } const config = BOOLEAN_FIELD_CONFIGS[entityType]; if (!config) { return false; } // Check if any boolean field patterns are present (: syntax, = syntax, or standalone) for (const field of config.booleanFields) { const colonPattern = new RegExp(`\\b${field}:(true|false)\\b`, 'i'); const equalsPattern = new RegExp(`\\b${field}=(true|false)\\b`, 'i'); const standalonePattern = new RegExp(`\\b${field}\\b(?!\\s*[:=])`, 'i'); if ( colonPattern.test(query) || equalsPattern.test(query) || standalonePattern.test(query) ) { return true; } } return false; } /** * Get all alternative translation formats for a query * Useful for fallback attempts if primary translation fails * * @param query - Original query string * @param entityType - Entity type for field configuration * @returns Array of alternative translated queries */ static getAlternativeTranslations( query: string, entityType: string ): string[] { if (!this.needsTranslation(query, entityType)) { return [query]; } const config = BOOLEAN_FIELD_CONFIGS[entityType]; if (!config) { return [query]; } const alternatives: string[] = []; // Add primary translation alternatives.push(this.translateQuery(query, entityType)); // Add original query (for reference and fallback) alternatives.push(query); // Add original query with lowercase boolean values (this is often expected by tests) let lowercaseQuery = query; for (const field of config.booleanFields) { const booleanPattern = new RegExp(`\\b${field}:(true|false)\\b`, 'gi'); lowercaseQuery = lowercaseQuery.replace( booleanPattern, (_match, boolValue) => { const lowerBoolValue = boolValue.toLowerCase(); return `${field}:${lowerBoolValue}`; } ); } if (lowercaseQuery !== query) { alternatives.push(lowercaseQuery); } // Add alternative format translations for (const altFormat of ALTERNATIVE_FORMATS) { let altQuery = query; for (const field of config.booleanFields) { const booleanPattern = new RegExp(`\\b${field}:(true|false)\\b`, 'gi'); altQuery = altQuery.replace(booleanPattern, (_match, boolValue) => { const lowerBoolValue = boolValue.toLowerCase() as 'true' | 'false'; const translatedValue = altFormat[lowerBoolValue]; return `${field}:${translatedValue}`; }); } if (altQuery !== query && altQuery !== lowercaseQuery) { alternatives.push(altQuery); } } // Remove duplicates while preserving order return [...new Set(alternatives)]; } /** * Get debug information about boolean field translation * * @param query - Original query string * @param entityType - Entity type * @returns Debug information object */ static getTranslationDebugInfo( query: string, entityType: string ): { originalQuery: string; translatedQuery: string; needsTranslation: boolean; entityType: string; detectedBooleanFields: string[]; alternativeTranslations: string[]; } { const needsTranslation = this.needsTranslation(query, entityType); const translatedQuery = this.translateQuery(query, entityType); const alternatives = this.getAlternativeTranslations(query, entityType); const config = BOOLEAN_FIELD_CONFIGS[entityType]; const detectedBooleanFields: string[] = []; if (config) { for (const field of config.booleanFields) { const colonPattern = new RegExp(`\\b${field}:(true|false)\\b`, 'i'); const equalsPattern = new RegExp(`\\b${field}=(true|false)\\b`, 'i'); const standalonePattern = new RegExp(`\\b${field}\\b(?!\\s*[:=])`, 'i'); if ( colonPattern.test(query) || equalsPattern.test(query) || standalonePattern.test(query) ) { detectedBooleanFields.push(field); } } } return { originalQuery: query, translatedQuery, needsTranslation, entityType, detectedBooleanFields, alternativeTranslations: alternatives, }; } /** * Add support for new boolean fields at runtime * * @param entityType - Entity type to update * @param fields - Additional boolean fields to support */ static addBooleanFields(entityType: string, fields: string[]): void { if (!BOOLEAN_FIELD_CONFIGS[entityType]) { BOOLEAN_FIELD_CONFIGS[entityType] = { booleanFields: [], translations: { true: '1', false: '0' }, }; } // Add new fields, avoiding duplicates const existingFields = new Set( BOOLEAN_FIELD_CONFIGS[entityType].booleanFields ); for (const field of fields) { if (!existingFields.has(field)) { BOOLEAN_FIELD_CONFIGS[entityType].booleanFields.push(field); } } } /** * Get supported boolean fields for an entity type * * @param entityType - Entity type to query * @returns Array of supported boolean field names */ static getSupportedBooleanFields(entityType: string): string[] { const config = BOOLEAN_FIELD_CONFIGS[entityType]; return config ? [...config.booleanFields] : []; } }

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