Skip to main content
Glama

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
NameRequiredDescriptionDefault
data_typeYesThe data type to build a query for
conditionsNoFilter conditions to combine into a RadQL query
logicNoLogical operator to combine conditionsAND
aggregationNoAggregation function to apply
aggregate_fieldNoField to aggregate (omit for count(*))
group_byNoFields to group by
time_groupNoTime-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), },
  • 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) }, ], };
  • 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") });
  • 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; }

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/rad-security/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server