radql_query_builder
Build RadQL queries programmatically from structured conditions to construct complex filter or stats queries for security data analysis in Kubernetes and cloud environments.
Instructions
Helper tool to build RadQL queries programmatically from structured conditions. Useful when you need to construct complex filter or stats queries from structured inputs.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| data_type | Yes | The data type to build a query for | |
| conditions | No | Filter conditions to combine into a RadQL query | |
| logic | No | Logical operator to combine conditions | AND |
| aggregation | No | Aggregation function to apply | |
| aggregate_field | No | Field to aggregate (omit for count(*)) | |
| group_by | No | Fields to group by | |
| time_group | No | Time-based grouping interval for datetime fields |
Implementation Reference
- src/index.ts:637-642 (registration)Registration of the 'radql_query_builder' tool in the MCP server, defining its name, description, and input schema.{ name: "radql_query_builder", description: "Helper tool to build RadQL queries programmatically from structured conditions. Useful when you need to construct complex filter or stats queries from structured inputs.", inputSchema: zodToJsonSchema(radql.RadQLQueryBuilderSchema), },
- src/index.ts:1574-1583 (handler)MCP tool dispatch handler that parses arguments using the schema and calls the buildRadQLQuery function.case "radql_query_builder": { const args = radql.RadQLQueryBuilderSchema.parse( request.params.arguments ); const response = radql.buildRadQLQuery(args); return { content: [ { type: "text", text: JSON.stringify(response, null, 2) }, ], };
- src/operations/radql.ts:73-99 (schema)Zod schema defining the input parameters for the radql_query_builder tool.export const RadQLQueryBuilderSchema = z.object({ data_type: z.string() .describe("The data type to build a query for"), conditions: z.array(z.object({ field: z.string(), operator: z.enum([":", "=", "!=", "!:", "<>", ">", ">=", "<", "<=", "contains", "starts_with", "ends_with"]), value: z.union([z.string(), z.number(), z.boolean()]), negate: z.boolean().optional() })).optional() .describe("Filter conditions to combine into a RadQL query"), logic: z.enum(["AND", "OR"]).optional().default("AND") .describe("Logical operator to combine conditions"), aggregation: z.enum(["count", "sum", "avg", "min", "max", "median"]).optional() .describe("Aggregation function to apply"), aggregate_field: z.string().optional() .describe("Field to aggregate (omit for count(*))"), group_by: z.array(z.string()).optional() .describe("Fields to group by"), time_group: z.enum(["second", "minute", "hour", "day", "month", "year"]).optional() .describe("Time-based grouping interval for datetime fields") });
- src/operations/radql.ts:334-432 (handler)Core handler function that implements the tool logic: constructs RadQL filters_query and stats_query from structured conditions, handling operators, quoting rules for special cases (dates, hyphens, wildcards), aggregations, and grouping.export function buildRadQLQuery( args: z.infer<typeof RadQLQueryBuilderSchema> ): { filters_query?: string; stats_query?: string } { const result: { filters_query?: string; stats_query?: string } = {}; if (args.conditions && args.conditions.length > 0) { const conditions = args.conditions.map(cond => { let query = ""; if (cond.negate) { query += "NOT "; } query += cond.field; // Map operator to RadQL syntax if (cond.operator === "contains") { // Quote wildcard values if they contain special characters const needsQuoting = typeof cond.value === "string" && ( cond.value.includes("-") || cond.value.includes(" ") || cond.value.includes(":") ); const valueStr = needsQuoting ? `"*${cond.value}*"` : `*${cond.value}*`; query += `:${valueStr}`; } else if (cond.operator === "starts_with") { const needsQuoting = typeof cond.value === "string" && ( cond.value.includes("-") || cond.value.includes(" ") || cond.value.includes(":") ); const valueStr = needsQuoting ? `"${cond.value}*"` : `${cond.value}*`; query += `:${valueStr}`; } else if (cond.operator === "ends_with") { const needsQuoting = typeof cond.value === "string" && ( cond.value.includes("-") || cond.value.includes(" ") || cond.value.includes(":") ); const valueStr = needsQuoting ? `"*${cond.value}"` : `*${cond.value}`; query += `:${valueStr}`; } else { // Quote string values to handle dates, hyphens, and special characters // The RadQL parser requires quoting for: // - Dates/timestamps (contain hyphens): "2024-01-01" // - UUIDs (contain hyphens): "550e8400-e29b-41d4-a716-446655440000" // - Strings with special characters: colons, spaces, etc. // - Any value that's not a simple alphanumeric string const value = cond.value; let valueStr: string; if (typeof value === "string") { // Check if the string needs quoting // Quote if it contains: spaces, hyphens, colons, or other special chars // Or if it looks like a date/timestamp const needsQuoting = value.includes(" ") || value.includes("-") || value.includes(":") || value.includes("(") || value.includes(")") || /^\d{4}-\d{2}-\d{2}/.test(value) || /[<>=!]/.test(value); valueStr = needsQuoting ? `"${value}"` : value; } else { valueStr = String(value); } query += `${cond.operator}${valueStr}`; } return query; }); result.filters_query = conditions.join(` ${args.logic} `); } if (args.aggregation) { let statsQuery = ""; if (args.aggregation === "count") { statsQuery = args.aggregate_field ? `count(${args.aggregate_field})` : "count()"; } else { if (!args.aggregate_field) { throw new Error(`${args.aggregation} requires an aggregate_field`); } statsQuery = `${args.aggregation}(${args.aggregate_field})`; } if (args.group_by && args.group_by.length > 0) { const groupByFields = args.group_by.map(field => { if (args.time_group && (field.includes("_at") || field.includes("timestamp") || field.includes("time"))) { return `${args.time_group}(${field})`; } return field; }); statsQuery += ` by ${groupByFields.join(", ")}`; } result.stats_query = statsQuery; } return result; }