@theethosteam/shopify-mcp
v0.1.0
Published
Multi-store read + write MCP server (and CLI) for the Shopify Admin GraphQL API. Per-store custom-app tokens (SHOPIFY_STORE_<ALIAS>), store-aware responses, tiered writes (routine executes, destructive confirm-gated), raw GraphQL passthrough. Runs via npx
Maintainers
Readme
@theethosteam/shopify-mcp
Multi-store read + write MCP server (and CLI) for the Shopify Admin GraphQL API. Built for agency use: one server, every client store, and every response names the store it ran against so data can never be misattributed.
- 19 typed tools — shop identity, products (CRUD), orders, customers, collections, locations, themes, webhooks — plus a raw GraphQL passthrough for everything else.
- Tiered writes — routine writes (create/update product, create webhook)
execute; deletes are dry-run unless
confirm:true; raw-passthrough mutations are refused unlessconfirm:true. - Multi-store — one env entry per store;
shopify_use_storeswitches the session default (request-scoped on the remote host, so users never clobber each other). - Runs three ways, like every Ethos connector: remote connector
(
https://mcp.theethosteam.com/api/shopify/mcp), stdio via npx, and CLI (shop).
Auth: per-store custom-app Admin tokens
No OAuth dance. Each store gets a custom app:
store admin → Settings → Apps and sales channels → Develop apps → Create app
→ enable the Admin API scopes you need (start with read_products,
write_products, read_orders, read_customers, read_themes, read_locations,
write_webhooks) → Install app → copy the Admin API access token
(shpat_…). The token is shown once.
Env
# One entry per store — alias is the suffix, lowercased ("bia" here):
SHOPIFY_STORE_BIA="born-in-apparel.myshopify.com|shpat_xxx"
SHOPIFY_STORE_A2="a2-phone-repair.myshopify.com|shpat_yyy"
# Single-store shorthand (registers as alias "default"):
SHOPIFY_STORE_DOMAIN=born-in-apparel.myshopify.com
SHOPIFY_ADMIN_TOKEN=shpat_xxx
# Optional:
SHOPIFY_ACTIVE_STORE=bia # default store when several are configured
SHOPIFY_API_VERSION=2026-07 # defaults to the pinned stableWith multiple stores and no active store set, tools refuse rather than
guess — pass store:"bia" or call shopify_use_store first.
Run
# MCP over stdio
npx -y @theethosteam/shopify-mcp
# CLI
npx -y -p @theethosteam/shopify-mcp shop whoami
npx -y -p @theethosteam/shopify-mcp shop products -q "status:active" -s bia
npx -y -p @theethosteam/shopify-mcp shop orders -q "financial_status:paid"
npx -y -p @theethosteam/shopify-mcp shop graphql '{ shop { name } }'Claude Code:
claude mcp add shopify -e SHOPIFY_STORE_DOMAIN=<shop>.myshopify.com -e SHOPIFY_ADMIN_TOKEN=shpat_... -- npx -y @theethosteam/shopify-mcpTools
| Tool | Tier |
|---|---|
| shopify_whoami · shopify_list_stores · shopify_use_store | awareness |
| shopify_list_products · shopify_get_product | read |
| shopify_create_product · shopify_update_product | routine write |
| shopify_delete_product | confirm-gated |
| shopify_list_orders · shopify_get_order | read |
| shopify_list_customers · shopify_get_customer | read |
| shopify_list_collections · shopify_list_locations · shopify_list_themes | read |
| shopify_list_webhooks · shopify_create_webhook | read / routine |
| shopify_delete_webhook | confirm-gated |
| shopify_graphql | read free / mutations confirm-gated |
List queries accept Shopify search syntax
(status:active, financial_status:paid, created_at:>2026-08-01, …) and
cursor pagination (first ≤ 50, after from the previous page's
pageInfo.endCursor).
Notes
- API version is pinned per release (
LATEST_STABLEincore/client.ts); Shopify versions the Admin API quarterly and supports each for 12 months — bump the pin with a normal version bump. - Throttled calls (
THROTTLED) retry once automatically. - Mutation soft failures (
userErrors) surface as tool errors with field paths. - The remote host's user-mode (OAuth) logins carry no Shopify creds yet —
Shopify tools on
mcp.theethosteam.comwork in bearer/admin mode (deployment env). Per-user store grants would follow theghl_pitspattern inconnector_userswhen needed.
