Shopify MCP
Connects to the Shopify Admin GraphQL API for managing products, collections, orders, customers, draft orders, inventory, locations, metafields, metaobjects, files, and redirects.
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 orders from last week"
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 Model Context Protocol (MCP) server that connects agents to the Shopify Admin GraphQL API. Use it to browse, edit, and clean up store data via a curated set of tools.
npm: @benwmerritt/shopify-mcp
binary: shopify-mcp
This project started from Ge Li's shopify-mcp. The unscoped shopify-mcp package on npm is theirs and does not include the changes in this repository.
Highlights
CRUD for products, collections, orders, and customers
Draft orders for quotes, manual orders, and B2B pricing
Inventory and location lookups for stock workflows
Metafields for custom data
Metaobject entry creation and lookup for existing definitions
URL redirects management
OAuth login flow with local token caching
Bulk product cleanup utilities
Fail-closed read-only mode for audit and QA agents
Related MCP server: Kockatoos Shopify MCP Server
Prerequisites
Node.js 20+
A Shopify custom app (OAuth or Admin API token)
Local setup (this repo)
Use this when you want to run the MCP server from this local checkout instead of a remote deployment.
Install dependencies and build:
npm install
npm run buildCreate local env config:
cp .env.example .envSet at least:
MYSHOPIFY_DOMAIN=your-store.myshopify.comEither:
SHOPIFY_CLIENT_ID=...andSHOPIFY_CLIENT_SECRET=...for a Dev Dashboard app owned by the store's organization; orSHOPIFY_ACCESS_TOKEN=shpat_xxxfor a static/manual token
REMOTE_MCP=false
Start local MCP (stdio):
npm run start:localstart:local uses stdio mode. Remote mode is only enabled with --remote or REMOTE_MCP=true.
Read-only mode
Start a capability-restricted server for QA, audit, and reporting agents:
shopify-mcp --read-only --domain=<YOUR_SHOP>.myshopify.com
# or
SHOPIFY_MCP_READ_ONLY=true npm run start:localRead-only mode exposes only a reviewed allowlist of lookup and reporting tools.
All mutating, mixed read/write, file-upload, and unknown future tools are hidden.
The allowlist is fail-closed, so a newly added tool does not appear in a
read-only instance until it is explicitly reviewed. get-status reports the
effective access mode, whether the boundary is enforced, and whether write
tools are exposed.
Use a least-privilege Shopify token as well when one is available. The server boundary is designed to remain useful when a deployment must temporarily share an existing token: agents connected to the read-only MCP instance cannot call the hidden mutation tools.
Install + run
Client credentials (same Shopify organization)
For a Dev Dashboard app installed on a store owned by the same Shopify organization, configure:
MYSHOPIFY_DOMAIN=your-store.myshopify.com
SHOPIFY_CLIENT_ID=your-client-id
SHOPIFY_CLIENT_SECRET=your-client-secretNo callback URL or browser consent is required. The MCP obtains Shopify's
24-hour access token at startup, caches it per permanent MyShopify domain in
~/.shopify-mcp/tokens.json, and renews it automatically before expiry.
Cached tokens include the client ID so a token created by a different app is
never silently reused after an app cutover.
Shopify does not allow this grant for public or custom-distribution apps on stores owned by another organization; use the authorization-code flow below for those apps.
Authorization-code OAuth
Create a custom app and copy Client ID and Client Secret.
In App setup, set App URL and Allowed redirection URLs to:
http://localhost:3456/callbackStart the OAuth flow:
npx @benwmerritt/shopify-mcp --oauth --domain=your-store.myshopify.com --clientId=xxx --clientSecret=yyyTokens are stored at ~/.shopify-mcp/tokens.json. After that, start the server with just the domain:
npx @benwmerritt/shopify-mcp --domain=your-store.myshopify.comOptional: override scopes with --scopes or SHOPIFY_SCOPES.
Access token (manual)
Create a custom app in Shopify
Enable Admin API scopes:
read_products,write_productsread_customers,write_customersread_orders,write_ordersread_draft_orders,write_draft_ordersread_inventory,write_inventoryread_locationsread_content,write_contentread_files,write_files
Install the app and copy the Admin API access token
Run:
shopify-mcp --accessToken=<YOUR_ACCESS_TOKEN> --domain=<YOUR_SHOP>.myshopify.comMCP client setup
Claude Desktop (local repo build)
Build first (npm run build), then point Claude Desktop at this repo's built entrypoint:
{
"mcpServers": {
"shopify-local": {
"command": "node",
"args": [
"/absolute/path/to/shopify-mcp/dist/index.js",
"--domain",
"your-store.myshopify.com"
],
"env": {
"SHOPIFY_ACCESS_TOKEN": "shpat_xxx",
"REMOTE_MCP": "false"
}
}
}
}If you completed OAuth locally, remove SHOPIFY_ACCESS_TOKEN and keep --domain.
Claude Desktop (npm package)
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": [
"@benwmerritt/shopify-mcp",
"--accessToken",
"<YOUR_ACCESS_TOKEN>",
"--domain",
"<YOUR_SHOP>.myshopify.com"
]
}
}
}If you completed OAuth, omit --accessToken and keep --domain.
Config paths:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%/Claude/claude_desktop_config.json
Remote MCP (Railway, etc.)
By default this server runs as a local stdio MCP. Passing --remote (or setting
REMOTE_MCP=true) switches it to HTTP/SSE mode so it can be deployed as a remote
MCP server for Claude.ai or other remote clients. This repo ships a Dockerfile
and railway.json so Railway builds and starts it in remote mode out of the box.
1. Get a token locally (one-time):
npx @benwmerritt/shopify-mcp --oauth --domain=your-store.myshopify.com --clientId=xxx --clientSecret=yyy
# Token saved to ~/.shopify-mcp/tokens.json2. Deploy to Railway:
Create a project from this repo. Railway reads
railway.jsonand builds theDockerfile, which starts the server with--remote.Set the service environment variables (Railway injects
PORTautomatically):
SHOPIFY_ACCESS_TOKEN=shpat_xxx # from tokens.json (or use the OAuth vars)
MYSHOPIFY_DOMAIN=your-store.myshopify.com
MCP_API_KEY=choose-a-long-random-string # required to authenticate remote clients
# REMOTE_MCP=true is already implied by the Dockerfile's --remote flag
# PORT is injected by Railway (defaults to 3000 when run locally)3. Connect:
Health check:
GET /healthStreamable HTTP:
/mcp, using POST for requests, including MCP 2026-07-28.Existing SSE clients:
GET /mcp?apiKey=<MCP_API_KEY>.Existing SSE messages:
POST /messages?apiKey=<MCP_API_KEY>.
Send Authorization: Bearer <MCP_API_KEY> with Streamable HTTP requests.
The existing apiKey query parameter also works on both transports. When
MCP_API_KEY is configured, missing or invalid credentials receive 401 on
all MCP routes except allowed OPTIONS preflights, which do not require credentials.
An explicit Bearer header takes precedence over the query key.
Without MCP_API_KEY, development mode binds only to 127.0.0.1.
External deployments, including containers that publish a port, must configure a
key to listen on all interfaces. The health endpoint remains unauthenticated.
Use HTTPS and configure a key for a public deployment. This shared-key scheme
is not an MCP OAuth authorization server.
MCP routes validate the actual Host header before Origin and authentication,
including requests without an Origin header and OPTIONS preflights. Allowed
hostnames are the configured public app hostname, localhost, 127.0.0.1, and
[::1], with an optional port. Add custom proxy or domain hostnames through
MCP_ALLOWED_HOSTS, comma-separated, such as mcp.example.com,internal-proxy.example.com.
Use hostnames without schemes or ports; matches are exact and case-insensitive.
X-Forwarded-Host is not trusted. Other or missing Host headers receive 403.
Native clients without an Origin header work when their Host is allowed. Browser requests to
MCP routes must use the configured public app origin, the local server origin,
or an exact origin listed in MCP_ALLOWED_ORIGINS, comma-separated, such as
https://client.example,https://another-client.example. Other origins receive
403, including preflight requests. Public app URL resolution continues to use
PUBLIC_BASE_URL, APP_URL, or the Railway public URL/domain variables.
The upload pages keep their existing URLs and short-lived upload-session checks.
Test the container locally before deploying:
docker build -t shopify-mcp .
docker run -p 3000:3000 \
-e MYSHOPIFY_DOMAIN=your-store.myshopify.com \
-e SHOPIFY_ACCESS_TOKEN=shpat_xxx \
-e MCP_API_KEY=test \
shopify-mcp
# then in another shell: curl localhost:3000/healthEnvironment variables (optional)
SHOPIFY_ACCESS_TOKEN=your_access_token
MYSHOPIFY_DOMAIN=your-store.myshopify.com
# Optional OAuth values:
# SHOPIFY_CLIENT_ID=your_client_id
# SHOPIFY_CLIENT_SECRET=your_client_secret
# SHOPIFY_SCOPES=comma,separated,scopes
# Hide every mutating or unreviewed tool (also available as `--read-only`):
# SHOPIFY_MCP_READ_ONLY=trueProtocol compatibility and upgrade notes
The server uses TypeScript SDK v2 and Zod 4. Local stdio selects the protocol
from the opening message. Remote POST /mcp supports both MCP 2026-07-28
and older initialization-based Streamable HTTP clients. Modern requests use
server/discover and per-request metadata rather than an initialization session.
Existing stdio commands, Shopify credentials, token renewal, OAuth setup, read-only flags, tool names, and legacy SSE connection URLs remain available. The same tool registrations and fail-closed allowlist serve every transport.
Compatibility limits:
Node 18 is no longer supported by SDK v2. Upgrade Node to 20+ before updating this server, or retain the previous release. The Docker image already uses Node 20.
Legacy SSE uses the SDK's frozen
server-legacycompatibility package. New integrations should use Streamable HTTP; the SSE bridge receives no new features.Legacy Streamable HTTP on POST
/mcpis stateless, with no session ID or replay. GET/mcpwithout protocol/session headers remains the original SSE endpoint. Streamable HTTP GET and DELETE session operations are unsupported. A reconnect to legacy SSE creates a new connection, as before.Browser clients from other origins must configure
MCP_ALLOWED_ORIGINS. API-key authentication remains separate from Shopify OAuth and does not provide automatic MCP OAuth discovery or token issuance.
Run npm test -- --runInBand for the application suite and
npm run test:connections for built-server connection and security tests.
Connection tests use SDK v1.17.1 and v2.0.0, explicitly pin modern clients to
2026-07-28, compare tool catalogs, and mock Shopify calls without store access.
See the research notes for official sources and migration details.
Tool catalog
Products
products— unified lookup/search/filter. Passidfor a single product; omitidto list/search with filters (title,status,vendor,tag, inventory, dates,hasImages, …). Returns the product's Shopify Standard Product Taxonomycategory({id, name, fullName}) inslim/standard/full. Page size capped at 100.create-productupdate-product— acceptscategory(Shopify Standard Product Taxonomy GID,vp-*prefix); the tool verifies the category actually stuck and throws a loud, actionable error if Shopify silently rejected the GID, instead of leaving you with a nullcategory. Also takescost(cost per item, on the simple form or per entry invariants; the response includescostonly when one was written, since reading it needsread_inventory; without that scope the write still succeeds and the response carries awarningsentry instead) andrenameOption: {from, to}to rename a product option in place without touching variant IDs (send it on its own; it cannot be rolled back if a later write fails).delete-productdelete-variantdelete-product-imagesbulk-update-productsbulk-delete-productscount-products-by-tagfind-products-by-metafield— list products that have / don't have / both for a givennamespace.key, paginated across the whole catalog via cursorsearch-taxonomy— browse Shopify's product category taxonomy; setincludeAttributes:trueto also return each category's attributes (e.g. Color, Pattern) and their allowed values
Collections
get-collectionsmanage-collection-productscreate-collectionupdate-collectiondelete-collection
Customers
get-customers(supports pagination viacursor)update-customer
Orders
orders— unified lookup/list. Passidfor a single order; omitidto list with filters (customerId,status, pagination viacursor). Replacesget-orders,get-order-by-id, andget-customer-orders.update-order
Draft Orders
draft-orders— unified lookup/list. Passidfor a single draft order; omitidto list with filters (status,query, pagination viacursor).create-draft-orderupdate-draft-ordercomplete-draft-order
Inventory
get-inventory-levelsupdate-inventory
Locations
get-locations
Metafields
get-metafields— server-side filter withkey+namespace(single field) orkeys: ["namespace.key", …](multi) via Shopify's nativemetafields(keys:); setincludeDefinitions:trueto merge ALL definitions with current values so empty/unfilled fields show up (value:null,isSet:false)set-metafield(create or update; supportsmetaobject_reference/list.metaobject_reference)bulk-set-variant-metafields— set metafields across many variants of one product in a singleproductVariantsBulkUpdatecall (up to 250 variants/call). UNIFORM mode (metafields) fans one value out to every variant and auto-discovers the variant IDs; PER-VARIANT mode (variants) sets different values per variant. Avoids oneset-metafieldcall per variant.delete-metafieldlist-metafield-definitions— discover metafield definitions for an owner type (PRODUCT, ORDER, CUSTOMER, …); each entry now includesconstraints(e.g.{key:"category", values:["vp-2","vp-2-2-3", …]}) so agents can see category-gating before writing (e.g.vehicle_*requiresvp-2*Vehicle categories; values on disallowed categories are silently filtered out by Shopify on read).get-metafield-options— resolve a metafield's selectable options in one call (for metaobject-reference fields, returns the available metaobject entries; for choice-lists, the allowed choices)
Metaobjects
list-metaobject-definitionsget-metaobject-definitioncreate-metaobject— optionalstatus(ACTIVE/DRAFT); defaults to Shopify'sDRAFTfor publishable definitions, passACTIVEto publish on createupdate-metaobject— edit fields on an existing entry (only provided keys change); optionalstatusto publish (ACTIVE) or unpublish (DRAFT)delete-metaobjectlist-metaobjects— returnsstatusper entry; optionalstatusfilter (applied client-side to the fetched page)get-metaobject— returns the entry's publishstatus
Files
get-files— list/search files in the storeattach-file-to-product— attach an existing media file to a productdetach-file-from-product— remove a media file from a productcreate-file-upload-session— start a browser upload session (remote mode only)get-file-upload-session— check an upload session (remote mode only)
URL redirects
get-redirectscreate-redirectdelete-redirect
Analytics
get-store-counts- Get all key counts in one call (products, variants, orders, customers, collections)get-product-issues- Audit products for problems (zero inventory, low stock, missing images, zero price)
Bulk Operations
start-bulk-export- Start async bulk export (products, orders, customers, inventory, or custom query)get-bulk-operation-status- Check progress of bulk operationget-bulk-operation-results- Download and parse completed results (summary, sample, or full)
Server
get-status- Report MCP server status, configured store, and connection health
Debugging
Tail Claude Desktop logs:
tail -n 20 -f ~/Library/Logs/Claude/mcp*.logLicense
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
The Mercado Pago MCP Server implements the Model Context Protocol to provide AI agents and LLMs with access to Mercado Pago's APIs and tools within compatible development environments. It acts as an intermediary that translates Mercado Pago resources into executable functions (tools) that AI applications can invoke to perform actions and automate flows. The server simplifies integration, enables using documentation to implement or improve code, and optimizes operations through natural language interactions without manual implementations.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
The Grafbase MCP server sits in front of a GraphQL API and exposes an MCP protocol-compliant interface that allows AI agents and LLMs to explore and query GraphQL APIs using natural language. It provides tools to search schemas, introspect types and fields, and execute GraphQL queries while minimizing context bloat by returning only relevant schema subsets, with built-in support for authentication, authorization, and configurable access control.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Related MCP Servers
- AlicenseCqualityDmaintenanceA Model Context Protocol server that provides comprehensive access to the Shopify Admin GraphQL API, enabling AI assistants to manage Shopify stores programmatically.1001MIT
- AlicenseCqualityDmaintenanceAn MCP server providing AI agents with full access to the Shopify Admin API via 136 tools for managing products, orders, customers, collections, and more.10020 npmMIT
- AlicenseNot gradedqualityDmaintenanceA comprehensive MCP server for Shopify Admin API integration, enabling AI assistants to manage products, orders, customers, inventory, analytics, and more through natural language.20 npm19MIT
- AlicenseNot gradedqualityDmaintenanceProduction-grade MCP server for the Shopify Admin GraphQL API, exposing typed tools for AI agents to manage products, orders, customers, and more.28 npmMIT