Shopify MCP
Provides read-only access to the Shopify Admin GraphQL API, enabling management of products, orders, customers, inventory, and more through a secure, mutation-blocking interface.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Shopify MCPshow me my products with inventory less than 5"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Shopify MCP
A single MCP server exposing the full Shopify Admin GraphQL API read surface (version 2026-04) through 6 universal tools. Read-only is enforced at the query-parser level: mutations are rejected before they ever reach Shopify, not merely discouraged. Multi-store by design: one server instance can serve many shops.
Built and maintained by Scalably. Runs on the Model Context Protocol. License: MIT.
Why read-only at the parser level? Giving an AI agent write access to a live store is how you end up with a deleted product or a wrong-priced variant. This server enforces read-only by parsing every query and rejecting mutations before they leave the process, not by trusting the model to behave, and not by relying on Shopify-side scopes alone. It's the safety boundary an agent in production actually needs. (more on the pattern)
Install
Claude Code:
claude mcp add shopify -e SHOPIFY_DOMAIN=my-store.myshopify.com -e SHOPIFY_ACCESS_TOKEN=shpat_... -- uvx scalably-shopify-mcpCodex:
codex mcp add shopify --env SHOPIFY_DOMAIN=my-store.myshopify.com --env SHOPIFY_ACCESS_TOKEN=shpat_... -- uvx scalably-shopify-mcpClaude Desktop: download shopify-mcp.mcpb from the latest GitHub release and open it.
Related MCP server: shopify-mcp
Setup
Single store (simplest)
SHOPIFY_DOMAINorSHOPIFY_SHOP_DOMAIN-<shop>.myshopify.comAuth path A:
SHOPIFY_ACCESS_TOKEN(legacyshpat_)Auth path B:
SHOPIFY_CLIENT_ID+SHOPIFY_CLIENT_SECRET(Dev Dashboard custom app, client-credentials OAuth, 24h tokens auto-refreshed)
The single store registers under alias default; callers can omit the shop argument on tool calls.
Multi-store (agency setups)
Set SHOPIFY_STORES to a JSON object mapping alias to store config:
{
"main": {"domain": "my-store.myshopify.com", "client_id": "...", "client_secret": "..."},
"outlet": {"domain": "my-store-outlet.myshopify.com", "client_id": "...", "client_secret": "..."},
"legacy": {"domain": "legacy-store.myshopify.com", "access_token": "shpat_..."}
}Each store can use either
client_id+client_secret(Dev Dashboard OAuth) oraccess_token(legacyshpat_).Aliases:
[a-z0-9][a-z0-9_-]{0,63}, lowercase-normalized on load.Token cache is per-store-domain; one throttled store doesn't block others.
Scopes needed (read-only)
Minimum viable: read_products read_orders read_customers.
Recommended baseline: read_products read_orders read_customers read_inventory read_locations read_fulfillments read_discounts read_content read_themes read_files read_markets read_metaobjects read_metaobject_definitions read_reports read_translations read_locales read_shipping.
Add read_all_orders for order history older than 60 days. Enable Protected customer data access in Dev Dashboard, Configuration, if the agent needs customer PII.
Tools (6)
Tool | What it does |
| List all Shopify stores configured for this agent. Call first. |
| Arbitrary read-only GraphQL. Mutations rejected by the parser. |
| Schema introspection, full catalog or a single type. |
| Launch an async bulk export (JSONL). |
| Poll a bulk operation status and download URL. |
| ShopifyQL analytics (SQL-like; requires |
Every non-list tool takes an optional shop argument (alias or domain). Required when more than one store is configured; auto-selected when exactly one.
Coverage
The full Admin GraphQL API read surface: any object, field, or connection accessible with the token's scopes is reachable via shopify_graphql_query. Anything large-scale (more than 10k records) should use shopify_bulk_query. Analytics goes through shopify_shopifyql.
Configuration
Variable | Required | Purpose |
| one of these or | Single-store admin domain, |
| see above | Legacy |
| see above | Dev Dashboard custom-app credentials (single-store auth path A) |
| no | JSON object mapping alias to store config; takes precedence over the single-store variables above |
| no | Prefix-key alternative to |
| no | HTTP request timeout in seconds (default 60) |
| no | INFO (default) or DEBUG |
Read-only enforcement
Every query is parsed with graphql-core before transmission. The parser rejects:
subscriptionoperations (not supported by the Admin API anyway)Any top-level
mutationexceptbulkOperationCancel(cancels an in-flight bulk job, no shop-data write)Malformed GraphQL (syntax errors)
Queries over 100KB
bulkOperationRunQuery is not in the generic parser allowlist. Legitimate bulk exports go through the dedicated shopify_bulk_query tool, which validates the inner query with the same read-only check before wrapping it in the bulk mutation. Single source of truth, no reliance on Shopify-side validation.
Rate limiting
Per-store cost-based leaky bucket (Shopify's model). Each response includes extensions.cost.throttleStatus. On THROTTLED errors, the server sleeps ceil((requestedQueryCost - currentlyAvailable) / restoreRate) seconds (minimum 1s) and retries up to 3 times before surfacing the error. Buckets are independent per store: a throttle on one store doesn't affect another.
Reply shape
Tool replies mirror the underlying call rather than a uniform envelope. shopify_list_stores returns a JSON array of {alias, domain, name, currency, auth_mode}; every GraphQL-backed tool (shopify_graphql_query, shopify_graphql_introspect, shopify_bulk_query, shopify_bulk_poll, shopify_shopifyql) returns the raw Shopify Admin API response, {"data": ..., "errors": ..., "extensions": ...}, unwrapped. Tool-level failures (bad input, redacted transport errors) raise a plain error.
Limits
100KB query size ceiling. Bulk exports: exactly one top-level connection per query, max 5 total connections, max depth 2, every nested connection node selects id without an alias; one bulk operation at a time per shop on API versions through 2025-10, up to 5 on 2026-01 and later. API version defaults to 2026-04; override per call with api_version="YYYY-MM".
Verify
Each release lists the package version, the .mcpb sha256 and the production commit it was derived from in CHANGELOG.md. CI runs the tests and a clean install of the built wheel on every push.
Privacy Policy
This connector runs locally, on your own machine, under your own Shopify credentials. It is a thin read-only bridge between your MCP client and Shopify's Admin API.
Data collection: The connector collects no personal data and contains no telemetry, analytics, or external reporting. It does not phone home.
Data usage: Shopify store data you query is returned to your local MCP client to fulfill your request, and is not used for any other purpose.
Data storage: The connector stores nothing persistently. Access tokens are held in memory only for the life of the process and are never written to disk. The only network destination is Shopify's own API (
*.myshopify.com), enforced by a domain allowlist.Third-party sharing: None. Data flows only between your machine and Shopify. No third party, including the connector's author, ever receives your data or credentials.
Retention: No data is retained by the connector after the process exits.
Secret handling: Access tokens, client secrets, and all Shopify token prefixes are redacted from logs and error messages.
Contact: hello@scalably.io
The canonical hosted version of this policy: https://scalably.io/connector-privacy.html
License
MIT. Copyright Scalably.
Learn more
We write about building production MCP servers and AI agents at scalably.io/blog:
How to build an MCP server in Python, the read-only enforcement pattern used here, from a server we run in production
What is an MCP server?, the host/client/server model
MCP Inspector: debug your MCP server, the silent failures to watch for
References
Available Tools
6 toolsshopify_bulk_pollARead-onlyIdempotent
Poll a bulk operation's status by ID.
Statuses: CREATED, RUNNING, COMPLETED, CANCELED, EXPIRED, FAILED.
On COMPLETED, the url field is a pre-signed JSONL download (valid 7 days).
On FAILED, partialDataUrl may hold partial results; errorCode explains why.
Args:
operation_id: Global ID of the bulk operation
(format: gid://shopify/BulkOperation/<numeric-id>).
shop: Store alias or domain the bulk op was launched on. Required when
multiple stores are configured.
api_version: Override API version (default "2026-04").
| Name | Required | Description | Default |
|---|---|---|---|
| shop | No | ||
| api_version | No | ||
| operation_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations (readOnlyHint, idempotentHint) by explaining the concrete outcomes: statuses (CREATED, RUNNING, COMPLETED, CANCELED, EXPIRED, FAILED), the pre-signed JSONL URL valid for 7 days on COMPLETED, and partialDataUrl/errorCode on FAILED. This adds valuable behavioral context that annotations do not capture, and it does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately concise and well-organized: a one-line purpose, a status list with outcome behavior, and then a clearly labeled Args section. Every sentence adds value—no fluff. It could be slightly more compact (e.g., merging statuses and outcomes), but it is efficient and easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a polling tool with an output schema, the description covers all necessary operational details: the ID format, shop requirement, API version default, and what happens on completion and failure. The output schema handles specific return fields, so the description need not enumerate them. Combined with the annotations (read-only, idempotent), an agent has everything needed to call this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must (and does) fully explain each parameter. It details the operation_id format (gid://shopify/BulkOperation/<numeric-id>), the shop parameter including when it is required (multiple stores configured), and the api_version override with the default value. This is far more informative than the schema's bare titles and types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Poll a bulk operation's status by ID.' It clearly distinguishes this from siblings like shopify_bulk_query (which presumably creates a bulk operation) and shopify_graphql_query by focusing on status polling. The purpose is unambiguous and leaves no room for misidentification.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the tool's function and provides context on how to use it (e.g., passing an operation_id in the proper format). It doesn't explicitly say 'use this after starting a bulk operation' or 'when not to use it,' but the description of the operation_id and the existence of shopify_bulk_query as a sibling make the intended workflow clear. No exclusions are stated, but the context is strong enough for an agent to infer the appropriate use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shopify_bulk_queryARead-only
Launch an async bulk export of a read-only GraphQL query.
Use for exporting datasets too large for paginated queries (>10k records, or anything you'd otherwise paginate hundreds of times). Shopify runs the query in the background and produces a JSONL file with all results.
Restrictions (enforced by Shopify):
Exactly one top-level connection per query.
Max 5 total connections, max depth 2.
Every nested connection node must select
idwithout an alias.API ≤ 2025-10: one bulk op at a time per shop. API ≥ 2026-01: up to 5.
Returns the BulkOperation ID - poll with shopify_bulk_poll.
Args: query: Read-only GraphQL document with a single root connection. shop: Store alias or domain. Required when multiple stores are configured. api_version: Override API version (default "2026-04").
| Name | Required | Description | Default |
|---|---|---|---|
| shop | No | ||
| query | Yes | ||
| api_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide readOnlyHint=true and openWorldHint=true, but the description significantly expands on behavioral details: async execution, background processing, JSONL output, restrictions (connection limits, depth limits, id requirement), and API version-specific concurrency limits. This goes well beyond the annotations, giving agents a full picture of what to expect.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured, front-loading the core purpose and usage context. The restrictions are clearly bullet-listed, and the Args section is logically placed. No redundant sentences; every sentence adds value. Minor deduction for not being even more streamlined, but it's appropriately sized given the complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (async, multiple restrictions, API version nuances), the description covers all critical aspects: purpose, usage, restrictions, return type (BulkOperation ID), and how to proceed (poll). The output schema likely describes the return structure, so not detailing the response format is acceptable. Sibling tools are distinct and the description clearly differentiates them.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 3 parameters with 0% description coverage; however, the description's 'Args' section provides meaningful context for each: 'query' is described as a read-only GraphQL document with a single root connection, 'shop' is clarified as a store alias or domain required when multiple stores are configured, and 'api_version' is noted as an override with a default. This adds value beyond the schema's type-only information, but could be even more explicit (e.g., format for query).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: launching an async bulk export of a read-only GraphQL query. It distinguishes itself from siblings by specifying it is for large datasets where paginated queries become impractical and explicitly mentions polling with shopify_bulk_poll for results. The verb 'launch' and resource 'async bulk export of a read-only GraphQL query' are specific and non-ambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage guidance: use when exporting datasets too large for paginated queries (>10k records or hundreds of pages). It also contrasts with 'normal' queries implicitly by referencing pagination alternatives. While it doesn't explicitly name shopify_graphql_query for smaller queries, the mention of 'paginated queries' serves as a clear alternative. Restrictions are thoroughly listed, aiding correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shopify_graphql_introspectARead-only
Introspect a Shopify store's Admin GraphQL schema.
Pass type_name to fetch a single type's fields (cheap, ~50 cost points).
Omit it for the full schema type catalog (expensive, ~800 cost points -
use sparingly).
Args:
type_name: GraphQL type name (e.g. "Order", "Product", "Customer").
Must match [A-Za-z_][A-Za-z0-9_]*. Omit for full schema.
shop: Store alias or domain (see shopify_list_stores). Required when
multiple stores are configured.
api_version: Override API version (default "2026-04").
| Name | Required | Description | Default |
|---|---|---|---|
| shop | No | ||
| type_name | No | ||
| api_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is established. The description adds valuable behavioral context: precise cost points for each mode, a caution to use the full schema sparingly, and clarifications on parameter defaults and requirements. No contradiction with annotations, and it goes beyond what annotations alone tell the agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tightly structured: the purpose is front-loaded in the first sentence, followed by a compact cost/usage paragraph, then a clean 'Args:' block. Every sentence adds essential information—no filler, no repetition. The layout makes scanning effortless.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only introspection tool, the description covers everything needed to call it correctly: mode selection, cost implications, parameter semantics, and references to the shop resolution tool. An output schema exists to handle return shapes. Combined with the annotations, nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, leaving the description to carry the full burden. It does this excellently: type_name is explained with a regex and examples, shop is tied to shopify_list_stores with a condition, and api_version is given a default and override instruction. Every parameter is fully documented beyond the raw schema, exceeding the baseline expected for low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('introspect') and resource ('Shopify store's Admin GraphQL schema'), and clearly distinguishes two modes: fetching a single type vs the full catalog. This unambiguously separates it from siblings like shopify_graphql_query, which performs actual queries. No ambiguity remains.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance on when to pass type_name (cheap, ~50 points) vs omit it (expensive, ~800 points, 'use sparingly'). It also tells when shop is required and references shopify_list_stores. However, it doesn't explicitly name sibling tools as alternatives for other operations, so the when-not-to-use guidance is slightly implicit. Still, the cost/size guidance is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shopify_graphql_queryARead-only
Execute a read-only GraphQL query against a Shopify store's Admin API.
Universal entry point for reading any data the token's scopes permit: products, variants, orders, customers, inventory, fulfillments, discounts, locations, markets, metafields, metaobjects, segments, shop settings, etc.
Full GraphQL reference: https://shopify.dev/docs/api/admin-graphql
Write mutations are rejected by design. The query string is parsed and validated as read-only before transmission.
Idiomatic patterns:
Pagination:
first: <=250,after: <cursor>, readpageInfo { hasNextPage endCursor }.Search: pass a Shopify search string to the
query:arg on connections, e.g.orders(first: 100, query: "created_at:>=2026-04-01 financial_status:paid").Money:
totalPriceSet { shopMoney { amount currencyCode } }.For datasets >10k records, use
shopify_bulk_queryinstead.
Args:
query: GraphQL document. Must be a query or a fragment. Subscription
and mutation operations are rejected - with one narrow exception,
bulkOperationCancel. For bulk exports, use shopify_bulk_query.
variables: Optional variables dict passed as GraphQL variables.
shop: Store alias (from shopify_list_stores) or domain. Required when
multiple stores are configured; optional (auto-selected) when there's
only one store.
api_version: Override API version (default "2026-04"). Format "YYYY-MM".
| Name | Required | Description | Default |
|---|---|---|---|
| shop | No | ||
| query | Yes | ||
| variables | No | ||
| api_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds real behavioral detail: 'The query string is parsed and validated as read-only before transmission,' and mutation/subscription operations are rejected except for the narrow `bulkOperationCancel` exception. This meaningfully expands on what the annotations already declare without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and structured into idiomatic patterns and per-argument details. It is somewhat long and repeats the bulk-query alternative twice, but the length earns its place because most content is call-critical rather than decorative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to explain returns. It covers the required query format, variables, shop selection, api versioning, pagination patterns, search usage, and the bulk export boundary. No essential call context appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description compensates by explaining each parameter: the GraphQL document shape and restrictions, the `variables` dict, the `shop` alias/domain requirements, and `api_version` default plus 'YYYY-MM' format. This turns a bare schema into usable guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Execute a read-only GraphQL query against a Shopify store's Admin API,' naming a specific verb, resource, and constraint. It then clarifies this is the 'Universal entry point for reading any data the token's scopes permit' and lists resource types, which distinguishes it from mutation and bulk siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly says to use the tool for reading any data the token permits and explicitly warns that write mutations are rejected. It also provides an alternative: 'For datasets >10k records, use shopify_bulk_query instead,' so an agent knows when to switch tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shopify_list_storesARead-only
List all Shopify stores configured for this agent.
Returns a JSON array of {alias, domain, name, currency, auth_mode}. The
name field is the merchant's own shop name from Shopify (fetched once per
process, cached). Use this list to match user intent - e.g., a user saying
"check the outlet" maps to the store whose name or domain contains
"outlet".
If only one store is configured, shop can be omitted on tool calls.
Args: refresh: If True, bypass the shop-name cache and re-fetch from Shopify. Use after a merchant renames a shop in the Shopify admin.
| Name | Required | Description | Default |
|---|---|---|---|
| refresh | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true and openWorldHint=true, so the description's extra detail about the cached `name` field and the `refresh` bypass behavior adds meaningful transparency. The description also discloses that data is fetched once per process and cached, which helps the agent understand freshness semantics beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded: it states the core purpose in the first sentence, then the return shape, usage guidance, and a single clearly documented parameter. Every sentence earns its place, and the Args section is minimal and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only listing tool with one optional parameter, the description is complete: it specifies the return fields, the caching behavior, the refresh condition, and the mapping use case. The output schema also exists, so the description does not need to over-explain return types, and no critical invocation detail is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema description coverage is 0%, the description fully documents the single `refresh` parameter: 'If True, bypass the shop-name cache and re-fetch from Shopify' and explains when to use it. This compensates for the missing schema description and gives the agent actionable semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List all Shopify stores configured for this agent.' It clearly explains the return shape and also gives a concrete use case, distinguishing this tool from the GraphQL and bulk-query siblings by emphasizing it returns the agent's configured store list, not API queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: to match user intent to a configured store, including a concrete example. It also provides the conditional guidance that if only one store is configured, `shop` can be omitted. It does not explicitly exclude alternatives, but the usage context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shopify_shopifyqlARead-only
Run a ShopifyQL analytics query against a Shopify store.
ShopifyQL is Shopify's SQL-like reporting language. Requires read_reports
scope. Consumes the same cost bucket as GraphQL.
Syntax: FROM SHOW [, ...] [BY ] [GROUP BY ] [WHERE ] [SINCE -Nd UNTIL today] [ORDER BY [ASC|DESC]] [LIMIT N]
Datasets: sales, orders, products, customers, inventory, sessions. Time tokens: -Nd / -Nw / -Nm / -Nq / -Ny, or named (today, yesterday, this_week, last_week, this_month, last_month, last_year).
Examples:
FROM sales SHOW total_sales GROUP BY day SINCE -7d UNTIL today ORDER BY day ASCFROM sales SHOW total_sales BY product_title ORDER BY total_sales DESC LIMIT 10 SINCE -30dFROM sales SHOW returning_customer_rate GROUP BY month SINCE -6mFROM sales SHOW net_sales SINCE -1q UNTIL todayFROM sessions SHOW sessions, conversion_rate GROUP BY referrer_source SINCE -14d
Returns tableData.columns, tableData.rows, and parseErrors.
When parsing fails, tableData is null and parseErrors contains
a list of human-readable error strings (e.g. "Column 'total_sale' not found").
Args: query: ShopifyQL query string. shop: Store alias or domain. Required when multiple stores are configured. api_version: Override API version (default "2026-04").
| Name | Required | Description | Default |
|---|---|---|---|
| shop | No | ||
| query | Yes | ||
| api_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark readOnlyHint, but the description adds substantial behavioral context: it specifies the cost bucket shared with GraphQL, returns `tableData.columns`, `tableData.rows`, and `parseErrors`, and explains the error behavior when parsing fails. This goes well beyond what the annotations declare, providing concrete operational expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but tightly organized: a one-line purpose, a syntax block, dataset/token listings, several examples, and a return-format note. Each section earns its place, and the most critical information is front-loaded. No fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a complex query language, the description is remarkably complete. It covers the syntax, allowed datasets, time tokens, example usages, return structure, and error handling. It even notes the API version default. There is no obvious missing information an agent would need to call it correctly, and the presence of an output schema further reduces the need for return-type detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must fully compensate. It does: it explains the `query` syntax in detail, clarifies `shop` as 'store alias or domain. Required when multiple stores are configured', and notes `api_version` overrides the default '2026-04'. This adds meaning far beyond the bare schema types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb ('Run'), resource ('ShopifyQL analytics query'), and target ('against a Shopify store'). The description also distinguishes it from siblings by positioning it as a reporting-language query, separate from GraphQL and bulk tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly explains the tool's domain ('analytics query', SQL-like reporting) and notes the required scope ('read_reports') and that it consumes the same cost bucket as GraphQL. However, it does not explicitly contrast with sibling tools (e.g., 'use this for analytics, use GraphQL for other queries'). The guidance is strong but not fully explicit about when to choose this over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v1.1.0- First observed
shopify_bulk_poll - First observed
shopify_bulk_query - First observed
shopify_graphql_introspect - First observed
shopify_graphql_query - First observed
shopify_list_stores - First observed
shopify_shopifyql
TDQS
Scored across 6 tools
Each tool has a distinct role: store discovery, direct GraphQL reads, schema introspection, async bulk exports, bulk status polling, and ShopifyQL analytics. The potential overlap between graphql_query and bulk_query is clearly resolved by scale and execution model guidance.
All tools share a consistent shopify_ prefix and snake_case style, with clear verb/noun combinations like list_stores, bulk_query, and bulk_poll. The name shopify_shopifyql is slightly redundant and breaks the verb-led pattern, but the overall convention remains predictable.
Six tools is well-scoped for a Shopify read/analytics MCP server. Each tool addresses a distinct need without redundancy, and the count is comfortably within the ideal range.
The universal GraphQL query tool provides read access to virtually any Shopify resource, while bulk_query and bulk_poll cover large exports and ShopifyQL covers analytics. Store discovery and schema introspection complete the read-only surface, leaving no significant operational dead ends.
Maintenance
Related MCP Connectors
Unified MCP server for 70+ eCommerce platforms: products, orders, customers, and more.
Federated commerce search across independent WooCommerce merchants. Keyless, read-only MCP server.
Shopify MCP Pack — wraps the Shopify Admin REST API (2024-01)
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProduction-grade MCP server for the Shopify Admin GraphQL API, exposing typed tools for AI agents to manage products, orders, customers, and more.10 npmMIT
- FlicenseNot gradedqualityCmaintenanceAn MCP server providing six scoped tools for Shopify's Admin API, enabling natural-language querying of chargebacks, orders, refunds, customers, and revenue.-
- AlicenseAqualityCmaintenanceA read-only MCP server that lets AI assistants answer Shopify store operations questions via tools like get_shop, list_products, get_product, and list_orders.4MIT
- FlicenseAqualityCmaintenanceSecurity-focused MCP server for Shopify Admin GraphQL with read-only queries by default and mutations requiring preview and one-time confirmation. It manages short-lived tokens internally and enforces strict scope and approval controls.46 npm-