> ## 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.

# Tools

> The twelve tools of the Grain MCP server, with their inputs, scopes, and budgets.

The Grain MCP server has twelve tools in three groups: discovery, query, and investigation. Each
tool declares the minimum OAuth scope it needs. The consent screen groups the scopes, so you know
what you grant. The tool names (`grain_query`, `grain_segment_compare`) are the identifiers that
the model sees. You rarely type them. The model picks the tool from your prompt.

Every tool except `grain_workspaces_list` also takes an optional `workspace` argument: a
workspace identifier, name, or site domain. A connection that covers more than one workspace
needs it. A connection that covers one workspace can omit it.

## Discovery: `mcp:read`

These tools describe what is in the tenant. They consume no query budget. An agent calls them
first on an unfamiliar tenant.

### `grain_workspaces_list`

Lists the workspaces that the connection can query. It takes no input. Each entry has the
workspace `identifier`, `name`, `uuid`, your `role`, and the site `domain` from the workspace
settings. The response also has a `scope` field: `all_workspaces`, `selected_workspaces`, or
`single_workspace`.

An example prompt is "Which Grain workspaces can you see?".

### `grain_events_list`

Lists the distinct event names that the tenant has received, in alphabetical order.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `limit` | integer | No | Maximum number of names to return. Range 1 to 100. Default `100`. |

An example prompt is "What events does my site track?".

### `grain_dimensions_discover`

Samples recent rows of one event and returns the property names that you can filter or group
by, split into custom and system properties. Values are never returned.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `eventName` | string | Yes | The event to sample, for example `page_view`. |
| `sampleSize` | integer | No | Rows to sample. Range 1 to 100. Default `5`. |

An example prompt is "What can I break `signup` down by?".

### `grain_integration_status`

Reports whether the Grain Tag sends data correctly. Call it before an investigation, so that you
know the data is complete.

An example prompt is "Is my tracking healthy?".

## Query: `mcp:query`

These tools wrap the Grain query engine with the same surprise detection that Kai uses in the
dashboard. A response includes structured hints (`_surprises`, `_narrativeHints`) about what is
concentrated, volatile, or changed in rank.

### `grain_query`

Runs a breakdown or a time series query with filters and grouping.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `metric` | enum | Yes | What to measure: `events`, `users` (unique users), or `revenue`. |
| `eventName` | string | Yes | The event to filter on, or `""` for all events. |
| `mode` | `'breakdown' \| 'timeseries'` | Yes | `breakdown` groups by a dimension. `timeseries` trends over time. |
| `groupBy` | string\[] | Yes | The dimension for a breakdown, for example `["eventName"]` or `["device"]`. Use `[]` for a time series. |
| `filters` | `Filter[]` | Yes | Property filters. Use `[]` for none. |
| `timeRange` | `TimeRange` | Yes | The window to query. |
| `limit` | integer | No | Maximum rows for a breakdown. Range 1 to 500. Default `10`. |

An example prompt is "Signups by country last week, top 5.".

### `grain_query_count`

Returns the total count of events that match the filters in a window. It costs less than
`grain_query` when you do not need rows.

An example prompt is "How many signups did I get this week?".

### `grain_query_compare`

Runs the same breakdown two times, for the current window and a previous window. It returns
both results and a comparison with deltas, rank changes, and percent changes.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `metric` | enum | Yes | `events`, `users`, or `revenue`. |
| `eventName` | string | Yes | The event to filter on, or `""` for all events. |
| `groupBy` | string\[] | Yes | The dimension to compare by, for example `["first_touch_source"]`. |
| `filters` | `Filter[]` | Yes | Property filters. Use `[]` for none. |
| `currentPeriod` | `TimeRange` | Yes | The current window. |
| `previousPeriod` | `TimeRange` | Yes | The previous window. Usually the preceding period of the same length. |

An example prompt is "Traffic sources this week versus last week, flag anything that moved more
than 20%.".

### `grain_query_digest`

Writes an end-of-period digest: top metrics, biggest movers, and anomalies. This is the tool
behind a daily briefing.

An example prompt is "Give me yesterday's digest.".

## Investigation: `mcp:investigate`

These tools answer "why did X happen" questions.

### `grain_correlate_event`

