mcp server
shopify-admin-mcp
MCP server for the Shopify Admin GraphQL API (2026-10) with live schema introspection
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- Node.js 20 or newer
{
"mcpServers": {
"acoderacom-shopify-admin-mcp": {
"command": "npx",
"args": [
"-y",
"@acodera/shopify-admin-mcp"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 26, 2026shopify-admin-mcp
MCP server for Shopify's Admin GraphQL API: typed tools for common store tasks, raw GraphQL for everything else, and live schema search so your AI assistant works against the exact API your store serves. Targets API version 2026-10.
Features
- 59 convenience tools for products, collections, publishing, metafields, metaobjects, customers, orders, inventory, discounts, files, themes, and markets
- Raw GraphQL and live schema search for anything the tools don't cover
- Theme files from a local folder: with
--theme-dir, theme writes send files by filename and a pull tool copies them back, so file content never has to pass through the conversation - Setup wizard that writes
.mcp.jsonfor you - Safety controls: read-only mode, toolsets, a live-theme guard, confined local uploads, and read-only or destructive annotations on every tool
- Both auth methods: Dev Dashboard client credentials (refreshed automatically) and legacy
shpat_tokens - Rate-limit aware: throttled requests wait for the cost bucket to refill, then retry
Quick Start
Run the setup wizard in your project folder:
npx -y @acodera/shopify-admin-mcp@latest setup
It runs on macOS, Linux and Windows. It checks your Node.js version, then asks what to set up:
- Connect to a store only: asks for your store and credentials, checks them, optionally adds the Shopify Dev MCP server, and creates or updates
.mcp.json. Theme edits are turned off (--disable-theme-writes), so the assistant can read themes but not change them; everything else, such as products and metafields, can be changed. Local files, such as product images, are uploaded from./uploads, which setup creates, unless.mcp.jsonalready sets an upload folder. - Full theme design with Horizon: also downloads Shopify's Horizon theme into
./themeand writesCLAUDE.md,THEME.mdandcustomizations.mdfrom acoderacom/claude-horizon, with the store and live theme filled in toCLAUDE.md. It switches on whatCLAUDE.mddescribes: live theme writes, theme files from./theme, uploads from./uploads, and the Shopify Dev MCP. The store's live theme must be a Horizon version the template supports (listed in itsversions.json), and the project gets that exact version. Otherwise setup says which version to switch to and stops without writing.mcp.json. Since the Shopify theme store only installs the newest Horizon, it offers to save an upload-readyhorizon-<version>.zipfor Online Store → Themes → Add theme → Upload zip file. - Full theme edit live site: for working on a copy of a live store's theme, Horizon or not, without Horizon's checks. First duplicate the live theme in the Shopify admin (Online Store → Themes → ⋯ → Duplicate) and give the copy a name. Setup lists the store's themes and you pick the copy Claude edits; the live theme is listed but can't be picked, and setup stops if the store has no copy. Live theme writes stay off and themes are locked (
--lock-themes), so the server refuses any change to the live theme and any theme create, duplicate, rename, delete or publish: you publish the copy yourself. Setup writesCLAUDE.md(no mockup rules) andcustomizations.mdfrom the template'slive-site/folder with the store and the copy's name, version and ID filled in, a blankTHEME.md, and an empty./theme. Then, by hand: download the copy (⋯ → Download theme file) and unzip it into./theme, and, when you want, ask Claude to learn the theme: it writesTHEME.mdfrom./theme, which stays blank until then. Store data such as products and menus is shared with the live site, so changes to it still show at once;CLAUDE.mdhas Claude ask first. Running setup again keeps./theme,THEME.mdand the chosen copy unless you change them.
Current values are prefilled and other servers are kept. Setup doesn't ask about the other options, such as read-only mode, toolsets or raw GraphQL; set them in .mcp.json by hand. Running "Connect to a store only" again keeps them; both theme design modes set the ones CLAUDE.md depends on. The secret is saved in plain text, so the file is added to .gitignore in a git repo and, on macOS and Linux, written readable only by you. Windows has no such file mode, so the file gets its folder's permissions: keep the project inside your user folder, where other users can't read it. Restart Claude Code (or run /mcp) to connect.
Manual setup
With Claude Code:
claude mcp add shopify \
-e SHOPIFY_STORE=mystore.myshopify.com \
-e SHOPIFY_CLIENT_ID=your_client_id \
-e SHOPIFY_CLIENT_SECRET=your_client_secret \
-- npx -y @acodera/shopify-admin-mcp
Or in .mcp.json, or the Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": ["-y", "@acodera/shopify-admin-mcp"],
"env": {
"SHOPIFY_STORE": "mystore.myshopify.com",
"SHOPIFY_CLIENT_ID": "${SHOPIFY_CLIENT_ID}",
"SHOPIFY_CLIENT_SECRET": "${SHOPIFY_CLIENT_SECRET}"
}
}
}
}
For a legacy token, set SHOPIFY_ACCESS_TOKEN instead of the client ID and secret. Claude Code expands ${VAR} from your shell, so .mcp.json can be committed without secrets; Claude Desktop doesn't, so write the values there directly.
Authentication
- Client credentials (recommended): create an app in the Dev Dashboard, configure the scopes below, release a version, install it on your store, and use its client ID and secret. The app and the store must belong to the same Shopify organization. Tokens last 24 hours and are refreshed automatically.
- Approved in the browser: for an app installed on a store outside the app's organization, such as a client's store or one you reach as a collaborator, where Shopify refuses client credentials with
shop_not_permitted. In setup, choose Client ID and secret, approved in the browser. It prints a redirect URL,http://localhost:3457/auth/callback, to add to the app's version in the Dev Dashboard (then release the version), opens Shopify's approval page, and exchanges the approval for an offline access token that lasts until the app is uninstalled or its secret is rotated. The client secret is only used for the approval;.mcp.jsongets the access token. - Legacy access token: the
shpat_token of an existing custom app.
Grant only the scopes for the tools you use:
| Scopes | Tools |
|---|---|
read_products, write_products | Products, variants, collections |
read_publications, write_publications | Publishing |
read_metaobjects, write_metaobjects | Metaobject entries |
read_metaobject_definitions, write_metaobject_definitions | Metaobject definitions |
| Scope of the owning resource | Metafields (e.g. read_products for product metafields) |
read_customers, write_customers | Customers |
read_orders (+ read_all_orders for orders older than 60 days) | Orders |
read_inventory, write_inventory, read_locations | Inventory |
read_discounts, write_discounts | Discounts |
read_files, write_files | Files |
read_themes, write_themes (+ theme-code exemption for writes) | Themes |
read_markets, write_markets | Markets |
Customer names, emails, phone numbers, and addresses are protected customer data, which your app must also be approved for.
Tools
Always available: shopify_graphql (any query or mutation; queries only in read-only mode), shopify_schema_search, and shopify_schema_details. The rest are grouped into toolsets, all registered by default:
| Toolset | Tools (each prefixed shopify_) |
|---|---|
products | products_list, product_get, product_create, product_update, product_delete, product_variants_create, product_variants_update |
collections | collections_list, collection_get, collection_create, collection_update, collection_delete |
publishing | publications_list, publish, unpublish |
metafields | metafields_list, metafields_set, metafield_delete, metafield_definitions_list, metafield_definition_create |
metaobjects | metaobject_definitions_list, metaobject_definition_create, metaobjects_list, metaobject_get, metaobject_create, metaobject_update, metaobject_upsert, metaobject_delete |
customers | customers_list, customer_get, customer_update |
orders | orders_list, order_get |
inventory | inventory_get_levels, inventory_adjust |
discounts | discounts_list, discount_get, discount_amount_off_create, discount_free_shipping_create, discount_bxgy_create, discount_activate, discount_deactivate, discount_delete, discount_codes_add |
files | files_list, file_upload, file_delete |
themes | themes_list, theme_files_list, theme_files_get, theme_files_upsert, theme_files_delete, theme_duplicate, theme_delete; theme_files_pull with --theme-dir |
markets | markets_list, market_get, market_create, market_update, market_delete |
A few inputs follow API 2026-10: collections define their products with sources (see CollectionCreateSourceTargetInput in shopify_schema_details), shopify_inventory_adjust needs the quantity you expect before the change (changeFromQuantity), and a discount takes one kind of eligibility (customerIds, customerSegmentIds, or marketIds) and items by collection or by product, not both.
Theme Files From a Local Folder
Theme files are usually edited in a local copy of the theme first. Sending a file's content through shopify_theme_files_upsert makes the assistant write out the whole file, which takes minutes for a large section. With --theme-dir pointing at the local copy:
shopify_theme_files_upsertsends a file given only itsfilenamefrom that folder: text as text, anything else as base64. When Shopify's write job is done, it reports for each file whether Shopify stored it as sent. Shopify regenerates JSON files such as templates (adding its header and reformatting them), so a file it returns changed is replaced in the folder with Shopify's copy.shopify_theme_files_pullcopies files or patterns such assections/*from a theme into the folder, up to 50 per call, and returns only filenames and checksums. Files that already match are left alone.
Files passed with content, contentBase64 or url work as before.
Safety
- Read-only mode (
--read-only) registers only tools that read data and rejects mutations in raw GraphQL. The document is parsed, so comments or extra operations can't slip one through. Use it whenever the assistant doesn't need to change the store: product descriptions and customer notes are written by other people and can carry instructions. - Toolsets (
--toolsets products,orders) shorten the tool list, but raw GraphQL can still reach anything your scopes allow. Add--disable-raw-graphqlto keep the assistant to the selected toolsets. Either way, the app's scopes are the real limit. - The live theme is protected: theme file writes and deletes on the published (
MAIN) theme are refused, including through raw GraphQL, wherethemePublishis refused too. Duplicate the theme, edit the copy, and publish it from the Shopify admin, or start with--allow-live-theme-writes. - Theme edits can be turned off entirely with
--disable-theme-writes: the theme write tools are left out, and raw GraphQL refuses every theme mutation (file writes,themeCreate,themeUpdate,themeDelete,themeDuplicate,themePublish) whichever theme it targets. It overrides--allow-live-theme-writes, and setup's "Connect to a store only" mode turns it on. - Themes can be locked with
--lock-themes: theme files can still be edited, butshopify_theme_duplicateandshopify_theme_deleteare left out, and raw GraphQL refusesthemeCreate,themeDuplicate,themeUpdate,themeDeleteandthemePublish, so copies can't be deleted or renamed and nothing can be published. Setup's "Full theme edit live site" mode turns it on. - The theme folder (
--theme-dir) is the only place theme files are sent from and pulled into. Paths that lead outside it, symlinks included, and files outside the theme's own folders (assets,blocks,config,layout,locales,sections,snippets,templates) are refused. - Local uploads are off until you set
--upload-dir(setup sets./uploadsin both modes).shopify_file_uploadthen accepts files inside that folder (symlinks resolved), as well as public URLs that Shopify fetches itself. - Credentials are only ever sent to
*.myshopify.com, and the server warns when secrets are passed as flags, since other processes can see them.
Configuration
Every option works as a flag after the package name (in args) or as an environment variable (in env):
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--store | SHOPIFY_STORE | required | mystore or mystore.myshopify.com |
--access-token | SHOPIFY_ACCESS_TOKEN | Legacy shpat_ token | |
--client-id | SHOPIFY_CLIENT_ID | Client credentials ID | |
--client-secret | SHOPIFY_CLIENT_SECRET | Client credentials secret | |
--api-version | SHOPIFY_API_VERSION | 2026-10 | YYYY-MM or unstable |
--toolsets | SHOPIFY_TOOLSETS | all | Comma-separated toolsets to register |
--upload-dir | SHOPIFY_UPLOAD_DIR | off | Absolute path that local uploads are confined to |
--theme-dir | SHOPIFY_THEME_DIR | off | Absolute path of a local copy of the theme that theme files are sent from and pulled into |
--read-only | SHOPIFY_READ_ONLY | off | Read tools only, no mutations |
--allow-live-theme-writes | SHOPIFY_ALLOW_LIVE_THEME_WRITES | off | Allow writing to and publishing the live theme |
--disable-theme-writes | SHOPIFY_DISABLE_THEME_WRITES | off | Refuse every theme change; overrides --allow-live-theme-writes |
--lock-themes | SHOPIFY_LOCK_THEMES | off | Keep theme file edits but refuse creating, duplicating, renaming, deleting and publishing themes |
--disable-raw-graphql | SHOPIFY_DISABLE_RAW_GRAPHQL | off | Leave out shopify_graphql |
For example: "args": ["-y", "@acodera/shopify-admin-mcp", "--read-only", "--toolsets", "products,orders,customers"].
- On/off variables accept
trueor1. When an option is set both ways, the flag wins; for on/off options, either one turns it on. - Blank values and unfilled references (
${VAR},$VAR) count as not set, so one config can list both auth methods. If both are filled in, the access token is used. - Use an absolute
--upload-dirand--theme-dir, since MCP clients start the server from their own working directory. - With an older
--api-version, raw GraphQL works but some tools may not. The server logs a warning if Shopify serves a different version than the one requested.
Schema Exploration
The server introspects the live schema in the background once it connects. shopify_schema_search finds types, queries, and mutations by keyword, and shopify_schema_details shows a type's fields or an operation's arguments. Deprecated fields are left out, which steers the assistant toward the current API.
Development
git clone https://github.com/acoderacom/shopify-admin-mcp.git
cd shopify-admin-mcp && git checkout dev && npm install
npm run build # or `npm run dev` to rebuild on change
npm test # unit tests; live tests skip themselves without credentials
npm run lint # type-check src and tests
Requires Node.js 22.12 or later. Setting SHOPIFY_STORE and credentials also runs the live tests; adding SHOPIFY_TEST_WRITES=1 runs write tests that create and then delete [MCP test] data, so only use it with a development store.
To contribute, branch from dev, add a changeset with npx changeset (not needed for docs, tests, or CI), and open a pull request into dev. Releases merge dev into main; the workflow then opens a Version Packages pull request, and merging it publishes to npm through trusted publishing with provenance.
License
MIT. See LICENSE.
Originally created by Colby McHenry as shopify-graphql-admin-mcp, and maintained by acoderacom.