Skip to main content
Glama
amittell

firewalla-mcp-server

search_target_lists

Filter and search target lists by name, owner, category, or targets within the Firewalla MSP firewall system using client-side queries for precise results.

Instructions

Search target lists with client-side filtering (convenience wrapper around get_target_lists)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
categoryNoFilter by category
limitNoMaximum number of target lists to return
ownerNoFilter by owner (global or box gid)
queryNoSearch query for target lists. Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:"description text". Examples: "category:social", "owner:global AND name:*Block*", "targets:*.gaming.com"

Implementation Reference

  • SearchTargetListsHandler class: the core MCP tool handler implementing validation (via validateCommonSearchParameters), query execution through searchTools.search_target_lists(), data processing, geographic enrichment (disabled), field normalization, and standardized ToolResponse creation. Wrapper with client-side filtering as noted in registry.
    export class SearchTargetListsHandler extends BaseToolHandler { name = 'search_target_lists'; description = `Target list searching with comprehensive filtering for categories, ownership, and content analysis. Search through Firewalla target lists including domains, IPs, and security categories for policy management and analysis. QUERY EXAMPLES: - Category filtering: "category:ad", "category:social_media", "category:malware" - Ownership: "owner:global", "owner:custom", "owner:user_defined" - Content type: "type:domain", "type:ip", "type:url_pattern" - Size filtering: "target_count:>100", "active_targets:>50" - Status queries: "enabled:true", "updated:>=2024-01-01" TARGET LIST MANAGEMENT: - Ad blocking lists: "category:ad AND enabled:true" - Security lists: "category:malware OR category:phishing OR category:threat" - Social media controls: "category:social_media AND owner:custom" - Custom domain lists: "owner:user_defined AND type:domain" - Large lists analysis: "target_count:>1000 AND category:security" CONTENT ANALYSIS: - Popular categories: group_by:"category" for category distribution - List effectiveness: "hit_count:>0 AND enabled:true" - Maintenance needed: "updated:<=30d AND enabled:true" - Unused lists: "hit_count:0 AND enabled:true" PERFORMANCE CONSIDERATIONS: - Target lists cached for 10 minutes for optimal performance - Use specific category filters for faster searches - Large lists (>10,000 targets) may have slower response times - Aggregate queries provide faster overview statistics FIELD NORMALIZATION: - Categories standardized to lowercase with consistent naming - Target counts validated as non-negative numbers - Timestamps normalized to ISO format - Unknown values replaced with "unknown" for consistency See the Target List Management guide for configuration details.`; category = 'search' as const; constructor() { // Enable field normalization for target lists (no geographic enrichment needed) super({ enableGeoEnrichment: false, // Target lists don't typically contain IP addresses enableFieldNormalization: true, // Ensure consistent snake_case field naming across all responses additionalMeta: { data_source: 'target_lists', entity_type: 'target_lists', supports_geographic_enrichment: false, supports_field_normalization: true, standardization_version: '2.0.0', }, }); } async execute( args: ToolArgs, firewalla: FirewallaClient ): Promise<ToolResponse> { const searchArgs = args as SearchTargetListsArgs; try { // Validate common search parameters const validation = validateCommonSearchParameters( searchArgs, this.name, 'target_lists' ); if (!validation.isValid) { return validation.response; } const searchTools = createSearchTools(firewalla); const searchParams: SearchParams = { query: searchArgs.query, limit: searchArgs.limit, offset: searchArgs.offset, cursor: searchArgs.cursor, sort_by: searchArgs.sort_by, sort_order: searchArgs.sort_order, group_by: searchArgs.group_by, aggregate: searchArgs.aggregate, }; const result = await withToolTimeout( async () => searchTools.search_target_lists(searchParams), this.name ); // Create unified response with standardized target list data const unifiedResponseData = { target_lists: SafeAccess.safeArrayMap( result.results, (list: TargetList) => ({ id: SafeAccess.getNestedValue(list as any, 'id', 'unknown'), name: SafeAccess.getNestedValue( list as any, 'name', 'Unknown List' ), category: SafeAccess.getNestedValue( list as any, 'category', 'unknown' ), owner: SafeAccess.getNestedValue(list as any, 'owner', 'unknown'), entry_count: SafeAccess.safeArrayAccess( list.targets, arr => arr.length, 0 ), }) ), count: SafeAccess.safeArrayAccess( (result as any).results, arr => arr.length, 0 ), query_executed: SafeAccess.getNestedValue(result as any, 'query', ''), execution_time_ms: SafeAccess.getNestedValue( result as any, 'execution_time_ms', 0 ), aggregations: SafeAccess.getNestedValue( result as any, 'aggregations', null ), query_info: { original_query: searchArgs.query, applied_filters: { grouping: !!searchArgs.group_by, sorting: !!searchArgs.sort_by, aggregation: !!searchArgs.aggregate, }, }, }; // Return unified response return this.createUnifiedResponse(unifiedResponseData); } catch (error: unknown) { if (error instanceof TimeoutError) { return createTimeoutErrorResponse(this.name, error.duration, 10000); } const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return createErrorResponse( this.name, `Failed to search target lists: ${errorMessage}`, ErrorType.SEARCH_ERROR ); } } }
  • Registration of the SearchTargetListsHandler instance in ToolRegistry constructor's registerHandlers() method, part of convenience wrappers section.
    this.register(new SearchTargetListsHandler()); // wrapper with client-side filtering
  • Import statement for SearchTargetListsHandler from ./handlers/search.ts (resolved to search.ts)
    SearchFlowsHandler, SearchAlarmsHandler, SearchRulesHandler, SearchDevicesHandler, SearchTargetListsHandler, } from './handlers/search.js';
  • TypeScript interface defining input schema for search_target_lists tool parameters, extending BaseSearchArgs (query: string, limit: number, etc.).
    export interface SearchTargetListsArgs extends BaseSearchArgs {}
  • Limit constant SEARCH_TARGET_LISTS=1000 used in getLimitValidationConfig for parameter validation in search_target_lists (referenced at lines 49,97,164).
    SEARCH_TARGET_LISTS: 1000,
  • Shared validation helper used by SearchTargetListsHandler (and other search handlers) for common parameters: limit (with tool-specific max), query syntax, fields for 'target_lists', cursor, group_by.
    function validateCommonSearchParameters( args: BaseSearchArgs, toolName: string, entityType: 'flows' | 'alarms' | 'rules' | 'devices' | 'target_lists' ): CommonSearchValidationResult { // Validate optional limit parameter with default const limitValidation = ParameterValidator.validateNumber( args.limit, 'limit', { required: false, defaultValue: 200, ...getLimitValidationConfig(toolName), } ); if (!limitValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Parameter validation failed', ErrorType.VALIDATION_ERROR, undefined, limitValidation.errors ), }; } // Validate required query parameter const queryValidation = ParameterValidator.validateRequiredString( args.query, 'query' ); if (!queryValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Query parameter validation failed', ErrorType.VALIDATION_ERROR, undefined, queryValidation.errors ), }; } // Validate query syntax const querySyntaxValidation = validateFirewallaQuerySyntax(args.query); if (!querySyntaxValidation.isValid) { const examples = getExampleQueries(entityType); return { isValid: false, response: createErrorResponse( toolName, 'Invalid query syntax', ErrorType.VALIDATION_ERROR, { query: args.query, syntax_errors: querySyntaxValidation.errors, examples: examples.slice(0, 3), hint: 'Use field:value syntax with logical operators (AND, OR, NOT)', }, querySyntaxValidation.errors ), }; } // Validate field names in the query const fieldValidation = QuerySanitizer.validateQueryFields( args.query, entityType ); if (!fieldValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Query contains invalid field names', ErrorType.VALIDATION_ERROR, { query: args.query, documentation: entityType === 'alarms' ? 'See /docs/error-handling-guide.md for troubleshooting' : 'See /docs/query-syntax-guide.md for valid field names', }, fieldValidation.errors ), }; } // Validate cursor format if provided if (args.cursor !== undefined) { const cursorValidation = ParameterValidator.validateCursor( args.cursor, 'cursor' ); if (!cursorValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Invalid cursor format', ErrorType.VALIDATION_ERROR, undefined, cursorValidation.errors ), }; } } // Validate group_by parameter if provided if (args.group_by !== undefined) { const groupByValidation = ParameterValidator.validateEnum( args.group_by, 'group_by', SEARCH_FIELDS[entityType], false ); if (!groupByValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Invalid group_by field', ErrorType.VALIDATION_ERROR, { group_by: args.group_by, valid_fields: SEARCH_FIELDS[entityType], documentation: 'See /docs/query-syntax-guide.md for valid fields', }, groupByValidation.errors ), }; } } return { isValid: true, limit: args.limit, query: args.query, cursor: args.cursor, groupBy: args.group_by, }; }

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