> ## Documentation Index
> Fetch the complete documentation index at: https://raindrop.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Query with RQL

> Analyze Raindrop events, traces, users, and conversations through MCP.

RQL lets your MCP client run one read-only `SELECT` over one project. Pass a project slug
provided by the user or already resolved in the current organization. Use `list_projects` to
discover projects or verify the selection when needed. You may also pass `org` when you have
access to multiple organizations. The server restricts the query to that organization and
project. The tool rejects queries when it cannot verify the organization's zero data retention
setting or when zero data retention is enabled.

Reach for RQL for aggregate questions: counts, `GROUP BY` breakdowns, trends, and comparisons
across events, traces, users, and conversations. Keep the dedicated tools for semantic search,
signal definitions, full events, conversation paging, and trace context.

Your agent loads `raindrop_skills` with `topic: "rql"` for a compact guide with common event
fields and an example query, and `topic: "rql_reference"` for the full table and function
reference. RQL returns redacted content and does not restore original PII.

## Query syntax

RQL supports `SELECT`, `FROM`, `WHERE`, `GROUP BY`, `ORDER BY`, and `LIMIT` over one of four virtual
tables: `events`, `traces`, `users`, or `conversations`. It supports the fields and functions in
the [RQL reference](/docs/mcp/rql-reference). It does not support joins, subqueries, unions, or
window functions. Give computed expressions aliases that do not reuse source column names.
`users` and `conversations` are lifetime and whole-conversation rollups.
Filtering by `last_seen` or `end_ts` selects recently active records; their `event_count` and
`message_count` still cover the full lifetime or conversation.

For event counts, use `uniqExact(event_id)`. For span counts, use
`uniqExact(tuple(trace_id, span_id))`. Recent reprojections can expose more than one physical
row per logical record. Event errors and span errors are different populations. Aggregates of
mutable fields can still reflect multiple versions.

## Time and cost limits

MCP enforces a window of at most seven days for `events` and `traces`. Pass optional
`time_range: {from, to}` with ISO timestamps to choose a historical or narrower window.
`from` is inclusive and `to` is exclusive. Omitting `time_range` selects the latest seven days.
Choose 24 hours when the question gives no time range.

The compiler applies this window independently of SQL filters. A timestamp predicate can
narrow the window but cannot widen or move it. Set `time_range` when searching older data;
changing only the SQL predicate can leave the query outside the selected window.
The response's `timeRange` reports the enforced bounds. Lifetime `users` and `conversations`
rollups do not use this window.

For example, this tool call counts events in a historical week:

```json theme={null}
{
  "project": "your-project",
  "query": "SELECT uniqExact(event_id) AS events FROM events",
  "time_range": {
    "from": "2026-01-01T00:00:00Z",
    "to": "2026-01-08T00:00:00Z"
  }
}
```

Ranges wider than seven days are rejected. For a longer investigation, query successive
windows. Keep the same explicit `time_range` when paging with `LIMIT` and `OFFSET`.

Filters on `ai_input` or `ai_output` require a `time_range` of 24 hours or less; add a
selective identity or event-name filter alongside them. `LIMIT` caps returned rows, not bytes
scanned. MCP uses the shared RQL compiler;
Triage retains its existing time-range behavior.

The query text limit is 20,000 characters. Queries return 100 rows by default and at most 1,000
with an explicit `LIMIT`. Each query runs for at most 30 seconds. Narrow a query after a timeout
or resource-limit error; do not retry it unchanged.

Each organization can have 8 RQL queries running at once through MCP. A query that arrives while
all 8 are busy waits up to 8 seconds for a slot, then fails with a retryable "too many RQL
queries" error.

## Examples

These examples use an explicit 24-hour window. Replace `chat_message` with an event name from
your project. Resolve signal names through `list_signals` before filtering by signal ID.

### Count events by model

```sql theme={null}
SELECT ai_model, uniqExact(event_id) AS events FROM events WHERE timestamp >= now() - INTERVAL 1 DAY GROUP BY ai_model ORDER BY events DESC LIMIT 20
```

### Count failed events and affected users

```sql theme={null}
SELECT uniqExact(event_id) AS events, uniqExactIf(event_id, has_errors) AS failed_events, uniqExactIf(user_id, has_errors) AS affected_users FROM events WHERE timestamp >= now() - INTERVAL 1 DAY
```

### Trend of event volume

```sql theme={null}
SELECT toStartOfHour(timestamp) AS hour, uniqExact(event_id) AS events FROM events WHERE timestamp >= now() - INTERVAL 1 DAY GROUP BY hour ORDER BY hour
```

### Discover property keys in recent events

```sql theme={null}
SELECT arrayJoin(mapKeys(properties)) AS property_key, uniqExact(event_id) AS events FROM events WHERE timestamp >= now() - INTERVAL 1 DAY AND event_name = 'chat_message' GROUP BY property_key ORDER BY events DESC LIMIT 20
```

### Search a narrow set of inputs

Pass a `time_range` of at most 24 hours with this query.

```sql theme={null}
SELECT event_id, timestamp, ai_input FROM events WHERE event_name = 'chat_message' AND match(ai_input, 'refund') ORDER BY timestamp DESC LIMIT 20
```

### Count failing spans

```sql theme={null}
SELECT span_name, uniqExact(tuple(trace_id, span_id)) AS failed_spans FROM traces WHERE timestamp >= now() - INTERVAL 1 DAY AND status = 'ERROR' GROUP BY span_name ORDER BY failed_spans DESC LIMIT 20
```

## Read the result

The result includes `columns`, `data`, `rowCount`, applied limit flags, truncation flags,
`statistics`, default-window information, and supported `reference_targets`. `rowCount` is the
number of returned rows before clipping. It is not a count of all matching events. Treat a
clipped result as incomplete and state its time range and limits in your answer.

A syntax error returns a message and source span. Correct the indicated part of the query.
If a query returns an event or trace ID that needs closer inspection, call `get_event` or
`get_trace` for the full evidence. An empty result or failed lookup does not prove that the
behavior never occurred. RQL cannot express regex signal definitions, signal properties, or
recurrence rules; use the signal tools for those questions.
