ClickStack observability MCP server for querying logs, metrics, traces, and
sessions, and for managing dashboards, alerts, sources, and saved searches.
TOOL SELECTION POLICY — read before querying:
Default to the builder query tools. They are more reliable and produce
structured, chart-ready results:
• clickstack_table — aggregations, top-N, single-value KPIs, breakdowns
• clickstack_timeseries — trends / metrics over time
• clickstack_search — browsing individual log/trace rows
• clickstack_event_patterns — recurring log/event pattern discovery
• clickstack_event_deltas — attributes that differ between two row groups
• clickstack_emerging_signals — patterns new or gone vs a baseline window
• clickstack_trace_waterfall — one trace as a parent/child span tree
• clickstack_trace_top_time_consuming_operations — slowest child operations in a trace
Do NOT reach for clickstack_sql first. Raw SQL is a last resort, reserved for
queries the builder tools genuinely cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
A single-source aggregation, top-N, time-series, or row browse must always
use a builder tool.
Discovery flow: clickstack_list_sources → clickstack_describe_source → query.
Fetch the query_guide prompt for detailed syntax, and create_dashboard for
dashboard authoring.
Protocol
Pass100/10020 / 20 pts
Connection, authentication, and protocol compatibility.
How to fix: On each tool, declare annotations.readOnlyHint, annotations.destructiveHint, and annotations.openWorldHint as booleans. The policy review separately assesses whether their values match the tool's actual behavior.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
List all data sources (logs, metrics, traces) and database connections available to this team. Returns source IDs, names, kinds, and connection IDs as a lightweight catalog. Metric sources additionally include metricNamesPreview — a sample of recently-reported metric names per kind — so metrics can be queried immediately.
NEXT STEP: After identifying the source(s) you need, call clickstack_describe_source with the sourceId to get the full column schema, attribute keys, and sampled values. This two-step approach avoids fetching expensive schema details for sources you do not need.
REQUIRED SOURCE FILTERS: when a source has `requiredSourceFilters`, every query against it MUST supply values for every column in `requiredSourceFilters` via the `sourceFilters` parameter. Call clickstack_get_source_filter_values to discover the available values, or check the sampled `sourceFilterValues` returned by clickstack_describe_source.
NOTE: For most queries, use source IDs with clickstack_timeseries, clickstack_table, clickstack_search, or clickstack_event_patterns. Connection IDs are only needed for clickstack_sql (raw ClickHouse SQL).
Metric sources may list a "summary" table in metricTables. Summary metrics are not supported by the builder tools — use clickstack_sql to look at them.
The description explains the capability, when to use it, and what to expect.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_list_sources",
"title": "List Sources & Connections",
"description": "List all data sources (logs, metrics, traces) and database connections available to this team. Returns source IDs, names, kinds, and connection IDs as a lightweight catalog. Metric sources additionally include metricNamesPreview — a sample of recently-reported metric names per kind — so metrics can be queried immediately.\n\nNEXT STEP: After identifying the source(s) you need, call clickstack_describe_source with the sourceId to get the full column schema, attribute keys, and sampled values. This two-step approach avoids fetching expensive schema details for sources you do not need.\n\nREQUIRED SOURCE FILTERS: when a source has `requiredSourceFilters`, every query against it MUST supply values for every column in `requiredSourceFilters` via the `sourceFilters` parameter. Call clickstack_get_source_filter_values to discover the available values, or check the sampled `sourceFilterValues` returned by clickstack_describe_source.\n\nNOTE: For most queries, use source IDs with clickstack_timeseries, clickstack_table, clickstack_search, or clickstack_event_patterns. Connection IDs are only needed for clickstack_sql (raw ClickHouse SQL).\n\nMetric sources may list a \"summary\" table in metricTables. Summary metrics are not supported by the builder tools — use clickstack_sql to look at them.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description100/100
CALL THIS BEFORE WRITING QUERIES — prevents unknown-column errors.
Returns the full column schema, map-attribute keys, and sampled low-cardinality values (e.g. SeverityText, StatusCode, ServiceName) for a single data source.
Workflow: call clickstack_list_sources first to get source IDs, then call this tool for each source you plan to query.
Returns:
- columns[]: column name, ClickHouse type, and JS type
- mapAttributeKeys: discovered keys in Map columns (e.g. SpanAttributes, ResourceAttributes)
- lowCardinalityValues: sampled values for LowCardinality(String) columns (SeverityText, StatusCode, ServiceName, etc.) — use these in filters instead of guessing
- mapAttributeValues: sampled top values for the most common map attribute keys (e.g. ResourceAttributes['service.name'] top values) — requires rollup tables
- requiredSourceFilters: when present, every query against this source MUST pass `sourceFilters` for each listed column. Sample values for each are returned as `sourceFilterValues` (capped); use clickstack_get_source_filter_values for the full paginated list.
Value sampling stops after 30 seconds. If it is cut short, the result still includes the columns and sets partial: true with skippedStages listing what is missing.
Cost: one describe call prevents 3–5 exploratory queries against non-existent columns.
The description explains the capability, when to use it, and what to expect.
Inputs97/100
Input documentation gives an agent enough context to populate the arguments.
sourceId
The source ID to describe. Get this from clickstack_list_sources.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_describe_source",
"title": "Describe Source Schema",
"description": "CALL THIS BEFORE WRITING QUERIES — prevents unknown-column errors.\n\nReturns the full column schema, map-attribute keys, and sampled low-cardinality values (e.g. SeverityText, StatusCode, ServiceName) for a single data source.\n\nWorkflow: call clickstack_list_sources first to get source IDs, then call this tool for each source you plan to query.\n\nReturns:\n- columns[]: column name, ClickHouse type, and JS type\n- mapAttributeKeys: discovered keys in Map columns (e.g. SpanAttributes, ResourceAttributes)\n- lowCardinalityValues: sampled values for LowCardinality(String) columns (SeverityText, StatusCode, ServiceName, etc.) — use these in filters instead of guessing\n- mapAttributeValues: sampled top values for the most common map attribute keys (e.g. ResourceAttributes['service.name'] top values) — requires rollup tables\n- requiredSourceFilters: when present, every query against this source MUST pass `sourceFilters` for each listed column. Sample values for each are returned as `sourceFilterValues` (capped); use clickstack_get_source_filter_values for the full paginated list.\n\nValue sampling stops after 30 seconds. If it is cut short, the result still includes the columns and sets partial: true with skippedStages listing what is missing.\n\nCost: one describe call prevents 3–5 exploratory queries against non-existent columns.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"sourceId": {
"type": "string",
"description": "The source ID to describe. Get this from clickstack_list_sources."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
List the available values for the required source filter columns on a single source. Use this BEFORE calling any query tool against a source whose configuration declares `requiredSourceFilters`. ONLY use this for sources that have `requiredSourceFilters`. Every such source requires values for every declared column on every query call, and this tool tells you which values exist.
Workflow:
1. clickstack_list_sources or clickstack_describe_source to see whether a source declares requiredSourceFilters and which columns it requires.
2. clickstack_get_source_filter_values to fetch the values for those columns.
3. Call your query tool with the sourceFilters parameter set, e.g.
sourceFilters: { "<columnA>": ["val1"], "<columnB>": ["val2"] }
CROSS-FILTER PRUNING: pass `selectedFilters` with the values you have already chosen for some columns to narrow the option list for the others.
PAGINATION: each column reports `totalAvailable`, `truncated`, and (when truncated) `nextOffset`. Use `limit` + `offset` to step through high-cardinality columns instead of pulling everything at once.
Describe the returned information so the agent knows whether it will answer the request.
Inputs90/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceId
Source ID (required). Must be a source whose configuration declares `requiredSourceFilters`. Use clickstack_list_sources or clickstack_describe_source to see which sources have requiredSourceFilters and the column names they expose.
Clear enough to supply this argument.
columns
Optional subset of filter column names to look up. Defaults to every column declared on the source's requiredSourceFilters. Unknown column names return an error listing the valid ones so the agent can retry.
Clear enough to supply this argument.
selectedFilters
Already-chosen filter values, keyed by column name. Pass the partial sourceFilters you alreadyhave so the response reflects only values that are co-occurring with those selections.
Clear enough to supply this argument.
limit
Maximum number of values to return per column (1-1000). Default: 20. Combine with offset to paginate columns that have many distinct values.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
offset
Number of values to skip per column. Default: 0. Use with limit to paginate when a column has more distinct values than the limit allows.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_source_filter_values",
"title": "List Source Filter Values",
"description": "List the available values for the required source filter columns on a single source. Use this BEFORE calling any query tool against a source whose configuration declares `requiredSourceFilters`. ONLY use this for sources that have `requiredSourceFilters`. Every such source requires values for every declared column on every query call, and this tool tells you which values exist.\n\nWorkflow:\n 1. clickstack_list_sources or clickstack_describe_source to see whether a source declares requiredSourceFilters and which columns it requires.\n 2. clickstack_get_source_filter_values to fetch the values for those columns.\n 3. Call your query tool with the sourceFilters parameter set, e.g.\n sourceFilters: { \"<columnA>\": [\"val1\"], \"<columnB>\": [\"val2\"] }\n\nCROSS-FILTER PRUNING: pass `selectedFilters` with the values you have already chosen for some columns to narrow the option list for the others.\n\nPAGINATION: each column reports `totalAvailable`, `truncated`, and (when truncated) `nextOffset`. Use `limit` + `offset` to step through high-cardinality columns instead of pulling everything at once.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"limit": {
"type": "integer",
"default": 20,
"maximum": 1000,
"minimum": 1,
"description": "Maximum number of values to return per column (1-1000). Default: 20. Combine with offset to paginate columns that have many distinct values."
},
"offset": {
"type": "integer",
"default": 0,
"minimum": 0,
"description": "Number of values to skip per column. Default: 0. Use with limit to paginate when a column has more distinct values than the limit allows."
},
"columns": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional subset of filter column names to look up. Defaults to every column declared on the source's requiredSourceFilters. Unknown column names return an error listing the valid ones so the agent can retry."
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Must be a source whose configuration declares `requiredSourceFilters`. Use clickstack_list_sources or clickstack_describe_source to see which sources have requiredSourceFilters and the column names they expose."
},
"selectedFilters": {
"type": "object",
"description": "Already-chosen filter values, keyed by column name. Pass the partial sourceFilters you alreadyhave so the response reflects only values that are co-occurring with those selections.",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
Create a new data source (omit id) or update an existing one (provide id) so shipped telemetry becomes queryable. Update is a full replace of the source definition. Required for all kinds: kind, name, connection, databaseName, tableName, timestampValueExpression. Kind-specific requirements: log & trace need defaultTableSelectExpression; trace also needs durationExpression, traceIdExpression, spanIdExpression, parentSpanIdExpression, spanNameExpression, spanKindExpression; session needs traceSourceId; metric needs metricTables and resourceAttributesExpression. Get connection and source IDs from clickstack_list_sources. On managed ClickStack instances, sources are provisioned for you: creation is rejected and an update honors only the `disabled` toggle, ignoring all other fields.
The description explains the capability, when to use it, and what to expect.
Inputs19/100
15 of 66 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
id
Source ID. Omit to create a new source, provide to update an existing one.
Clear enough to supply this argument.
kind
Source kind. Determines which fields are required.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
Human-friendly source name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
connection
Connection ID this source reads from. Get IDs from clickstack_list_sources.
Clear enough to supply this argument.
databaseName
ClickHouse database name (maps to from.databaseName).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tableName
ClickHouse table name (maps to from.tableName). Required for all kinds except metric (where it may be empty) and promql (use a placeholder).
Clear enough to supply this argument.
timestampValueExpression
Expression/column used as the primary timestamp.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
section
Optional grouping section label.
Explain the meaning of this value, not just its name.
disabled
When true, the source is hidden from source selectors in the UI. Defaults to false. On update this is part of the full replace: omitting it resets the source to enabled. On managed ClickStack instances, this is the only field an update can change (all others are ignored) and omitting it leaves the source unchanged.
Clear enough to supply this argument.
querySettings › items › setting
Not provided
Missing description. Explain what this value means and how to supply it.
querySettings › items › value
Not provided
Missing description. Explain what this value means and how to supply it.
filterSettings › databaseName
Not provided
Missing description. Explain what this value means and how to supply it.
filterSettings › tableName
Not provided
Missing description. Explain what this value means and how to supply it.
filterSettings › columns › items › name
Not provided
Missing description. Explain what this value means and how to supply it.
filterSettings › columns › items › label
Not provided
Missing description. Explain what this value means and how to supply it.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Permanently delete a data source by ID. Other sources may reference it (e.g. a trace source linked to a log source) — those links are left dangling, so check dependencies first. Use clickstack_list_sources to find available source IDs.
The description explains the capability, when to use it, and what to expect.
Inputs50/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
id
Source ID to delete.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_delete_source",
"title": "Delete Source",
"description": "Permanently delete a data source by ID. Other sources may reference it (e.g. a trace source linked to a log source) — those links are left dangling, so check dependencies first. Use clickstack_list_sources to find available source IDs.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"description": "Source ID to delete."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
DISCOVERY: Use this after clickstack_describe_source when you need more metric names than the per-kind sample shows, or when you want to narrow by kind / name pattern / time window. Returns paginated metric names per kind (gauge/sum/histogram/exponential histogram/summary) with optional unit and description (when the OTel-default columns are present). Pass the returned `nextCursor` back unchanged to fetch the next page.
Summary metrics are listed for discovery only — they cannot be passed to clickstack_timeseries / clickstack_table; query them with clickstack_sql against the table in the source's metricTables.summary.
Workflow: clickstack_list_sources → clickstack_describe_source → clickstack_list_metrics → clickstack_describe_metric → clickstack_timeseries|clickstack_table.
The description explains the capability, when to use it, and what to expect.
Inputs93/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceId
Source ID. Must reference a metric source — get IDs from clickstack_list_sources.
Clear enough to supply this argument.
kind
Optional metric kind filter. Omit to scan every populated kind on the source (gauge, sum, histogram, exponential histogram, summary). Set to narrow results to one kind. NOTE: summary metrics are discovery-only — they cannot be passed to clickstack_timeseries / clickstack_table; query them with clickstack_sql.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
namePattern
Optional ClickHouse ILIKE pattern applied to MetricName server-side. Use % as the wildcard. Examples: "system.cpu.%", "%duration%", "http.server.%".
Clear enough to supply this argument.
startTime
Restrict to metrics with data points after this ISO 8601 timestamp. Default: 24 hours before endTime (or now).
Clear enough to supply this argument.
endTime
End of the time window as ISO 8601. Default: now.
Clear enough to supply this argument.
limit
Max metrics returned per page. Default 50, max 500.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
cursor
Opaque pagination cursor returned by a previous call as `nextCursor`. Pass it back unchanged to get the next page.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_list_metrics",
"title": "List Metric Names",
"description": "DISCOVERY: Use this after clickstack_describe_source when you need more metric names than the per-kind sample shows, or when you want to narrow by kind / name pattern / time window. Returns paginated metric names per kind (gauge/sum/histogram/exponential histogram/summary) with optional unit and description (when the OTel-default columns are present). Pass the returned `nextCursor` back unchanged to fetch the next page.\n\nSummary metrics are listed for discovery only — they cannot be passed to clickstack_timeseries / clickstack_table; query them with clickstack_sql against the table in the source's metricTables.summary.\n\nWorkflow: clickstack_list_sources → clickstack_describe_source → clickstack_list_metrics → clickstack_describe_metric → clickstack_timeseries|clickstack_table.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"kind": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram",
"summary"
],
"type": "string",
"description": "Optional metric kind filter. Omit to scan every populated kind on the source (gauge, sum, histogram, exponential histogram, summary). Set to narrow results to one kind. NOTE: summary metrics are discovery-only — they cannot be passed to clickstack_timeseries / clickstack_table; query them with clickstack_sql."
},
"limit": {
"type": "integer",
"default": 50,
"maximum": 500,
"minimum": 1,
"description": "Max metrics returned per page. Default 50, max 500."
},
"cursor": {
"type": "string",
"description": "Opaque pagination cursor returned by a previous call as `nextCursor`. Pass it back unchanged to get the next page."
},
"endTime": {
"type": "string",
"description": "End of the time window as ISO 8601. Default: now."
},
"sourceId": {
"type": "string",
"description": "Source ID. Must reference a metric source — get IDs from clickstack_list_sources."
},
"startTime": {
"type": "string",
"description": "Restrict to metrics with data points after this ISO 8601 timestamp. Default: 24 hours before endTime (or now)."
},
"namePattern": {
"type": "string",
"description": "Optional ClickHouse ILIKE pattern applied to MetricName server-side. Use % as the wildcard. Examples: \"system.cpu.%\", \"%duration%\", \"http.server.%\"."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
DRILL-DOWN: Use after clickstack_list_metrics (or after a clickstack_describe_source sample) to get attribute keys, sampled values, unit, and description for a specific (metricName, kind) pair. Attribute keys vary per metric — not per source — so always call this before clickstack_timeseries / clickstack_table for any metric you've never queried.
REQUIRES `kind` — pass the gauge/sum/histogram/exponential histogram/summary value emitted alongside the metric name by clickstack_list_metrics or clickstack_describe_source. A metric name can legitimately live in more than one kind (e.g. "container.cpu.usage" appears in both gauge and sum); call this tool once per kind you care about.
kind:"summary" is accepted for discovery (attribute keys, sampled values, unit, description), but summary metrics cannot be queried with clickstack_timeseries / clickstack_table — use clickstack_sql against the table in the source's metricTables.summary.
attributeValuesMeta on each kind reports sampledKeys (queried for values) and truncatedKeys (skipped by the per-call sampling cap) — a key in truncatedKeys was never queried, so query it directly if you need its values.
Workflow: clickstack_list_sources → clickstack_list_metrics → clickstack_describe_metric → clickstack_timeseries|clickstack_table.
The description explains the capability, when to use it, and what to expect.
Inputs96/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceId
Source ID. Must reference a metric source — get IDs from clickstack_list_sources.
Clear enough to supply this argument.
metricName
OTel metric name to describe (e.g. "system.cpu.utilization", "http.server.request.duration"). Discover via clickstack_list_metrics or clickstack_describe_source.
Clear enough to supply this argument.
kind
Metric kind: "gauge" | "sum" | "histogram" | "exponential histogram" | "summary". Required. Discover via clickstack_list_metrics (which returns name + kind per entry) or clickstack_describe_source (which groups metric-name samples by kind). A metric name can legitimately live in more than one kind (e.g. "container.cpu.usage" appears in both gauge and sum) — pick the kind matching the value you want to query.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
startTime
Restrict discovery to data points after this ISO 8601 timestamp. Default: 24 hours before endTime (or now).
Clear enough to supply this argument.
endTime
End of the discovery window as ISO 8601. Default: now.
Clear enough to supply this argument.
sampleValues
When true (default), sample up to 10 distinct values per attribute key for the top 12 attributes. Set false to skip value sampling for faster responses on high-cardinality metrics.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_describe_metric",
"title": "Describe Metric",
"description": "DRILL-DOWN: Use after clickstack_list_metrics (or after a clickstack_describe_source sample) to get attribute keys, sampled values, unit, and description for a specific (metricName, kind) pair. Attribute keys vary per metric — not per source — so always call this before clickstack_timeseries / clickstack_table for any metric you've never queried.\n\nREQUIRES `kind` — pass the gauge/sum/histogram/exponential histogram/summary value emitted alongside the metric name by clickstack_list_metrics or clickstack_describe_source. A metric name can legitimately live in more than one kind (e.g. \"container.cpu.usage\" appears in both gauge and sum); call this tool once per kind you care about.\n\nkind:\"summary\" is accepted for discovery (attribute keys, sampled values, unit, description), but summary metrics cannot be queried with clickstack_timeseries / clickstack_table — use clickstack_sql against the table in the source's metricTables.summary.\n\nattributeValuesMeta on each kind reports sampledKeys (queried for values) and truncatedKeys (skipped by the per-call sampling cap) — a key in truncatedKeys was never queried, so query it directly if you need its values.\n\nWorkflow: clickstack_list_sources → clickstack_list_metrics → clickstack_describe_metric → clickstack_timeseries|clickstack_table.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"metricName",
"kind"
],
"properties": {
"kind": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram",
"summary"
],
"type": "string",
"description": "Metric kind: \"gauge\" | \"sum\" | \"histogram\" | \"exponential histogram\" | \"summary\". Required. Discover via clickstack_list_metrics (which returns name + kind per entry) or clickstack_describe_source (which groups metric-name samples by kind). A metric name can legitimately live in more than one kind (e.g. \"container.cpu.usage\" appears in both gauge and sum) — pick the kind matching the value you want to query."
},
"endTime": {
"type": "string",
"description": "End of the discovery window as ISO 8601. Default: now."
},
"sourceId": {
"type": "string",
"description": "Source ID. Must reference a metric source — get IDs from clickstack_list_sources."
},
"startTime": {
"type": "string",
"description": "Restrict discovery to data points after this ISO 8601 timestamp. Default: 24 hours before endTime (or now)."
},
"metricName": {
"type": "string",
"minLength": 1,
"description": "OTel metric name to describe (e.g. \"system.cpu.utilization\", \"http.server.request.duration\"). Discover via clickstack_list_metrics or clickstack_describe_source."
},
"sampleValues": {
"type": "boolean",
"default": true,
"description": "When true (default), sample up to 10 distinct values per attribute key for the top 12 attributes. Set false to skip value sampling for faster responses on high-cardinality metrics."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Without an ID: list all alerts as a high-level summary (id, name, displayName, tags, state, source, interval). Optionally filter by state (e.g. state="ALERT" for firing alerts). With an ID: get full alert detail including configuration, displayName, tags, and recent evaluation history.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
id
Alert ID. Omit to list all alerts, provide to get full detail.
Clear enough to supply this argument.
state
Filter list by alert state (only applies when id is omitted). Use "ALERT" to find currently firing alerts.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_alert",
"title": "Get Alert(s)",
"description": "Without an ID: list all alerts as a high-level summary (id, name, displayName, tags, state, source, interval). Optionally filter by state (e.g. state=\"ALERT\" for firing alerts). With an ID: get full alert detail including configuration, displayName, tags, and recent evaluation history.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string",
"description": "Alert ID. Omit to list all alerts, provide to get full detail."
},
"state": {
"enum": [
"ALERT",
"OK",
"DISABLED",
"INSUFFICIENT_DATA"
],
"type": "string",
"description": "Filter list by alert state (only applies when id is omitted). Use \"ALERT\" to find currently firing alerts."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
List available webhook destinations (id, name, service type). Use the returned id as the webhookId when creating alerts with clickstack_save_alert.
The description explains the capability, when to use it, and what to expect.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_webhook",
"title": "List Webhooks",
"description": "List available webhook destinations (id, name, service type). Use the returned id as the webhookId when creating alerts with clickstack_save_alert.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Create a new webhook (omit id) or update an existing one (provide id). Use the returned id as the webhookId when creating alerts with clickstack_save_alert. Required: name, service (slack, generic, or incidentio), and url. For the slack service the url host must end in slack.com and headers/queryParams/body are not supported. On update, readable fields (description, body) are a full replace while write-only headers/queryParams are preserved when omitted (send {} to clear); changing the destination clears omitted write-only secrets.
The description explains the capability, when to use it, and what to expect.
Inputs97/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
id
Webhook ID. Omit to create a new webhook, provide to update an existing one.
Clear enough to supply this argument.
name
Human-friendly webhook name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
service
Webhook service type. "slack" posts a fixed Block Kit payload and does not support headers/queryParams/body.
Clear enough to supply this argument.
url
Destination URL. For the slack service the host must end in slack.com. Private/reserved IPs and internal hosts are rejected.
Clear enough to supply this argument.
description
Optional description shown in the UI. On update this is a full replace: omitting it clears the stored description.
Clear enough to supply this argument.
headers
Optional HTTP headers (key -> value). Not supported for the slack service. On update these are write-only: omitting them PRESERVES the stored values; send an empty object ({}) to clear them. If the destination (url or service) changes, omitted headers are cleared.
Clear enough to supply this argument.
queryParams
Optional query parameters (key -> value). Not supported for the slack service. Same write-only update semantics as headers.
Clear enough to supply this argument.
body
Optional request body template. Not supported for the slack service. On update this is a full replace: omitting it clears the stored body.
Clear enough to supply this argument.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_save_webhook",
"title": "Create or Update Webhook",
"description": "Create a new webhook (omit id) or update an existing one (provide id). Use the returned id as the webhookId when creating alerts with clickstack_save_alert. Required: name, service (slack, generic, or incidentio), and url. For the slack service the url host must end in slack.com and headers/queryParams/body are not supported. On update, readable fields (description, body) are a full replace while write-only headers/queryParams are preserved when omitted (send {} to clear); changing the destination clears omitted write-only secrets.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"service",
"url"
],
"properties": {
"id": {
"type": "string",
"description": "Webhook ID. Omit to create a new webhook, provide to update an existing one."
},
"url": {
"type": "string",
"description": "Destination URL. For the slack service the host must end in slack.com. Private/reserved IPs and internal hosts are rejected."
},
"body": {
"type": "string",
"description": "Optional request body template. Not supported for the slack service. On update this is a full replace: omitting it clears the stored body."
},
"name": {
"type": "string",
"minLength": 1,
"description": "Human-friendly webhook name."
},
"headers": {
"type": "object",
"description": "Optional HTTP headers (key -> value). Not supported for the slack service. On update these are write-only: omitting them PRESERVES the stored values; send an empty object ({}) to clear them. If the destination (url or service) changes, omitted headers are cleared.",
"additionalProperties": {
"type": "string"
}
},
"service": {
"enum": [
"slack",
"generic",
"incidentio"
],
"type": "string",
"description": "Webhook service type. \"slack\" posts a fixed Block Kit payload and does not support headers/queryParams/body."
},
"description": {
"type": "string",
"description": "Optional description shown in the UI. On update this is a full replace: omitting it clears the stored description."
},
"queryParams": {
"type": "object",
"description": "Optional query parameters (key -> value). Not supported for the slack service. Same write-only update semantics as headers.",
"additionalProperties": {
"type": "string"
}
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Permanently delete a webhook by ID. Blocked while any alert still references it — reassign or delete those alerts first. Use clickstack_get_webhook to list available webhook IDs.
The description explains the capability, when to use it, and what to expect.
Inputs50/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
id
Webhook ID to delete.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_delete_webhook",
"title": "Delete Webhook",
"description": "Permanently delete a webhook by ID. Blocked while any alert still references it — reassign or delete those alerts first. Use clickstack_get_webhook to list available webhook IDs.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"description": "Webhook ID to delete."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description91/100
Create a new alert (omit id) or update an existing one (provide id). Alerts monitor a saved search, a dashboard tile, or an inline chart config (source "inline" + chartConfig — no saved search or dashboard needed) and fire when the metric crosses a threshold. At least one webhook notification channel is required: pass "channels" for 1-10 targets, or the legacy singular "channel" for one. Updates replace the alert configuration rather than merging it, so read the alert first and resend its full "channels" array to avoid dropping channels you did not mean to remove.
Explain mutations, irreversible effects, or prerequisites that matter before calling this tool.
Inputs62/100
80 of 114 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
id
Alert ID. Omit to create a new alert, provide to update an existing one.
Clear enough to supply this argument.
source
Alert source type: "saved_search" monitors a saved search, "tile" monitors a dashboard tile, and "inline" carries its own chartConfig without requiring a saved search or dashboard.
Clear enough to supply this argument.
savedSearchId
Saved search ID (required when source is saved_search).
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
dashboardId
Dashboard ID (required when source is tile).
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
tileId
Tile ID within the dashboard (required when source is tile). Must be a line, stacked bar, or number tile.
Clear enough to supply this argument.
groupBy
Group-by key for saved search alerts.
Explain the meaning of this value, not just its name.
chartConfig › anyOf › 0 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › displayType
Line chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 0 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › aggFn
Aggregation function. "count" requires no valueExpression; all others do. METRIC SOURCES: "increase" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use "quantile" with level or "count".
Column or expression to aggregate. Required for all aggFn except "count". Use PascalCase for top-level columns (e.g. "Duration", "StatusCode"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).
METRIC SOURCES: optional — defaults to "Value" (the metric value column) when metricType/metricName are set.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › where
Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible "Where" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › select › items › alias
Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. "Requests", "P95 Latency", "Error Rate"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed).
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › level
Percentile level for aggFn="quantile". REQUIRED for histogram and exponential histogram metrics with aggFn:"quantile".
Format category. "duration" auto-formats elapsed times as e.g. "1.2s" (use factor for input unit). "time" formats clock-style durations. "byte" formats as KB/MB/GB. "data_rate" formats as bytes/sec. "throughput" formats as count/sec. "currency" prepends a symbol. "percent" appends %, and divides the value by 100 (0.5 becomes 50%).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:"sql") against the table in the source's metricTables.summary.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › asRatio
Plot as ratio of two metrics (requires exactly 2 select items)
Clear enough to supply this argument.
chartConfig › anyOf › 0 › compareToPreviousPeriod
Overlay the previous period as a dashed comparison series.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Arithmetic expression over the tile's select items by position: "A" is select[0], "B" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. "A / (A + B) * 100" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error.
Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. "Error rate %").
Clear enough to supply this argument.
chartConfig › anyOf › 0 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 0 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › displayType
Stacked bar chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 1 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 1 › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 1 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › displayType
Stacked line (area) chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 2 › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 2 › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 2 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 3 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 3 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › displayType
Single aggregate scalar value
Clear enough to supply this argument.
chartConfig › anyOf › 3 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 3 › color
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › backgroundChart › type
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › backgroundChart › color
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 3 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 4 › configType
Must be "sql" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › displayType
How to render the SQL results. Alerts evaluate line, stacked_bar, stacked_line, or number charts only.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › connectionId
Connection ID (not sourceId) – call clickstack_list_sources to find available connections
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › sourceId
Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › sqlTemplate
Raw ClickHouse SQL query. SQL guidelines:
1. ALWAYS include a LIMIT clause to avoid excessive data.
2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.
- $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))
- $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)
- $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)
- $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.
- NEVER hardcode a fixed time range unless the user specifically asks for it.
- $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.
3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.
- $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)
- $__interval_s expands to {intervalSeconds:Int64}
- These macros are only available for time-series charts; do not use them for other display types.
4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.
- $__filters and $__sourceTable both require sourceId to be set on this tile.
- IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include
the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.
Example:
SELECT
$__timeInterval(TimestampTime) AS ts,
count()
FROM $__sourceTable
WHERE $__timeFilter(TimestampTime)
AND $__filters
GROUP BY ServiceName, ts
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 4 › compareToPreviousPeriod
Overlay the previous period as a dashed comparison series. Valid only when displayType is "line", ignored otherwise.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is "line", ignored otherwise.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › color
Static color for the displayed number, as a palette token such as "chart-blue" or "chart-success". Valid only when displayType is "number", ignored otherwise. Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › where
Not supported on Raw SQL alert configs. Filter inside the sqlTemplate.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › whereLanguage
Not supported on Raw SQL alert configs. Filter inside the sqlTemplate.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
threshold
Threshold value for triggering the alert.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
thresholdType
How the metric value is compared against the threshold.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
thresholdMax
Upper bound (required when thresholdType is between or not_between, must be >= threshold).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
detectionMode
How the alert fires: "threshold" compares against the threshold, "anomaly" compares against a baseline built from recent history. Omitting it resets an existing anomaly alert to threshold, so pass back what clickstack_get_alert returned when updating.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
anomalyConfig › bucketSizeSeconds
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › zScoreThreshold
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › condition
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › minAbsoluteDelta
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › nonNegative
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › maxSeries
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › baselineLookbackMinutes
Not provided
Missing description. Explain what this value means and how to supply it.
interval
Evaluation interval. Anomaly alerts support 5m, 15m, 30m, and 1h.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
scheduleOffsetMinutes
Offset from the interval boundary in minutes (must be < interval).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
scheduleStartAt
Absolute UTC anchor for window alignment (ISO 8601).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
channel › type
Channel type for alert notifications.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
channel › webhookId
Webhook destination ID (required for webhook channel).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
Alert title template (supports Handlebars syntax).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
displayName
Display name shown for the alert in the UI. Defaults to the saved search name, dashboard tile name, or inline chartConfig name when omitted. Overridden by the "name" field in alert notifications when provided.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tags
Tags for the alert. Defaults to the tags of the referenced saved search or dashboard when omitted; inline alerts default to an empty list.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_save_alert",
"title": "Create or Update Alert",
"description": "Create a new alert (omit id) or update an existing one (provide id). Alerts monitor a saved search, a dashboard tile, or an inline chart config (source \"inline\" + chartConfig — no saved search or dashboard needed) and fire when the metric crosses a threshold. At least one webhook notification channel is required: pass \"channels\" for 1-10 targets, or the legacy singular \"channel\" for one. Updates replace the alert configuration rather than merging it, so read the alert first and resend its full \"channels\" array to avoid dropping channels you did not mean to remove.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"source",
"threshold",
"thresholdType",
"interval"
],
"properties": {
"id": {
"type": "string",
"description": "Alert ID. Omit to create a new alert, provide to update an existing one."
},
"name": {
"type": "string",
"maxLength": 512,
"minLength": 1,
"description": "Alert title template (supports Handlebars syntax)."
},
"tags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 32
},
"maxItems": 50,
"description": "Tags for the alert. Defaults to the tags of the referenced saved search or dashboard when omitted; inline alerts default to an empty list."
},
"source": {
"enum": [
"saved_search",
"tile",
"inline"
],
"type": "string",
"description": "Alert source type: \"saved_search\" monitors a saved search, \"tile\" monitors a dashboard tile, and \"inline\" carries its own chartConfig without requiring a saved search or dashboard."
},
"tileId": {
"type": "string",
"description": "Tile ID within the dashboard (required when source is tile). Must be a line, stacked bar, or number tile."
},
"channel": {
"type": "object",
"required": [
"type",
"webhookId"
],
"properties": {
"type": {
"type": "string",
"const": "webhook",
"description": "Channel type for alert notifications."
},
"webhookId": {
"type": "string",
"description": "Webhook destination ID (required for webhook channel)."
}
},
"description": "Alert notification channel configuration.",
"additionalProperties": false
},
"groupBy": {
"type": "string",
"description": "Group-by key for saved search alerts."
},
"message": {
"type": "string",
"maxLength": 4096,
"minLength": 1,
"description": "Alert message template (supports Handlebars syntax)."
},
"channels": {
"type": "array",
"items": {
"$ref": "#/properties/channel"
},
"maxItems": 10,
"minItems": 1,
"description": "Notification channels (1-10). Provide this or \"channel\"; if both, \"channel\" must match the first entry."
},
"interval": {
"enum": [
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"6h",
"12h",
"1d"
],
"type": "string",
"description": "Evaluation interval. Anomaly alerts support 5m, 15m, 30m, and 1h."
},
"threshold": {
"type": "number",
"description": "Threshold value for triggering the alert."
},
"chartConfig": {
"anyOf": [
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"type": "string",
"description": "Display name for the alert query, used in notification titles when the alert has no explicit name."
},
"where": {
"type": "string",
"maxLength": 10000,
"description": "Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"any",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function. \"count\" requires no valueExpression; all others do. METRIC SOURCES: \"increase\" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use \"quantile\" with level or \"count\"."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed)."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level for aggFn=\"quantile\". REQUIRED for histogram and exponential histogram metrics with aggFn:\"quantile\"."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible \"Where\" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\"). Required when metricType is set."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:\"sql\") against the table in the source's metricTables.summary."
},
"periodAggFn": {
"enum": [
"delta"
],
"type": "string",
"description": "Alias for isDelta accepted for round-tripping configs read from get tools: \"delta\" is equivalent to isDelta: true."
},
"numberFormat": {
"type": "object",
"required": [
"output"
],
"properties": {
"unit": {
"type": "string",
"description": "Suffix appended to the value (e.g. \" req/s\")"
},
"factor": {
"type": "number",
"description": "Input unit factor for \"time\" or \"duration\" output. 1 = seconds, 0.001 = milliseconds, 0.000001 = microseconds, 0.000000001 = nanoseconds."
},
"output": {
"enum": [
"currency",
"percent",
"byte",
"time",
"duration",
"number",
"data_rate",
"throughput"
],
"type": "string",
"description": "Format category. \"duration\" auto-formats elapsed times as e.g. \"1.2s\" (use factor for input unit). \"time\" formats clock-style durations. \"byte\" formats as KB/MB/GB. \"data_rate\" formats as bytes/sec. \"throughput\" formats as count/sec. \"currency\" prepends a symbol. \"percent\" appends %, and divides the value by 100 (0.5 becomes 50%)."
},
"average": {
"type": "boolean",
"description": "Abbreviate large numbers (e.g. 1.2m)"
},
"mantissa": {
"type": "integer",
"description": "Decimal places (0–10). Not used for \"time\" or \"duration\" output."
},
"decimalBytes": {
"type": "boolean",
"description": "Use decimal base for bytes (1KB = 1000). Only for \"byte\" output."
},
"currencySymbol": {
"type": "string",
"description": "Currency symbol (e.g. \"$\"). Only for \"currency\" output."
},
"thousandSeparated": {
"type": "boolean",
"description": "Separate thousands (e.g. 1,234,567)"
}
},
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts.",
"additionalProperties": false
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage",
"default": "lucene"
},
"valueExpression": {
"type": "string",
"description": "Column or expression to aggregate. Required for all aggFn except \"count\". Use PascalCase for top-level columns (e.g. \"Duration\", \"StatusCode\"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set."
}
},
"additionalProperties": false
},
"maxItems": 20,
"minItems": 1,
"description": "Metrics to plot (one series per item)"
},
"asRatio": {
"type": "boolean",
"description": "Plot as ratio of two metrics (requires exactly 2 select items)"
},
"groupBy": {
"type": "string",
"description": "Column to split/group by. Top-level columns use PascalCase (e.g. \"SpanName\", \"StatusCode\"). Span attributes: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). Resource attributes: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name'])."
},
"formulas": {
"type": "array",
"items": {
"type": "object",
"required": [
"expression"
],
"properties": {
"alias": {
"type": "string",
"description": "Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. \"Error rate %\")."
},
"expression": {
"type": "string",
"maxLength": 1024,
"description": "Arithmetic expression over the tile's select items by position: \"A\" is select[0], \"B\" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. \"A / (A + B) * 100\" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
}
},
"additionalProperties": false
},
"maxItems": 10,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "line",
"description": "Line chart over time"
},
"seriesLimit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"enum": [
"sql",
"lucene"
],
"type": "string"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero."
},
"showOperandSeries": {
"type": "boolean",
"description": "Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula)."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string"
},
"formulas": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "stacked_bar",
"description": "Stacked bar chart over time"
},
"seriesLimit": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/seriesLimit",
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"showOperandSeries": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/select"
},
"asRatio": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/asRatio"
},
"groupBy": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/groupBy"
},
"formulas": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas"
},
"sourceId": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/sourceId"
},
"fillNulls": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/fillNulls"
},
"displayType": {
"type": "string",
"const": "stacked_line",
"description": "Stacked line (area) chart over time"
},
"seriesLimit": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/seriesLimit"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/numberFormat"
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"showOperandSeries": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/alignDateRangeToGranularity"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"color": {
"enum": [
"chart-blue",
"chart-orange",
"chart-red",
"chart-cyan",
"chart-green",
"chart-pink",
"chart-purple",
"chart-light-blue",
"chart-brown",
"chart-gray",
"chart-success",
"chart-warning",
"chart-error"
],
"type": "string",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\", \"chart-green\", or \"chart-success\" (see the enum for the full set). Applied unless a colorRules entry matches the value."
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items"
},
"maxItems": 20,
"minItems": 1,
"description": "Exactly one metric to display — unless `formulas` is set, in which case the select items are the formula operands and the (single) formula value is displayed instead."
},
"formulas": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas/items"
},
"maxItems": 1,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session). Number tiles support a single formula and always display the formula value (operand series are hidden)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"colorRules": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "number"
},
"operator": {
"enum": [
"gt",
"gte",
"lt",
"lte"
],
"type": "string"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "array",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2
},
"operator": {
"type": "string",
"const": "between"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 200
}
]
},
"operator": {
"enum": [
"eq",
"neq"
],
"type": "string"
}
},
"additionalProperties": false
}
]
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]."
},
"displayType": {
"type": "string",
"const": "number",
"description": "Single aggregate scalar value"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"backgroundChart": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"line",
"area"
],
"type": "string"
},
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
}
},
"description": "Optional background trend sparkline drawn behind the number, derived from a time-bucketed version of the same query (useful for SLO / error-budget tiles where the trend over the window matters). { type, color? }: type is \"line\" or \"area\"; color is an optional palette token override (the sparkline inherits the tile color when unset). Builder number tiles only; raw SQL number tiles have no time dimension to bucket. Example: { type: \"area\", color: \"chart-blue\" }.",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"configType",
"displayType",
"connectionId",
"sqlTemplate"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\" or \"chart-success\". Valid only when displayType is \"number\", ignored otherwise. Applied unless a colorRules entry matches the value."
},
"where": {
"not": {},
"description": "Not supported on Raw SQL alert configs. Filter inside the sqlTemplate."
},
"sourceId": {
"type": "string",
"description": "Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId."
},
"fillNulls": {
"type": "boolean"
},
"colorRules": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/colorRules/items"
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]. Valid only when displayType is \"number\", ignored otherwise."
},
"configType": {
"type": "string",
"const": "sql",
"description": "Must be \"sql\" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need."
},
"displayType": {
"enum": [
"line",
"stacked_bar",
"stacked_line",
"number"
],
"type": "string",
"description": "How to render the SQL results. Alerts evaluate line, stacked_bar, stacked_line, or number charts only."
},
"sqlTemplate": {
"type": "string",
"description": "\nRaw ClickHouse SQL query. SQL guidelines:\n\n1. ALWAYS include a LIMIT clause to avoid excessive data.\n2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.\n - $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))\n - $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)\n - $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)\n - $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.\n - NEVER hardcode a fixed time range unless the user specifically asks for it.\n - $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.\n3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.\n - $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)\n - $__interval_s expands to {intervalSeconds:Int64}\n - These macros are only available for time-series charts; do not use them for other display types.\n4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.\n - $__filters and $__sourceTable both require sourceId to be set on this tile.\n - IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include\n the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.\n\nExample:\n\nSELECT\n $__timeInterval(TimestampTime) AS ts,\n count()\nFROM $__sourceTable\nWHERE $__timeFilter(TimestampTime)\n AND $__filters\nGROUP BY ServiceName, ts\n"
},
"connectionId": {
"type": "string",
"description": "Connection ID (not sourceId) – call clickstack_list_sources to find available connections"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/4/properties/where"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is \"line\", ignored otherwise."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series. Valid only when displayType is \"line\", ignored otherwise."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
}
],
"description": "Chart configuration for inline alerts (required when source is \"inline\"). Same shape as a dashboard tile config, limited to displayType line, stacked_bar, stacked_line, or number. Omit configType for the builder variant (sourceId + select); set configType to \"sql\" for the Raw SQL variant (connectionId + sqlTemplate; the template must use the $__timeFilter and $__timeInterval macros so each evaluation window can be queried)."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID (required when source is tile)."
},
"displayName": {
"anyOf": [
{
"type": "string",
"maxLength": 512,
"minLength": 1
},
{
"type": "null"
}
],
"description": "Display name shown for the alert in the UI. Defaults to the saved search name, dashboard tile name, or inline chartConfig name when omitted. Overridden by the \"name\" field in alert notifications when provided."
},
"thresholdMax": {
"type": "number",
"description": "Upper bound (required when thresholdType is between or not_between, must be >= threshold)."
},
"anomalyConfig": {
"type": "object",
"properties": {
"condition": {
"enum": [
"above",
"below",
"above_or_below"
],
"type": "string",
"default": "above_or_below"
},
"maxSeries": {
"type": "integer",
"default": 100,
"maximum": 1000,
"minimum": 1
},
"nonNegative": {
"type": "boolean",
"default": true
},
"zScoreThreshold": {
"type": "number",
"default": 3,
"exclusiveMinimum": 0
},
"minAbsoluteDelta": {
"type": "number",
"default": 0,
"minimum": 0
},
"bucketSizeSeconds": {
"type": "integer",
"default": 60,
"maximum": 3600,
"minimum": 60
},
"baselineLookbackMinutes": {
"type": "integer",
"default": 120,
"maximum": 1440,
"minimum": 1
}
},
"description": "Tuning for an anomaly alert. Only valid when detectionMode is \"anomaly\". Omitting it resets every field to its default.",
"additionalProperties": false
},
"detectionMode": {
"enum": [
"threshold",
"anomaly"
],
"type": "string",
"description": "How the alert fires: \"threshold\" compares against the threshold, \"anomaly\" compares against a baseline built from recent history. Omitting it resets an existing anomaly alert to threshold, so pass back what clickstack_get_alert returned when updating."
},
"savedSearchId": {
"type": "string",
"description": "Saved search ID (required when source is saved_search)."
},
"thresholdType": {
"enum": [
"above",
"below",
"above_exclusive",
"below_or_equal",
"equal",
"not_equal",
"between",
"not_between"
],
"type": "string",
"description": "How the metric value is compared against the threshold."
},
"scheduleStartAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"description": "Absolute UTC anchor for window alignment (ISO 8601)."
},
"scheduleOffsetMinutes": {
"type": "integer",
"maximum": 1439,
"minimum": 0,
"description": "Offset from the interval boundary in minutes (must be < interval)."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Replay anomaly alert settings against up to the last 24 hours of data and report how many notifications the alert would have sent, which series fired, and when. Use it to tune anomalyConfig before saving an alert with clickstack_save_alert. Target either an existing anomaly alert (alertId, with optional interval/anomalyConfig overrides) or an unsaved draft (source + savedSearchId, dashboardId + tileId, or chartConfig). Nothing is saved and no notifications are sent. The replay runs the scheduler’s current logic on the data available now, starts every series as not firing, and assumes every notification is delivered. result.notifications counts every series; "series" lists at most the 25 with the most notifications (seriesOmitted counts the rest), each with its 5 most recent episodes (episodesOmitted counts the rest). The whole call has a 30s budget; if it runs out, completed evaluations are returned with range.complete false and a partial_coverage warning. Always pass warnings and degraded results on to the user: they mean the counts are incomplete or less reliable.
The description explains the capability, when to use it, and what to expect.
Inputs61/100
72 of 106 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
alertId
Existing anomaly alert to backtest. Its query is used as saved; only "interval" and "anomalyConfig" can be overridden. Omit to backtest an unsaved draft described by "source".
Clear enough to supply this argument.
source
Draft target type, mutually exclusive with alertId: "saved_search" (savedSearchId, optional groupBy), "tile" (an existing dashboard chart: dashboardId + tileId, read as it is now), or "inline" (chartConfig, for any custom query).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
savedSearchId
Saved search ID (source "saved_search").
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
groupBy
Group-by key for saved search drafts.
Explain the meaning of this value, not just its name.
dashboardId
Dashboard ID (source "tile").
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
tileId
Tile ID (source "tile").
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
chartConfig › anyOf › 0 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › displayType
Line chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 0 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › aggFn
Aggregation function. "count" requires no valueExpression; all others do. METRIC SOURCES: "increase" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use "quantile" with level or "count".
Column or expression to aggregate. Required for all aggFn except "count". Use PascalCase for top-level columns (e.g. "Duration", "StatusCode"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).
METRIC SOURCES: optional — defaults to "Value" (the metric value column) when metricType/metricName are set.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › where
Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible "Where" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › select › items › alias
Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. "Requests", "P95 Latency", "Error Rate"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed).
Clear enough to supply this argument.
chartConfig › anyOf › 0 › select › items › level
Percentile level for aggFn="quantile". REQUIRED for histogram and exponential histogram metrics with aggFn:"quantile".
Format category. "duration" auto-formats elapsed times as e.g. "1.2s" (use factor for input unit). "time" formats clock-style durations. "byte" formats as KB/MB/GB. "data_rate" formats as bytes/sec. "throughput" formats as count/sec. "currency" prepends a symbol. "percent" appends %, and divides the value by 100 (0.5 becomes 50%).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:"sql") against the table in the source's metricTables.summary.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 0 › asRatio
Plot as ratio of two metrics (requires exactly 2 select items)
Clear enough to supply this argument.
chartConfig › anyOf › 0 › compareToPreviousPeriod
Overlay the previous period as a dashed comparison series.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero.
Clear enough to supply this argument.
chartConfig › anyOf › 0 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Arithmetic expression over the tile's select items by position: "A" is select[0], "B" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. "A / (A + B) * 100" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error.
Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. "Error rate %").
Clear enough to supply this argument.
chartConfig › anyOf › 0 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 0 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › displayType
Stacked bar chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 1 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 1 › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 1 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
chartConfig › anyOf › 1 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 1 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › displayType
Stacked line (area) chart over time
Clear enough to supply this argument.
chartConfig › anyOf › 2 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 2 › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 2 › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
chartConfig › anyOf › 2 › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
chartConfig › anyOf › 2 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Clear enough to supply this argument.
chartConfig › anyOf › 3 › where
Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default.
Clear enough to supply this argument.
chartConfig › anyOf › 3 › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › displayType
Single aggregate scalar value
Clear enough to supply this argument.
chartConfig › anyOf › 3 › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
chartConfig › anyOf › 3 › color
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › backgroundChart › type
Not provided
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 3 › backgroundChart › color
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Clear enough to supply this argument.
chartConfig › anyOf › 3 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › configType
Must be "sql" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › displayType
How to render the SQL results. Alerts evaluate line, stacked_bar, stacked_line, or number charts only.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › connectionId
Connection ID (not sourceId) – call clickstack_list_sources to find available connections
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › sourceId
Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › sqlTemplate
Raw ClickHouse SQL query. SQL guidelines:
1. ALWAYS include a LIMIT clause to avoid excessive data.
2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.
- $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))
- $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)
- $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)
- $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.
- NEVER hardcode a fixed time range unless the user specifically asks for it.
- $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.
3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.
- $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)
- $__interval_s expands to {intervalSeconds:Int64}
- These macros are only available for time-series charts; do not use them for other display types.
4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.
- $__filters and $__sourceTable both require sourceId to be set on this tile.
- IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include
the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.
Example:
SELECT
$__timeInterval(TimestampTime) AS ts,
count()
FROM $__sourceTable
WHERE $__timeFilter(TimestampTime)
AND $__filters
GROUP BY ServiceName, ts
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
chartConfig › anyOf › 4 › compareToPreviousPeriod
Overlay the previous period as a dashed comparison series. Valid only when displayType is "line", ignored otherwise.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is "line", ignored otherwise.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › color
Static color for the displayed number, as a palette token such as "chart-blue" or "chart-success". Valid only when displayType is "number", ignored otherwise. Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › name
Display name for the alert query, used in notification titles when the alert has no explicit name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › where
Not supported on Raw SQL alert configs. Filter inside the sqlTemplate.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
chartConfig › anyOf › 4 › whereLanguage
Not supported on Raw SQL alert configs. Filter inside the sqlTemplate.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
interval
Evaluation interval. Required for drafts; overrides an existing alert's interval. Anomaly alerts support 5m, 15m, 30m, and 1h.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
anomalyConfig › bucketSizeSeconds
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › zScoreThreshold
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › condition
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › minAbsoluteDelta
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › nonNegative
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › maxSeries
Not provided
Missing description. Explain what this value means and how to supply it.
anomalyConfig › baselineLookbackMinutes
Not provided
Missing description. Explain what this value means and how to supply it.
scheduleOffsetMinutes
Drafts only. Offset from the interval boundary in minutes (must be < interval).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
scheduleStartAt
Drafts only. Absolute UTC anchor for window alignment.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
startTime
Start of the backtest range as ISO 8601. Default: 24 hours before endTime. The range is capped at 24 hours.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
endTime
End of the backtest range as ISO 8601. Default: now.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_backtest_anomaly_alert",
"title": "Backtest Anomaly Alert",
"description": "Replay anomaly alert settings against up to the last 24 hours of data and report how many notifications the alert would have sent, which series fired, and when. Use it to tune anomalyConfig before saving an alert with clickstack_save_alert. Target either an existing anomaly alert (alertId, with optional interval/anomalyConfig overrides) or an unsaved draft (source + savedSearchId, dashboardId + tileId, or chartConfig). Nothing is saved and no notifications are sent. The replay runs the scheduler’s current logic on the data available now, starts every series as not firing, and assumes every notification is delivered. result.notifications counts every series; \"series\" lists at most the 25 with the most notifications (seriesOmitted counts the rest), each with its 5 most recent episodes (episodesOmitted counts the rest). The whole call has a 30s budget; if it runs out, completed evaluations are returned with range.complete false and a partial_coverage warning. Always pass warnings and degraded results on to the user: they mean the counts are incomplete or less reliable.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"source": {
"enum": [
"saved_search",
"tile",
"inline"
],
"type": "string",
"description": "Draft target type, mutually exclusive with alertId: \"saved_search\" (savedSearchId, optional groupBy), \"tile\" (an existing dashboard chart: dashboardId + tileId, read as it is now), or \"inline\" (chartConfig, for any custom query)."
},
"tileId": {
"type": "string",
"description": "Tile ID (source \"tile\")."
},
"alertId": {
"type": "string",
"description": "Existing anomaly alert to backtest. Its query is used as saved; only \"interval\" and \"anomalyConfig\" can be overridden. Omit to backtest an unsaved draft described by \"source\"."
},
"endTime": {
"type": "string",
"description": "End of the backtest range as ISO 8601. Default: now."
},
"groupBy": {
"type": "string",
"description": "Group-by key for saved search drafts."
},
"interval": {
"enum": [
"5m",
"15m",
"30m",
"1h"
],
"type": "string",
"description": "Evaluation interval. Required for drafts; overrides an existing alert's interval. Anomaly alerts support 5m, 15m, 30m, and 1h."
},
"startTime": {
"type": "string",
"description": "Start of the backtest range as ISO 8601. Default: 24 hours before endTime. The range is capped at 24 hours."
},
"chartConfig": {
"anyOf": [
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"type": "string",
"description": "Display name for the alert query, used in notification titles when the alert has no explicit name."
},
"where": {
"type": "string",
"maxLength": 10000,
"description": "Chart-level filter applied to every select item (combined with each item's own `where` via AND). Lucene syntax by default."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"any",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function. \"count\" requires no valueExpression; all others do. METRIC SOURCES: \"increase\" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use \"quantile\" with level or \"count\"."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed)."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level for aggFn=\"quantile\". REQUIRED for histogram and exponential histogram metrics with aggFn:\"quantile\"."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible \"Where\" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\"). Required when metricType is set."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:\"sql\") against the table in the source's metricTables.summary."
},
"periodAggFn": {
"enum": [
"delta"
],
"type": "string",
"description": "Alias for isDelta accepted for round-tripping configs read from get tools: \"delta\" is equivalent to isDelta: true."
},
"numberFormat": {
"type": "object",
"required": [
"output"
],
"properties": {
"unit": {
"type": "string",
"description": "Suffix appended to the value (e.g. \" req/s\")"
},
"factor": {
"type": "number",
"description": "Input unit factor for \"time\" or \"duration\" output. 1 = seconds, 0.001 = milliseconds, 0.000001 = microseconds, 0.000000001 = nanoseconds."
},
"output": {
"enum": [
"currency",
"percent",
"byte",
"time",
"duration",
"number",
"data_rate",
"throughput"
],
"type": "string",
"description": "Format category. \"duration\" auto-formats elapsed times as e.g. \"1.2s\" (use factor for input unit). \"time\" formats clock-style durations. \"byte\" formats as KB/MB/GB. \"data_rate\" formats as bytes/sec. \"throughput\" formats as count/sec. \"currency\" prepends a symbol. \"percent\" appends %, and divides the value by 100 (0.5 becomes 50%)."
},
"average": {
"type": "boolean",
"description": "Abbreviate large numbers (e.g. 1.2m)"
},
"mantissa": {
"type": "integer",
"description": "Decimal places (0–10). Not used for \"time\" or \"duration\" output."
},
"decimalBytes": {
"type": "boolean",
"description": "Use decimal base for bytes (1KB = 1000). Only for \"byte\" output."
},
"currencySymbol": {
"type": "string",
"description": "Currency symbol (e.g. \"$\"). Only for \"currency\" output."
},
"thousandSeparated": {
"type": "boolean",
"description": "Separate thousands (e.g. 1,234,567)"
}
},
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts.",
"additionalProperties": false
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage",
"default": "lucene"
},
"valueExpression": {
"type": "string",
"description": "Column or expression to aggregate. Required for all aggFn except \"count\". Use PascalCase for top-level columns (e.g. \"Duration\", \"StatusCode\"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set."
}
},
"additionalProperties": false
},
"maxItems": 20,
"minItems": 1,
"description": "Metrics to plot (one series per item)"
},
"asRatio": {
"type": "boolean",
"description": "Plot as ratio of two metrics (requires exactly 2 select items)"
},
"groupBy": {
"type": "string",
"description": "Column to split/group by. Top-level columns use PascalCase (e.g. \"SpanName\", \"StatusCode\"). Span attributes: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). Resource attributes: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name'])."
},
"formulas": {
"type": "array",
"items": {
"type": "object",
"required": [
"expression"
],
"properties": {
"alias": {
"type": "string",
"description": "Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. \"Error rate %\")."
},
"expression": {
"type": "string",
"maxLength": 1024,
"description": "Arithmetic expression over the tile's select items by position: \"A\" is select[0], \"B\" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. \"A / (A + B) * 100\" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
}
},
"additionalProperties": false
},
"maxItems": 10,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "line",
"description": "Line chart over time"
},
"seriesLimit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"enum": [
"sql",
"lucene"
],
"type": "string"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero."
},
"showOperandSeries": {
"type": "boolean",
"description": "Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula)."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string"
},
"formulas": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "stacked_bar",
"description": "Stacked bar chart over time"
},
"seriesLimit": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/seriesLimit",
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"showOperandSeries": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/select"
},
"asRatio": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/asRatio"
},
"groupBy": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/groupBy"
},
"formulas": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas"
},
"sourceId": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/sourceId"
},
"fillNulls": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/fillNulls"
},
"displayType": {
"type": "string",
"const": "stacked_line",
"description": "Stacked line (area) chart over time"
},
"seriesLimit": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/seriesLimit"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/numberFormat"
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"showOperandSeries": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"$ref": "#/properties/chartConfig/anyOf/1/properties/alignDateRangeToGranularity"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"color": {
"enum": [
"chart-blue",
"chart-orange",
"chart-red",
"chart-cyan",
"chart-green",
"chart-pink",
"chart-purple",
"chart-light-blue",
"chart-brown",
"chart-gray",
"chart-success",
"chart-warning",
"chart-error"
],
"type": "string",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\", \"chart-green\", or \"chart-success\" (see the enum for the full set). Applied unless a colorRules entry matches the value."
},
"where": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items"
},
"maxItems": 20,
"minItems": 1,
"description": "Exactly one metric to display — unless `formulas` is set, in which case the select items are the formula operands and the (single) formula value is displayed instead."
},
"formulas": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/formulas/items"
},
"maxItems": 1,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session). Number tiles support a single formula and always display the formula value (operand series are hidden)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"colorRules": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "number"
},
"operator": {
"enum": [
"gt",
"gte",
"lt",
"lte"
],
"type": "string"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "array",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2
},
"operator": {
"type": "string",
"const": "between"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 200
}
]
},
"operator": {
"enum": [
"eq",
"neq"
],
"type": "string"
}
},
"additionalProperties": false
}
]
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]."
},
"displayType": {
"type": "string",
"const": "number",
"description": "Single aggregate scalar value"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/whereLanguage"
},
"backgroundChart": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"line",
"area"
],
"type": "string"
},
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color"
}
},
"description": "Optional background trend sparkline drawn behind the number, derived from a time-bucketed version of the same query (useful for SLO / error-budget tiles where the trend over the window matters). { type, color? }: type is \"line\" or \"area\"; color is an optional palette token override (the sparkline inherits the tile color when unset). Builder number tiles only; raw SQL number tiles have no time dimension to bucket. Example: { type: \"area\", color: \"chart-blue\" }.",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"configType",
"displayType",
"connectionId",
"sqlTemplate"
],
"properties": {
"name": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/name"
},
"color": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/color",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\" or \"chart-success\". Valid only when displayType is \"number\", ignored otherwise. Applied unless a colorRules entry matches the value."
},
"where": {
"not": {},
"description": "Not supported on Raw SQL alert configs. Filter inside the sqlTemplate."
},
"sourceId": {
"type": "string",
"description": "Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId."
},
"fillNulls": {
"type": "boolean"
},
"colorRules": {
"type": "array",
"items": {
"$ref": "#/properties/chartConfig/anyOf/3/properties/colorRules/items"
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]. Valid only when displayType is \"number\", ignored otherwise."
},
"configType": {
"type": "string",
"const": "sql",
"description": "Must be \"sql\" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need."
},
"displayType": {
"enum": [
"line",
"stacked_bar",
"stacked_line",
"number"
],
"type": "string",
"description": "How to render the SQL results. Alerts evaluate line, stacked_bar, stacked_line, or number charts only."
},
"sqlTemplate": {
"type": "string",
"description": "\nRaw ClickHouse SQL query. SQL guidelines:\n\n1. ALWAYS include a LIMIT clause to avoid excessive data.\n2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.\n - $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))\n - $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)\n - $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)\n - $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.\n - NEVER hardcode a fixed time range unless the user specifically asks for it.\n - $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.\n3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.\n - $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)\n - $__interval_s expands to {intervalSeconds:Int64}\n - These macros are only available for time-series charts; do not use them for other display types.\n4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.\n - $__filters and $__sourceTable both require sourceId to be set on this tile.\n - IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include\n the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.\n\nExample:\n\nSELECT\n $__timeInterval(TimestampTime) AS ts,\n count()\nFROM $__sourceTable\nWHERE $__timeFilter(TimestampTime)\n AND $__filters\nGROUP BY ServiceName, ts\n"
},
"connectionId": {
"type": "string",
"description": "Connection ID (not sourceId) – call clickstack_list_sources to find available connections"
},
"numberFormat": {
"$ref": "#/properties/chartConfig/anyOf/0/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/chartConfig/anyOf/4/properties/where"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is \"line\", ignored otherwise."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series. Valid only when displayType is \"line\", ignored otherwise."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
}
],
"description": "Chart configuration for inline alerts (required when source is \"inline\"). Same shape as a dashboard tile config, limited to displayType line, stacked_bar, stacked_line, or number. Omit configType for the builder variant (sourceId + select); set configType to \"sql\" for the Raw SQL variant (connectionId + sqlTemplate; the template must use the $__timeFilter and $__timeInterval macros so each evaluation window can be queried)."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID (source \"tile\")."
},
"anomalyConfig": {
"type": "object",
"properties": {
"condition": {
"enum": [
"above",
"below",
"above_or_below"
],
"type": "string",
"default": "above_or_below"
},
"maxSeries": {
"type": "integer",
"default": 100,
"maximum": 1000,
"minimum": 1
},
"nonNegative": {
"type": "boolean",
"default": true
},
"zScoreThreshold": {
"type": "number",
"default": 3,
"exclusiveMinimum": 0
},
"minAbsoluteDelta": {
"type": "number",
"default": 0,
"minimum": 0
},
"bucketSizeSeconds": {
"type": "integer",
"default": 60,
"maximum": 3600,
"minimum": 60
},
"baselineLookbackMinutes": {
"type": "integer",
"default": 120,
"maximum": 1440,
"minimum": 1
}
},
"description": "Anomaly tuning. For drafts, omitted fields use the defaults. For an existing alert, each supplied field overrides the alert's value and omitted fields keep it.",
"additionalProperties": false
},
"savedSearchId": {
"type": "string",
"description": "Saved search ID (source \"saved_search\")."
},
"scheduleStartAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"description": "Drafts only. Absolute UTC anchor for window alignment."
},
"scheduleOffsetMinutes": {
"type": "integer",
"maximum": 1439,
"minimum": 0,
"description": "Drafts only. Offset from the interval boundary in minutes (must be < interval)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Without an ID: list all dashboards (returns IDs, names, tags). With an ID: get full dashboard detail including all tiles and configuration.
The description explains the capability, when to use it, and what to expect.
Inputs93/100
Input documentation gives an agent enough context to populate the arguments.
id
Dashboard ID. Omit to list all dashboards, provide to get full detail.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_dashboard",
"title": "Get Dashboard(s)",
"description": "Without an ID: list all dashboards (returns IDs, names, tags). With an ID: get full dashboard detail including all tiles and configuration.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string",
"description": "Dashboard ID. Omit to list all dashboards, provide to get full detail."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description84/100
Retrieve a single tile from a dashboard by tileId. Useful for inspecting one tile without loading the full dashboard. Use clickstack_get_dashboard (without an ID) to list dashboards, then clickstack_get_dashboard (with an ID) to see all tile IDs.
Describe the returned information so the agent knows whether it will answer the request.
Inputs75/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
dashboardId
Dashboard ID.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
tileId
Tile ID within the dashboard. Obtain from clickstack_get_dashboard.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_dashboard_tile",
"title": "Get a Single Dashboard Tile",
"description": "Retrieve a single tile from a dashboard by tileId. Useful for inspecting one tile without loading the full dashboard. Use clickstack_get_dashboard (without an ID) to list dashboards, then clickstack_get_dashboard (with an ID) to see all tile IDs.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"dashboardId",
"tileId"
],
"properties": {
"tileId": {
"type": "string",
"description": "Tile ID within the dashboard. Obtain from clickstack_get_dashboard."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
clickstack_save_dashboardReview unavailable-/100
This tool could not be scored. Rerun the review.
Original tool metadata
{
"name": "clickstack_save_dashboard",
"title": "Create or Update Dashboard",
"description": "Create a new dashboard (omit id) or update an existing one (provide id). Call clickstack_list_sources first to obtain sourceId and connectionId values. IMPORTANT: After saving a dashboard, always run clickstack_query_tiles to validate every tile in one call (or clickstack_query_tile for a single tile) and confirm the queries work and return expected data. Tiles can silently fail due to incorrect filter syntax, missing attributes, or wrong column names. TIP: To update a single tile without resubmitting all tiles, use clickstack_patch_dashboard instead.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"tiles"
],
"properties": {
"id": {
"type": "string",
"description": "Dashboard ID. Omit to create a new dashboard, provide to update an existing one."
},
"name": {
"type": "string",
"description": "Dashboard name"
},
"tags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 32
},
"maxItems": 50,
"description": "Dashboard tags. Up to 50 tags, each at most 32 characters."
},
"tiles": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"type": "number",
"default": 4,
"minimum": 1,
"description": "Height in grid rows. Default 4"
},
"w": {
"type": "number",
"default": 12,
"maximum": 24,
"minimum": 1,
"description": "Width in grid columns (1–24). Default 12"
},
"x": {
"type": "number",
"default": 0,
"maximum": 23,
"minimum": 0,
"description": "Horizontal grid position (0–23). Default 0"
},
"y": {
"type": "number",
"default": 0,
"minimum": 0,
"description": "Vertical grid position. Default 0"
},
"id": {
"type": "string",
"maxLength": 36,
"description": "Tile ID (auto-generated if omitted)"
},
"name": {
"type": "string",
"minLength": 1,
"description": "Tile title shown on the dashboard"
},
"tabId": {
"type": "string",
"maxLength": 256,
"minLength": 1,
"description": "Tab within the container this tile belongs to. Requires containerId to be set and must match a tab id on that container. Omit to render in the container's shell (useful when the container has zero or one tabs, or when a tile should appear above the tab bar)."
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"not": {},
"description": "Not supported on this tile type. Filter via each select item's `where`."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"any",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function. \"count\" requires no valueExpression; all others do. METRIC SOURCES: \"increase\" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use \"quantile\" with level or \"count\"."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed)."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level for aggFn=\"quantile\". REQUIRED for histogram and exponential histogram metrics with aggFn:\"quantile\"."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible \"Where\" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\"). Required when metricType is set."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:\"sql\") against the table in the source's metricTables.summary."
},
"periodAggFn": {
"enum": [
"delta"
],
"type": "string",
"description": "Alias for isDelta accepted for round-tripping configs read from get tools: \"delta\" is equivalent to isDelta: true."
},
"numberFormat": {
"type": "object",
"required": [
"output"
],
"properties": {
"unit": {
"type": "string",
"description": "Suffix appended to the value (e.g. \" req/s\")"
},
"factor": {
"type": "number",
"description": "Input unit factor for \"time\" or \"duration\" output. 1 = seconds, 0.001 = milliseconds, 0.000001 = microseconds, 0.000000001 = nanoseconds."
},
"output": {
"enum": [
"currency",
"percent",
"byte",
"time",
"duration",
"number",
"data_rate",
"throughput"
],
"type": "string",
"description": "Format category. \"duration\" auto-formats elapsed times as e.g. \"1.2s\" (use factor for input unit). \"time\" formats clock-style durations. \"byte\" formats as KB/MB/GB. \"data_rate\" formats as bytes/sec. \"throughput\" formats as count/sec. \"currency\" prepends a symbol. \"percent\" appends %, and divides the value by 100 (0.5 becomes 50%)."
},
"average": {
"type": "boolean",
"description": "Abbreviate large numbers (e.g. 1.2m)"
},
"mantissa": {
"type": "integer",
"description": "Decimal places (0–10). Not used for \"time\" or \"duration\" output."
},
"decimalBytes": {
"type": "boolean",
"description": "Use decimal base for bytes (1KB = 1000). Only for \"byte\" output."
},
"currencySymbol": {
"type": "string",
"description": "Currency symbol (e.g. \"$\"). Only for \"currency\" output."
},
"thousandSeparated": {
"type": "boolean",
"description": "Separate thousands (e.g. 1,234,567)"
}
},
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts.",
"additionalProperties": false
},
"whereLanguage": {
"enum": [
"sql",
"lucene"
],
"type": "string",
"default": "lucene"
},
"valueExpression": {
"type": "string",
"description": "Column or expression to aggregate. Required for all aggFn except \"count\". Use PascalCase for top-level columns (e.g. \"Duration\", \"StatusCode\"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set."
}
},
"additionalProperties": false
},
"maxItems": 20,
"minItems": 1,
"description": "Metrics to plot (one series per item)"
},
"asRatio": {
"type": "boolean",
"description": "Plot as ratio of two metrics (requires exactly 2 select items)"
},
"groupBy": {
"type": "string",
"description": "Column to split/group by. Top-level columns use PascalCase (e.g. \"SpanName\", \"StatusCode\"). Span attributes: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). Resource attributes: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name'])."
},
"formulas": {
"type": "array",
"items": {
"type": "object",
"required": [
"expression"
],
"properties": {
"alias": {
"type": "string",
"description": "Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. \"Error rate %\")."
},
"expression": {
"type": "string",
"maxLength": 1024,
"description": "Arithmetic expression over the tile's select items by position: \"A\" is select[0], \"B\" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. \"A / (A + B) * 100\" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error."
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
}
},
"additionalProperties": false
},
"maxItems": 10,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "line",
"description": "Line chart over time"
},
"seriesLimit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero."
},
"showOperandSeries": {
"type": "boolean",
"description": "Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula)."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"type": "string",
"maxLength": 256,
"minLength": 1,
"description": "Container this tile belongs to. Must reference the id of a container in the dashboard-level containers array. Omit to render the tile in the ungrouped area."
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string"
},
"formulas": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "stacked_bar",
"description": "Stacked bar chart over time"
},
"seriesLimit": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/seriesLimit",
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/select"
},
"asRatio": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/asRatio"
},
"groupBy": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/groupBy"
},
"formulas": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/sourceId"
},
"fillNulls": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/fillNulls"
},
"displayType": {
"type": "string",
"const": "stacked_line",
"description": "Stacked line (area) chart over time"
},
"seriesLimit": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/seriesLimit"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/numberFormat"
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"$ref": "#/properties/tiles/items/anyOf/1/properties/config/properties/alignDateRangeToGranularity"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"having": {
"type": "string",
"maxLength": 10000,
"description": "Post-aggregation SQL HAVING expression. Example: \"Count > 100\" to drop groups with few rows, or \"StatusMessage != ''\" to drop empty-message rows from a groupBy: \"StatusMessage\" table. Mirrors the same field on the REST table chart config in `externalDashboardTableChartConfigSchema`.\n\nDASHBOARD VARIABLES: accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which expand to 1=1 while the variable has no selection, as well as a bare $variableName reference (which renders as NULL when nothing is selected)."
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string",
"description": "Group rows by this column. Use PascalCase for top-level columns (e.g. \"SpanName\"). For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"onClick": {
"anyOf": [
{
"type": "object",
"required": [
"type",
"target"
],
"properties": {
"type": {
"type": "string",
"const": "search",
"description": "Link to the /search page for a log or trace source."
},
"target": {
"anyOf": [
{
"type": "object",
"required": [
"mode",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Concrete source ID (for type=search) or dashboard ID (for type=dashboard). Get source IDs from clickstack_list_sources; get dashboard IDs from clickstack_get_dashboard (no id arg returns the list). For type=search the source kind must be \"log\" or \"trace\"; the /search page does not render metric/session sources."
},
"mode": {
"type": "string",
"const": "id"
}
},
"description": "Link to a specific source or dashboard by its concrete ID.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"mode",
"template"
],
"properties": {
"mode": {
"type": "string",
"const": "template"
},
"template": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered against the clicked row, then resolved by NAME on the destination team. Example: \"ServiceOverview-{{ServiceName}}\" assumes a row column ServiceName whose value is the name of a source/dashboard. Prefer mode=\"id\" when the target is known up-front; it survives renames."
}
},
"description": "Link to a source/dashboard whose name comes from a column on the clicked row.",
"additionalProperties": false
}
],
"description": "Destination resolver. mode=\"id\" pins a specific source/dashboard; mode=\"template\" picks one at click time from a row column.Linking by ID is preferred, but using a template is valid when the destination dashboard depends on the clicked row's content"
},
"filters": {
"type": "array",
"items": {
"type": "object",
"required": [
"kind",
"expression",
"template"
],
"properties": {
"kind": {
"type": "string",
"const": "expressionTemplate",
"description": "Literal \"expressionTemplate\"; only kind supported today."
},
"template": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered with the clicked row's columns. Example: \"{{ServiceName}}\" pulls the row's ServiceName column value. Columns can be referenced by series alias."
},
"expression": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Column or SQL expression the rendered template is matched against. Example: \"ServiceName\" or \"SpanAttributes['http.route']\". Filters that share an expression are merged into a single IN clause on the destination."
}
},
"description": "One templated equality filter applied on the destination page. Use filters to pre-populate the destination search/dashboard with a row-driven IN clause (e.g. \"ServiceName IN ('api')\") rather than dropping the user into an unscoped view.",
"additionalProperties": false
},
"maxItems": 50,
"description": "Optional list of templated equality filters. Each filter becomes an `expression IN ('rendered-value')` clause on the destination; filters that share an expression are merged into one IN clause."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"description": "Filter language for `whereTemplate` and `filters` (\"lucene\" or \"sql\"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values."
},
"whereTemplate": {
"type": "string",
"maxLength": 10000,
"description": "Optional Handlebars-style WHERE template rendered against the clicked row and placed in the destination's `where` query param. Example: \"ServiceName = '{{service.name}}'\" pulls service.name from the row. Use Lucene or SQL syntax matching `whereLanguage`. Prefer `filters` (below) for simple equality; filters merge nicely on the destination."
}
},
"description": "Row-click handler that opens the /search page. Use this to drill from an aggregated table row down to the underlying log/trace events for that row.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"type",
"target"
],
"properties": {
"type": {
"type": "string",
"const": "dashboard",
"description": "Link to another ClickStack dashboard."
},
"target": {
"$ref": "#/properties/tiles/items/anyOf/3/properties/config/properties/onClick/anyOf/0/properties/target"
},
"filters": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/3/properties/config/properties/onClick/anyOf/0/properties/filters/items"
},
"maxItems": 50,
"description": "Optional list of templated equality filters. The destination dashboard auto-populates its filter list with these (matched by expression), so prefer this over whereTemplate when the target dashboard already declares the same filter expressions. If the destination dashboard does not declare a top-level filter whose `expression` matches, that value is dropped at click time and the destination opens unfiltered for that expression."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"description": "Filter language for `whereTemplate` and `filters` (\"lucene\" or \"sql\"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values."
},
"whereTemplate": {
"type": "string",
"maxLength": 10000,
"description": "Optional Handlebars-style WHERE template applied to the destination dashboard's global filter. Useful when the target dashboard exposes a single global scope rather than per-tile filters."
}
},
"description": "Row-click handler that opens another dashboard. Use this to drill from a high-level overview table down to a per-service or per-endpoint dashboard.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"type",
"urlTemplate"
],
"properties": {
"type": {
"type": "string",
"const": "external",
"description": "Link to an arbitrary external URL (e.g. Grafana, Langfuse)."
},
"urlTemplate": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered against the clicked row, e.g. \"https://example.com/d/abc?var-service={{ServiceName}}\". The rendered value MUST be an absolute http(s) URL; relative URLs and non-http(s) schemes (javascript:, data:, etc.) are rejected at click time. This variant references no HyperDX source or dashboard."
}
},
"description": "Row-click handler that opens an external URL in a new tab. Use this to link out to a third-party tool (Grafana, Langfuse, runbooks, etc.).",
"additionalProperties": false
}
],
"description": "Row-click navigation for tiles that render as tables (Table tiles always; SQL tiles only when displayType is \"table\"). type=\"search\" links to the /search page for a log/trace source; type=\"dashboard\" links to another dashboard; type=\"external\" links to an arbitrary external http(s) URL. All support Handlebars `{{column}}` templating against the clicked row for the target/url, whereTemplate, and filter values.\n\nExamples:\n1. Drill into search for the clicked service: \n { \"type\": \"search\", \"target\": { \"mode\": \"id\", \"id\": \"<trace-source-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n2. Drill into a per-service dashboard: \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"id\", \"id\": \"<dashboard-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n3. Resolve the destination from the row (rare; prefer mode=\"id\"): \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"template\", \"template\": \"{{TargetDashboardName}}\" }, \"whereLanguage\": \"lucene\" }\n4. Link out to an external tool: \n { \"type\": \"external\", \"urlTemplate\": \"https://grafana.example.com/d/abc?var-service={{ServiceName}}\" }"
},
"orderBy": {
"type": "string",
"description": "Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"formulas": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "table",
"description": "Tabular aggregated data"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/showOperandSeries"
},
"groupByColumnsOnLeft": {
"type": "boolean",
"description": "Render Group By columns on the left side of the table, before the series columns. Default false (Group By columns on the right)."
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"color": {
"enum": [
"chart-blue",
"chart-orange",
"chart-red",
"chart-cyan",
"chart-green",
"chart-pink",
"chart-purple",
"chart-light-blue",
"chart-brown",
"chart-gray",
"chart-success",
"chart-warning",
"chart-error"
],
"type": "string",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\", \"chart-green\", or \"chart-success\" (see the enum for the full set). Applied unless a colorRules entry matches the value."
},
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1,
"description": "Exactly one metric to display — unless `formulas` is set, in which case the select items are the formula operands and the (single) formula value is displayed instead."
},
"formulas": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/formulas/items"
},
"maxItems": 1,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session). Number tiles support a single formula and always display the formula value (operand series are hidden)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"colorRules": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "number"
},
"operator": {
"enum": [
"gt",
"gte",
"lt",
"lte"
],
"type": "string"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "array",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2
},
"operator": {
"type": "string",
"const": "between"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 200
}
]
},
"operator": {
"enum": [
"eq",
"neq"
],
"type": "string"
}
},
"additionalProperties": false
}
]
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]."
},
"displayType": {
"type": "string",
"const": "number",
"description": "Single aggregate scalar value"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"backgroundChart": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"line",
"area"
],
"type": "string"
},
"color": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/color"
}
},
"description": "Optional background trend sparkline drawn behind the number, derived from a time-bucketed version of the same query (useful for SLO / error-budget tiles where the trend over the window matters). { type, color? }: type is \"line\" or \"area\"; color is an optional palette token override (the sparkline inherits the tile color when unset). Builder number tiles only; raw SQL number tiles have no time dimension to bucket. Example: { type: \"area\", color: \"chart-blue\" }.",
"additionalProperties": false
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"limit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of slices (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups."
},
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1
},
"groupBy": {
"type": "string",
"description": "Column that defines pie slices. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"orderBy": {
"type": "string",
"description": "Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which slices are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "pie",
"description": "Pie chart"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"limit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of bars (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups."
},
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1
},
"groupBy": {
"type": "string",
"description": "Column(s) that define the bars. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"orderBy": {
"type": "string",
"description": "Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which bars are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "bar",
"description": "Bar chart — one bar per group value (not a time series)"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"heatmapMode",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1,
"description": "Defines the aggregate value displayed for each heatmap series."
},
"groupBy": {
"type": "string",
"description": "SQL GROUP BY expression defining the series shown in the heatmap."
},
"sourceId": {
"type": "string",
"description": "Source ID of a Trace, Log, or Metric source - call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "heatmap",
"description": "Series heatmap: one row per groupBy value, each cell colored by the aggregated value over time"
},
"heatmapMode": {
"type": "string",
"const": "series",
"description": "Must be \"series\" for a series heatmap"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Row-level filter applied before bucketing. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"valueExpression"
],
"properties": {
"countExpression": {
"type": "string",
"description": "Custom count expression (e.g. \"count()\"). Optional; defaults are applied by the renderer."
},
"valueExpression": {
"type": "string",
"minLength": 1,
"description": "Numeric column or expression to bucket. Required and must be non-empty. Use \"Duration\" for trace latency heatmaps, or any other numeric column."
},
"heatmapScaleType": {
"enum": [
"log",
"linear"
],
"type": "string",
"description": "Color scale: \"log\" or \"linear\""
}
},
"additionalProperties": false
},
"maxItems": 1,
"minItems": 1,
"description": "Exactly one heatmap series"
},
"sourceId": {
"type": "string",
"description": "Source ID. Must be a Trace source today; use clickstack_list_sources and pick one whose kind is \"trace\"."
},
"displayType": {
"type": "string",
"const": "heatmap",
"description": "Heatmap chart. Without `heatmapMode` it is a distribution heatmap, which buckets a numeric value on the y-axis and requires a Trace source"
},
"heatmapMode": {
"type": "string",
"const": "distribution",
"description": "Omit for a distribution heatmap"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Display formatting for bucket values. Example: { output: \"duration\", factor: 0.000000001 } to format nanosecond durations as human-readable time."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Filter in Lucene syntax. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "string",
"default": "",
"description": "Columns to display (empty = defaults). Example: \"body,service.name,duration\""
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "search",
"description": "Log/event search results list"
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Filter in Lucene syntax. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "string",
"default": "",
"description": "Pattern expression — column or expression to mine patterns from. Leave empty to use the source default (Body for logs, SpanName for traces). Example: \"Body\", \"SpanName\", \"SpanAttributes['http.url']\""
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "event_patterns",
"description": "Event pattern mining tile"
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType"
],
"properties": {
"markdown": {
"type": "string",
"default": ""
},
"displayType": {
"type": "string",
"const": "markdown",
"description": "Free-form Markdown text tile"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/y"
},
"id": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"configType",
"displayType",
"connectionId",
"sqlTemplate"
],
"properties": {
"color": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/color",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\" or \"chart-success\". Valid only when displayType is \"number\", ignored otherwise. Applied unless a colorRules entry matches the value."
},
"onClick": {
"$ref": "#/properties/tiles/items/anyOf/3/properties/config/properties/onClick",
"description": "Row-click navigation for tiles that render as tables (Table tiles always; SQL tiles only when displayType is \"table\"). type=\"search\" links to the /search page for a log/trace source; type=\"dashboard\" links to another dashboard; type=\"external\" links to an arbitrary external http(s) URL. All support Handlebars `{{column}}` templating against the clicked row for the target/url, whereTemplate, and filter values.\n\nExamples:\n1. Drill into search for the clicked service: \n { \"type\": \"search\", \"target\": { \"mode\": \"id\", \"id\": \"<trace-source-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n2. Drill into a per-service dashboard: \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"id\", \"id\": \"<dashboard-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n3. Resolve the destination from the row (rare; prefer mode=\"id\"): \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"template\", \"template\": \"{{TargetDashboardName}}\" }, \"whereLanguage\": \"lucene\" }\n4. Link out to an external tool: \n { \"type\": \"external\", \"urlTemplate\": \"https://grafana.example.com/d/abc?var-service={{ServiceName}}\" }"
},
"sourceId": {
"type": "string",
"description": "Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId."
},
"fillNulls": {
"type": "boolean"
},
"colorRules": {
"type": "array",
"items": {
"$ref": "#/properties/tiles/items/anyOf/4/properties/config/properties/colorRules/items"
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]. Valid only when displayType is \"number\", ignored otherwise."
},
"configType": {
"type": "string",
"const": "sql",
"description": "Must be \"sql\" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need."
},
"displayType": {
"enum": [
"line",
"stacked_bar",
"stacked_line",
"table",
"number",
"pie",
"bar"
],
"type": "string",
"description": "How to render the SQL results"
},
"sqlTemplate": {
"type": "string",
"description": "\nRaw ClickHouse SQL query. SQL guidelines:\n\n1. ALWAYS include a LIMIT clause to avoid excessive data.\n2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.\n - $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))\n - $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)\n - $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)\n - $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.\n - NEVER hardcode a fixed time range unless the user specifically asks for it.\n - $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.\n3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.\n - $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)\n - $__interval_s expands to {intervalSeconds:Int64}\n - These macros are only available for time-series charts; do not use them for other display types.\n4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.\n - $__filters and $__sourceTable both require sourceId to be set on this tile.\n - IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include\n the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.\n\nExample:\n\nSELECT\n $__timeInterval(TimestampTime) AS ts,\n count()\nFROM $__sourceTable\nWHERE $__timeFilter(TimestampTime)\n AND $__filters\nGROUP BY ServiceName, ts\n"
},
"connectionId": {
"type": "string",
"description": "Connection ID (not sourceId) – call clickstack_list_sources to find available connections"
},
"numberFormat": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is \"line\", ignored otherwise."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series. Valid only when displayType is \"line\", ignored otherwise."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
}
]
},
"description": "Array of dashboard tiles. Each tile needs a name, optional layout (x/y/w/h), and a config block. The config block varies by displayType – use clickstack_list_sources for sourceId and connectionId values.\n\nExample tiles:\n1. Line chart: { \"name\": \"Error Rate\", \"config\": { \"displayType\": \"line\", \"sourceId\": \"<from list_sources>\", \"groupBy\": \"ResourceAttributes['service.name']\", \"select\": [{ \"aggFn\": \"count\", \"where\": \"StatusCode:STATUS_CODE_ERROR\", \"alias\": \"Errors\" }] } }\n2. Table: { \"name\": \"Top Endpoints\", \"config\": { \"displayType\": \"table\", \"sourceId\": \"<from list_sources>\", \"groupBy\": \"SpanAttributes['http.route']\", \"select\": [{ \"aggFn\": \"count\", \"alias\": \"Requests\" }, { \"aggFn\": \"avg\", \"valueExpression\": \"Duration\", \"alias\": \"Avg Duration\", \"numberFormat\": { \"output\": \"duration\", \"factor\": 0.000000001 } }] } }\n (per-series numberFormat lets one column render as a duration while a sibling count column stays a plain number)\n3. Number: { \"name\": \"Total Requests\", \"config\": { \"displayType\": \"number\", \"sourceId\": \"<from list_sources>\", \"select\": [{ \"aggFn\": \"count\", \"alias\": \"Requests\" }], \"numberFormat\": { \"output\": \"number\", \"average\": true } } }\n4. Number (duration): { \"name\": \"P95 Latency\", \"config\": { \"displayType\": \"number\", \"sourceId\": \"<from list_sources>\", \"select\": [{ \"aggFn\": \"quantile\", \"level\": 0.95, \"valueExpression\": \"Duration\", \"alias\": \"P95 Latency\" }], \"numberFormat\": { \"output\": \"duration\", \"factor\": 0.000000001 } } }\n5. Heatmap: { \"name\": \"Latency Heatmap\", \"config\": { \"displayType\": \"heatmap\", \"sourceId\": \"<from list_sources, must be a Trace source>\", \"select\": [{ \"valueExpression\": \"Duration\" }], \"numberFormat\": { \"output\": \"duration\", \"factor\": 0.000000001 } } }"
},
"filters": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"name",
"type",
"expression",
"sourceId"
],
"properties": {
"id": {
"type": "string",
"description": "Filter identity. On UPDATE of an existing dashboard, every filter in the array MUST carry an id: pass the exact id returned by clickstack_get_dashboard for any filter you are keeping (so saved values bound to it stay attached), and generate a fresh random hex/ObjectId string for any filter you are adding in this update. Omitting `id` on an existing filter would orphan its saved values; reusing an existing id for a new filter would silently overwrite the old one. On CREATE (no top-level `id` on the dashboard call), filter `id` may be omitted and one will be generated server-side."
},
"name": {
"type": "string",
"minLength": 1,
"description": "Human-readable filter label shown in the dashboard filter bar dropdown."
},
"type": {
"type": "string",
"const": "QUERY_EXPRESSION",
"description": "Filter type discriminator for a filter whose dropdown values are queried from a source column (expression + sourceId)."
},
"where": {
"type": "string",
"description": "Optional WHERE clause scoping the dropdown values (e.g. \"level:error\" in Lucene). DEPENDENT FILTERS: this clause may reference ANOTHER filter's variable, which chains one dropdown off another (pick a service, and this filter's dropdown only offers that service's endpoints). The upstream filter must set isVariableEnabled: true; this one does not have to. With whereLanguage \"sql\", prefer $__filter(<expression>, $<variableName>) so the dropdown lists every value until the upstream filter is set; a bare $variableName leaves this dropdown empty until then. With whereLanguage \"lucene\" a bare reference is already safe: it renders as (\"\") with nothing selected, which matches all. Reference a SIBLING filter's variable only: naming this filter's own variable collapses its dropdown to the values already picked."
},
"sourceId": {
"$ref": "#/properties/id",
"description": "Source the filter values are pulled from (for the dropdown). Get IDs from clickstack_list_sources."
},
"expression": {
"type": "string",
"minLength": 1,
"description": "Column or SQL expression this filter binds to. Example: \"ServiceName\" or \"SpanAttributes['http.method']\". IMPORTANT: This is the key that table-tile onClick filters match against when a row click navigates here. An onClick filter whose `expression` is not declared in any of this dashboard's filters is silently dropped at click time. Declare an expression here for every column you plan to drive via row-click."
},
"variableName": {
"type": "string",
"pattern": "^[a-zA-Z][a-zA-Z0-9_]*$",
"maxLength": 64,
"description": "Token that tiles reference this filter's selected value by, eg. $variableName. Must start with a letter and may contain only letters, numbers, and underscores, up to 64 characters. A default is determined based on the display name. Must be unique across the dashboard's variable-enabled filters. Rejected when isVariableEnabled is not true."
},
"maxSelections": {
"type": "integer",
"maximum": 1,
"minimum": 1,
"description": "Set to 1 to make this filter SINGLE-SELECT: the user can pick at most one value. In PromQL, a single-select variable expands to its raw value by default (for exact matchers such as {job=\"$job\"}), while a multi-select one expands to an escaped regex (for {job=~\"$job\"}). Omit for the normal multi-select behavior."
},
"minSelections": {
"type": "integer",
"maximum": 1,
"minimum": 0,
"description": "Set to 1 to make this filter REQUIRED. Until the user picks at least one value for it, the tiles that read this filter refuse to load and show a \"missing required filters\" message instead. By default, tiles that reference this filter by its variable or receive a broadcasted value from this filter will be blocked. isGlobalRequirement widens the block to all tiles.Only 0 and 1 are accepted; omit the field (or pass 0) for the normal optional behavior, which is usually what you want."
},
"whereLanguage": {
"$ref": "#/properties/tiles/items/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"description": "Filter language for `where` (\"lucene\" or \"sql\"). Optional, but set it explicitly."
},
"sourceMetricType": {
"enum": [
"gauge",
"histogram",
"sum",
"summary",
"exponential histogram"
],
"type": "string",
"description": "Required only when `sourceId` is a Metric source; picks which metric table the dropdown values come from."
},
"isVariableEnabled": {
"type": "boolean",
"description": "Whether the selected value is exposed to tile queries as a dashboard variable named by variableName. Omitting the field means DISABLED. Tiles reference it as $variableName, or (preferred) via $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>) in any SQL condition (a select item's `where`, a tile-level `where`, `having`, or a raw SQL tile's sqlTemplate). Another filter's `where` can reference it too, which chains that filter's dropdown off this one."
},
"appliesToSourceIds": {
"type": "array",
"items": {
"$ref": "#/properties/id"
},
"description": "Optional list of source IDs that this filter is applied to. Omit (or pass `undefined`) to apply the filter to ALL tiles regardless of source — this is the recommended default. A non-empty array restricts the filter to only tiles whose source ID is in the list; tiles on other sources are not affected by the dropdown value at all. Useful on mixed-source dashboards where a column (e.g. SpanName) only exists on a subset of sources. Scopes the broadcast condition only, so a non-empty array is rejected when isBroadcastEnabled is false."
},
"isBroadcastEnabled": {
"type": "boolean",
"description": "Whether the selected value is applied as a filter condition on every builder tile this filter applies to (see appliesToSourceIds), and on every raw SQL tile using the $__filters macro. Omitting the field means ENABLED. Set false to build a variable-only filter that tiles opt into by name."
},
"isGlobalRequirement": {
"type": "boolean",
"description": "Widens a REQUIRED filter (minSelections: 1) to block EVERY tile on the dashboard, not just the ones that read it. Ignored unless minSelections is 1."
}
},
"description": "A dashboard filter whose dropdown values are queried from a source. Each filter binds a label/name to a column expression on a source. Every filter either broadcasts its selected value to matching tiles as a condition (isBroadcastEnabled, the default), exposes it to tile queries as a variable (isVariableEnabled + variableName), or both. Typically pick only ONE.Filters are also the contract for row-click navigation: a table tile's onClick.filters[i].expression must match a filter declared here for the value to land.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"type",
"options"
],
"properties": {
"id": {
"$ref": "#/properties/filters/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/filters/items/anyOf/0/properties/name"
},
"type": {
"type": "string",
"const": "STATIC_LIST",
"description": "Filter type discriminator for a filter whose dropdown offers a fixed hand-authored list; no source query."
},
"options": {
"type": "array",
"items": {
"type": "string",
"maxLength": 10000,
"minLength": 1
},
"maxItems": 1000,
"minItems": 1,
"description": "The values the dropdown offers, in display order. 1-1000 unique, non-empty strings."
},
"variableName": {
"$ref": "#/properties/filters/items/anyOf/0/properties/variableName",
"description": "Token that tiles reference this filter's selected value by, eg. $variableName. Must start with a letter and may contain only letters, numbers, and underscores, up to 64 characters. A default is determined based on the display name. Must be unique across the dashboard's variable-enabled filters."
},
"maxSelections": {
"$ref": "#/properties/filters/items/anyOf/0/properties/maxSelections"
},
"minSelections": {
"$ref": "#/properties/filters/items/anyOf/0/properties/minSelections"
},
"isGlobalRequirement": {
"$ref": "#/properties/filters/items/anyOf/0/properties/isGlobalRequirement"
}
},
"description": "A variable-only dashboard filter whose dropdown offers a hand-authored options list. Use it when the values are a fixed business list (environments, tiers, regions) rather than derivable from the data. The selected value reaches tiles only as $variableName — typically via $__filter(<expression>, $<variableName>) with the column passed explicitly, since the filter has no expression of its own.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"name",
"type",
"sourceId",
"expression"
],
"properties": {
"id": {
"$ref": "#/properties/filters/items/anyOf/0/properties/id"
},
"name": {
"$ref": "#/properties/filters/items/anyOf/0/properties/name"
},
"type": {
"type": "string",
"const": "SOURCE_FILTER",
"description": "Filter type discriminator for a filter backed by one of the columns a source declares in its `requiredSourceFilters` (its filterSettings)."
},
"sourceId": {
"$ref": "#/properties/id",
"description": "ID of a source whose `requiredSourceFilters` declares `expression` as one of its columns. Get IDs and their requiredSourceFilters from clickstack_list_sources or clickstack_describe_source. Rejected when the source does not declare the column."
},
"expression": {
"type": "string",
"minLength": 1,
"description": "The required column this filter collects values for. MUST match one of the `requiredSourceFilters.columns[].name` values on `sourceId`'s source."
},
"variableName": {
"$ref": "#/properties/filters/items/anyOf/0/properties/variableName",
"description": "Token that tiles reference this filter's selected value by, eg. $variableName. Must start with a letter and may contain only letters, numbers, and underscores, up to 64 characters. A default is determined based on the display name. Must be unique across the dashboard's variable-enabled filters. A SOURCE_FILTER always publishes its selection as a variable, so this field only renames the token; omit it to get the default derived from `name` (e.g. \"Cluster\" publishes $Cluster)."
},
"maxSelections": {
"$ref": "#/properties/filters/items/anyOf/0/properties/maxSelections"
},
"minSelections": {
"type": "integer",
"default": 1,
"maximum": 1,
"minimum": 0,
"description": "Defaults to 1 (REQUIRED), which is almost always right: a source that declares the column cannot be queried until a value is chosen. Pass 0 only to drop the explicit \"missing required filters\" message."
},
"appliesToSourceIds": {
"type": "array",
"items": {
"$ref": "#/properties/id"
},
"description": "Optional list of source IDs the selection is applied to. Omit to apply it to EVERY tile. Set it to the subset of sources that declare this column when the dashboard mixes sources and the same column name means different things."
},
"isGlobalRequirement": {
"$ref": "#/properties/filters/items/anyOf/0/properties/isGlobalRequirement"
}
},
"description": "A dashboard filter backed by a required source filter (core filter): one of the columns a source declares in `requiredSourceFilters`. ONLY use when the source declares required source Filters, and should always be declared for each required unique source filter column.\n\nMODES ARE FIXED: a SOURCE_FILTER always BROADCASTS (the selection supplies the required column's values to every tile whose source declares that column, and to the `$__filters` macro of raw SQL tiles) AND is always VARIABLE-ENABLED (the selection is also published as $<variableName>). Reference the variable only when the value must appear somewhere the required-column predicate cannot reach (a CTE, a JOIN condition, a SELECT expression) via $__filter(<expression>, $<variableName>).",
"additionalProperties": false
}
],
"description": "A dashboard-level filter the user can adjust in the dashboard filter bar. Three types: QUERY_EXPRESSION queries its dropdown values from a source column; STATIC_LIST declares them inline and is always variable-only; SOURCE_FILTER binds to a column from a source's `requiredSourceFilters` and is REQUIRED whenever a tile queries such a source."
},
"description": "Optional dashboard-level filters. These define the dropdowns in the dashboard filter bar AND the expressions that table-tile row-click navigation can populate. If another tile's onClick targets THIS dashboard with `filters: [{ expression: \"X\", ... }]`, this array MUST declare a filter whose `expression` is \"X\". Otherwise the value is dropped on arrival and the destination opens unfiltered.\n\nThree filter types: QUERY_EXPRESSION queries its dropdown values from a source column, STATIC_LIST declares them inline via `options` and is always variable-only (it has no expression to broadcast), and SOURCE_FILTER binds to a column a source declares in its `requiredSourceFilters`.\n\nSOURCE_FILTER type filters should always be added to a dashboard if any of the tiles query a source with requiredSourceFilters (indicated by clickstack_list_sources / clickstack_describe_source), and should never be used otherwise. Add one SOURCE_FILTER per distinct required column in `requiredSourceFilters`. Without it the tile renders an empty state instead of data. One SOURCE_FILTER covers every source that declares a column of the same name, so a dashboard mixing a log and a trace source that both require `cluster` needs one `cluster` filter, not two.\n\nA QUERY_EXPRESSION filter runs in one of two modes (or both). BROADCAST (the default) applies the selected value as a condition on matching tiles with no per-tile wiring. VARIABLE (isVariableEnabled) exposes the value to tile queries as $variableName, which the tile must reference explicitly. Prefer broadcast; reach for a variable in advanced cases. Enabling both on one filter applies the value twice.\n\nBy default, a broadcast filter applies to every tile on the dashboard. On mixed-source dashboards, use variable mode or the optional `appliesToSourceIds` field to restrict a filter to only the tiles whose source carries the referenced column — leave `appliesToSourceIds` omitted to keep the broadcast-to-all-tiles default. `appliesToSourceIds` does NOT scope variable references; any tile may reference any variable.\n\nExample (broadcast to every tile, the common case):\n[\n { \"type\": \"QUERY_EXPRESSION\", \"name\": \"Service\", \"expression\": \"ServiceName\",\n \"sourceId\": \"<trace-source-id>\", \"whereLanguage\": \"sql\" }\n]\n\nExample (scoped on a mixed log/trace/metric dashboard):\n[\n { \"type\": \"QUERY_EXPRESSION\", \"name\": \"Service\", \"expression\": \"SpanName\",\n \"sourceId\": \"<trace-source-id>\", \"whereLanguage\": \"sql\",\n \"appliesToSourceIds\": [\"<trace-source-id>\"] }\n]\n\nExample (variable only, referenced by tiles as $service):\n[\n { \"type\": \"QUERY_EXPRESSION\", \"name\": \"Service\", \"expression\": \"ServiceName\",\n \"sourceId\": \"<trace-source-id>\", \"whereLanguage\": \"sql\",\n \"isBroadcastEnabled\": false, \"isVariableEnabled\": true, \"variableName\": \"service\" }\n]\nA tile then uses it as $__filter(ServiceName, $service) in a SQL where clause, which expands to 1=1 while nothing is selected.\n\nExample (static list: fixed hand-authored values, always a variable, no source query):\n[\n { \"type\": \"STATIC_LIST\", \"name\": \"Environment\",\n \"options\": [\"prod\", \"staging\", \"dev\"], \"variableName\": \"env\" }\n]\nA tile references it as $__filter(ResourceAttributes['deployment.environment'], $env). Always pass the column explicitly: the one-argument $__filter($env) form reuses the filter's own expression, which a static filter does not have. Prefer STATIC_LIST when the values are a fixed business list or a curated subset rather than derivable from the data.\n\nExample (dependent filter: the Endpoint dropdown only lists the selected service's endpoints):\n[\n { \"type\": \"QUERY_EXPRESSION\", \"name\": \"Service\", \"expression\": \"ServiceName\",\n \"sourceId\": \"<trace-source-id>\", \"whereLanguage\": \"sql\",\n \"isVariableEnabled\": true, \"variableName\": \"service\" },\n { \"type\": \"QUERY_EXPRESSION\", \"name\": \"Endpoint\", \"expression\": \"SpanName\",\n \"sourceId\": \"<trace-source-id>\", \"whereLanguage\": \"sql\",\n \"where\": \"$__filter(ServiceName, $service)\" }\n]\nA filter's `where` scopes only the values ITS dropdown offers; it is not applied to any tile. That is why Service keeps broadcasting here: its variable is read by the Endpoint dropdown, not by a tile, so the value is never applied twice."
},
"containers": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title",
"collapsed"
],
"properties": {
"id": {
"type": "string",
"maxLength": 256,
"minLength": 1
},
"tabs": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title"
],
"properties": {
"id": {
"type": "string",
"maxLength": 256,
"minLength": 1
},
"title": {
"type": "string",
"maxLength": 256,
"minLength": 1
}
},
"additionalProperties": false
},
"maxItems": 20
},
"title": {
"type": "string",
"maxLength": 256,
"minLength": 1
},
"bordered": {
"type": "boolean"
},
"collapsed": {
"type": "boolean"
},
"collapsible": {
"type": "boolean"
}
},
"additionalProperties": false
},
"maxItems": 50,
"description": "Optional dashboard organization layer. Each container groups one or more tiles visually and may carry a tab bar. Tiles join a container by setting tile.containerId; tiles further select a tab by setting tile.tabId.\n\nRules:\n- Container ids must be unique on the dashboard.\n- Tab ids must be unique within a container.\n- A tile.containerId must reference a container id in this array.\n- A tile.tabId must reference a tab id on the same container.\n- tile.tabId requires tile.containerId.\n\nContainer shape: { id, title, collapsed, collapsible?, bordered?, tabs? }. `collapsed` is required. `collapsible` and `bordered` are optional and persisted absent when omitted; the renderer treats absence as true. Two or more tabs render as a tab bar; zero or one tab renders as a plain group header.\n\nExample:\n[\n { \"id\": \"service-health\", \"title\": \"Service Health\", \"collapsed\": false,\n \"tabs\": [ { \"id\": \"errors\", \"title\": \"Errors\" }, { \"id\": \"latency\", \"title\": \"Latency\" } ] },\n { \"id\": \"overview\", \"title\": \"Overview\", \"collapsed\": true }\n]"
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description88/100
Make targeted updates to a dashboard without resubmitting the full object. You can update dashboard-level fields (name, tags) and/or replace a single tile by tileId — all in one call. Unmentioned tiles and fields are preserved. Use clickstack_get_dashboard_tile to inspect a tile before patching it. IMPORTANT: After patching a tile, run clickstack_query_tile to confirm the query still works.
Explain mutations, irreversible effects, or prerequisites that matter before calling this tool.
Inputs46/100
133 of 241 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
dashboardId
Dashboard ID.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
name
New dashboard name. Omit to keep the current name.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tags
New tags array (replaces all existing tags). Omit to keep the current tags. Up to 50 tags, each at most 32 characters.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tileId
ID of the tile to replace. Must be paired with `tile`. Obtain tile IDs from clickstack_get_dashboard.
Clear enough to supply this argument.
tile › anyOf › 0 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 0 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 0 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Resolve the mismatch between this description and its schema constraints.
tile › anyOf › 0 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Resolve the mismatch between this description and its schema constraints.
Aggregation function. "count" requires no valueExpression; all others do. METRIC SOURCES: "increase" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use "quantile" with level or "count".
Column or expression to aggregate. Required for all aggFn except "count". Use PascalCase for top-level columns (e.g. "Duration", "StatusCode"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).
METRIC SOURCES: optional — defaults to "Value" (the metric value column) when metricType/metricName are set.
Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible "Where" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. "Requests", "P95 Latency", "Error Rate"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Format category. "duration" auto-formats elapsed times as e.g. "1.2s" (use factor for input unit). "time" formats clock-style durations. "byte" formats as KB/MB/GB. "data_rate" formats as bytes/sec. "throughput" formats as count/sec. "currency" prepends a symbol. "percent" appends %, and divides the value by 100 (0.5 becomes 50%).
METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:"sql") against the table in the source's metricTables.summary.
Overlay the previous period as a dashed comparison series.
Clear enough to supply this argument.
tile › anyOf › 0 › config › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 0 › config › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Arithmetic expression over the tile's select items by position: "A" is select[0], "B" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. "A / (A + B) * 100" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error.
Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. "Error rate %").
Clear enough to supply this argument.
tile › anyOf › 0 › config › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
tile › anyOf › 1 › name
Tile title. Omit to keep the existing title.
Clear enough to supply this argument.
tile › anyOf › 1 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Clear enough to supply this argument.
tile › anyOf › 1 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Clear enough to supply this argument.
tile › anyOf › 1 › config › displayType
Stacked bar chart over time
Clear enough to supply this argument.
tile › anyOf › 1 › config › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
tile › anyOf › 1 › config › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › config › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › config › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 1 › config › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
tile › anyOf › 1 › config › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 2 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 2 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Clear enough to supply this argument.
tile › anyOf › 2 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 2 › config › displayType
Stacked line (area) chart over time
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 2 › config › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
tile › anyOf › 2 › config › groupBy
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › config › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › config › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 2 › config › seriesLimit
Maximum number of series to fetch (the "Series Limit" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N.
Clear enough to supply this argument.
tile › anyOf › 2 › config › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Clear enough to supply this argument.
tile › anyOf › 3 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 3 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Clear enough to supply this argument.
tile › anyOf › 3 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Clear enough to supply this argument.
tile › anyOf › 3 › config › displayType
Tabular aggregated data
Clear enough to supply this argument.
tile › anyOf › 3 › config › sourceId
Source ID – call clickstack_list_sources
Clear enough to supply this argument.
tile › anyOf › 3 › config › groupBy
Group rows by this column. Use PascalCase for top-level columns (e.g. "SpanName"). For attributes: SpanAttributes['key'] or ResourceAttributes['key'].
Clear enough to supply this argument.
tile › anyOf › 3 › config › having
Post-aggregation SQL HAVING expression. Example: "Count > 100" to drop groups with few rows, or "StatusMessage != ''" to drop empty-message rows from a groupBy: "StatusMessage" table. Mirrors the same field on the REST table chart config in `externalDashboardTableChartConfigSchema`.
DASHBOARD VARIABLES: accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which expand to 1=1 while the variable has no selection, as well as a bare $variableName reference (which renders as NULL when nothing is selected).
Clear enough to supply this argument.
tile › anyOf › 3 › config › orderBy
Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '"P95 Latency" DESC'.
Clear enough to supply this argument.
tile › anyOf › 3 › config › asRatio
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 3 › config › groupByColumnsOnLeft
Render Group By columns on the left side of the table, before the series columns. Default false (Group By columns on the right).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Concrete source ID (for type=search) or dashboard ID (for type=dashboard). Get source IDs from clickstack_list_sources; get dashboard IDs from clickstack_get_dashboard (no id arg returns the list). For type=search the source kind must be "log" or "trace"; the /search page does not render metric/session sources.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Handlebars-style template rendered against the clicked row, then resolved by NAME on the destination team. Example: "ServiceOverview-{{ServiceName}}" assumes a row column ServiceName whose value is the name of a source/dashboard. Prefer mode="id" when the target is known up-front; it survives renames.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Optional Handlebars-style WHERE template rendered against the clicked row and placed in the destination's `where` query param. Example: "ServiceName = '{{service.name}}'" pulls service.name from the row. Use Lucene or SQL syntax matching `whereLanguage`. Prefer `filters` (below) for simple equality; filters merge nicely on the destination.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Filter language for `whereTemplate` and `filters` ("lucene" or "sql"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Column or SQL expression the rendered template is matched against. Example: "ServiceName" or "SpanAttributes['http.route']". Filters that share an expression are merged into a single IN clause on the destination.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Handlebars-style template rendered with the clicked row's columns. Example: "{{ServiceName}}" pulls the row's ServiceName column value. Columns can be referenced by series alias.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Optional Handlebars-style WHERE template applied to the destination dashboard's global filter. Useful when the target dashboard exposes a single global scope rather than per-tile filters.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Filter language for `whereTemplate` and `filters` ("lucene" or "sql"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Handlebars-style template rendered against the clicked row, e.g. "https://example.com/d/abc?var-service={{ServiceName}}". The rendered value MUST be an absolute http(s) URL; relative URLs and non-http(s) schemes (javascript:, data:, etc.) are rejected at click time. This variant references no HyperDX source or dashboard.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 3 › config › showOperandSeries
Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 4 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › config › displayType
Single aggregate scalar value
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › config › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 4 › config › color
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Static color for the displayed number, as a palette token such as "chart-blue", "chart-green", or "chart-success" (see the enum for the full set). Applied unless a colorRules entry matches the value.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 5 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › displayType
Pie chart
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › groupBy
Column that defines pie slices. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key'].
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › orderBy
Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which slices are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '"P95 Latency" DESC'.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 5 › config › limit
Maximum number of slices (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 6 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › displayType
Bar chart — one bar per group value (not a time series)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › groupBy
Column(s) that define the bars. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key'].
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › orderBy
Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which bars are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '"P95 Latency" DESC'.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 6 › config › limit
Maximum number of bars (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 7 › config › where
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › config › whereLanguage
Not supported on this tile type. Filter via each select item's `where`.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › config › displayType
Series heatmap: one row per groupBy value, each cell colored by the aggregated value over time
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › config › heatmapMode
Must be "series" for a series heatmap
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › config › sourceId
Source ID of a Trace, Log, or Metric source - call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 7 › config › groupBy
SQL GROUP BY expression defining the series shown in the heatmap.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 8 › config › displayType
Heatmap chart. Without `heatmapMode` it is a distribution heatmap, which buckets a numeric value on the y-axis and requires a Trace source
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › config › heatmapMode
Omit for a distribution heatmap
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › config › sourceId
Source ID. Must be a Trace source today; use clickstack_list_sources and pick one whose kind is "trace".
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › config › where
Row-level filter applied before bucketing. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 8 › config › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 9 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › config › displayType
Log/event search results list
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 9 › config › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 9 › config › where
Filter in Lucene syntax. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 9 › config › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 9 › config › select
Columns to display (empty = defaults). Example: "body,service.name,duration"
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 10 › name
Tile title. Omit to keep the existing title.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 10 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › config › displayType
Event pattern mining tile
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 10 › config › sourceId
Source ID – call clickstack_list_sources
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tile › anyOf › 10 › config › where
Filter in Lucene syntax. Example: "level:error"
DASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage "sql" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as ("") and the translator drops it to a match-all.
Clear enough to supply this argument.
tile › anyOf › 10 › config › whereLanguage
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 10 › config › select
Pattern expression — column or expression to mine patterns from. Leave empty to use the source default (Body for logs, SpanName for traces). Example: "Body", "SpanName", "SpanAttributes['http.url']"
Clear enough to supply this argument.
tile › anyOf › 11 › name
Tile title. Omit to keep the existing title.
Clear enough to supply this argument.
tile › anyOf › 11 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 11 › config › displayType
Free-form Markdown text tile
Clear enough to supply this argument.
tile › anyOf › 11 › config › markdown
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › name
Tile title. Omit to keep the existing title.
Clear enough to supply this argument.
tile › anyOf › 12 › x
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › y
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › w
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › h
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › containerId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › tabId
Not provided
Missing description. Explain what this value means and how to supply it.
tile › anyOf › 12 › config › configType
Must be "sql" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need.
Clear enough to supply this argument.
tile › anyOf › 12 › config › displayType
How to render the SQL results
Clear enough to supply this argument.
tile › anyOf › 12 › config › connectionId
Connection ID (not sourceId) – call clickstack_list_sources to find available connections
Clear enough to supply this argument.
tile › anyOf › 12 › config › sourceId
Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId.
Clear enough to supply this argument.
tile › anyOf › 12 › config › sqlTemplate
Raw ClickHouse SQL query. SQL guidelines:
1. ALWAYS include a LIMIT clause to avoid excessive data.
2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.
- $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))
- $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)
- $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)
- $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.
- NEVER hardcode a fixed time range unless the user specifically asks for it.
- $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.
3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.
- $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)
- $__interval_s expands to {intervalSeconds:Int64}
- These macros are only available for time-series charts; do not use them for other display types.
4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.
- $__filters and $__sourceTable both require sourceId to be set on this tile.
- IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include
the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.
Example:
SELECT
$__timeInterval(TimestampTime) AS ts,
count()
FROM $__sourceTable
WHERE $__timeFilter(TimestampTime)
AND $__filters
GROUP BY ServiceName, ts
Clear enough to supply this argument.
tile › anyOf › 12 › config › fillNulls
Not provided
Missing description. Explain what this value means and how to supply it.
Overlay the previous period as a dashed comparison series. Valid only when displayType is "line", ignored otherwise.
Clear enough to supply this argument.
tile › anyOf › 12 › config › fitYAxisToData
Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is "line", ignored otherwise.
Clear enough to supply this argument.
tile › anyOf › 12 › config › color
Static color for the displayed number, as a palette token such as "chart-blue" or "chart-success". Valid only when displayType is "number", ignored otherwise. Applied unless a colorRules entry matches the value.
Clear enough to supply this argument.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_patch_dashboard",
"title": "Patch Dashboard",
"description": "Make targeted updates to a dashboard without resubmitting the full object. You can update dashboard-level fields (name, tags) and/or replace a single tile by tileId — all in one call. Unmentioned tiles and fields are preserved. Use clickstack_get_dashboard_tile to inspect a tile before patching it. IMPORTANT: After patching a tile, run clickstack_query_tile to confirm the query still works.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"dashboardId"
],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "New dashboard name. Omit to keep the current name."
},
"tags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 32
},
"maxItems": 50,
"description": "New tags array (replaces all existing tags). Omit to keep the current tags. Up to 50 tags, each at most 32 characters."
},
"tile": {
"anyOf": [
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"type": "number",
"minimum": 1
},
"w": {
"type": "number",
"maximum": 24,
"minimum": 1
},
"x": {
"type": "number",
"maximum": 23,
"minimum": 0
},
"y": {
"type": "number",
"minimum": 0
},
"name": {
"type": "string",
"minLength": 1,
"description": "Tile title. Omit to keep the existing title."
},
"tabId": {
"type": "string",
"maxLength": 256,
"minLength": 1
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"not": {},
"description": "Not supported on this tile type. Filter via each select item's `where`."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"any",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function. \"count\" requires no valueExpression; all others do. METRIC SOURCES: \"increase\" computes the per-bucket counter increase for Sum metrics (reset-aware). For Gauges use last_value/avg/min/max. For Histograms and Exponential Histograms use \"quantile\" with level or \"count\"."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read. Heatmap select items are the only exception (no alias needed)."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level for aggFn=\"quantile\". REQUIRED for histogram and exponential histogram metrics with aggFn:\"quantile\"."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter for THIS series (compiles to `countIf(...)`). This is how you filter a builder tile: the chart editor renders it as the tile's visible \"Where\" box, so the user can see and edit it. To scope the whole tile to a subset of rows, put the same `where` on every select item; use different filters per item for cohort comparisons (errors vs total). There is no tile-level `where` for these tile types. Lucene syntax by default. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\"). Required when metricType is set."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when the tile sourceId is a metric source. summary is not supported by the renderer — chart summary metrics with a raw SQL tile (configType:\"sql\") against the table in the source's metricTables.summary."
},
"periodAggFn": {
"enum": [
"delta"
],
"type": "string",
"description": "Alias for isDelta accepted for round-tripping configs read from get tools: \"delta\" is equivalent to isDelta: true."
},
"numberFormat": {
"type": "object",
"required": [
"output"
],
"properties": {
"unit": {
"type": "string",
"description": "Suffix appended to the value (e.g. \" req/s\")"
},
"factor": {
"type": "number",
"description": "Input unit factor for \"time\" or \"duration\" output. 1 = seconds, 0.001 = milliseconds, 0.000001 = microseconds, 0.000000001 = nanoseconds."
},
"output": {
"enum": [
"currency",
"percent",
"byte",
"time",
"duration",
"number",
"data_rate",
"throughput"
],
"type": "string",
"description": "Format category. \"duration\" auto-formats elapsed times as e.g. \"1.2s\" (use factor for input unit). \"time\" formats clock-style durations. \"byte\" formats as KB/MB/GB. \"data_rate\" formats as bytes/sec. \"throughput\" formats as count/sec. \"currency\" prepends a symbol. \"percent\" appends %, and divides the value by 100 (0.5 becomes 50%)."
},
"average": {
"type": "boolean",
"description": "Abbreviate large numbers (e.g. 1.2m)"
},
"mantissa": {
"type": "integer",
"description": "Decimal places (0–10). Not used for \"time\" or \"duration\" output."
},
"decimalBytes": {
"type": "boolean",
"description": "Use decimal base for bytes (1KB = 1000). Only for \"byte\" output."
},
"currencySymbol": {
"type": "string",
"description": "Currency symbol (e.g. \"$\"). Only for \"currency\" output."
},
"thousandSeparated": {
"type": "boolean",
"description": "Separate thousands (e.g. 1,234,567)"
}
},
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts.",
"additionalProperties": false
},
"whereLanguage": {
"enum": [
"sql",
"lucene"
],
"type": "string",
"default": "lucene"
},
"valueExpression": {
"type": "string",
"description": "Column or expression to aggregate. Required for all aggFn except \"count\". Use PascalCase for top-level columns (e.g. \"Duration\", \"StatusCode\"). For span attributes use: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). For resource attributes use: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name']).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set."
}
},
"additionalProperties": false
},
"maxItems": 20,
"minItems": 1,
"description": "Metrics to plot (one series per item)"
},
"asRatio": {
"type": "boolean",
"description": "Plot as ratio of two metrics (requires exactly 2 select items)"
},
"groupBy": {
"type": "string",
"description": "Column to split/group by. Top-level columns use PascalCase (e.g. \"SpanName\", \"StatusCode\"). Span attributes: SpanAttributes['key'] (e.g. SpanAttributes['http.method']). Resource attributes: ResourceAttributes['key'] (e.g. ResourceAttributes['service.name'])."
},
"formulas": {
"type": "array",
"items": {
"type": "object",
"required": [
"expression"
],
"properties": {
"alias": {
"type": "string",
"description": "Display label for the formula series (chart legend / column header). Falls back to the raw expression text when unset. Always set a short, human-readable alias (e.g. \"Error rate %\")."
},
"expression": {
"type": "string",
"maxLength": 1024,
"description": "Arithmetic expression over the tile's select items by position: \"A\" is select[0], \"B\" is select[1], etc. Supports + - * /, parentheses, and numeric constants — e.g. \"A / (A + B) * 100\" for a success rate. Division by zero or a missing operand renders as a gap (NULL), not an error."
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Per-series display formatting, applied to this series only (overrides any tile-level numberFormat). Controls how the series number value(s) are formatted for display. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
}
},
"additionalProperties": false
},
"maxItems": 10,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "line",
"description": "Line chart over time"
},
"seriesLimit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero."
},
"showOperandSeries": {
"type": "boolean",
"description": "Only meaningful with `formulas`: when false, only the formula series are returned and the raw operand series (the select items) are hidden. Defaults to true (operands shown alongside the formula)."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"type": "string",
"maxLength": 256,
"minLength": 1
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string"
},
"formulas": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"fillNulls": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"const": "stacked_bar",
"description": "Stacked bar chart over time"
},
"seriesLimit": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/seriesLimit",
"description": "Maximum number of series to fetch (the \"Series Limit\" display setting). Keeps the top-N groups by aggregated value over the queried range and drops the rest. Requires `groupBy`; ignored on a chart without one. Three-state: omit to apply the default render cap, 0 for unlimited, or a positive N to keep the top N."
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/select"
},
"asRatio": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/asRatio"
},
"groupBy": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/groupBy"
},
"formulas": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/sourceId"
},
"fillNulls": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/fillNulls"
},
"displayType": {
"type": "string",
"const": "stacked_line",
"description": "Stacked line (area) chart over time"
},
"seriesLimit": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/seriesLimit"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/numberFormat"
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/showOperandSeries"
},
"alignDateRangeToGranularity": {
"$ref": "#/properties/tile/anyOf/1/properties/config/properties/alignDateRangeToGranularity"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"having": {
"type": "string",
"maxLength": 10000,
"description": "Post-aggregation SQL HAVING expression. Example: \"Count > 100\" to drop groups with few rows, or \"StatusMessage != ''\" to drop empty-message rows from a groupBy: \"StatusMessage\" table. Mirrors the same field on the REST table chart config in `externalDashboardTableChartConfigSchema`.\n\nDASHBOARD VARIABLES: accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which expand to 1=1 while the variable has no selection, as well as a bare $variableName reference (which renders as NULL when nothing is selected)."
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1
},
"asRatio": {
"type": "boolean"
},
"groupBy": {
"type": "string",
"description": "Group rows by this column. Use PascalCase for top-level columns (e.g. \"SpanName\"). For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"onClick": {
"anyOf": [
{
"type": "object",
"required": [
"type",
"target"
],
"properties": {
"type": {
"type": "string",
"const": "search",
"description": "Link to the /search page for a log or trace source."
},
"target": {
"anyOf": [
{
"type": "object",
"required": [
"mode",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Concrete source ID (for type=search) or dashboard ID (for type=dashboard). Get source IDs from clickstack_list_sources; get dashboard IDs from clickstack_get_dashboard (no id arg returns the list). For type=search the source kind must be \"log\" or \"trace\"; the /search page does not render metric/session sources."
},
"mode": {
"type": "string",
"const": "id"
}
},
"description": "Link to a specific source or dashboard by its concrete ID.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"mode",
"template"
],
"properties": {
"mode": {
"type": "string",
"const": "template"
},
"template": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered against the clicked row, then resolved by NAME on the destination team. Example: \"ServiceOverview-{{ServiceName}}\" assumes a row column ServiceName whose value is the name of a source/dashboard. Prefer mode=\"id\" when the target is known up-front; it survives renames."
}
},
"description": "Link to a source/dashboard whose name comes from a column on the clicked row.",
"additionalProperties": false
}
],
"description": "Destination resolver. mode=\"id\" pins a specific source/dashboard; mode=\"template\" picks one at click time from a row column.Linking by ID is preferred, but using a template is valid when the destination dashboard depends on the clicked row's content"
},
"filters": {
"type": "array",
"items": {
"type": "object",
"required": [
"kind",
"expression",
"template"
],
"properties": {
"kind": {
"type": "string",
"const": "expressionTemplate",
"description": "Literal \"expressionTemplate\"; only kind supported today."
},
"template": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered with the clicked row's columns. Example: \"{{ServiceName}}\" pulls the row's ServiceName column value. Columns can be referenced by series alias."
},
"expression": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Column or SQL expression the rendered template is matched against. Example: \"ServiceName\" or \"SpanAttributes['http.route']\". Filters that share an expression are merged into a single IN clause on the destination."
}
},
"description": "One templated equality filter applied on the destination page. Use filters to pre-populate the destination search/dashboard with a row-driven IN clause (e.g. \"ServiceName IN ('api')\") rather than dropping the user into an unscoped view.",
"additionalProperties": false
},
"maxItems": 50,
"description": "Optional list of templated equality filters. Each filter becomes an `expression IN ('rendered-value')` clause on the destination; filters that share an expression are merged into one IN clause."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"description": "Filter language for `whereTemplate` and `filters` (\"lucene\" or \"sql\"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values."
},
"whereTemplate": {
"type": "string",
"maxLength": 10000,
"description": "Optional Handlebars-style WHERE template rendered against the clicked row and placed in the destination's `where` query param. Example: \"ServiceName = '{{service.name}}'\" pulls service.name from the row. Use Lucene or SQL syntax matching `whereLanguage`. Prefer `filters` (below) for simple equality; filters merge nicely on the destination."
}
},
"description": "Row-click handler that opens the /search page. Use this to drill from an aggregated table row down to the underlying log/trace events for that row.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"type",
"target"
],
"properties": {
"type": {
"type": "string",
"const": "dashboard",
"description": "Link to another ClickStack dashboard."
},
"target": {
"$ref": "#/properties/tile/anyOf/3/properties/config/properties/onClick/anyOf/0/properties/target"
},
"filters": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/3/properties/config/properties/onClick/anyOf/0/properties/filters/items"
},
"maxItems": 50,
"description": "Optional list of templated equality filters. The destination dashboard auto-populates its filter list with these (matched by expression), so prefer this over whereTemplate when the target dashboard already declares the same filter expressions. If the destination dashboard does not declare a top-level filter whose `expression` matches, that value is dropped at click time and the destination opens unfiltered for that expression."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"description": "Filter language for `whereTemplate` and `filters` (\"lucene\" or \"sql\"). Optional, but set it explicitly so the destination knows how to parse rendered whereTemplate / filter values."
},
"whereTemplate": {
"type": "string",
"maxLength": 10000,
"description": "Optional Handlebars-style WHERE template applied to the destination dashboard's global filter. Useful when the target dashboard exposes a single global scope rather than per-tile filters."
}
},
"description": "Row-click handler that opens another dashboard. Use this to drill from a high-level overview table down to a per-service or per-endpoint dashboard.",
"additionalProperties": false
},
{
"type": "object",
"required": [
"type",
"urlTemplate"
],
"properties": {
"type": {
"type": "string",
"const": "external",
"description": "Link to an arbitrary external URL (e.g. Grafana, Langfuse)."
},
"urlTemplate": {
"type": "string",
"maxLength": 10000,
"minLength": 1,
"description": "Handlebars-style template rendered against the clicked row, e.g. \"https://example.com/d/abc?var-service={{ServiceName}}\". The rendered value MUST be an absolute http(s) URL; relative URLs and non-http(s) schemes (javascript:, data:, etc.) are rejected at click time. This variant references no HyperDX source or dashboard."
}
},
"description": "Row-click handler that opens an external URL in a new tab. Use this to link out to a third-party tool (Grafana, Langfuse, runbooks, etc.).",
"additionalProperties": false
}
],
"description": "Row-click navigation for tiles that render as tables (Table tiles always; SQL tiles only when displayType is \"table\"). type=\"search\" links to the /search page for a log/trace source; type=\"dashboard\" links to another dashboard; type=\"external\" links to an arbitrary external http(s) URL. All support Handlebars `{{column}}` templating against the clicked row for the target/url, whereTemplate, and filter values.\n\nExamples:\n1. Drill into search for the clicked service: \n { \"type\": \"search\", \"target\": { \"mode\": \"id\", \"id\": \"<trace-source-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n2. Drill into a per-service dashboard: \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"id\", \"id\": \"<dashboard-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n3. Resolve the destination from the row (rare; prefer mode=\"id\"): \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"template\", \"template\": \"{{TargetDashboardName}}\" }, \"whereLanguage\": \"lucene\" }\n4. Link out to an external tool: \n { \"type\": \"external\", \"urlTemplate\": \"https://grafana.example.com/d/abc?var-service={{ServiceName}}\" }"
},
"orderBy": {
"type": "string",
"description": "Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"formulas": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/formulas"
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "table",
"description": "Tabular aggregated data"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"showOperandSeries": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/showOperandSeries"
},
"groupByColumnsOnLeft": {
"type": "boolean",
"description": "Render Group By columns on the left side of the table, before the series columns. Default false (Group By columns on the right)."
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"color": {
"enum": [
"chart-blue",
"chart-orange",
"chart-red",
"chart-cyan",
"chart-green",
"chart-pink",
"chart-purple",
"chart-light-blue",
"chart-brown",
"chart-gray",
"chart-success",
"chart-warning",
"chart-error"
],
"type": "string",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\", \"chart-green\", or \"chart-success\" (see the enum for the full set). Applied unless a colorRules entry matches the value."
},
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 20,
"minItems": 1,
"description": "Exactly one metric to display — unless `formulas` is set, in which case the select items are the formula operands and the (single) formula value is displayed instead."
},
"formulas": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/formulas/items"
},
"maxItems": 1,
"description": "METRIC, LOG, AND TRACE SOURCES. Derived series computed from the select items via letter-ref arithmetic (\"A\" = select[0], \"B\" = select[1], ...). Example: [{ expression: \"A / B * 100\", alias: \"Error rate %\" }] with select = [errors count, total count]. Each formula adds one series computed in ClickHouse. Cannot be combined with asRatio (express the ratio as a formula instead). Rejected on other source kinds (e.g. session). Number tiles support a single formula and always display the formula value (operand series are hidden)."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"colorRules": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "number"
},
"operator": {
"enum": [
"gt",
"gte",
"lt",
"lte"
],
"type": "string"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"type": "array",
"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2
},
"operator": {
"type": "string",
"const": "between"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"operator",
"value",
"color"
],
"properties": {
"color": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/color"
},
"label": {
"type": "string",
"maxLength": 40
},
"value": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 200
}
]
},
"operator": {
"enum": [
"eq",
"neq"
],
"type": "string"
}
},
"additionalProperties": false
}
]
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]."
},
"displayType": {
"type": "string",
"const": "number",
"description": "Single aggregate scalar value"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"backgroundChart": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"line",
"area"
],
"type": "string"
},
"color": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/color"
}
},
"description": "Optional background trend sparkline drawn behind the number, derived from a time-bucketed version of the same query (useful for SLO / error-budget tiles where the trend over the window matters). { type, color? }: type is \"line\" or \"area\"; color is an optional palette token override (the sparkline inherits the tile color when unset). Builder number tiles only; raw SQL number tiles have no time dimension to bucket. Example: { type: \"area\", color: \"chart-blue\" }.",
"additionalProperties": false
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"limit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of slices (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups."
},
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1
},
"groupBy": {
"type": "string",
"description": "Column that defines pie slices. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"orderBy": {
"type": "string",
"description": "Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which slices are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "pie",
"description": "Pie chart"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"limit": {
"type": "integer",
"minimum": 0,
"description": "Maximum number of bars (SQL LIMIT). Without a custom `orderBy`, keeps the top-N groups by the aggregated value, descending; with an `orderBy` keeps the first N in that order. Omit or set 0 to fetch all groups."
},
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1
},
"groupBy": {
"type": "string",
"description": "Column(s) that define the bars. Use PascalCase for top-level columns. For attributes: SpanAttributes['key'] or ResourceAttributes['key']."
},
"orderBy": {
"type": "string",
"description": "Optional custom SQL ORDER BY expression. Overrides the default value-descending ordering and, combined with `limit`, controls which bars are kept. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "bar",
"description": "Bar chart — one bar per group value (not a time series)"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"heatmapMode",
"sourceId",
"select"
],
"properties": {
"where": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
},
"select": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items"
},
"maxItems": 1,
"minItems": 1,
"description": "Defines the aggregate value displayed for each heatmap series."
},
"groupBy": {
"type": "string",
"description": "SQL GROUP BY expression defining the series shown in the heatmap."
},
"sourceId": {
"type": "string",
"description": "Source ID of a Trace, Log, or Metric source - call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "heatmap",
"description": "Series heatmap: one row per groupBy value, each cell colored by the aggregated value over time"
},
"heatmapMode": {
"type": "string",
"const": "series",
"description": "Must be \"series\" for a series heatmap"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/where"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId",
"select"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Row-level filter applied before bucketing. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"valueExpression"
],
"properties": {
"countExpression": {
"type": "string",
"description": "Custom count expression (e.g. \"count()\"). Optional; defaults are applied by the renderer."
},
"valueExpression": {
"type": "string",
"minLength": 1,
"description": "Numeric column or expression to bucket. Required and must be non-empty. Use \"Duration\" for trace latency heatmaps, or any other numeric column."
},
"heatmapScaleType": {
"enum": [
"log",
"linear"
],
"type": "string",
"description": "Color scale: \"log\" or \"linear\""
}
},
"additionalProperties": false
},
"maxItems": 1,
"minItems": 1,
"description": "Exactly one heatmap series"
},
"sourceId": {
"type": "string",
"description": "Source ID. Must be a Trace source today; use clickstack_list_sources and pick one whose kind is \"trace\"."
},
"displayType": {
"type": "string",
"const": "heatmap",
"description": "Heatmap chart. Without `heatmapMode` it is a distribution heatmap, which buckets a numeric value on the y-axis and requires a Trace source"
},
"heatmapMode": {
"type": "string",
"const": "distribution",
"description": "Omit for a distribution heatmap"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Display formatting for bucket values. Example: { output: \"duration\", factor: 0.000000001 } to format nanosecond durations as human-readable time."
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Filter in Lucene syntax. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "string",
"default": "",
"description": "Columns to display (empty = defaults). Example: \"body,service.name,duration\""
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "search",
"description": "Log/event search results list"
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType",
"sourceId"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Filter in Lucene syntax. Example: \"level:error\"\n\nDASHBOARD VARIABLES: a reference to a variable-enabled dashboard filter expands here in either language ($variableName renders as quoted SQL values, or as a Lucene value list in a Lucene input). With whereLanguage \"sql\" this also accepts $__filter(<expression>, $<variableName>) and $__conditionalAll(<condition>, $<variableName>), which are preferred because they expand to 1=1 while nothing is selected, where a bare SQL reference renders as NULL. The two macros have no meaning in a Lucene input and are matched as literal text; write ServiceName:$variableName there. A Lucene reference needs no macro: with nothing selected it renders as (\"\") and the translator drops it to a match-all."
},
"select": {
"type": "string",
"default": "",
"description": "Pattern expression — column or expression to mine patterns from. Leave empty to use the source default (Body for logs, SpanName for traces). Example: \"Body\", \"SpanName\", \"SpanAttributes['http.url']\""
},
"sourceId": {
"type": "string",
"description": "Source ID – call clickstack_list_sources"
},
"displayType": {
"type": "string",
"const": "event_patterns",
"description": "Event pattern mining tile"
},
"whereLanguage": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/whereLanguage",
"default": "lucene"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"displayType"
],
"properties": {
"markdown": {
"type": "string",
"default": ""
},
"displayType": {
"type": "string",
"const": "markdown",
"description": "Free-form Markdown text tile"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"config"
],
"properties": {
"h": {
"$ref": "#/properties/tile/anyOf/0/properties/h"
},
"w": {
"$ref": "#/properties/tile/anyOf/0/properties/w"
},
"x": {
"$ref": "#/properties/tile/anyOf/0/properties/x"
},
"y": {
"$ref": "#/properties/tile/anyOf/0/properties/y"
},
"name": {
"$ref": "#/properties/tile/anyOf/0/properties/name"
},
"tabId": {
"$ref": "#/properties/tile/anyOf/0/properties/tabId"
},
"config": {
"type": "object",
"required": [
"configType",
"displayType",
"connectionId",
"sqlTemplate"
],
"properties": {
"color": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/color",
"description": "Static color for the displayed number, as a palette token such as \"chart-blue\" or \"chart-success\". Valid only when displayType is \"number\", ignored otherwise. Applied unless a colorRules entry matches the value."
},
"onClick": {
"$ref": "#/properties/tile/anyOf/3/properties/config/properties/onClick",
"description": "Row-click navigation for tiles that render as tables (Table tiles always; SQL tiles only when displayType is \"table\"). type=\"search\" links to the /search page for a log/trace source; type=\"dashboard\" links to another dashboard; type=\"external\" links to an arbitrary external http(s) URL. All support Handlebars `{{column}}` templating against the clicked row for the target/url, whereTemplate, and filter values.\n\nExamples:\n1. Drill into search for the clicked service: \n { \"type\": \"search\", \"target\": { \"mode\": \"id\", \"id\": \"<trace-source-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n2. Drill into a per-service dashboard: \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"id\", \"id\": \"<dashboard-id>\" }, \"whereLanguage\": \"sql\", \"filters\": [{ \"kind\": \"expressionTemplate\", \"expression\": \"ServiceName\", \"template\": \"{{ServiceName}}\" }] }\n3. Resolve the destination from the row (rare; prefer mode=\"id\"): \n { \"type\": \"dashboard\", \"target\": { \"mode\": \"template\", \"template\": \"{{TargetDashboardName}}\" }, \"whereLanguage\": \"lucene\" }\n4. Link out to an external tool: \n { \"type\": \"external\", \"urlTemplate\": \"https://grafana.example.com/d/abc?var-service={{ServiceName}}\" }"
},
"sourceId": {
"type": "string",
"description": "Source ID for the table this query reads from (call clickstack_list_sources). ALWAYS set this for raw SQL tiles UNLESS the query reads from multiple tables (e.g. JOINs or sub-queries spanning several sources), in which case omit it. sourceId is REQUIRED by two macros: $__filters and $__sourceTable. The sourceId must belong to the same connection as connectionId."
},
"fillNulls": {
"type": "boolean"
},
"colorRules": {
"type": "array",
"items": {
"$ref": "#/properties/tile/anyOf/4/properties/config/properties/colorRules/items"
},
"maxItems": 10,
"description": "Conditional colors for the number, evaluated in array order with the last matching rule winning; falls back to color (then the default text color) when none match. Up to 10 rules. Each rule is { operator, value, color, label? }: operator gt | gte | lt | lte with a number value, between with a [min, max] value, or eq | neq with a number or string value. color is a palette token. Example: [{ operator: \"gte\", value: 500, color: \"chart-error\", label: \"Critical\" }]. Valid only when displayType is \"number\", ignored otherwise."
},
"configType": {
"type": "string",
"const": "sql",
"description": "Must be \"sql\" for raw SQL tiles. ADVANCED: Only use raw SQL tiles when the builder tile types cannot express the query you need."
},
"displayType": {
"enum": [
"line",
"stacked_bar",
"stacked_line",
"table",
"number",
"pie",
"bar"
],
"type": "string",
"description": "How to render the SQL results"
},
"sqlTemplate": {
"type": "string",
"description": "\nRaw ClickHouse SQL query. SQL guidelines:\n\n1. ALWAYS include a LIMIT clause to avoid excessive data.\n2. ALWAYS include a date/time filter in the WHERE clause using either macros or raw parameters to ensure the chart responds to user selected time range.\n - $__timeFilter(col) expands to col >= toDateTime(fromUnixTimestamp64Milli({startDateMilliseconds:Int64})) AND col <= toDateTime(fromUnixTimestamp64Milli({endDateMilliseconds:Int64}))\n - $__timeFilter_ms(col) is the same but should be used when col has millisecond precision (DateTime64 type)\n - $__dateFilter(col) is the same but should be used when col has Day granularity (Date type)\n - $__dateTimeFilter(dateCol, dateTimeCol) should be used when there are both Date and DateTime columns that should be filtered on.\n - NEVER hardcode a fixed time range unless the user specifically asks for it.\n - $__fromTime and $__toTime can be expanded to {startDateMilliseconds:Int64} and {endDateMilliseconds:Int64}, but prefer the full filter macros for readability.\n3. ALWAYS include a granularity macro or parameter for time series (line or bar charts) to ensure the chart's granularity responds to user selected time bucket size.\n - $__timeInterval(col) expands to toStartOfInterval(TimestampTime, INTERVAL {intervalSeconds:Int64} second)\n - $__interval_s expands to {intervalSeconds:Int64}\n - These macros are only available for time-series charts; do not use them for other display types.\n4. STRONGLY RECOMMENDED: use the $__filters and $__sourceTable macros to ensure the tile reacts to dashboard-level filters and source selectors.\n - $__filters and $__sourceTable both require sourceId to be set on this tile.\n - IMPORTANT: when the sourceId refers to a source with `requiredSourceFilters`: the sqlTemplate MUST include\n the literal $__filters macro in its WHERE clause (e.g. `WHERE $__timeFilter(ts) AND $__filters`) — saves are rejected otherwise.\n\nExample:\n\nSELECT\n $__timeInterval(TimestampTime) AS ts,\n count()\nFROM $__sourceTable\nWHERE $__timeFilter(TimestampTime)\n AND $__filters\nGROUP BY ServiceName, ts\n"
},
"connectionId": {
"type": "string",
"description": "Connection ID (not sourceId) – call clickstack_list_sources to find available connections"
},
"numberFormat": {
"$ref": "#/properties/tile/anyOf/0/properties/config/properties/select/items/properties/numberFormat",
"description": "Controls how the number value(s) are formatted for display. Applies to series or numbers without a series-level numberFormat. Most useful: { output: \"duration\", factor: 0.000000001 } to auto-format nanosecond durations, or { output: \"number\", mantissa: 2, thousandSeparated: true } for clean counts."
},
"fitYAxisToData": {
"type": "boolean",
"description": "Scale the y-axis to the data range instead of starting at zero. Valid only when displayType is \"line\", ignored otherwise."
},
"compareToPreviousPeriod": {
"type": "boolean",
"description": "Overlay the previous period as a dashed comparison series. Valid only when displayType is \"line\", ignored otherwise."
},
"alignDateRangeToGranularity": {
"type": "boolean"
}
},
"additionalProperties": false
},
"containerId": {
"$ref": "#/properties/tile/anyOf/0/properties/containerId"
}
},
"additionalProperties": false
}
],
"description": "The full replacement tile definition. Replaces the tile matched by tileId. Layout fields (x, y, w, h), name, and containerId/tabId default to the existing tile's values when omitted, so you only need to specify what changed."
},
"tileId": {
"type": "string",
"description": "ID of the tile to replace. Must be paired with `tile`. Obtain tile IDs from clickstack_get_dashboard."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Permanently delete a dashboard by ID. Also removes any alerts attached to its tiles. Use clickstack_get_dashboard (without an ID) to list available dashboard IDs.
The description explains the capability, when to use it, and what to expect.
Inputs50/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
id
Dashboard ID to delete.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_delete_dashboard",
"title": "Delete Dashboard",
"description": "Permanently delete a dashboard by ID. Also removes any alerts attached to its tiles. Use clickstack_get_dashboard (without an ID) to list available dashboard IDs.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"description": "Dashboard ID to delete."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Search dashboards by name and/or tags. Returns matching dashboards with their IDs, names, and tags. More targeted than clickstack_get_dashboard (which lists all dashboards). At least one of query or tags must be provided.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
query
Search term to match against dashboard names (case-insensitive substring match).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
tags
Filter to dashboards that have ALL of these tags.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_search_dashboards",
"title": "Search Dashboards",
"description": "Search dashboards by name and/or tags. Returns matching dashboards with their IDs, names, and tags. More targeted than clickstack_get_dashboard (which lists all dashboards). At least one of query or tags must be provided.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"tags": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "Filter to dashboards that have ALL of these tags."
},
"query": {
"type": "string",
"maxLength": 200,
"description": "Search term to match against dashboard names (case-insensitive substring match)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description81/100
Execute the query for a specific tile on an existing dashboard. Useful for validating that a tile returns data or for spot-checking results without rebuilding the query from scratch. Use clickstack_get_dashboard with an ID to find tile IDs.
SOURCE FILTERS: when the tile reads a source that declares `requiredSourceFilters`, pass `sourceFilters` here to stand in for the dropdown selection so the validation query has values to run with.
Describe the returned information so the agent knows whether it will answer the request.
Inputs79/100
6 of 7 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
dashboardId
Dashboard ID.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
tileId
Tile ID within the dashboard. Obtain from clickstack_get_dashboard.
Clear enough to supply this argument.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
variableValues › items › name
Variable name, as declared by a filter's variableName. Get the list from clickstack_get_dashboard.
Clear enough to supply this argument.
variableValues › items › values
Values to treat as selected. An empty array means nothing is selected for this variable. For a STATIC_LIST filter's variable, every value must be one of the filter's declared options.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_query_tile",
"title": "Query a Dashboard Tile",
"description": "Execute the query for a specific tile on an existing dashboard. Useful for validating that a tile returns data or for spot-checking results without rebuilding the query from scratch. Use clickstack_get_dashboard with an ID to find tile IDs.\n\nSOURCE FILTERS: when the tile reads a source that declares `requiredSourceFilters`, pass `sourceFilters` here to stand in for the dropdown selection so the validation query has values to run with.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"dashboardId",
"tileId"
],
"properties": {
"tileId": {
"type": "string",
"description": "Tile ID within the dashboard. Obtain from clickstack_get_dashboard."
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID."
},
"sourceFilters": {
"type": "object",
"description": "Source-filter values to apply to this tile query, keyed by column name, e.g. { \"ServiceName\": [\"api\"] }. These stand in for the dashboard-level source-filter dropdown selection when the tile's source declares `requiredSourceFilters`. Call clickstack_get_source_filter_values to discover valid values. Ignored for sources without requiredSourceFilters.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"variableValues": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"values"
],
"properties": {
"name": {
"type": "string",
"description": "Variable name, as declared by a filter's variableName. Get the list from clickstack_get_dashboard."
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"description": "Values to treat as selected. An empty array means nothing is selected for this variable. For a STATIC_LIST filter's variable, every value must be one of the filter's declared options."
}
},
"additionalProperties": false
},
"description": "Optional simulated dashboard variable selection for this run. Every variable the dashboard declares defaults to EMPTY, which is the state a freshly-opened dashboard is in. Supply values here to check that a tile narrows as expected once the user picks something. Variables not listed stay empty."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Run the queries for many tiles of a dashboard in ONE call and return a compact per-tile success/failure summary. This is the efficient way to validate an entire dashboard after clickstack_save_dashboard — prefer it over calling clickstack_query_tile once per tile. Accepts a dashboard ID and an optional list of tile IDs. Markdown tiles are excluded by default; a markdown tile passed explicitly in tileIds is returned with status "skipped". A tile that fails is reported inline with its error and the overall call still succeeds, so one broken tile does not hide the rest, and unrecognized tile IDs come back as unknownTileIds rather than failing. At most 50 tiles run per call; any beyond that are returned as unrunTileIds — call again with those as tileIds to run the remainder. Drill into a specific failing tile with clickstack_query_tile.
SOURCE FILTERS: when tiles read a source that declares `requiredSourceFilters`, pass `sourceFilters` here to stand in for the dashboard-level SOURCE_FILTER dropdown selections. Without them each such tile is reported as status "error" with a "requires source filter values" message.
The description explains the capability, when to use it, and what to expect.
Inputs75/100
6 of 7 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
dashboardId
Dashboard ID.
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
tileIds
Tile IDs to run. Default: every non-markdown tile on the dashboard. Obtain IDs from clickstack_get_dashboard. At most 500 IDs per call.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
variableValues › items › name
Variable name, as declared by a filter's variableName. Get the list from clickstack_get_dashboard.
Clear enough to supply this argument.
variableValues › items › values
Values to treat as selected. An empty array means nothing is selected for this variable. For a STATIC_LIST filter's variable, every value must be one of the filter's declared options.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_query_tiles",
"title": "Query Multiple Dashboard Tiles",
"description": "Run the queries for many tiles of a dashboard in ONE call and return a compact per-tile success/failure summary. This is the efficient way to validate an entire dashboard after clickstack_save_dashboard — prefer it over calling clickstack_query_tile once per tile. Accepts a dashboard ID and an optional list of tile IDs. Markdown tiles are excluded by default; a markdown tile passed explicitly in tileIds is returned with status \"skipped\". A tile that fails is reported inline with its error and the overall call still succeeds, so one broken tile does not hide the rest, and unrecognized tile IDs come back as unknownTileIds rather than failing. At most 50 tiles run per call; any beyond that are returned as unrunTileIds — call again with those as tileIds to run the remainder. Drill into a specific failing tile with clickstack_query_tile.\n\nSOURCE FILTERS: when tiles read a source that declares `requiredSourceFilters`, pass `sourceFilters` here to stand in for the dashboard-level SOURCE_FILTER dropdown selections. Without them each such tile is reported as status \"error\" with a \"requires source filter values\" message.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"dashboardId"
],
"properties": {
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"tileIds": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 500,
"description": "Tile IDs to run. Default: every non-markdown tile on the dashboard. Obtain IDs from clickstack_get_dashboard. At most 500 IDs per call."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"dashboardId": {
"type": "string",
"description": "Dashboard ID."
},
"sourceFilters": {
"type": "object",
"description": "Source-filter values applied to EVERY tile in this batch, keyed by column name, e.g. { \"ServiceName\": [\"api\"] }. These stand in for the dashboard-level SOURCE_FILTER dropdown selection when a tile's source declares `requiredSourceFilters`. Call clickstack_get_source_filter_values to discover valid values. Ignored for tiles whose source has no requiredSourceFilters.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"variableValues": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"values"
],
"properties": {
"name": {
"type": "string",
"description": "Variable name, as declared by a filter's variableName. Get the list from clickstack_get_dashboard."
},
"values": {
"type": "array",
"items": {
"type": "string"
},
"description": "Values to treat as selected. An empty array means nothing is selected for this variable. For a STATIC_LIST filter's variable, every value must be one of the filter's declared options."
}
},
"additionalProperties": false
},
"description": "Optional simulated dashboard variable selection for this run. Every variable the dashboard declares defaults to EMPTY, which is the state a freshly-opened dashboard is in. Supply values here to check that a tile narrows as expected once the user picks something. Variables not listed stay empty."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description85/100
Plot metrics over time as a line or stacked bar chart. Use this when you need to visualize trends, compare time-series, or monitor metric changes over a time window.
PREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
Requires sourceId — call clickstack_list_sources then clickstack_describe_source first. Each select item defines one plotted series.
Column naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method'].
── METRIC SOURCES ──
When sourceId is a metric source, each select item MUST set metricType ("gauge"|"sum"|"histogram"|"exponential histogram") and metricName (the OTel metric name). valueExpression defaults to "Value" — set it explicitly only to transform the value.
Discovery: clickstack_describe_source returns a per-kind metric-name sample; clickstack_list_metrics paginates the full catalog; clickstack_describe_metric returns attribute keys + sampled values for a single metric.
Per kind: gauge uses last_value/avg/min/max (or aggFn:any + isDelta:true for Prometheus-style delta); sum uses aggFn:"increase" for the counter increase, or sum/avg on the computed rate; histogram and exponential histogram use aggFn:"quantile" + level for percentiles, or aggFn:"count" for total bucket count.
TOP-N CAP: aggFn:"increase" + groupBy is capped at 20 groups by the renderer (top by max bucket sum). Narrow with where/groupBy to see other groups.
summary metrics are not supported by the query renderer — query them with clickstack_sql against the table in the source's metricTables.summary.
SOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.
The description explains the capability, when to use it, and what to expect.
Inputs87/100
18 of 19 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID (required). Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
select › items › aggFn
Aggregation function:
count – count matching rows (no valueExpression needed)
sum / avg / min / max – aggregate a numeric column (valueExpression required)
count_distinct – unique value count (valueExpression required)
quantile – percentile; also set level (valueExpression required)
last_value – most recent value of a column
none – pass a raw expression through unchanged
increase – METRIC-ONLY (Sum/counter): per-bucket counter increase, reset-aware. Requires metricType:"sum" and metricName.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › valueExpression
ClickHouse SQL expression to aggregate. Required for every aggFn except "count". Top-level columns are PascalCase (Duration, StatusCode); map attributes use bracket syntax: SpanAttributes['key'], ResourceAttributes['key']. Any ClickHouse expression is allowed — common useful forms: "Duration / 1e6" (ns→ms), "toFloat64OrZero(SpanAttributes['response.size_bytes'])" (cast attribute), "if(StatusCode = 'STATUS_CODE_ERROR', 1, 0)" (boolean→numeric for ratios).
METRIC SOURCES: optional — defaults to "Value" (the metric value column) when metricType/metricName are set. Set explicitly only if you want to transform the metric value (e.g. "Value / 1e6").
Clear enough to supply this argument.
select › items › where
Conditional aggregation filter — restricts which rows are included in THIS metric (combined with the top-level time/where filter via AND). Compiles to <aggFn>If(...): e.g. quantile + where=Timestamp<X → quantileIf(0.99)(Duration, Timestamp<X). Use this to compute before/after deltas or per-segment metrics in a single query: set where: "Timestamp < '2026-05-09T23:40:00Z'" on one item and "Timestamp >= '2026-05-09T23:40:00Z'" on another to get baseline-vs-anomaly p99 in one round trip — much faster than re-running the same query with a different time range. Examples (lucene): "level:error", "service.name:api AND http.status_code:>=500". Set whereLanguage:"sql" for raw SQL conditions like "SpanAttributes['http.method'] = 'POST'" or "Timestamp < '2026-05-09 23:40:00'".
Clear enough to supply this argument.
select › items › whereLanguage
Query language for the per-item conditional filter. Use "sql" when comparing to literal timestamps or arbitrary attribute expressions. Default: lucene
Clear enough to supply this argument.
select › items › alias
Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. "Requests", "P95 Latency", "Error Rate"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › level
Percentile level. Required when aggFn is "quantile" on a histogram or exponential histogram metric, optional otherwise. Allowed values: 0.5, 0.9, 0.95, 0.99
Clear enough to supply this argument.
select › items › metricType
METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when sourceId is a metric source. Discover via clickstack_describe_source (sample) or clickstack_describe_metric.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › metricName
METRIC SOURCES ONLY. OTel metric name (e.g. "system.cpu.utilization", "http.server.request.duration"). Required when metricType is set. Discover via clickstack_list_metrics or clickstack_describe_source.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › isDelta
METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket: (argMax(Value) - argMin(Value)) * bucketSecs / timeDiff. Use for cumulative gauges where you want to chart growth per bucket. Default false.
Clear enough to supply this argument.
shape
Chart shape. "line" for line chart (default), "stacked_bar" for stacked bar chart, "stacked_line" for stacked line (area) chart.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
where
Row filter applied to ALL select items. Scopes the entire query — use to restrict by service, severity, etc. Each select item can also have its own per-metric "where" for cohort comparisons. When both are set, they are ANDed together.
Clear enough to supply this argument.
whereLanguage
Query language for the "where" filter. Default: lucene.
IMPORTANT: the syntax in "where" MUST match "whereLanguage".
Lucene (default): Column:value, Column.mapKey:value, Column:>100
SQL: Column = 'value', SpanAttributes['key'] = 'value'
Lucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use "sql" for IN(...) lists, complex expressions, or function calls.
IMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.
Common mistake: writing Column:value (Lucene) but setting whereLanguage to "sql". If your filter uses colon syntax, leave whereLanguage as "lucene" (the default).
Clear enough to supply this argument.
groupBy
Column(s) or ClickHouse expression(s) to group/split by. Accepts a SINGLE entry or MULTIPLE entries as a comma-delimited list — multi-column groupBy expresses multi-dimensional breakdowns in one query (e.g. "ServiceName, SpanName, StatusMessage") instead of running one query per dimension. For "table" displayType, the result has one row per distinct combination of group values. Top-level columns use PascalCase ("SpanName", "StatusCode"). Map attributes: SpanAttributes['key'], ResourceAttributes['key'].
Arbitrary ClickHouse expressions are also allowed in groupBy — useful when you need to group by a derived column without falling back to raw SQL:
- "substring(Body, 1, 80)" — group by body prefix (log pattern bucketing)
- "toStartOfInterval(Timestamp, INTERVAL 5 MINUTE)" — explicit time bucketing in a table view, alongside another dimension (granularity only works for line/stacked_bar)
- "JSONExtractString(Body, 'event')" — parse a JSON field from the body
- "if(Duration > 1e9, 'slow', 'fast')" — coarse boolean buckets
Comma splitting is bracket-aware, so multi-arg function calls work as single entries.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
orderBy
Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '"P95 Latency" DESC'.
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
granularity
Time bucket size for the chart. Format: "<number> <unit>" where unit is second, minute, hour, or day.
CORRECT: "1 minute", "5 minute", "1 hour", "1 day"
WRONG: "1m", "5min", "1h" (abbreviations are not supported)
Omit to let HyperDX pick automatically based on the time range.
Clear enough to supply this argument.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_timeseries",
"title": "Time-Series Chart",
"description": "Plot metrics over time as a line or stacked bar chart. Use this when you need to visualize trends, compare time-series, or monitor metric changes over a time window.\n\nPREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).\n\nRequires sourceId — call clickstack_list_sources then clickstack_describe_source first. Each select item defines one plotted series.\n\nColumn naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method'].\n\n── METRIC SOURCES ──\nWhen sourceId is a metric source, each select item MUST set metricType (\"gauge\"|\"sum\"|\"histogram\"|\"exponential histogram\") and metricName (the OTel metric name). valueExpression defaults to \"Value\" — set it explicitly only to transform the value.\nDiscovery: clickstack_describe_source returns a per-kind metric-name sample; clickstack_list_metrics paginates the full catalog; clickstack_describe_metric returns attribute keys + sampled values for a single metric.\nPer kind: gauge uses last_value/avg/min/max (or aggFn:any + isDelta:true for Prometheus-style delta); sum uses aggFn:\"increase\" for the counter increase, or sum/avg on the computed rate; histogram and exponential histogram use aggFn:\"quantile\" + level for percentiles, or aggFn:\"count\" for total bucket count.\nTOP-N CAP: aggFn:\"increase\" + groupBy is capped at 20 groups by the renderer (top by max bucket sum). Narrow with where/groupBy to see other groups.\nsummary metrics are not supported by the query renderer — query them with clickstack_sql against the table in the source's metricTables.summary.\n\nSOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"select"
],
"properties": {
"shape": {
"enum": [
"line",
"stacked_bar",
"stacked_line"
],
"type": "string",
"default": "line",
"description": "Chart shape. \"line\" for line chart (default), \"stacked_bar\" for stacked bar chart, \"stacked_line\" for stacked line (area) chart."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter applied to ALL select items. Scopes the entire query — use to restrict by service, severity, etc. Each select item can also have its own per-metric \"where\" for cohort comparisons. When both are set, they are ANDed together."
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function:\n count – count matching rows (no valueExpression needed)\n sum / avg / min / max – aggregate a numeric column (valueExpression required)\n count_distinct – unique value count (valueExpression required)\n quantile – percentile; also set level (valueExpression required)\n last_value – most recent value of a column\n none – pass a raw expression through unchanged\n increase – METRIC-ONLY (Sum/counter): per-bucket counter increase, reset-aware. Requires metricType:\"sum\" and metricName."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level. Required when aggFn is \"quantile\" on a histogram or exponential histogram metric, optional otherwise. Allowed values: 0.5, 0.9, 0.95, 0.99"
},
"where": {
"type": "string",
"default": "",
"description": "Conditional aggregation filter — restricts which rows are included in THIS metric (combined with the top-level time/where filter via AND). Compiles to <aggFn>If(...): e.g. quantile + where=Timestamp<X → quantileIf(0.99)(Duration, Timestamp<X). Use this to compute before/after deltas or per-segment metrics in a single query: set where: \"Timestamp < '2026-05-09T23:40:00Z'\" on one item and \"Timestamp >= '2026-05-09T23:40:00Z'\" on another to get baseline-vs-anomaly p99 in one round trip — much faster than re-running the same query with a different time range. Examples (lucene): \"level:error\", \"service.name:api AND http.status_code:>=500\". Set whereLanguage:\"sql\" for raw SQL conditions like \"SpanAttributes['http.method'] = 'POST'\" or \"Timestamp < '2026-05-09 23:40:00'\"."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket: (argMax(Value) - argMin(Value)) * bucketSecs / timeDiff. Use for cumulative gauges where you want to chart growth per bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\", \"http.server.request.duration\"). Required when metricType is set. Discover via clickstack_list_metrics or clickstack_describe_source."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when sourceId is a metric source. Discover via clickstack_describe_source (sample) or clickstack_describe_metric."
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the per-item conditional filter. Use \"sql\" when comparing to literal timestamps or arbitrary attribute expressions. Default: lucene"
},
"valueExpression": {
"type": "string",
"description": "ClickHouse SQL expression to aggregate. Required for every aggFn except \"count\". Top-level columns are PascalCase (Duration, StatusCode); map attributes use bracket syntax: SpanAttributes['key'], ResourceAttributes['key']. Any ClickHouse expression is allowed — common useful forms: \"Duration / 1e6\" (ns→ms), \"toFloat64OrZero(SpanAttributes['response.size_bytes'])\" (cast attribute), \"if(StatusCode = 'STATUS_CODE_ERROR', 1, 0)\" (boolean→numeric for ratios).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set. Set explicitly only if you want to transform the metric value (e.g. \"Value / 1e6\")."
}
},
"additionalProperties": false
},
"maxItems": 10,
"minItems": 1,
"description": "Metrics to plot on the chart. Each item defines one series. Example: [{ aggFn: \"count\" }, { aggFn: \"avg\", valueExpression: \"Duration\" }]"
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"groupBy": {
"type": "string",
"description": "Column(s) or ClickHouse expression(s) to group/split by. Accepts a SINGLE entry or MULTIPLE entries as a comma-delimited list — multi-column groupBy expresses multi-dimensional breakdowns in one query (e.g. \"ServiceName, SpanName, StatusMessage\") instead of running one query per dimension. For \"table\" displayType, the result has one row per distinct combination of group values. Top-level columns use PascalCase (\"SpanName\", \"StatusCode\"). Map attributes: SpanAttributes['key'], ResourceAttributes['key'].\n\nArbitrary ClickHouse expressions are also allowed in groupBy — useful when you need to group by a derived column without falling back to raw SQL:\n - \"substring(Body, 1, 80)\" — group by body prefix (log pattern bucketing)\n - \"toStartOfInterval(Timestamp, INTERVAL 5 MINUTE)\" — explicit time bucketing in a table view, alongside another dimension (granularity only works for line/stacked_bar)\n - \"JSONExtractString(Body, 'event')\" — parse a JSON field from the body\n - \"if(Duration > 1e9, 'slow', 'fast')\" — coarse boolean buckets\nComma splitting is bracket-aware, so multi-arg function calls work as single entries."
},
"orderBy": {
"type": "string",
"description": "Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"granularity": {
"type": "string",
"description": "Time bucket size for the chart. Format: \"<number> <unit>\" where unit is second, minute, hour, or day.\nCORRECT: \"1 minute\", \"5 minute\", \"1 hour\", \"1 day\"\nWRONG: \"1m\", \"5min\", \"1h\" (abbreviations are not supported)\n\nOmit to let HyperDX pick automatically based on the time range."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the \"where\" filter. Default: lucene.\nIMPORTANT: the syntax in \"where\" MUST match \"whereLanguage\".\n Lucene (default): Column:value, Column.mapKey:value, Column:>100\n SQL: Column = 'value', SpanAttributes['key'] = 'value'\n\nLucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use \"sql\" for IN(...) lists, complex expressions, or function calls.\nIMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.\n\nCommon mistake: writing Column:value (Lucene) but setting whereLanguage to \"sql\". If your filter uses colon syntax, leave whereLanguage as \"lucene\" (the default)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
Compute aggregated metrics as a table, single number, pie chart, or bar chart. Use this for grouped aggregations, top-N queries, single-value KPIs, or proportional breakdowns.
PREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
Requires sourceId — call clickstack_list_sources then clickstack_describe_source first.
Use the top-level "where" to scope the entire query (e.g. filter by service). Each select item can also have its own "where" for per-metric cohort comparisons (compiles to <aggFn>If(...)). Both can be used together.
Column naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method']. Map attributes work in groupBy and valueExpression, including toFloat64OrZero(SpanAttributes['key']).
Shape auto-upgrade: if shape is "number", "pie", or "bar" but select has >1 item, it is transparently upgraded to "table".
── METRIC SOURCES ──
When sourceId is a metric source, each select item MUST set metricType ("gauge"|"sum"|"histogram"|"exponential histogram") and metricName (the OTel metric name). valueExpression defaults to "Value" — set it explicitly only to transform the value.
Discovery: clickstack_describe_source returns a per-kind metric-name sample; clickstack_list_metrics paginates the full catalog; clickstack_describe_metric returns attribute keys + sampled values for a single metric.
Per kind: gauge uses last_value/avg/min/max; sum uses aggFn:"increase" for counter increase (top-N capped at 20 groups when combined with groupBy), or sum/avg on the rate; histogram and exponential histogram use aggFn:"quantile" + level for percentiles, or aggFn:"count" for total bucket count.
summary metrics are not supported by the query renderer — query them with clickstack_sql against the table in the source's metricTables.summary.
SOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.
The description explains the capability, when to use it, and what to expect.
Inputs85/100
17 of 18 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID (required). Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
select › items › aggFn
Aggregation function:
count – count matching rows (no valueExpression needed)
sum / avg / min / max – aggregate a numeric column (valueExpression required)
count_distinct – unique value count (valueExpression required)
quantile – percentile; also set level (valueExpression required)
last_value – most recent value of a column
none – pass a raw expression through unchanged
increase – METRIC-ONLY (Sum/counter): per-bucket counter increase, reset-aware. Requires metricType:"sum" and metricName.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › valueExpression
ClickHouse SQL expression to aggregate. Required for every aggFn except "count". Top-level columns are PascalCase (Duration, StatusCode); map attributes use bracket syntax: SpanAttributes['key'], ResourceAttributes['key']. Any ClickHouse expression is allowed — common useful forms: "Duration / 1e6" (ns→ms), "toFloat64OrZero(SpanAttributes['response.size_bytes'])" (cast attribute), "if(StatusCode = 'STATUS_CODE_ERROR', 1, 0)" (boolean→numeric for ratios).
METRIC SOURCES: optional — defaults to "Value" (the metric value column) when metricType/metricName are set. Set explicitly only if you want to transform the metric value (e.g. "Value / 1e6").
Clear enough to supply this argument.
select › items › where
Conditional aggregation filter — restricts which rows are included in THIS metric (combined with the top-level time/where filter via AND). Compiles to <aggFn>If(...): e.g. quantile + where=Timestamp<X → quantileIf(0.99)(Duration, Timestamp<X). Use this to compute before/after deltas or per-segment metrics in a single query: set where: "Timestamp < '2026-05-09T23:40:00Z'" on one item and "Timestamp >= '2026-05-09T23:40:00Z'" on another to get baseline-vs-anomaly p99 in one round trip — much faster than re-running the same query with a different time range. Examples (lucene): "level:error", "service.name:api AND http.status_code:>=500". Set whereLanguage:"sql" for raw SQL conditions like "SpanAttributes['http.method'] = 'POST'" or "Timestamp < '2026-05-09 23:40:00'".
Clear enough to supply this argument.
select › items › whereLanguage
Query language for the per-item conditional filter. Use "sql" when comparing to literal timestamps or arbitrary attribute expressions. Default: lucene
Clear enough to supply this argument.
select › items › alias
Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. "Requests", "P95 Latency", "Error Rate"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › level
Percentile level. Required when aggFn is "quantile" on a histogram or exponential histogram metric, optional otherwise. Allowed values: 0.5, 0.9, 0.95, 0.99
Clear enough to supply this argument.
select › items › metricType
METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when sourceId is a metric source. Discover via clickstack_describe_source (sample) or clickstack_describe_metric.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › metricName
METRIC SOURCES ONLY. OTel metric name (e.g. "system.cpu.utilization", "http.server.request.duration"). Required when metricType is set. Discover via clickstack_list_metrics or clickstack_describe_source.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select › items › isDelta
METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket: (argMax(Value) - argMin(Value)) * bucketSecs / timeDiff. Use for cumulative gauges where you want to chart growth per bucket. Default false.
Clear enough to supply this argument.
shape
Output shape: "table" (grouped rows, default), "number" (single scalar), "pie" (pie chart), or "bar" (categorical bar chart). If "number", "pie", or "bar" is set with select.length > 1, it is auto-upgraded to "table". groupBy is ignored when shape is "number".
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
where
Row filter applied to ALL select items. This scopes the entire query — use it to restrict by service, severity, etc. Each select item can also have its own per-metric "where" for cohort comparisons. When both are set, they are ANDed together.
Lucene example: "ServiceName:frontend"
SQL example: "ServiceName = 'frontend'"
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
whereLanguage
Query language for the "where" filter. Default: lucene.
IMPORTANT: the syntax in "where" MUST match "whereLanguage".
Lucene (default): Column:value, Column.mapKey:value, Column:>100
SQL: Column = 'value', SpanAttributes['key'] = 'value'
Lucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use "sql" for IN(...) lists, complex expressions, or function calls.
IMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.
Common mistake: writing Column:value (Lucene) but setting whereLanguage to "sql". If your filter uses colon syntax, leave whereLanguage as "lucene" (the default).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
groupBy
Column(s) or ClickHouse expression(s) to group/split by. Accepts a SINGLE entry or MULTIPLE entries as a comma-delimited list — multi-column groupBy expresses multi-dimensional breakdowns in one query (e.g. "ServiceName, SpanName, StatusMessage") instead of running one query per dimension. For "table" displayType, the result has one row per distinct combination of group values. Top-level columns use PascalCase ("SpanName", "StatusCode"). Map attributes: SpanAttributes['key'], ResourceAttributes['key'].
Arbitrary ClickHouse expressions are also allowed in groupBy — useful when you need to group by a derived column without falling back to raw SQL:
- "substring(Body, 1, 80)" — group by body prefix (log pattern bucketing)
- "toStartOfInterval(Timestamp, INTERVAL 5 MINUTE)" — explicit time bucketing in a table view, alongside another dimension (granularity only works for line/stacked_bar)
- "JSONExtractString(Body, 'event')" — parse a JSON field from the body
- "if(Duration > 1e9, 'slow', 'fast')" — coarse boolean buckets
Comma splitting is bracket-aware, so multi-arg function calls work as single entries.
Clear enough to supply this argument.
orderBy
Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '"P95 Latency" DESC'.
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_table",
"title": "Aggregation Table",
"description": "Compute aggregated metrics as a table, single number, pie chart, or bar chart. Use this for grouped aggregations, top-N queries, single-value KPIs, or proportional breakdowns.\n\nPREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).\n\nRequires sourceId — call clickstack_list_sources then clickstack_describe_source first.\n\nUse the top-level \"where\" to scope the entire query (e.g. filter by service). Each select item can also have its own \"where\" for per-metric cohort comparisons (compiles to <aggFn>If(...)). Both can be used together.\n\nColumn naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method']. Map attributes work in groupBy and valueExpression, including toFloat64OrZero(SpanAttributes['key']).\n\nShape auto-upgrade: if shape is \"number\", \"pie\", or \"bar\" but select has >1 item, it is transparently upgraded to \"table\".\n\n── METRIC SOURCES ──\nWhen sourceId is a metric source, each select item MUST set metricType (\"gauge\"|\"sum\"|\"histogram\"|\"exponential histogram\") and metricName (the OTel metric name). valueExpression defaults to \"Value\" — set it explicitly only to transform the value.\nDiscovery: clickstack_describe_source returns a per-kind metric-name sample; clickstack_list_metrics paginates the full catalog; clickstack_describe_metric returns attribute keys + sampled values for a single metric.\nPer kind: gauge uses last_value/avg/min/max; sum uses aggFn:\"increase\" for counter increase (top-N capped at 20 groups when combined with groupBy), or sum/avg on the rate; histogram and exponential histogram use aggFn:\"quantile\" + level for percentiles, or aggFn:\"count\" for total bucket count.\nsummary metrics are not supported by the query renderer — query them with clickstack_sql against the table in the source's metricTables.summary.\n\nSOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"select"
],
"properties": {
"shape": {
"enum": [
"table",
"number",
"pie",
"bar"
],
"type": "string",
"default": "table",
"description": "Output shape: \"table\" (grouped rows, default), \"number\" (single scalar), \"pie\" (pie chart), or \"bar\" (categorical bar chart). If \"number\", \"pie\", or \"bar\" is set with select.length > 1, it is auto-upgraded to \"table\". groupBy is ignored when shape is \"number\"."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter applied to ALL select items. This scopes the entire query — use it to restrict by service, severity, etc. Each select item can also have its own per-metric \"where\" for cohort comparisons. When both are set, they are ANDed together.\n\nLucene example: \"ServiceName:frontend\"\nSQL example: \"ServiceName = 'frontend'\""
},
"select": {
"type": "array",
"items": {
"type": "object",
"required": [
"aggFn"
],
"properties": {
"aggFn": {
"enum": [
"avg",
"count",
"count_distinct",
"last_value",
"max",
"min",
"quantile",
"sum",
"none",
"increase"
],
"type": "string",
"description": "Aggregation function:\n count – count matching rows (no valueExpression needed)\n sum / avg / min / max – aggregate a numeric column (valueExpression required)\n count_distinct – unique value count (valueExpression required)\n quantile – percentile; also set level (valueExpression required)\n last_value – most recent value of a column\n none – pass a raw expression through unchanged\n increase – METRIC-ONLY (Sum/counter): per-bucket counter increase, reset-aware. Requires metricType:\"sum\" and metricName."
},
"alias": {
"type": "string",
"description": "Display label for this series — used in chart legends, table column headers, CSV exports, and onClick templates. Always set a short, human-readable alias (e.g. \"Requests\", \"P95 Latency\", \"Error Rate\"). Without an alias the UI shows the raw ClickHouse expression (e.g. count(), quantile(0.95)(Duration)) which is hard to read."
},
"level": {
"enum": [
"0.5",
"0.9",
"0.95",
"0.99"
],
"type": "string",
"description": "Percentile level. Required when aggFn is \"quantile\" on a histogram or exponential histogram metric, optional otherwise. Allowed values: 0.5, 0.9, 0.95, 0.99"
},
"where": {
"type": "string",
"default": "",
"description": "Conditional aggregation filter — restricts which rows are included in THIS metric (combined with the top-level time/where filter via AND). Compiles to <aggFn>If(...): e.g. quantile + where=Timestamp<X → quantileIf(0.99)(Duration, Timestamp<X). Use this to compute before/after deltas or per-segment metrics in a single query: set where: \"Timestamp < '2026-05-09T23:40:00Z'\" on one item and \"Timestamp >= '2026-05-09T23:40:00Z'\" on another to get baseline-vs-anomaly p99 in one round trip — much faster than re-running the same query with a different time range. Examples (lucene): \"level:error\", \"service.name:api AND http.status_code:>=500\". Set whereLanguage:\"sql\" for raw SQL conditions like \"SpanAttributes['http.method'] = 'POST'\" or \"Timestamp < '2026-05-09 23:40:00'\"."
},
"isDelta": {
"type": "boolean",
"description": "METRIC SOURCES ONLY (gauge metrics). When true, computes the Prometheus-style delta over each bucket: (argMax(Value) - argMin(Value)) * bucketSecs / timeDiff. Use for cumulative gauges where you want to chart growth per bucket. Default false."
},
"metricName": {
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric name (e.g. \"system.cpu.utilization\", \"http.server.request.duration\"). Required when metricType is set. Discover via clickstack_list_metrics or clickstack_describe_source."
},
"metricType": {
"enum": [
"gauge",
"sum",
"histogram",
"exponential histogram"
],
"type": "string",
"description": "METRIC SOURCES ONLY. OTel metric kind: gauge, sum, histogram, or exponential histogram. Required (with metricName) when sourceId is a metric source. Discover via clickstack_describe_source (sample) or clickstack_describe_metric."
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the per-item conditional filter. Use \"sql\" when comparing to literal timestamps or arbitrary attribute expressions. Default: lucene"
},
"valueExpression": {
"type": "string",
"description": "ClickHouse SQL expression to aggregate. Required for every aggFn except \"count\". Top-level columns are PascalCase (Duration, StatusCode); map attributes use bracket syntax: SpanAttributes['key'], ResourceAttributes['key']. Any ClickHouse expression is allowed — common useful forms: \"Duration / 1e6\" (ns→ms), \"toFloat64OrZero(SpanAttributes['response.size_bytes'])\" (cast attribute), \"if(StatusCode = 'STATUS_CODE_ERROR', 1, 0)\" (boolean→numeric for ratios).\n\nMETRIC SOURCES: optional — defaults to \"Value\" (the metric value column) when metricType/metricName are set. Set explicitly only if you want to transform the metric value (e.g. \"Value / 1e6\")."
}
},
"additionalProperties": false
},
"maxItems": 10,
"minItems": 1,
"description": "Metrics to compute. Each item defines one aggregation column. For \"number\" shape, provide exactly 1 item. Example: [{ aggFn: \"count\" }, { aggFn: \"avg\", valueExpression: \"Duration\" }]"
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"groupBy": {
"type": "string",
"description": "Column(s) or ClickHouse expression(s) to group/split by. Accepts a SINGLE entry or MULTIPLE entries as a comma-delimited list — multi-column groupBy expresses multi-dimensional breakdowns in one query (e.g. \"ServiceName, SpanName, StatusMessage\") instead of running one query per dimension. For \"table\" displayType, the result has one row per distinct combination of group values. Top-level columns use PascalCase (\"SpanName\", \"StatusCode\"). Map attributes: SpanAttributes['key'], ResourceAttributes['key'].\n\nArbitrary ClickHouse expressions are also allowed in groupBy — useful when you need to group by a derived column without falling back to raw SQL:\n - \"substring(Body, 1, 80)\" — group by body prefix (log pattern bucketing)\n - \"toStartOfInterval(Timestamp, INTERVAL 5 MINUTE)\" — explicit time bucketing in a table view, alongside another dimension (granularity only works for line/stacked_bar)\n - \"JSONExtractString(Body, 'event')\" — parse a JSON field from the body\n - \"if(Duration > 1e9, 'slow', 'fast')\" — coarse boolean buckets\nComma splitting is bracket-aware, so multi-arg function calls work as single entries."
},
"orderBy": {
"type": "string",
"description": "Sort results by this column. When ordering by an alias that contains spaces or special characters, wrap the alias in quotes: e.g. '\"P95 Latency\" DESC'."
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the \"where\" filter. Default: lucene.\nIMPORTANT: the syntax in \"where\" MUST match \"whereLanguage\".\n Lucene (default): Column:value, Column.mapKey:value, Column:>100\n SQL: Column = 'value', SpanAttributes['key'] = 'value'\n\nLucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use \"sql\" for IN(...) lists, complex expressions, or function calls.\nIMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.\n\nCommon mistake: writing Column:value (Lucene) but setting whereLanguage to \"sql\". If your filter uses colon syntax, leave whereLanguage as \"lucene\" (the default)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description90/100
Browse individual log/event/trace rows. Use this when you need to see raw events, investigate specific log lines, or drill into individual records matching a filter.
PREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
Requires sourceId — call clickstack_list_sources then clickstack_describe_source first.
For aggregated metrics, use clickstack_table instead. For pattern discovery, use clickstack_event_patterns instead.
Set denoise=true to automatically filter out high-frequency repetitive patterns, surfacing only unusual or interesting events.
Column naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method'].
SOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.
The description explains the capability, when to use it, and what to expect.
Inputs81/100
8 of 9 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID (required). Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
where
Row filter.
FIRST: pick a language (whereLanguage):
Lucene (default): Column:value e.g. level:error
Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET
SQL: Column = 'value' e.g. StatusCode = 500
SQL map attrs: SpanAttributes['key'] = 'value'
MAP ATTRIBUTES:
Lucene uses DOT notation: SpanAttributes.http.method:GET
SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'
WRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)
WRONG: level = "error" (SQL syntax with whereLanguage:"lucene")
SUBSTRING TRAP: Lucene field:value matches ANY row containing "value" as a substring, not exact equality.
SpanKind:Server matches "Server", "ServerStreaming", "InternalServer", etc.
For exact match, use SQL: SpanKind = 'Server'
Clear enough to supply this argument.
whereLanguage
Query language for the "where" filter. Default: lucene.
IMPORTANT: the syntax in "where" MUST match "whereLanguage".
Lucene (default): Column:value, Column.mapKey:value, Column:>100
SQL: Column = 'value', SpanAttributes['key'] = 'value'
Lucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use "sql" for IN(...) lists, complex expressions, or function calls.
IMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.
Common mistake: writing Column:value (Lucene) but setting whereLanguage to "sql". If your filter uses colon syntax, leave whereLanguage as "lucene" (the default).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
columns
Comma-separated columns to include in search results. Leave empty for defaults. Example: "Body,ServiceName,Duration"
Clear enough to supply this argument.
maxResults
Maximum number of rows to return (1-200). Default: 50. Use smaller values to reduce response size.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
denoise
When true, automatically removes events matching high-frequency patterns (those accounting for >10% of sampled events) from the results. Useful for cutting through log noise to find unusual or interesting events. Adds ~1-2s of latency for the pattern sampling queries.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_search",
"title": "Search Events",
"description": "Browse individual log/event/trace rows. Use this when you need to see raw events, investigate specific log lines, or drill into individual records matching a filter.\n\nPREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).\n\nRequires sourceId — call clickstack_list_sources then clickstack_describe_source first.\n\nFor aggregated metrics, use clickstack_table instead. For pattern discovery, use clickstack_event_patterns instead.\n\nSet denoise=true to automatically filter out high-frequency repetitive patterns, surfacing only unusual or interesting events.\n\nColumn naming: top-level columns are PascalCase (Duration, StatusCode). Map attributes use bracket syntax: SpanAttributes['http.method'].\n\nSOURCE FILTERS: when the source declares `requiredSourceFilters` (see clickstack_describe_source / clickstack_list_sources), you MUST pass `sourceFilters` with at least one value for every required column.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Row filter.\n\nFIRST: pick a language (whereLanguage):\n Lucene (default): Column:value e.g. level:error\n Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET\n SQL: Column = 'value' e.g. StatusCode = 500\n SQL map attrs: SpanAttributes['key'] = 'value'\n\nMAP ATTRIBUTES:\n Lucene uses DOT notation: SpanAttributes.http.method:GET\n SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'\n\nWRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)\nWRONG: level = \"error\" (SQL syntax with whereLanguage:\"lucene\")\n\nSUBSTRING TRAP: Lucene field:value matches ANY row containing \"value\" as a substring, not exact equality.\n SpanKind:Server matches \"Server\", \"ServerStreaming\", \"InternalServer\", etc.\n For exact match, use SQL: SpanKind = 'Server'"
},
"columns": {
"type": "string",
"default": "",
"description": "Comma-separated columns to include in search results. Leave empty for defaults. Example: \"Body,ServiceName,Duration\""
},
"denoise": {
"type": "boolean",
"default": false,
"description": "When true, automatically removes events matching high-frequency patterns (those accounting for >10% of sampled events) from the results. Useful for cutting through log noise to find unusual or interesting events. Adds ~1-2s of latency for the pattern sampling queries."
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"maxResults": {
"type": "number",
"default": 50,
"maximum": 200,
"minimum": 1,
"description": "Maximum number of rows to return (1-200). Default: 50. Use smaller values to reduce response size."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the \"where\" filter. Default: lucene.\nIMPORTANT: the syntax in \"where\" MUST match \"whereLanguage\".\n Lucene (default): Column:value, Column.mapKey:value, Column:>100\n SQL: Column = 'value', SpanAttributes['key'] = 'value'\n\nLucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use \"sql\" for IN(...) lists, complex expressions, or function calls.\nIMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.\n\nCommon mistake: writing Column:value (Lucene) but setting whereLanguage to \"sql\". If your filter uses colon syntax, leave whereLanguage as \"lucene\" (the default)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Discover the most common log messages and event patterns. Samples random events, clusters them using the Drain algorithm, and returns patterns sorted by frequency with estimated counts and time trends.
PREFER THIS TOOL over clickstack_search or clickstack_table when the goal is to understand what kinds of messages, errors, or events exist — e.g. "sample logs", "what errors are happening", "show me common messages", "what does this service log". It returns frequency-ranked patterns instead of raw rows, giving a much better overview.
Also use when asked about "top patterns", "common logs", "noisy services", "recurring messages", or log noise analysis.
Each pattern includes a "whereSnippet" — use it as the "where" parameter in a follow-up clickstack_search call to browse matching raw events.
Requires sourceId — call clickstack_list_sources then clickstack_describe_source first.
PREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
When to use which tool:
- clickstack_event_patterns: clustering / recurring shapes / noise analysis
- clickstack_search: raw individual rows
- clickstack_table: aggregated metrics / counts / top-N
The description explains the capability, when to use it, and what to expect.
Inputs80/100
9 of 10 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID (required). Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
where
Row filter.
FIRST: pick a language (whereLanguage):
Lucene (default): Column:value e.g. level:error
Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET
SQL: Column = 'value' e.g. StatusCode = 500
SQL map attrs: SpanAttributes['key'] = 'value'
MAP ATTRIBUTES:
Lucene uses DOT notation: SpanAttributes.http.method:GET
SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'
WRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)
WRONG: level = "error" (SQL syntax with whereLanguage:"lucene")
SUBSTRING TRAP: Lucene field:value matches ANY row containing "value" as a substring, not exact equality.
SpanKind:Server matches "Server", "ServerStreaming", "InternalServer", etc.
For exact match, use SQL: SpanKind = 'Server'
Clear enough to supply this argument.
whereLanguage
Query language for the "where" filter. Default: lucene.
IMPORTANT: the syntax in "where" MUST match "whereLanguage".
Lucene (default): Column:value, Column.mapKey:value, Column:>100
SQL: Column = 'value', SpanAttributes['key'] = 'value'
Lucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use "sql" for IN(...) lists, complex expressions, or function calls.
IMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.
Common mistake: writing Column:value (Lucene) but setting whereLanguage to "sql". If your filter uses colon syntax, leave whereLanguage as "lucene" (the default).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sampleSize
Number of random rows to sample for pattern mining. Default: 10000. Higher values produce more accurate patterns but take longer.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
bodyExpression
Column expression to mine patterns from. Auto-detected from the source if omitted (Body for logs, SpanName for traces). Example: "Body", "SpanName", "SpanAttributes['http.url']"
Clear enough to supply this argument.
topN
Number of top patterns to return (1-100). Default: 20.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
trendBuckets
Number of time buckets for per-pattern trend sparklines (0-60). Default: 24. Compare bucket counts at start vs end to spot patterns that started or stopped mid-window. Set to 0 to disable trend computation (smaller response).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_event_patterns",
"title": "Event Pattern Mining",
"description": "Discover the most common log messages and event patterns. Samples random events, clusters them using the Drain algorithm, and returns patterns sorted by frequency with estimated counts and time trends.\n\nPREFER THIS TOOL over clickstack_search or clickstack_table when the goal is to understand what kinds of messages, errors, or events exist — e.g. \"sample logs\", \"what errors are happening\", \"show me common messages\", \"what does this service log\". It returns frequency-ranked patterns instead of raw rows, giving a much better overview.\n\nAlso use when asked about \"top patterns\", \"common logs\", \"noisy services\", \"recurring messages\", or log noise analysis.\n\nEach pattern includes a \"whereSnippet\" — use it as the \"where\" parameter in a follow-up clickstack_search call to browse matching raw events.\n\nRequires sourceId — call clickstack_list_sources then clickstack_describe_source first.\n\nPREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).\n\nWhen to use which tool:\n - clickstack_event_patterns: clustering / recurring shapes / noise analysis\n - clickstack_search: raw individual rows\n - clickstack_table: aggregated metrics / counts / top-N",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"topN": {
"type": "number",
"default": 20,
"maximum": 100,
"minimum": 1,
"description": "Number of top patterns to return (1-100). Default: 20."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter.\n\nFIRST: pick a language (whereLanguage):\n Lucene (default): Column:value e.g. level:error\n Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET\n SQL: Column = 'value' e.g. StatusCode = 500\n SQL map attrs: SpanAttributes['key'] = 'value'\n\nMAP ATTRIBUTES:\n Lucene uses DOT notation: SpanAttributes.http.method:GET\n SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'\n\nWRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)\nWRONG: level = \"error\" (SQL syntax with whereLanguage:\"lucene\")\n\nSUBSTRING TRAP: Lucene field:value matches ANY row containing \"value\" as a substring, not exact equality.\n SpanKind:Server matches \"Server\", \"ServerStreaming\", \"InternalServer\", etc.\n For exact match, use SQL: SpanKind = 'Server'"
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"sampleSize": {
"type": "number",
"default": 10000,
"maximum": 25000,
"minimum": 1,
"description": "Number of random rows to sample for pattern mining. Default: 10000. Higher values produce more accurate patterns but take longer."
},
"trendBuckets": {
"type": "number",
"default": 24,
"maximum": 60,
"minimum": 0,
"description": "Number of time buckets for per-pattern trend sparklines (0-60). Default: 24. Compare bucket counts at start vs end to spot patterns that started or stopped mid-window. Set to 0 to disable trend computation (smaller response)."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the \"where\" filter. Default: lucene.\nIMPORTANT: the syntax in \"where\" MUST match \"whereLanguage\".\n Lucene (default): Column:value, Column.mapKey:value, Column:>100\n SQL: Column = 'value', SpanAttributes['key'] = 'value'\n\nLucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use \"sql\" for IN(...) lists, complex expressions, or function calls.\nIMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.\n\nCommon mistake: writing Column:value (Lucene) but setting whereLanguage to \"sql\". If your filter uses colon syntax, leave whereLanguage as \"lucene\" (the default)."
},
"bodyExpression": {
"type": "string",
"description": "Column expression to mine patterns from. Auto-detected from the source if omitted (Body for logs, SpanName for traces). Example: \"Body\", \"SpanName\", \"SpanAttributes['http.url']\""
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description100/100
Rank the properties of two row groups (logs or trace spans) by how much their value distributions differ. Same algorithm as the in-app Event Deltas view (DBDeltaChart). High-cardinality fields (IDs, request IDs, timestamps) are filtered out by default so the ranking surfaces the categorical attributes that actually separate the two groups. Score is computed after normalizing each group to 100% so it's robust to different group sizes.
USE THIS INSTEAD OF MANUAL PIVOTS. When two row sets visibly differ and you don't know which attribute(s) separate them, the standard agentic move is to run a GROUP BY for each candidate attribute and compare. event_deltas does this for ALL attributes in one call, ranked by signal strength — usually 1 call instead of 5–20.
NARROW the target to the specific outlier rows. A broad target mostly contains healthy rows, so the ranking comes back noisy. The narrower target — the sharper the ranking.
TYPICAL USES (any source — logs or traces):
- Slow vs fast spans (MOST COMMON for latency triage):
target = {where: <op-filter> AND Duration > <threshold>},
baseline = {where: <op-filter> AND Duration <= <threshold>}
Scope BOTH to the same operation/endpoint via `<op-filter>`; the ranked attribute(s) are then what discriminates the slow invocations of THAT operation from the fast ones. Skipping the op-filter gives a noisy "which operation is slow" answer instead of "which sub-set of one operation is slow".
- Before vs after a deploy / incident onset:
target = {window: after onset}, baseline = {window: before onset}
- Failing vs succeeding rows:
target = {where: <failing filter>}, baseline = {where: <succeeding filter>}
- One service / endpoint vs the rest:
target = {where: ServiceName=X}, baseline = {where: ServiceName != X}
Any pair of row sets over the same source works — the tool just asks "what is statistically different about target vs baseline".
WHEN NOT TO USE: when the question is already known to be about a specific attribute (use clickstack_table groupBy), when you want raw rows (use clickstack_search), or when you need a time-series shape (use clickstack_timeseries).
PREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).
OUTPUT SHAPE: an array of properties, each with rank, key, score, semanticBoost (true for well-known OTel attrs like service.name / http.method / error.type / status), targetCount and baselineCount (sample sizes), and topDeltas — the values whose share shifted most, each with `value`, `targetPct`, `baselinePct`, and `diffPct`. topDeltas already contains the full per-value comparison for that attribute, so there is no separate target/baseline distribution to consult.
IMPORTANT — DO NOT STOP AT RANK 1. The top ~5 ranked properties are often INDEPENDENT axes that together explain the population shift (e.g. a regression localized on the intersection of two attributes). Scan down the list until the score visibly drops to noise level; any property well above that floor is a candidate axis to combine with the others.
The description explains the capability, when to use it, and what to expect.
Inputs79/100
13 of 14 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID. Works for trace and log sources. Call clickstack_list_sources for available sources.
Clear enough to supply this argument.
target › startTime
Start of the group window as ISO 8601.
Clear enough to supply this argument.
target › endTime
End of the group window as ISO 8601.
Clear enough to supply this argument.
target › where
Optional row filter (Lucene by default, SQL via whereLanguage). Combined with the time window via AND. Useful for restricting the group to a service, endpoint, or other dimension.
Clear enough to supply this argument.
target › whereLanguage
Query language for where. Default: lucene.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
baseline › startTime
Start of the group window as ISO 8601.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
baseline › endTime
End of the group window as ISO 8601.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
baseline › where
Optional row filter (Lucene by default, SQL via whereLanguage). Combined with the time window via AND. Useful for restricting the group to a service, endpoint, or other dimension.
Clear enough to supply this argument.
baseline › whereLanguage
Query language for where. Default: lucene.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sampleSize
Rows to sample from each group. Default: 500. Larger samples give more stable rankings at the cost of latency.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
topN
Number of top-ranked properties to return in `properties`. Default: 20.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
includeHidden
When true, include denylisted/high-cardinality properties in a separate `hidden` array. Default: false (mirrors UI behavior — these are noisy).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
topValuesPerProperty
How many top values per property to include in the response. Default: 6.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_event_deltas",
"title": "Compare Events: Target vs Baseline",
"description": "Rank the properties of two row groups (logs or trace spans) by how much their value distributions differ. Same algorithm as the in-app Event Deltas view (DBDeltaChart). High-cardinality fields (IDs, request IDs, timestamps) are filtered out by default so the ranking surfaces the categorical attributes that actually separate the two groups. Score is computed after normalizing each group to 100% so it's robust to different group sizes.\n\nUSE THIS INSTEAD OF MANUAL PIVOTS. When two row sets visibly differ and you don't know which attribute(s) separate them, the standard agentic move is to run a GROUP BY for each candidate attribute and compare. event_deltas does this for ALL attributes in one call, ranked by signal strength — usually 1 call instead of 5–20.\n\nNARROW the target to the specific outlier rows. A broad target mostly contains healthy rows, so the ranking comes back noisy. The narrower target — the sharper the ranking.\n\nTYPICAL USES (any source — logs or traces):\n - Slow vs fast spans (MOST COMMON for latency triage):\n target = {where: <op-filter> AND Duration > <threshold>},\n baseline = {where: <op-filter> AND Duration <= <threshold>}\n Scope BOTH to the same operation/endpoint via `<op-filter>`; the ranked attribute(s) are then what discriminates the slow invocations of THAT operation from the fast ones. Skipping the op-filter gives a noisy \"which operation is slow\" answer instead of \"which sub-set of one operation is slow\".\n - Before vs after a deploy / incident onset:\n target = {window: after onset}, baseline = {window: before onset}\n - Failing vs succeeding rows:\n target = {where: <failing filter>}, baseline = {where: <succeeding filter>}\n - One service / endpoint vs the rest:\n target = {where: ServiceName=X}, baseline = {where: ServiceName != X}\n Any pair of row sets over the same source works — the tool just asks \"what is statistically different about target vs baseline\".\n\nWHEN NOT TO USE: when the question is already known to be about a specific attribute (use clickstack_table groupBy), when you want raw rows (use clickstack_search), or when you need a time-series shape (use clickstack_timeseries).\n\nPREFER THIS over clickstack_sql. Only drop to raw SQL for things the builder tools cannot express — JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query).\n\nOUTPUT SHAPE: an array of properties, each with rank, key, score, semanticBoost (true for well-known OTel attrs like service.name / http.method / error.type / status), targetCount and baselineCount (sample sizes), and topDeltas — the values whose share shifted most, each with `value`, `targetPct`, `baselinePct`, and `diffPct`. topDeltas already contains the full per-value comparison for that attribute, so there is no separate target/baseline distribution to consult.\n\nIMPORTANT — DO NOT STOP AT RANK 1. The top ~5 ranked properties are often INDEPENDENT axes that together explain the population shift (e.g. a regression localized on the intersection of two attributes). Scan down the list until the score visibly drops to noise level; any property well above that floor is a candidate axis to combine with the others.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"target",
"baseline"
],
"properties": {
"topN": {
"type": "number",
"default": 20,
"maximum": 100,
"minimum": 1,
"description": "Number of top-ranked properties to return in `properties`. Default: 20."
},
"target": {
"type": "object",
"required": [
"startTime",
"endTime"
],
"properties": {
"where": {
"type": "string",
"default": "",
"description": "Optional row filter (Lucene by default, SQL via whereLanguage). Combined with the time window via AND. Useful for restricting the group to a service, endpoint, or other dimension."
},
"endTime": {
"type": "string",
"description": "End of the group window as ISO 8601."
},
"startTime": {
"type": "string",
"description": "Start of the group window as ISO 8601."
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for where. Default: lucene."
}
},
"description": "Target (\"outlier\") group — the rows you suspect are different (e.g. the recent slow window, the failing requests, the affected segment).",
"additionalProperties": false
},
"baseline": {
"type": "object",
"required": [
"startTime",
"endTime"
],
"properties": {
"where": {
"$ref": "#/properties/target/properties/where"
},
"endTime": {
"$ref": "#/properties/target/properties/endTime"
},
"startTime": {
"$ref": "#/properties/target/properties/startTime"
},
"whereLanguage": {
"$ref": "#/properties/target/properties/whereLanguage"
}
},
"description": "Baseline (\"inlier\") group — the rows considered normal (e.g. an earlier healthy window, the successful requests, the unaffected segment).",
"additionalProperties": false
},
"sourceId": {
"type": "string",
"description": "Source ID. Works for trace and log sources. Call clickstack_list_sources for available sources."
},
"sampleSize": {
"type": "number",
"default": 500,
"maximum": 5000,
"minimum": 100,
"description": "Rows to sample from each group. Default: 500. Larger samples give more stable rankings at the cost of latency."
},
"includeHidden": {
"type": "boolean",
"default": false,
"description": "When true, include denylisted/high-cardinality properties in a separate `hidden` array. Default: false (mirrors UI behavior — these are noisy)."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"topValuesPerProperty": {
"type": "number",
"default": 6,
"maximum": 20,
"minimum": 2,
"description": "How many top values per property to include in the response. Default: 6."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Detect what is NEW or GONE between an earlier baseline window and a current window — log/event patterns that emerged, ramped up, or stopped. This answers "what changed / what is novel?" — NOT "what attribute value differs?".
USE THIS for status checks, health reports, post-deploy diffs, and any "call out anything new or worth a closer look" question. It mines event patterns (Drain) in BOTH windows and set-differences them:
- emerging: patterns whose share of the window is >= minShareRatio× higher now than in baseline (includes brand-new templates absent from baseline)
- disappeared: patterns that were common in baseline but >= minShareRatio× rarer (or absent) now
WHY NOT clickstack_event_deltas: event_deltas compares ATTRIBUTE VALUE DISTRIBUTIONS between two row groups (e.g. "region shifted toward eu-west"). It CANNOT surface a brand-new log template or a new endpoint that simply did not exist before — a novel signal has no baseline distribution to shift. Use emerging_signals for novelty/emergence (set membership over time); use event_deltas for "what is different about these rows" (distribution shift within a shared population).
Requires sourceId — call clickstack_list_sources / clickstack_describe_source first. Provide two non-overlapping windows: the current window to characterize and an earlier baseline. Typically baselineEndTime == currentStartTime.
CALIBRATION: routine variance is not novelty. A pattern that merely wobbled in volume is NOT emerging; only report shifts past minShareRatio. An empty emerging list is a valid, informative answer ("nothing novel") — do not manufacture findings.
The description explains the capability, when to use it, and what to expect.
Inputs85/100
11 of 12 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Source ID (required). Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
where
Row filter.
FIRST: pick a language (whereLanguage):
Lucene (default): Column:value e.g. level:error
Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET
SQL: Column = 'value' e.g. StatusCode = 500
SQL map attrs: SpanAttributes['key'] = 'value'
MAP ATTRIBUTES:
Lucene uses DOT notation: SpanAttributes.http.method:GET
SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'
WRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)
WRONG: level = "error" (SQL syntax with whereLanguage:"lucene")
SUBSTRING TRAP: Lucene field:value matches ANY row containing "value" as a substring, not exact equality.
SpanKind:Server matches "Server", "ServerStreaming", "InternalServer", etc.
For exact match, use SQL: SpanKind = 'Server'
Clear enough to supply this argument.
whereLanguage
Query language for the "where" filter. Default: lucene.
IMPORTANT: the syntax in "where" MUST match "whereLanguage".
Lucene (default): Column:value, Column.mapKey:value, Column:>100
SQL: Column = 'value', SpanAttributes['key'] = 'value'
Lucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use "sql" for IN(...) lists, complex expressions, or function calls.
IMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.
Common mistake: writing Column:value (Lucene) but setting whereLanguage to "sql". If your filter uses colon syntax, leave whereLanguage as "lucene" (the default).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
bodyExpression
Column expression to mine patterns from. Auto-detected from the source if omitted (Body for logs, SpanName for traces). Example: "Body", "SpanName", "SpanAttributes['http.url']".
Clear enough to supply this argument.
currentStartTime
Start of the CURRENT / report window (ISO 8601). This is the window you want to characterize (e.g. the last hour).
Clear enough to supply this argument.
currentEndTime
End of the CURRENT / report window (ISO 8601). Required — pass the current timestamp for a window ending now.
Clear enough to supply this argument.
baselineStartTime
Start of the BASELINE window (ISO 8601) — an earlier "normal" period to compare against. Should NOT overlap the current window.
Clear enough to supply this argument.
baselineEndTime
End of the BASELINE window (ISO 8601). Typically equals currentStartTime (the baseline ends where the current window begins).
Clear enough to supply this argument.
sampleSize
Rows sampled per window for pattern mining. Default 10000.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
topN
Max emerging + disappeared patterns to return each. Default 20.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
minShareRatio
How many times more frequent (by share of window) a pattern must be in the current window vs baseline to count as EMERGING (and vice-versa for DISAPPEARED). Default 3× — a pattern must have tripled its share to qualify as a shift, not just noise.
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_emerging_signals",
"title": "Emerging & Disappeared Signals",
"description": "Detect what is NEW or GONE between an earlier baseline window and a current window — log/event patterns that emerged, ramped up, or stopped. This answers \"what changed / what is novel?\" — NOT \"what attribute value differs?\".\n\nUSE THIS for status checks, health reports, post-deploy diffs, and any \"call out anything new or worth a closer look\" question. It mines event patterns (Drain) in BOTH windows and set-differences them:\n - emerging: patterns whose share of the window is >= minShareRatio× higher now than in baseline (includes brand-new templates absent from baseline)\n - disappeared: patterns that were common in baseline but >= minShareRatio× rarer (or absent) now\n\nWHY NOT clickstack_event_deltas: event_deltas compares ATTRIBUTE VALUE DISTRIBUTIONS between two row groups (e.g. \"region shifted toward eu-west\"). It CANNOT surface a brand-new log template or a new endpoint that simply did not exist before — a novel signal has no baseline distribution to shift. Use emerging_signals for novelty/emergence (set membership over time); use event_deltas for \"what is different about these rows\" (distribution shift within a shared population).\n\nRequires sourceId — call clickstack_list_sources / clickstack_describe_source first. Provide two non-overlapping windows: the current window to characterize and an earlier baseline. Typically baselineEndTime == currentStartTime.\n\nCALIBRATION: routine variance is not novelty. A pattern that merely wobbled in volume is NOT emerging; only report shifts past minShareRatio. An empty emerging list is a valid, informative answer (\"nothing novel\") — do not manufacture findings.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"currentStartTime",
"currentEndTime",
"baselineStartTime",
"baselineEndTime"
],
"properties": {
"topN": {
"type": "number",
"default": 20,
"maximum": 100,
"minimum": 1,
"description": "Max emerging + disappeared patterns to return each. Default 20."
},
"where": {
"type": "string",
"default": "",
"description": "Row filter.\n\nFIRST: pick a language (whereLanguage):\n Lucene (default): Column:value e.g. level:error\n Lucene map attrs: Column.key:value e.g. SpanAttributes.http.method:GET\n SQL: Column = 'value' e.g. StatusCode = 500\n SQL map attrs: SpanAttributes['key'] = 'value'\n\nMAP ATTRIBUTES:\n Lucene uses DOT notation: SpanAttributes.http.method:GET\n SQL uses BRACKET notation: SpanAttributes['http.method'] = 'GET'\n\nWRONG: SpanAttributes['key']:value (Lucene cannot parse bracket syntax)\nWRONG: level = \"error\" (SQL syntax with whereLanguage:\"lucene\")\n\nSUBSTRING TRAP: Lucene field:value matches ANY row containing \"value\" as a substring, not exact equality.\n SpanKind:Server matches \"Server\", \"ServerStreaming\", \"InternalServer\", etc.\n For exact match, use SQL: SpanKind = 'Server'"
},
"sourceId": {
"type": "string",
"description": "Source ID (required). Call clickstack_list_sources to find available sources."
},
"sampleSize": {
"type": "number",
"default": 10000,
"maximum": 25000,
"minimum": 1,
"description": "Rows sampled per window for pattern mining. Default 10000."
},
"minShareRatio": {
"type": "number",
"default": 3,
"minimum": 1,
"description": "How many times more frequent (by share of window) a pattern must be in the current window vs baseline to count as EMERGING (and vice-versa for DISAPPEARED). Default 3× — a pattern must have tripled its share to qualify as a shift, not just noise."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for the \"where\" filter. Default: lucene.\nIMPORTANT: the syntax in \"where\" MUST match \"whereLanguage\".\n Lucene (default): Column:value, Column.mapKey:value, Column:>100\n SQL: Column = 'value', SpanAttributes['key'] = 'value'\n\nLucene supports comparisons (>= > < <=), wildcards (field:val*), ranges ([1 TO 5]), and map attributes via dot notation. Use \"sql\" for IN(...) lists, complex expressions, or function calls.\nIMPORTANT: Lucene field:value is a SUBSTRING match (ilike), not exact equality. field:val* is prefix-within-substring, not a true prefix match. For exact matching or reliable wildcards, use SQL: WHERE field = 'value' or WHERE field LIKE 'val%'.\n\nCommon mistake: writing Column:value (Lucene) but setting whereLanguage to \"sql\". If your filter uses colon syntax, leave whereLanguage as \"lucene\" (the default)."
},
"bodyExpression": {
"type": "string",
"description": "Column expression to mine patterns from. Auto-detected from the source if omitted (Body for logs, SpanName for traces). Example: \"Body\", \"SpanName\", \"SpanAttributes['http.url']\"."
},
"currentEndTime": {
"type": "string",
"description": "End of the CURRENT / report window (ISO 8601). Required — pass the current timestamp for a window ending now."
},
"baselineEndTime": {
"type": "string",
"description": "End of the BASELINE window (ISO 8601). Typically equals currentStartTime (the baseline ends where the current window begins)."
},
"currentStartTime": {
"type": "string",
"description": "Start of the CURRENT / report window (ISO 8601). This is the window you want to characterize (e.g. the last hour)."
},
"baselineStartTime": {
"type": "string",
"description": "Start of the BASELINE window (ISO 8601) — an earlier \"normal\" period to compare against. Should NOT overlap the current window."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description93/100
Execute raw ClickHouse SQL. LAST-RESORT TOOL — do NOT reach for this first.
Default to the builder tools for querying; they are more reliable and produce richer, structured results:
• clickstack_table — aggregations, top-N, single-value KPIs, breakdowns
• clickstack_timeseries — trends / metrics over time
• clickstack_search — browsing individual log/trace rows
• clickstack_event_patterns — recurring log/event pattern discovery
• clickstack_event_deltas — attributes that differ between two row groups
• clickstack_emerging_signals — patterns new or gone vs a baseline window
• clickstack_trace_waterfall — one trace as a parent/child span tree
• clickstack_trace_top_time_consuming_operations — slowest child operations in a trace
ONLY use raw SQL when the query genuinely cannot be expressed by a builder tool — i.e. it requires JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query). A single-table aggregation, top-N, time-series, or row browse is ALWAYS a builder-tool job, never raw SQL. If you are unsure, try the builder tool first and only fall back to SQL if it cannot express what you need.
Requires connectionId — call clickstack_list_sources to find connections. Pass sourceId too when querying a source, so $__sourceTable resolves to its table. Call clickstack_describe_source to discover column names before writing SQL.
SOURCE FILTERS: when querying a table backed by a registered source, pass `sourceId` so the `$__sourceTable` and `$__filters` macros resolve. If that source declares `requiredSourceFilters`, you MUST also pass `sourceFilters` AND include `$__filters` in your WHERE clause. Source filter values are rendered as `<column> IN (<value>, <value2>, ...)` conditions.
Results are always returned as table rows — for time-series semantics, include a time column and ORDER BY it in your SQL.
The description explains the capability, when to use it, and what to expect.
Inputs83/100
5 of 6 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
connectionId
Connection ID (required). This is the only split tool that needs a connectionId instead of sourceId. Call clickstack_list_sources to find available connections.
Clear enough to supply this argument.
sourceId
Source ID. OPTIONAL but recommended when the query targets a table backed by a registered source. Required when the source declares `requiredSourceFilters` (see clickstack_list_sources / clickstack_describe_source) or when using the `$__filters` or `$__sourceTable` macros. When set, sourceId's `connection` must match `connectionId`.
Clear enough to supply this argument.
sql
Raw ClickHouse SQL query. Always include a LIMIT clause to avoid excessive data.
TIME FILTERING (preferred path):
$__timeFilter(column) — column >= <start> AND column <= <end> (DateTime precision)
$__timeFilter_ms(column) — same with DateTime64 millisecond precision
{startDateMilliseconds:Int64} / {endDateMilliseconds:Int64} — epoch ms parameters
LITERAL-CAST FALLBACKS:
parseDateTime64BestEffortOrNull('2024-01-01T00:00:00Z')
toDateTime64('2024-01-01 00:00:00', 9)
OTHER MACROS:
$__dateFilter(column) — Date precision
$__dateTimeFilter(dateCol, timeCol) — filters on Date + DateTime columns
$__dt(dateCol, timeCol) — alias for $__dateTimeFilter
$__fromTime / $__toTime — start/end as DateTime values
$__fromTime_ms / $__toTime_ms — start/end as DateTime64 values
$__timeInterval(column) — time bucket expression: toStartOfInterval(toDateTime(column), INTERVAL ...)
$__timeInterval_ms(column) — same with millisecond precision
$__interval_s — raw interval in seconds
$__filters — replaced with the `column IN (…)` predicates derived from the provided `sourceFilters`. Resolves to `(1=1)` when there are no source filters. REQUIRED in the WHERE clause when querying a source with `requiredSourceFilters` (see SOURCE FILTERS below). Requires sourceId. $__sourceTable — expands to the source's database.table. Requires sourceId.
{intervalSeconds:Int64} / {intervalMilliseconds:Int64} — bucket size parameters
In the examples, replace <table> with a source's `table` and <timestampColumn> with the first expression in its `timestampColumn`, both from clickstack_list_sources, or pass that source as sourceId and use $__sourceTable. For a metric source, use a table from its metricTables qualified with its `database`. Table and column names differ between sources, so do not guess them.
Example (time-series, with sourceId):
SELECT $__timeInterval(<timestampColumn>) AS ts, ServiceName, count() FROM $__sourceTable WHERE $__timeFilter(<timestampColumn>) GROUP BY ServiceName, ts ORDER BY ts
Example (table):
SELECT ServiceName, count() AS n FROM <table> WHERE <timestampColumn> >= fromUnixTimestamp64Milli({startDateMilliseconds:Int64}) AND <timestampColumn> < fromUnixTimestamp64Milli({endDateMilliseconds:Int64}) GROUP BY ServiceName ORDER BY n DESC LIMIT 20
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
startTime
Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours).
Clear enough to supply this argument.
endTime
End of the query window as ISO 8601. Default: now.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_sql",
"title": "Raw SQL Query",
"description": "Execute raw ClickHouse SQL. LAST-RESORT TOOL — do NOT reach for this first.\n\nDefault to the builder tools for querying; they are more reliable and produce richer, structured results:\n • clickstack_table — aggregations, top-N, single-value KPIs, breakdowns\n • clickstack_timeseries — trends / metrics over time\n • clickstack_search — browsing individual log/trace rows\n • clickstack_event_patterns — recurring log/event pattern discovery\n • clickstack_event_deltas — attributes that differ between two row groups\n • clickstack_emerging_signals — patterns new or gone vs a baseline window\n • clickstack_trace_waterfall — one trace as a parent/child span tree\n • clickstack_trace_top_time_consuming_operations — slowest child operations in a trace\n\nONLY use raw SQL when the query genuinely cannot be expressed by a builder tool — i.e. it requires JOINs, sub-queries, CTEs, window functions, tables not registered as sources, or summary-type metrics (the metricTables.summary table on a metric source, which the builder tools cannot query). A single-table aggregation, top-N, time-series, or row browse is ALWAYS a builder-tool job, never raw SQL. If you are unsure, try the builder tool first and only fall back to SQL if it cannot express what you need.\n\nRequires connectionId — call clickstack_list_sources to find connections. Pass sourceId too when querying a source, so $__sourceTable resolves to its table. Call clickstack_describe_source to discover column names before writing SQL.\n\nSOURCE FILTERS: when querying a table backed by a registered source, pass `sourceId` so the `$__sourceTable` and `$__filters` macros resolve. If that source declares `requiredSourceFilters`, you MUST also pass `sourceFilters` AND include `$__filters` in your WHERE clause. Source filter values are rendered as `<column> IN (<value>, <value2>, ...)` conditions.\n\nResults are always returned as table rows — for time-series semantics, include a time column and ORDER BY it in your SQL.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"connectionId",
"sql"
],
"properties": {
"sql": {
"type": "string",
"description": "Raw ClickHouse SQL query. Always include a LIMIT clause to avoid excessive data.\n\nTIME FILTERING (preferred path):\n $__timeFilter(column) — column >= <start> AND column <= <end> (DateTime precision)\n $__timeFilter_ms(column) — same with DateTime64 millisecond precision\n {startDateMilliseconds:Int64} / {endDateMilliseconds:Int64} — epoch ms parameters\n\nLITERAL-CAST FALLBACKS:\n parseDateTime64BestEffortOrNull('2024-01-01T00:00:00Z')\n toDateTime64('2024-01-01 00:00:00', 9)\n\nOTHER MACROS:\n $__dateFilter(column) — Date precision\n $__dateTimeFilter(dateCol, timeCol) — filters on Date + DateTime columns\n $__dt(dateCol, timeCol) — alias for $__dateTimeFilter\n $__fromTime / $__toTime — start/end as DateTime values\n $__fromTime_ms / $__toTime_ms — start/end as DateTime64 values\n $__timeInterval(column) — time bucket expression: toStartOfInterval(toDateTime(column), INTERVAL ...)\n $__timeInterval_ms(column) — same with millisecond precision\n $__interval_s — raw interval in seconds\n $__filters — replaced with the `column IN (…)` predicates derived from the provided `sourceFilters`. Resolves to `(1=1)` when there are no source filters. REQUIRED in the WHERE clause when querying a source with `requiredSourceFilters` (see SOURCE FILTERS below). Requires sourceId. $__sourceTable — expands to the source's database.table. Requires sourceId.\n {intervalSeconds:Int64} / {intervalMilliseconds:Int64} — bucket size parameters\n\nIn the examples, replace <table> with a source's `table` and <timestampColumn> with the first expression in its `timestampColumn`, both from clickstack_list_sources, or pass that source as sourceId and use $__sourceTable. For a metric source, use a table from its metricTables qualified with its `database`. Table and column names differ between sources, so do not guess them.\n\nExample (time-series, with sourceId):\n SELECT $__timeInterval(<timestampColumn>) AS ts, ServiceName, count() FROM $__sourceTable WHERE $__timeFilter(<timestampColumn>) GROUP BY ServiceName, ts ORDER BY ts\n\nExample (table):\n SELECT ServiceName, count() AS n FROM <table> WHERE <timestampColumn> >= fromUnixTimestamp64Milli({startDateMilliseconds:Int64}) AND <timestampColumn> < fromUnixTimestamp64Milli({endDateMilliseconds:Int64}) GROUP BY ServiceName ORDER BY n DESC LIMIT 20"
},
"endTime": {
"type": "string",
"description": "End of the query window as ISO 8601. Default: now."
},
"sourceId": {
"type": "string",
"description": "Source ID. OPTIONAL but recommended when the query targets a table backed by a registered source. Required when the source declares `requiredSourceFilters` (see clickstack_list_sources / clickstack_describe_source) or when using the `$__filters` or `$__sourceTable` macros. When set, sourceId's `connection` must match `connectionId`."
},
"startTime": {
"type": "string",
"description": "Start of the query window as ISO 8601. Default: 15 minutes ago. If results are empty, try a wider range (e.g. 24 hours)."
},
"connectionId": {
"type": "string",
"description": "Connection ID (required). This is the only split tool that needs a connectionId instead of sourceId. Call clickstack_list_sources to find available connections."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Without an ID: list all saved searches as a high-level summary (id, name, tags). With an ID: get full saved search detail including query, source, filters, and configuration.
The description explains the capability, when to use it, and what to expect.
Inputs93/100
Input documentation gives an agent enough context to populate the arguments.
id
Saved search ID. Omit to list all saved searches, provide to get full detail.
Clear enough to supply this argument.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_get_saved_search",
"title": "Get Saved Search(es)",
"description": "Without an ID: list all saved searches as a high-level summary (id, name, tags). With an ID: get full saved search detail including query, source, filters, and configuration.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string",
"description": "Saved search ID. Omit to list all saved searches, provide to get full detail."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description75/100
Create a new saved search (omit id) or update an existing one (provide id). A saved search stores a reusable query against a data source. Use clickstack_list_sources to find the sourceId.
Explain mutations, irreversible effects, or prerequisites that matter before calling this tool.
Inputs87/100
14 of 15 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
id
Saved search ID. Omit to create a new saved search, provide to update an existing one.
Clear enough to supply this argument.
name
Human-friendly name for the saved search.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
select
Columns/fields to retrieve. Leave empty for defaults. Example: "body,service.name,duration"
Clear enough to supply this argument.
where
Filter condition string in the language specified by whereLanguage. Example (lucene): "level:error", Example (sql): "StatusCode = 'Error'"
Clear enough to supply this argument.
whereLanguage
Language for the where filter. Default: lucene.
Clear enough to supply this argument.
orderBy
Sort expression. Example: "Timestamp DESC"
Clear enough to supply this argument.
sourceId
Source ID — call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
tags
Tags for organizing saved searches. Up to 50 tags, each at most 32 characters.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
filters › items › anyOf › 0 › type
Filter language: lucene or sql.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
filters › items › anyOf › 0 › condition
Filter condition string.
Clear enough to supply this argument.
filters › items › anyOf › 1 › type
Structured SQL AST filter.
Clear enough to supply this argument.
filters › items › anyOf › 1 › operator
Comparison operator.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
filters › items › anyOf › 1 › left
Left operand (column or expression).
Clear enough to supply this argument.
filters › items › anyOf › 1 › right
Right operand (value or expression).
Clear enough to supply this argument.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
Annotations25/100
Declare readOnlyHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"destructiveHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_save_saved_search",
"title": "Create or Update Saved Search",
"description": "Create a new saved search (omit id) or update an existing one (provide id). A saved search stores a reusable query against a data source. Use clickstack_list_sources to find the sourceId.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"sourceId"
],
"properties": {
"id": {
"type": "string",
"description": "Saved search ID. Omit to create a new saved search, provide to update an existing one."
},
"name": {
"type": "string",
"maxLength": 512,
"minLength": 1,
"description": "Human-friendly name for the saved search."
},
"tags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 32
},
"maxItems": 50,
"description": "Tags for organizing saved searches. Up to 50 tags, each at most 32 characters."
},
"where": {
"type": "string",
"description": "Filter condition string in the language specified by whereLanguage. Example (lucene): \"level:error\", Example (sql): \"StatusCode = 'Error'\""
},
"select": {
"type": "string",
"description": "Columns/fields to retrieve. Leave empty for defaults. Example: \"body,service.name,duration\""
},
"filters": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"type",
"condition"
],
"properties": {
"type": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"description": "Filter language: lucene or sql."
},
"condition": {
"type": "string",
"description": "Filter condition string."
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"type",
"operator",
"left",
"right"
],
"properties": {
"left": {
"type": "string",
"description": "Left operand (column or expression)."
},
"type": {
"type": "string",
"const": "sql_ast",
"description": "Structured SQL AST filter."
},
"right": {
"type": "string",
"description": "Right operand (value or expression)."
},
"operator": {
"enum": [
"=",
"<",
">",
"!=",
"<=",
">="
],
"type": "string",
"description": "Comparison operator."
}
},
"additionalProperties": false
}
],
"description": "Filter applied to the saved search."
},
"description": "Additional structured filters."
},
"orderBy": {
"type": "string",
"description": "Sort expression. Example: \"Timestamp DESC\""
},
"sourceId": {
"type": "string",
"description": "Source ID — call clickstack_list_sources to find available sources."
},
"sourceFilters": {
"type": "object",
"description": "Source filter values keyed by column name. Only available for sources with filterSettings defined. Format: { \"<columnName>\": [\"<value>\"] }. A column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }, but only for columns whose source marks them `allowAll: true`; using it on any other column is rejected.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"whereLanguage": {
"enum": [
"sql",
"lucene"
],
"type": "string",
"description": "Language for the where filter. Default: lucene."
}
},
"additionalProperties": false
},
"annotations": {
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description84/100
List all teams the current user belongs to and identify which team is active for this session. Use this to discover available teams when the user works across multiple teams.
To switch teams, the MCP client must include the `x-hdx-team` HTTP header set to the target team ID on subsequent requests. The header is validated against the user’s team memberships — requests for teams the user does not belong to will be rejected.
Describe the returned information so the agent knows whether it will answer the request.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_list_teams",
"title": "List Teams",
"description": "List all teams the current user belongs to and identify which team is active for this session. Use this to discover available teams when the user works across multiple teams.\n\nTo switch teams, the MCP client must include the `x-hdx-team` HTTP header set to the target team ID on subsequent requests. The header is validated against the user’s team memberships — requests for teams the user does not belong to will be rejected.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description100/100
Fetch all spans in ONE trace and return them as a parent/child waterfall, pre-ordered for human-readable display. Use this for "show me a concrete example trace" or "what happened in trace X" investigations — the tool walks the cascade for you instead of forcing the model to write self-JOINs in raw SQL.
NOT THE RIGHT TOOL when the question is "where does the time go across MANY slow traces of operation X" — that is the aggregate question, and the answer is clickstack_trace_top_time_consuming_operations (called per affected (service, operation) with `minParentDurationMs`). Use this tool only when you want a single concrete example to inspect, or after the aggregate breakdown has already identified a suspicious operation.
Two modes:
1. Specific trace: pass `traceId`. Returns every span in that trace.
2. Auto-pick: pass `pickFilter` + `pickBy`. The tool finds one matching trace (slowest / first_error / most_recent) and returns its full tree.
Each returned span has: depth (root=0), spanId, parentSpanId, serviceName, spanName, spanKind, durationMs, statusCode, statusMessage, timestamp, and spanAttributes. Spans are pre-order DFS — child spans follow their parent in execution order. The tool also surfaces a `summary` section with the picked TraceId, total span count, and root span info.
When the trace source has a linked logSourceId (the standard config), the response also includes a `logs[]` array of correlated log rows that share the same TraceId — sorted by timestamp, each carrying its `spanId` so the agent can attribute messages to specific spans. Disable with `includeLogs:false`. If the log source declares `requiredSourceFilters`, include its columns in `sourceFilters` too (one map shared with the trace source, matched by column name).
Prefer this over running raw SQL with JOINs on TraceId — it uses the source's configured traceIdExpression / parentSpanIdExpression / spanIdExpression so attribute extraction stays consistent with the rest of the platform.
PAIR TOOL: clickstack_trace_top_time_consuming_operations is the aggregate counterpart — given a parent-span filter, it ranks child operations by total time across MANY matching traces. Use that when the question is "where does time go in slow X" (aggregate), and use THIS tool when the question is "show me one example of a slow X" (single trace).
The description explains the capability, when to use it, and what to expect.
Inputs82/100
10 of 11 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Trace source ID. Must be a source of kind "trace". Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
traceId
Specific TraceId to look up. When provided, the tool fetches every span in this trace and returns them as a parent/child tree. When omitted, the tool auto-picks one trace using pickFilter + pickBy. With an explicit traceId and no startTime, the tool probes the trace back to 90 days; pass startTime only to reach a trace older than that.
Clear enough to supply this argument.
pickFilter
Filter (Lucene by default, SQL via pickFilterLanguage) used to narrow which trace to auto-pick when traceId is not provided. Example shapes (Lucene): `ServiceName:<some-service>`, `ServiceName:<svc> AND SpanName:"<some-operation>"`, `StatusCode:<status-value>` (status values come from the source schema's keyColumns). Ignored when traceId is provided.
Clear enough to supply this argument.
pickFilterLanguage
Query language for pickFilter. Default: lucene
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
pickBy
How to choose which trace to return when traceId is not provided.
slowest – trace with the longest single span (use for latency investigations)
first_error – earliest trace containing a span with STATUS_CODE_ERROR
most_recent – the most recent trace matching pickFilter
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
startTime
Start of the search window as ISO 8601. Default: 15 minutes ago for auto-pick. When traceId is set, the window is instead derived from the trace's own span timestamps (probed back to 90 days), so pass startTime only to look up a trace older than 90 days.
Clear enough to supply this argument.
endTime
End of the search window as ISO 8601. Default: now.
Clear enough to supply this argument.
maxSpans
Cap on spans returned in the tree (1–2000). Default 500. A trace with more spans than this will be truncated; the response notes the truncation.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
includeLogs
When true and the trace source has a linked logSourceId, also fetch log rows that share the same TraceId and inline them in the response as `logs[]`. Each log row carries its spanId so the agent can attribute messages to specific spans. No-op if the trace source has no logSourceId configured.
Clear enough to supply this argument.
maxLogs
Cap on correlated log rows returned (1–1000). Default 100. Has no effect when includeLogs is false or the trace source has no logSourceId.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_trace_waterfall",
"title": "Trace Waterfall (single trace)",
"description": "Fetch all spans in ONE trace and return them as a parent/child waterfall, pre-ordered for human-readable display. Use this for \"show me a concrete example trace\" or \"what happened in trace X\" investigations — the tool walks the cascade for you instead of forcing the model to write self-JOINs in raw SQL.\n\nNOT THE RIGHT TOOL when the question is \"where does the time go across MANY slow traces of operation X\" — that is the aggregate question, and the answer is clickstack_trace_top_time_consuming_operations (called per affected (service, operation) with `minParentDurationMs`). Use this tool only when you want a single concrete example to inspect, or after the aggregate breakdown has already identified a suspicious operation.\n\nTwo modes:\n 1. Specific trace: pass `traceId`. Returns every span in that trace.\n 2. Auto-pick: pass `pickFilter` + `pickBy`. The tool finds one matching trace (slowest / first_error / most_recent) and returns its full tree.\n\nEach returned span has: depth (root=0), spanId, parentSpanId, serviceName, spanName, spanKind, durationMs, statusCode, statusMessage, timestamp, and spanAttributes. Spans are pre-order DFS — child spans follow their parent in execution order. The tool also surfaces a `summary` section with the picked TraceId, total span count, and root span info.\n\nWhen the trace source has a linked logSourceId (the standard config), the response also includes a `logs[]` array of correlated log rows that share the same TraceId — sorted by timestamp, each carrying its `spanId` so the agent can attribute messages to specific spans. Disable with `includeLogs:false`. If the log source declares `requiredSourceFilters`, include its columns in `sourceFilters` too (one map shared with the trace source, matched by column name).\n\nPrefer this over running raw SQL with JOINs on TraceId — it uses the source's configured traceIdExpression / parentSpanIdExpression / spanIdExpression so attribute extraction stays consistent with the rest of the platform.\n\nPAIR TOOL: clickstack_trace_top_time_consuming_operations is the aggregate counterpart — given a parent-span filter, it ranks child operations by total time across MANY matching traces. Use that when the question is \"where does time go in slow X\" (aggregate), and use THIS tool when the question is \"show me one example of a slow X\" (single trace).",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId"
],
"properties": {
"pickBy": {
"enum": [
"slowest",
"first_error",
"most_recent"
],
"type": "string",
"default": "slowest",
"description": "How to choose which trace to return when traceId is not provided.\n slowest – trace with the longest single span (use for latency investigations)\n first_error – earliest trace containing a span with STATUS_CODE_ERROR\n most_recent – the most recent trace matching pickFilter"
},
"endTime": {
"type": "string",
"description": "End of the search window as ISO 8601. Default: now."
},
"maxLogs": {
"type": "number",
"default": 100,
"maximum": 1000,
"minimum": 1,
"description": "Cap on correlated log rows returned (1–1000). Default 100. Has no effect when includeLogs is false or the trace source has no logSourceId."
},
"traceId": {
"type": "string",
"description": "Specific TraceId to look up. When provided, the tool fetches every span in this trace and returns them as a parent/child tree. When omitted, the tool auto-picks one trace using pickFilter + pickBy. With an explicit traceId and no startTime, the tool probes the trace back to 90 days; pass startTime only to reach a trace older than that."
},
"maxSpans": {
"type": "number",
"default": 500,
"maximum": 2000,
"minimum": 1,
"description": "Cap on spans returned in the tree (1–2000). Default 500. A trace with more spans than this will be truncated; the response notes the truncation."
},
"sourceId": {
"type": "string",
"description": "Trace source ID. Must be a source of kind \"trace\". Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the search window as ISO 8601. Default: 15 minutes ago for auto-pick. When traceId is set, the window is instead derived from the trace's own span timestamps (probed back to 90 days), so pass startTime only to look up a trace older than 90 days."
},
"pickFilter": {
"type": "string",
"default": "",
"description": "Filter (Lucene by default, SQL via pickFilterLanguage) used to narrow which trace to auto-pick when traceId is not provided. Example shapes (Lucene): `ServiceName:<some-service>`, `ServiceName:<svc> AND SpanName:\"<some-operation>\"`, `StatusCode:<status-value>` (status values come from the source schema's keyColumns). Ignored when traceId is provided."
},
"includeLogs": {
"type": "boolean",
"default": true,
"description": "When true and the trace source has a linked logSourceId, also fetch log rows that share the same TraceId and inline them in the response as `logs[]`. Each log row carries its spanId so the agent can attribute messages to specific spans. No-op if the trace source has no logSourceId configured."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for BOTH the trace source and its linked log source (if includeLogs is true), in one map keyed by column name: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }. Each entry is matched to each source by name against that source's `requiredSourceFilters`. Every column the trace source requires must have at least one value Logs will be skipped if any log source required filter is not provided.Call clickstack_get_source_filter_values to discover valid values. Ignored for sources without requiredSourceFilters.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"pickFilterLanguage": {
"enum": [
"lucene",
"sql"
],
"type": "string",
"default": "lucene",
"description": "Query language for pickFilter. Default: lucene"
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
Top Time-Consuming Operations Across Matching Traces
The title clearly communicates the tool’s action and subject. Keep it concise.
Description100/100
Given a parent-span filter and a time window, return the child operations contributing the most cumulative time across all traces matching the parent filter. Same algorithm as the in-app "Top Most Time Consuming Operations" chart on the service dashboard.
WHAT IT DOES (two-stage, runs as one SQL):
1. Pick distinct TraceIds where the parent span matches `parentFilter` in the window. Optionally restrict to `minParentDurationMs` to focus on slow parents.
2. Aggregate ALL spans across those traces (excluding the matching root span itself) by (ServiceName, SpanName), ranked by `total_time_ms` DESC.
USE WHEN: investigating "where is the time going" for a slow operation. Filter to a specific (ServiceName, SpanName) pair and set `minParentDurationMs` to the threshold above which a parent span counts as "slow" for your investigation.
MULTIPLE OPERATIONS SLOW: when more than one operation shows elevated latency, call this tool ONCE PER (service, operation) and compare the top child rows across the result sets. Operations with the same top child likely share a cause; operations with different top children are independent regressions that happen to co-occur. DO NOT merge multiple operations into a single parentFilter — the cumulative rank then conflates independent investigations into one noisy answer.
RANKING METRIC: `total_time_ms = sum(Duration)` across all matching child spans. This captures the true contribution to elapsed time — a fast-but-frequent child can dominate the latency even if its p99 is unremarkable.
RETURNS: array of rows, each with `service`, `operation`, `total_time_ms`, `calls`, `in_parents` (how many parent traces contained at least one such span), `p50_ms`, `p99_ms`. Plus a `summary` block with the matched-parent count.
NEXT STEP after this tool: once a dominant slow child operation is identified, the canonical follow-up is clickstack_event_deltas with slow-vs-fast spans of THAT child operation as target/baseline (target = {where: SpanName='<slow-child>' AND Duration > X}, baseline = {where: SpanName='<slow-child>' AND Duration <= Y}). The ranked attributes surface what distinguishes slow invocations of the child operation from fast ones.
CROSS-SERVICE BREAKDOWN: this tool does NOT scope children to the parent's service. Slow cross-service calls (database, cache, upstream HTTP) surface naturally — useful for triage.
PAIR TOOL: clickstack_trace_waterfall returns ONE concrete trace as a parent/child tree. Use it for an example after this tool's aggregate breakdown has pointed you at the slow downstream operation.
The description explains the capability, when to use it, and what to expect.
Inputs78/100
7 of 8 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
sourceId
Trace source ID. Must be a source of kind="trace". Call clickstack_list_sources to find available sources.
Clear enough to supply this argument.
parentFilter
SQL WHERE clause that selects the PARENT spans you want to break down. The tool finds the distinct TraceIds matching this filter, then aggregates all spans within those traces. Use SQL syntax (not Lucene). Example: "ServiceName = '<your-service>' AND SpanName = '<your-operation>'".
SCOPE TO A SPECIFIC OPERATION, not just a service. A service-only filter mixes every endpoint together and returns whatever has the loudest child-time across all parents, which usually isn't what you want. Always include a SpanName (or another operation-level discriminator). To compare two slow operations, call this tool once per operation and diff the results — two operations with similar p99 don't necessarily share a slow child.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
startTime
Start of the parent-filter time window as ISO 8601. REQUIRED.
Clear enough to supply this argument.
endTime
End of the parent-filter time window as ISO 8601. REQUIRED.
Clear enough to supply this argument.
minParentDurationMs
When set, only break down parent spans whose Duration ≥ this value. Use to focus the breakdown on slow parents (e.g. 1000 to only look at parents that took ≥ 1 second).
Clear enough to supply this argument.
topN
Number of top operations to return, ranked by total_time_ms DESC. Default 20.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
maxParentTraces
Safety cap on the number of distinct parent TraceIds considered. A breakdown over more than this many parent traces gets truncated to the first N. Default 100000.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
sourceFilters › additionalProperties › anyOf › 0 › all
Not provided
Missing description. Explain what this value means and how to supply it.
Annotations25/100
Declare destructiveHint, idempotentHint, openWorldHint based on the tool’s actual behavior.
{
"readOnlyHint": true
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clickstack_trace_top_time_consuming_operations",
"title": "Top Time-Consuming Operations Across Matching Traces",
"description": "Given a parent-span filter and a time window, return the child operations contributing the most cumulative time across all traces matching the parent filter. Same algorithm as the in-app \"Top Most Time Consuming Operations\" chart on the service dashboard.\n\nWHAT IT DOES (two-stage, runs as one SQL):\n 1. Pick distinct TraceIds where the parent span matches `parentFilter` in the window. Optionally restrict to `minParentDurationMs` to focus on slow parents.\n 2. Aggregate ALL spans across those traces (excluding the matching root span itself) by (ServiceName, SpanName), ranked by `total_time_ms` DESC.\n\nUSE WHEN: investigating \"where is the time going\" for a slow operation. Filter to a specific (ServiceName, SpanName) pair and set `minParentDurationMs` to the threshold above which a parent span counts as \"slow\" for your investigation.\n\nMULTIPLE OPERATIONS SLOW: when more than one operation shows elevated latency, call this tool ONCE PER (service, operation) and compare the top child rows across the result sets. Operations with the same top child likely share a cause; operations with different top children are independent regressions that happen to co-occur. DO NOT merge multiple operations into a single parentFilter — the cumulative rank then conflates independent investigations into one noisy answer.\n\nRANKING METRIC: `total_time_ms = sum(Duration)` across all matching child spans. This captures the true contribution to elapsed time — a fast-but-frequent child can dominate the latency even if its p99 is unremarkable.\n\nRETURNS: array of rows, each with `service`, `operation`, `total_time_ms`, `calls`, `in_parents` (how many parent traces contained at least one such span), `p50_ms`, `p99_ms`. Plus a `summary` block with the matched-parent count.\n\nNEXT STEP after this tool: once a dominant slow child operation is identified, the canonical follow-up is clickstack_event_deltas with slow-vs-fast spans of THAT child operation as target/baseline (target = {where: SpanName='<slow-child>' AND Duration > X}, baseline = {where: SpanName='<slow-child>' AND Duration <= Y}). The ranked attributes surface what distinguishes slow invocations of the child operation from fast ones.\n\nCROSS-SERVICE BREAKDOWN: this tool does NOT scope children to the parent's service. Slow cross-service calls (database, cache, upstream HTTP) surface naturally — useful for triage.\n\nPAIR TOOL: clickstack_trace_waterfall returns ONE concrete trace as a parent/child tree. Use it for an example after this tool's aggregate breakdown has pointed you at the slow downstream operation.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"sourceId",
"parentFilter",
"startTime",
"endTime"
],
"properties": {
"topN": {
"type": "number",
"default": 20,
"maximum": 100,
"minimum": 1,
"description": "Number of top operations to return, ranked by total_time_ms DESC. Default 20."
},
"endTime": {
"type": "string",
"description": "End of the parent-filter time window as ISO 8601. REQUIRED."
},
"sourceId": {
"type": "string",
"description": "Trace source ID. Must be a source of kind=\"trace\". Call clickstack_list_sources to find available sources."
},
"startTime": {
"type": "string",
"description": "Start of the parent-filter time window as ISO 8601. REQUIRED."
},
"parentFilter": {
"type": "string",
"maxLength": 4096,
"description": "SQL WHERE clause that selects the PARENT spans you want to break down. The tool finds the distinct TraceIds matching this filter, then aggregates all spans within those traces. Use SQL syntax (not Lucene). Example: \"ServiceName = '<your-service>' AND SpanName = '<your-operation>'\".\n\nSCOPE TO A SPECIFIC OPERATION, not just a service. A service-only filter mixes every endpoint together and returns whatever has the loudest child-time across all parents, which usually isn't what you want. Always include a SpanName (or another operation-level discriminator). To compare two slow operations, call this tool once per operation and diff the results — two operations with similar p99 don't necessarily share a slow child."
},
"sourceFilters": {
"type": "object",
"description": "Required filter values for sources whose configuration declares `requiredSourceFilters`. Keyed by column name (the values returned by clickstack_get_source_filter_values or the sampled `sourceFilterValues` from clickstack_describe_source).\n\nFORMAT: { \"<columnName>\": [\"<value1>\", \"<value2>\"] }\nMultiple values for one column become a `column IN (...)` predicate.\n\nALL OPTION: a column may instead be pinned to every value with { \"<columnName>\": { \"all\": true } }. This is ONLY accepted for columns whose source marks them `allowAll: true` (see requiredSourceFilters in clickstack_list_sources / clickstack_describe_source, or the `allowAll` flag from clickstack_get_source_filter_values); using it on any other column is rejected. Prefer explicit values when they're known.\n\nREQUIRED for any source whose summary in clickstack_list_sources or clickstack_describe_source includes `requiredSourceFilters`. Every column listed there must have at least one value set. Queries that omit a required column are rejected with an error telling you which columns are missing and how to recover.\n\nPARTIAL FILTERS: when you supply values for some but not all required columns, the tool will try to auto-resolve the missing columns by looking up values cross-pruned against the ones you provided — if any missing column has exactly one remaining value it is filled in automatically. The resolved set is echoed back as `resolvedSourceFilters` in the response so you can supply it explicitly on the next call.\n\nIgnored for sources without requiredSourceFilters: pass nothing.",
"additionalProperties": {
"anyOf": [
{
"type": "object",
"required": [
"all"
],
"properties": {
"all": {
"type": "boolean",
"const": true
}
},
"additionalProperties": false
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"maxParentTraces": {
"type": "number",
"default": 100000,
"maximum": 1000000,
"minimum": 100,
"description": "Safety cap on the number of distinct parent TraceIds considered. A breakdown over more than this many parent traces gets truncated to the first N. Default 100000."
},
"minParentDurationMs": {
"type": "number",
"minimum": 0,
"description": "When set, only break down parent spans whose Duration ≥ this value. Use to focus the breakdown on slow parents (e.g. 1000 to only look at parents that took ≥ 1 second)."
}
},
"additionalProperties": false
},
"annotations": {
"readOnlyHint": true
}
}
Loading score analytics…
Put your MCP to the test
A few tasks worth trying with this server, chosen from its reviewed tools. These have not been run.
01Search dashboards by name and/or tags
02List Sources & ConnectionsList all data sources (logs, metrics, traces) and database connections available to this team.
03Get Dashboard(s)Without an ID: list all dashboards (returns IDs, names, tags).
04Get Alert(s)Without an ID: list all alerts as a high-level summary (id, name, displayName, tags, state, source, interval).
05List TeamsList all teams the current user belongs to and identify which team is active for this session.
Want to run these tasks against your MCP server with us?
mcp.clickhouse.cloud setup, tools, quality score, publishing readiness, and alternatives.
How do I add mcp.clickhouse.cloud to Claude, ChatGPT, or Cursor?
Add mcp.clickhouse.cloud to Claude, ChatGPT, or Cursor by connecting its remote MCP URL in each client's MCP settings. In Claude, add a custom connector. In ChatGPT, add an MCP app. In Cursor, add an MCP server under Settings. The MCP URL is https://mcp.clickhouse.cloud/clickstack.
Is mcp.clickhouse.cloud MCP ready for ChatGPT and Claude?
As of October 14, 2026, mcp.clickhouse.cloud scores 90/100 on Manufact's MCP publishing checklist. The scan does not yet meet ChatGPT publishing checks and meets Claude publishing checks. Passing these checks does not guarantee marketplace approval.
How clear is mcp.clickhouse.cloud's MCP tool documentation?
As of October 14, 2026, mcp.clickhouse.cloud scores 72/100 in Manufact's review of tool titles, descriptions, input and output schemas, and behavior annotations. The review covers 33 of 33 discovered tools. The quality score measures documentation clarity; runtime behavior and marketplace readiness require separate checks.
What are the best alternatives to mcp.clickhouse.cloud?
As of October 14, 2026, alternatives to mcp.clickhouse.cloud in developer-tools on the Manufact MCP catalog include killfear-held-at-the-gate.netlify.app, AgentMail, Manufact Cloud, Authdog, and Apify MCP Server.
How can mcp.clickhouse.cloud improve its MCP documentation?
clickstack_save_source is the lowest-scoring reviewed tool at 57/100. No output schema is declared. Add one for structured results so clients can interpret returned fields. Open its review for feedback and a copyable fix prompt, then rerun the documentation review after updating your tool metadata.
Not your MCP?
Review any public or OAuth MCP server for protocol compatibility, tool documentation, and ChatGPT and Claude publishing readiness. No account required.