query
Run advanced Plausible Analytics queries for custom property breakdowns, behavioral filters, or multi-dimension time series. Use when standard metrics are not enough.
Instructions
Execute a raw Plausible Stats API v2 query. Use this for advanced queries that the other tools don't cover, such as custom property breakdowns, behavioral filters, or combining multiple dimensions with time series.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| site_id | Yes | Domain of the site (e.g. 'example.com') | |
| metrics | Yes | Metrics to retrieve | |
| date_range | Yes | Date range preset or custom [start, end] | |
| dimensions | No | Dimensions to group by | |
| filters | No | Filters in Plausible v2 syntax | |
| order_by | No | Order by, e.g. [['visitors', 'desc']] | |
| pagination | No | Pagination options | |
| include | No | Include options (imports, time_labels, comparisons) |
Implementation Reference
- src/index.ts:275-337 (handler)The MCP tool handler for 'query'. It accepts advanced Plausible Stats API v2 parameters (site_id, metrics, date_range, dimensions, filters, order_by, pagination, include) and calls client.query(), returning the raw JSON result.
// --- Tool: query (raw/advanced) --- server.tool( "query", "Execute a raw Plausible Stats API v2 query. Use this for advanced queries that the other tools don't cover, such as custom property breakdowns, behavioral filters, or combining multiple dimensions with time series.", { site_id: z.string().describe("Domain of the site (e.g. 'example.com')"), metrics: z.array(z.string()).describe("Metrics to retrieve"), date_range: z .union([z.string(), z.tuple([z.string(), z.string()])]) .describe("Date range preset or custom [start, end]"), dimensions: z.array(z.string()).optional().describe("Dimensions to group by"), filters: z.array(z.any()).optional().describe("Filters in Plausible v2 syntax"), order_by: z .array(z.any()) .optional() .describe("Order by, e.g. [['visitors', 'desc']]"), pagination: z .object({ limit: z.number().optional(), offset: z.number().optional(), }) .optional() .describe("Pagination options"), include: z .object({ imports: z.boolean().optional(), time_labels: z.boolean().optional(), total_rows: z.boolean().optional(), comparisons: z .object({ mode: z.string(), date_range: z .union([z.string(), z.tuple([z.string(), z.string()])]) .optional(), }) .optional(), }) .optional() .describe("Include options (imports, time_labels, comparisons)"), }, async ({ site_id, metrics, date_range, dimensions, filters, order_by, pagination, include }) => { const result = await client.query({ site_id, metrics, date_range, dimensions: dimensions ?? undefined, filters: filters ?? undefined, order_by: order_by ?? undefined, pagination: pagination ?? undefined, include: include ?? undefined, }); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } ); - src/index.ts:280-315 (schema)Input schema (Zod) for the 'query' tool, defining all parameters including site_id, metrics, date_range, dimensions, filters, order_by, pagination, and include with nested comparison support.
{ site_id: z.string().describe("Domain of the site (e.g. 'example.com')"), metrics: z.array(z.string()).describe("Metrics to retrieve"), date_range: z .union([z.string(), z.tuple([z.string(), z.string()])]) .describe("Date range preset or custom [start, end]"), dimensions: z.array(z.string()).optional().describe("Dimensions to group by"), filters: z.array(z.any()).optional().describe("Filters in Plausible v2 syntax"), order_by: z .array(z.any()) .optional() .describe("Order by, e.g. [['visitors', 'desc']]"), pagination: z .object({ limit: z.number().optional(), offset: z.number().optional(), }) .optional() .describe("Pagination options"), include: z .object({ imports: z.boolean().optional(), time_labels: z.boolean().optional(), total_rows: z.boolean().optional(), comparisons: z .object({ mode: z.string(), date_range: z .union([z.string(), z.tuple([z.string(), z.string()])]) .optional(), }) .optional(), }) .optional() .describe("Include options (imports, time_labels, comparisons)"), }, - src/index.ts:277-278 (registration)Registration of the 'query' tool via server.tool() with the name 'query'.
server.tool( "query", - src/plausible-client.ts:61-79 (helper)The PlausibleClient.query() method that performs the actual HTTP POST request to /api/v2/query with the PlausibleQueryParams, sending the Bearer token for authentication and returning the parsed JSON result.
async query(params: PlausibleQueryParams): Promise<PlausibleQueryResult> { const response = await fetch(`${this.baseUrl}/api/v2/query`, { method: "POST", headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify(params), }); if (!response.ok) { const body = await response.text(); throw new Error( `Plausible API error (${response.status}): ${body}` ); } return response.json() as Promise<PlausibleQueryResult>; } - src/plausible-client.ts:6-26 (schema)TypeScript interface PlausibleQueryParams defining the shape of parameters accepted by the query method (site_id, metrics, date_range, dimensions, filters, order_by, pagination, include with comparisons).
export interface PlausibleQueryParams { site_id: string; metrics: string[]; date_range: string | [string, string]; dimensions?: string[]; filters?: unknown[]; order_by?: unknown[]; pagination?: { limit?: number; offset?: number; }; include?: { imports?: boolean; time_labels?: boolean; total_rows?: boolean; comparisons?: { mode: string; date_range?: string | [string, string]; }; }; }