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

# Tool reference

> Every tool exposed by Grain's MCP server — inputs, scopes, and what each one is good for.

Grain exposes eleven tools over MCP, grouped into three buckets: **discovery**, **query**, and **investigation**. Each tool declares the minimum OAuth scope it needs, and the consent screen groups scopes so you always know what you're granting.

<Info>
  The names below (`grain.query`, `grain.segment.compare`, …) are the identifiers the LLM sees. You almost never type them yourself — the model picks the right tool from your natural‑language prompt.
</Info>

## Discovery — `mcp:read`

Zero‑cost tools that describe what's in the workspace. Agents typically call these first on an unfamiliar workspace.

### `grain.events.list`

Lists distinct event names the workspace has ingested. Returns up to 100 names, alphabetical.

<ParamField body="limit" type="integer" default="100">
  Maximum number of events to return. Range: 1–100.
</ParamField>

**Good prompt:** *"What events does my site track?"*

### `grain.dimensions.discover`

Samples recent events and returns the dimensions (properties) you can filter or group by, with cardinality hints and redacted sample values.

<ParamField body="eventName" type="string">
  Narrow discovery to a specific event. Omit to sample across all events.
</ParamField>

<ParamField body="timeRange" type="TimeRange">
  Window to sample from. Defaults to the last 7 days.
</ParamField>

**Good prompt:** *"What can I break `signup` down by?"*

### `grain.integration.status`

Checks whether the Grain analytics tag is reporting correctly — useful before an investigation so you know the data itself is trustworthy.

**Good prompt:** *"Is my tracking healthy?"*

## Query — `mcp:query`

The workhorses. These wrap Grain's query engine with the same surprise‑detection layer Kai uses in the dashboard, so responses include structured hints (`_surprises`, `_narrativeHints`) about what's concentrated, volatile, or shifting in rank.

### `grain.query`

Breakdown or timeseries query with filters and grouping.

<ParamField body="metric" type="enum" required>
  What to measure: `events`, `unique_visitors`, `unique_sessions`, …
</ParamField>

<ParamField body="eventName" type="string" required>
  Event to filter on, or `""` for all events.
</ParamField>

<ParamField body="mode" type="'breakdown' | 'timeseries'" required>
  `breakdown` groups by dimension; `timeseries` trends over time.
</ParamField>

<ParamField body="groupBy" type="string[]">
  Dimensions to group by (breakdown mode). Use `[]` for timeseries.
</ParamField>

<ParamField body="filters" type="Filter[]">
  Property filters. Supported operators: `eq`, `neq`, `gt`, `lt`, `gte`, `lte`.
</ParamField>

<ParamField body="timeRange" type="TimeRange" required>
  `{ last: '7d' }` or `{ from: ISO, to: ISO }`.
</ParamField>

<ParamField body="limit" type="integer" default="10">
  Max rows for breakdown. 1–500.
</ParamField>

**Good prompt:** *"Signups by country last week, top 5."*

### `grain.query.count`

Total count of events matching filters over a window. Cheaper than `grain.query` when you don't need rows.

**Good prompt:** *"How many signups did I get this week?"*

### `grain.query.compare`

Runs the same query twice — current window and a previous window — and returns both plus a comparison with deltas and percent changes.

<ParamField body="timeRange" type="TimeRange" required>
  Current window.
</ParamField>

<ParamField body="compareTo" type="TimeRange" required>
  Prior window to compare against. Often the preceding period of the same length.
</ParamField>

**Good prompt:** *"Traffic sources this week vs last week, flag anything that moved more than 20%."*

### `grain.query.digest`

Generates an end‑of‑period digest: top metrics, biggest movers, and anomalies. This is the tool behind the "daily briefing" pattern.

**Good prompt:** *"Give me yesterday's digest."*

## Investigation — `mcp:investigate`

The heavy‑hitters. These power the kind of "why did X happen?" questions that normally take a human an hour of dashboard clicking.

### `grain.correlate_event`

Given a target event, finds other events whose occurrence correlates with it above baseline. Great for "what did users do right before they converted" style questions.

**Good prompt:** *"What events do users fire in the 10 minutes before `purchase_completed`?"*

### `grain.track.analyze`

Analyzes a Track — Grain's two‑step funnel primitive (`start_event → goal_event` within a time window). Returns conversion rate, biggest drop‑off dimensions, and per‑segment breakdowns.

<ParamField body="startEvent" type="string" required>
  The event that starts the funnel.
</ParamField>

<ParamField body="goalEvent" type="string" required>
  The event that completes it.
</ParamField>

<ParamField body="windowSeconds" type="integer">
  How long the user has to complete. Default: 1 hour.
</ParamField>

**Good prompt:** *"How many visitors who hit `checkout_started` finished with `purchase_completed` within 30 minutes last week? Where did they drop off?"*

### `grain.segment.compare`

Compares two cohorts (defined by filters) on a metric and surfaces the dimensions where they differ most.

**Good prompt:** *"Compare users who converted vs users who bounced on the pricing page. What's different about them?"*

### `grain.sessions.cluster`

Clusters sessions by behavioral signature. Returns representative sessions per cluster so an agent can summarize *"users in cluster A hit the pricing page twice then left; cluster B…"*.

**Good prompt:** *"Cluster sessions from users who abandoned checkout yesterday."*

## Shared shapes

All query‑family tools speak the same vocabulary.

### `Filter`

```ts theme={null}
{
  property: string;    // e.g. "browser", "utm_source"
  op: "eq" | "neq" | "gt" | "lt" | "gte" | "lte";
  value: string | number | boolean;
}
```

<Note>
  `in` and `contains` aren't supported by the backend yet. If your agent hallucinates one, call `grain.query` will reject it with a clear error.
</Note>

### `TimeRange`

```ts theme={null}
{ last: "1h" | "24h" | "7d" | "30d" | "90d" }
// or
{ from: "2026-04-01T00:00:00Z", to: "2026-04-07T23:59:59Z" }
```

### Default event properties

Every event Grain ingests carries these properties automatically — filter or group by them without any setup:

```
device, browser, os, session_id,
utm_source, utm_medium, utm_campaign, utm_term, utm_content,
first_touch_source, first_touch_medium, first_touch_campaign, first_touch_referrer_category,
page, full_url, timestamp, referrer, referrer_domain, referrer_category,
previous_page, landing_page, title, language, timezone,
screen_resolution, viewport
```

Referrer categories are `direct | organic | paid | social | email | referral`.

## Budgets and limits

Grain enforces a per‑request budget so a chatty agent can't accidentally saturate your workspace:

| Budget       | Limit                | What counts                                                                         |
| ------------ | -------------------- | ----------------------------------------------------------------------------------- |
| Query calls  | 16 per MCP request   | `grain.query`, `grain.query.count`, investigation tools (`grain.query.compare` = 2) |
| Compute time | 20 s per MCP request | Wall‑clock for Next.js‑native analysis (not yet exposed over MCP)                   |
| Row cap      | 500                  | `grain.query` breakdown `limit` ceiling                                             |

If an agent hits the budget mid‑session, it receives a structured error and typically asks you to narrow the question.

## See also

<CardGroup cols={2}>
  <Card title="Security & scopes" icon="shield-check" href="/ai-tools/mcp/security">
    How scopes gate these tools.
  </Card>

  <Card title="Query API" icon="server" href="/api-reference/query-api/overview">
    The raw HTTP API these tools wrap.
  </Card>
</CardGroup>
