Read-only MCP for the Shopify Admin GraphQL API. 6 tools, full read surface, multi-store.
Config is the same across clients — only the file and path differ.
{
"mcpServers": {
"io-github-pavle-scalably-shopify-mcp": {
"command": "<see-readme>",
"args": []
}
}
}Are you the author?
Add this badge to your README to show your security score and help users find safe servers.
A single MCP server exposing 100% of the 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.
No automated test available for this server. Check the GitHub README for setup instructions.
Five weighted categories — click any category to see the underlying evidence.
No known CVEs.
No package registry to scan.
Be the first to review
Have you used this server?
Share your experience — it helps other developers decide.
Sign in to write a review.
Others in ecommerce
Argentine business automation: Mercado Pago, AFIP/ARCA, WhatsApp, banking, shipping (7 packages).
A command line tool for setting up commercetools MCP server
Rent GPUs, robots, drones, and construction gear on RIGShare; also onboards equipment owners.
MCP server for Chestniy ZNAK (Честный ЗНАК) API — product marking verification. No auth needed for
MCP Security Weekly
Get CVE alerts and security updates for io.github.pavle-Scalably/shopify-mcp and similar servers.
Start a conversation
Ask a question, share a tip, or report an issue.
Sign in to join the discussion.
A single MCP server exposing 100% of the 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)
pip install -r requirements.txt
# Single store (simplest)
export SHOPIFY_DOMAIN="my-store.myshopify.com"
export SHOPIFY_ACCESS_TOKEN="shpat_..." # or SHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET
python server.py
Then point any MCP client at the server. See Authentication below for multi-store and OAuth client-credentials setup.
| Tool | Description |
|---|---|
shopify_list_stores | Lists configured stores. Agent calls first. |
shopify_graphql_query | Arbitrary read-only GraphQL. Mutations rejected by the parser. |
shopify_graphql_introspect | Schema introspection — full catalog or single type. |
shopify_bulk_query | Launch async bulk export (JSONL). |
shopify_bulk_poll | Poll bulk operation status + download URL. |
shopify_shopifyql | ShopifyQL analytics (SQL-like; requires read_reports). |
Every non-list tool takes an optional shop argument (alias or domain). Required when >1 store configured; auto-selected when exactly 1.
100% of 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 (>10k records) should use shopify_bulk_query. Analytics goes through shopify_shopifyql.
Set SHOPIFY_STORES to a JSON object mapping alias → 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_..."}
}
client_id+client_secret (Dev Dashboard OAuth, 24h tokens auto-refreshed per store) OR access_token (legacy shpat_).[a-z0-9][a-z0-9_-]{0,63}. Lowercase-normalized on load.If SHOPIFY_STORES is unset, the MCP falls back to single-store env vars:
SHOPIFY_DOMAIN or SHOPIFY_SHOP_DOMAIN — <shop>.myshopify.comSHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET (Dev Dashboard)SHOPIFY_ACCESS_TOKEN (legacy shpat_)The single store registers under alias default — callers can omit shop argument on tool calls.
Every query is parsed with graphql-core before transmission. The parser rejects:
subscription operations (not supported by Admin API anyway)mutation EXCEPT bulkOperationCancel (cancels an in-flight bulk job, no shop-data write)