run_shopifyql_query
Execute ShopifyQL analytics queries on store data and return results as an ASCII table or raw JSON payload.
Instructions
Run a ShopifyQL query against the store and return the result as a rendered ASCII table. ShopifyQL is Shopify's SQL-like analytics language. Examples: 'FROM sales SHOW total_sales BY day SINCE -30d TIMESERIES', 'FROM products SHOW product_title, quantity_sold BY product_id SINCE -7d ORDER BY quantity_sold DESC LIMIT 10'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ShopifyQL query string. Example: 'FROM sales SHOW total_sales, gross_sales BY day SINCE -30d TIMESERIES' | |
| raw | No | Return the raw unformatted JSON payload instead of a rendered table. |
Implementation Reference
- src/tools/analytics.ts:90-157 (handler)The 'run_shopifyql_query' tool handler: registers the tool with server.tool(), executes the ShopifyQL GraphQL query via ShopifyClient.graphql(), handles parse errors, and returns either raw JSON or a rendered ASCII table.
export function registerAnalyticsTools( server: McpServer, client: ShopifyClient, ): void { server.tool( "run_shopifyql_query", "Run a ShopifyQL query against the store and return the result as a rendered ASCII table. ShopifyQL is Shopify's SQL-like analytics language. Examples: 'FROM sales SHOW total_sales BY day SINCE -30d TIMESERIES', 'FROM products SHOW product_title, quantity_sold BY product_id SINCE -7d ORDER BY quantity_sold DESC LIMIT 10'.", runShopifyqlSchema, async (args) => { const data = await client.graphql<{ shopifyqlQuery: ShopifyqlResponse | null; }>(RUN_SHOPIFYQL_QUERY, { query: args.query }); const resp = data.shopifyqlQuery; if (!resp) { return { content: [{ type: "text" as const, text: "ShopifyQL returned no response." }], }; } if (resp.parseErrors && resp.parseErrors.length > 0) { return { content: [ { type: "text" as const, text: [ "ShopifyQL parse errors:", ...resp.parseErrors.map( (e) => ` [${e.code}] ${e.message}${e.range ? ` (line ${e.range.start.line}:${e.range.start.character})` : ""}`, ), ].join("\n"), }, ], }; } if (!resp.tableData) { return { content: [ { type: "text" as const, text: `No table data returned (typename=${resp.__typename ?? "unknown"}).`, }, ], }; } if (args.raw) { return { content: [ { type: "text" as const, text: resp.tableData.unformattedData ?? JSON.stringify(resp.tableData, null, 2), }, ], }; } return { content: [ { type: "text" as const, text: [ `Rows: ${resp.tableData.rowData.length}`, renderTable(resp.tableData), ].join("\n"), }, ], }; }, ); } - src/tools/analytics.ts:55-65 (schema)Input schema for run_shopifyql_query: 'query' (string) the ShopifyQL query string, and 'raw' (boolean, default false) to return raw JSON instead of a rendered table.
const runShopifyqlSchema = { query: z .string() .describe( "ShopifyQL query string. Example: 'FROM sales SHOW total_sales, gross_sales BY day SINCE -30d TIMESERIES'", ), raw: z .boolean() .default(false) .describe("Return the raw unformatted JSON payload instead of a rendered table."), }; - src/tools/analytics.ts:32-53 (helper)The GraphQL query string used by the tool, named RUN_SHOPIFYQL_QUERY, which calls shopifyqlQuery with the provided query string and extracts tableData and parseErrors.
const RUN_SHOPIFYQL_QUERY = /* GraphQL */ ` query RunShopifyQL($query: String!) { shopifyqlQuery(query: $query) { __typename ... on TableResponse { tableData { columns { name displayName dataType } rowData unformattedData } parseErrors { code message range { start { line character } end { line character } } } } } } `; - src/tools/analytics.ts:67-88 (helper)The renderTable helper function that formats TableData (columns + rows) into an ASCII table for human-readable output.
function renderTable(td: TableData): string { if (td.rowData.length === 0) { return "(no rows)"; } const headers = td.columns.map((c) => c.displayName); const widths = headers.map((h, i) => Math.max( h.length, ...td.rowData.map((row) => (row[i] ?? "").length), ), ); const pad = (s: string, w: number) => s + " ".repeat(Math.max(0, w - s.length)); const headerLine = headers.map((h, i) => pad(h, widths[i] ?? 0)).join(" | "); const sepLine = widths.map((w) => "-".repeat(w)).join("-+-"); const bodyLines = td.rowData.map((row) => row.map((cell, i) => pad(cell ?? "", widths[i] ?? 0)).join(" | "), ); const typeLine = td.columns .map((c, i) => pad(`(${c.dataType})`, widths[i] ?? 0)) .join(" | "); return [headerLine, typeLine, sepLine, ...bodyLines].join("\n"); } - src/server.ts:68-68 (registration)Registration call: registerAnalyticsTools is invoked with the MCP server and Shopify client in buildContext.
registerAnalyticsTools(s, shopify);