Skip to main content
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.
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.

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.
limit
integer
default:"100"
Maximum number of events to return. Range: 1–100.
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.
eventName
string
Narrow discovery to a specific event. Omit to sample across all events.
timeRange
TimeRange
Window to sample from. Defaults to the last 7 days.
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.
metric
enum
required
What to measure: events, unique_visitors, unique_sessions, …
eventName
string
required
Event to filter on, or "" for all events.
mode
'breakdown' | 'timeseries'
required
breakdown groups by dimension; timeseries trends over time.
groupBy
string[]
Dimensions to group by (breakdown mode). Use [] for timeseries.
filters
Filter[]
Property filters. Supported operators: eq, neq, gt, lt, gte, lte.
timeRange
TimeRange
required
{ last: '7d' } or { from: ISO, to: ISO }.
limit
integer
default:"10"
Max rows for breakdown. 1–500.
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.
timeRange
TimeRange
required
Current window.
compareTo
TimeRange
required
Prior window to compare against. Often the preceding period of the same length.
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.
startEvent
string
required
The event that starts the funnel.
goalEvent
string
required
The event that completes it.
windowSeconds
integer
How long the user has to complete. Default: 1 hour.
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

{
  property: string;    // e.g. "browser", "utm_source"
  op: "eq" | "neq" | "gt" | "lt" | "gte" | "lte";
  value: string | number | boolean;
}
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.

TimeRange

{ 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:
BudgetLimitWhat counts
Query calls16 per MCP requestgrain.query, grain.query.count, investigation tools (grain.query.compare = 2)
Compute time20 s per MCP requestWall‑clock for Next.js‑native analysis (not yet exposed over MCP)
Row cap500grain.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

Security & scopes

How scopes gate these tools.

Query API

The raw HTTP API these tools wrap.