Takes a metric that changed and a timestamp, then scans the hours around it for traffic
sources, campaigns, devices, and other dimensions that moved at the same time. It returns
candidate explanations with a confidence level, not proven causes.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `metricName` | string | Yes | The metric that changed, for example `signups`. |
| `changeTimestamp` | ISO 8601 string | Yes | When the change happened. |
| `lookbackHours` | integer | No | Hours to scan on each side. Range 1 to 168. Default `24`. |

An example prompt is "Signups dropped around 2 PM on Tuesday. What else changed then?".

### `grain_track_analyze`

Analyzes journeys that end in a goal event. It returns the conversions and the unique users
who converted in the window.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `goalEvent` | string | Yes | The event that completes the journey, for example `purchase`. |
| `filters` | `Filter[]` | Yes | Narrows the population. Use `[]` for none. |
| `timeRange` | `TimeRange` | Yes | The window to analyze. |

An example prompt is "How many visitors completed `purchase` last month?".

### `grain_segment_compare`

Compares two cohorts, each defined by filters. For each cohort it returns event counts, unique
users, events per user, top events, top sources, and the device mix.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `segmentALabel`, `segmentBLabel` | string | Yes | A name for each cohort. |
| `segmentAFilters`, `segmentBFilters` | `Filter[]` | Yes | At least one filter per cohort. |
| `timeRange` | `TimeRange` | Yes | The window to compare. |

An example prompt is "Compare users who converted versus users who bounced on the pricing page.
What is different about them?".

### `grain_sessions_cluster`

Finds sessions that match an event and filters. It returns each session's duration, events,
device, country, source, and landing page, so an agent can read what those users did.

| Field | Type | Required | Meaning |
| - | - | - | - |
| `eventName` | string | No | An event that the session must contain. Omit it for all sessions. |
| `filters` | `Filter[]` | Yes | Narrows the sessions. Use `[]` for none. |
| `timeRange` | `TimeRange` | Yes | The window to search. |
| `limit` | integer | No | Maximum sessions. Range 1 to 100. Default `20`. |

An example prompt is "Cluster sessions from users who abandoned checkout yesterday.".

## Shared shapes

Every query tool uses the same two shapes.

| Shape | Field | Type | Values |
| - | - | - | - |
| `Filter` | `field` | string | A property name, for example `device`, `utm_source`, or `eventName`. |
| `Filter` | `op` | enum | `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `not_in`, `contains`, `not_contains`. |
| `Filter` | `value` | string, number, or array | The value to compare with. `in` and `not_in` take an array. |
| `TimeRange` | `preset` | string | `last_7_days`, `last_30_days`, or `custom`. |
| `TimeRange` | `start`, `end` | `YYYY-MM-DD` | The window for `custom`, for example `2026-04-01` to `2026-04-07`. |

Filter values are case-sensitive and match the stored values. For example, `device` is
`Mobile`, `Desktop`, or `Tablet`. Numeric values in `gt`, `gte`, `lt`, and `lte` compare as
numbers.

<Note>
  Totals over all events (`eventName` is `""`) leave out Grain's own telemetry, such as heatmap and
  session events whose names start with `_grain_`. To count those events, name them in `eventName`
  or in an `eventName` filter.
</Note>

Every event carries these properties. You can filter or group by them without setup:

```text theme={null}
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
```

The referrer categories are `direct`, `organic`, `paid`, `social`, `email`, and `referral`.
Read [Automatic properties](/core/event-properties) for the meaning of each property.

## Budgets

Grain enforces a budget per MCP request, so that an agent cannot saturate the tenant.

| Budget | Limit | Where |
| - | - | - |
| Query calls | 16 per MCP request | `grain_query`, `grain_query_count`, and the investigation tools. `grain_query_compare` counts as 2. |
| Compute time | 20 s per MCP request | Wall-clock time for Next.js-native analysis. Not yet exposed over MCP. |
| Rows | 500 | The `limit` ceiling of a `grain_query` breakdown. |
| Event names | 100 | The `limit` ceiling of `grain_events_list`. |

If an agent reaches the budget in a session, it receives a structured error. The agent then asks
you to narrow the question. The tools wrap the same engine as the Query API. Read
[Query API](/api-reference/query-api/overview) for the HTTP interface.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.