Run queryHONEYCOMB_MCP_RUN_QUERY
Run an aggregate query or return a scoped set of raw rows from a Honeycomb dataset.
When to use this tool:
- "Reconstruct the events for one session" — filter to the session and request the needed raw_row_columns.
- "Compute a percentile / histogram of X" — use P50/P99/HEATMAP calculations.
- "Show me error rate before and after deploy" — use two named calcs + a formula, scoped by time.
- "Rank services by p99 latency" — use P99 with a breakdown + order.
- "See distinct values of X and their frequency" — COUNT with a breakdown on X.
- "Compare request volume across services" — COUNT breakdown on service.name.
- "Find endpoints where tail latency exceeds 1s" — P99 + having clause.
- "Generate a heatmap of request duration" — HEATMAP calculation.
When NOT to use this tool:
- Discovering what spans or operations exist → use list_spans instead.
- Looking at a specific trace → use get_trace instead.
- Finding existing saved queries → use find_queries instead.
- Exploring which columns a dataset has → use get_dataset_columns or find_columns first.
Pairs with: list_spans, get_span_details, find_columns, get_dataset_columns, get_trace, run_bubbleup.
<examples>
Basic COUNT over the last 24 hours:
```json
{"environment_slug": "production", "dataset_slug": "api",
"query_spec": {"calculations": [{"op": "COUNT"}], "from": "-24h"}}
```
Raw rows for one session, limited to ten selected columns and up to 100 matching events:
```json
{"environment_slug": "production", "dataset_slug": "agent-events",
"query_spec": {
"filters": [{"column": "session.id", "op": "=", "value": "session-123"}],
"from": "-2h"},
"raw_row_columns": [
"session.id", "gen_ai.operation.name", "gen_ai.agent.name", "gen_ai.tool.name",
"gen_ai.tool.call.id", "gen_ai.tool.call.arguments", "gen_ai.tool.call.result",
"error", "duration_ms", "trace.trace_id"],
"results_limit": 100}
```
When a raw-row response includes next_cursor, fetch the next page by repeating the request with the same scope, replace the prior time fields in query_spec with the response Metadata's absolute from and to, and pass next_cursor as cursor. Continue until next_cursor is omitted.
Error rate formula: two named calcs combined with a formula, ordered by the formula name (the correct ordering style when formulas are present). The passthrough formula "volume" surfaces a raw calc value alongside formulas:
```json
{"environment_slug": "production", "dataset_slug": "api",
"query_spec": {
"calculations": [
{"op": "COUNT", "name": "total"},
{"op": "COUNT", "name": "errors", "filters": [{"column": "error", "op": "=", "value": true}]}],
"formulas": [
{"name": "error_rate", "expression": "$errors / $total * 100"},
{"name": "volume", "expression": "$total"}],
"breakdowns": ["service.name"],
"orders": [{"column": "error_rate", "order": "descending"}],
"from": "-1h", "limit": 20}}
```
Relational fields: any.X in a breakdown requires a matching WHERE filter on the same any.X column:
```json
{"environment_slug": "production", "dataset_slug": "traces",
"query_spec": {
"calculations": [{"op": "COUNT"}, {"op": "P99", "column": "duration_ms"}],
"filters": [{"column": "any.http.route", "op": "exists"}],
"breakdowns": ["any.http.route"],
"from": "-2h"}}
```
</examples>
<interpreting_results>
The response is rendered as Markdown with these sections (each is omitted if empty):
- "# Results" — a Markdown table of aggregate rows. Headers are breakdown columns followed by calculation columns. When formulas are present, the table contains ONLY breakdown columns and formula columns — raw calculation columns (including percentiles like P50/P95, and even named COUNTs) are NOT rendered. To surface a raw calculation's value alongside formulas, add a passthrough formula such as {"name": "p95", "expression": "$p95_latency"}. If a breakdown's cardinality exceeded the spec's limit, an "OTHER" row collapses the remainder; a "TOTAL" row may also appear summing across groups. A "Truncated: shown N / total M" footer indicates more rows than the table displays.
- 1D heatmaps render inline within Results when a HEATMAP calculation has no breakdown.
- "# Raw Rows" — present when raw_row_columns is provided. Contains matching events restricted to those columns, plus timestamp. The row and column counts share a 1000-value budget. Metadata includes the effective absolute from and to. A full page also includes next_cursor; pass it as cursor in an otherwise equivalent request with those absolute time bounds to fetch more rows. Pagination is not a snapshot.
- "# Time Series" — ASCII line graphs per group when the spec has a granularity (time-bucketed series). Width 120, height 12.
- "# Heatmaps" — 2D time-series heatmaps when a HEATMAP calculation is paired with breakdowns or granularity.
- "# Markers" — deploy/incident markers overlapping the time range, when present. Includes both dataset-scoped and environment-wide markers; the Scope column labels each row "dataset" or "environment".
- "# Query Spec" — the canonicalized JSON spec the server actually executed. Useful when comparing what you sent to what ran.
- "Metadata:" YAML block at the bottom — contains query_run_pk (passable to get_query_results), query_url (Honeycomb permalink to share with humans), query_result_json / query_result_image (download URLs), elapsed_str, granularity, total (result count), rows_examined. When the requested or auto-selected granularity was adjusted (clamped to the valid window, or raised to the metrics-dataset floor), granularity_note explains the change and granularity_requested echoes an explicit request.
When data is sampled, a sampling banner appears above Results listing the mean sample rate and which calculations are sample-rate-weighted vs. raw. If mean_sample_rate > 10x and usage_mode is off, an extra warning notes that COUNT values are corrected estimates and won't match raw trace span counts.
When results contain a trace.trace_id column (grouped-by or in raw rows), a "Trace links" block above Results lists ready-to-use UI URLs for those traces. These are already scoped to this query's time range — pass them through verbatim. Do NOT hand-build a trace URL from a trace ID: a link without the query's time scope resolves against a default 2h window and fails to load older traces.
</interpreting_results>
Important: filter operators use symbols (=, >=, !=). Expression functions inside calculated_fields use words (GTE, EQUALS). Never use GTE/LTE as filter operators.