Shopify MCP Server
Enables interaction with Shopify store data via the GraphQL Admin API to manage products, customers, orders, and collections. Supports multi-store configurations and provides comprehensive management tools for e-commerce administration in both local and remote environments.
README
Shopify MCP Server
MCP Server for Shopify API, enabling interaction with store data through GraphQL API. This server provides tools for managing products, customers, orders, and more.
📦 Package Name: @tzenderman/shopify-mcp
🚀 NPX Command: npx @tzenderman/shopify-mcp
✅ Fully API Compliant: All 35 tools have been validated against the Shopify Admin GraphQL API specification to ensure compatibility and reliability.
🌐 Deployment Modes: Now supports both local (stdio) and remote (HTTP) deployment:
- Local Mode: Run directly in Claude Desktop via stdio transport
- Remote Mode: Deploy as an HTTP server with OAuth 2.0 authentication on Render, Heroku, etc.
- Documentation: See REMOTE_SERVER.md for remote deployment guide
Features
- Multi-Store Support: Manage multiple Shopify stores from a single MCP server instance
- Product Management: Create, update products, manage variants and images
- Collection Management: Create, update collections and manage product associations
- Customer Management: Load customer data and manage customer tags
- Order Management: Advanced order querying and filtering, draft order creation
- Menu Management: Create, update, and delete navigation menus
- GraphQL Integration: Direct integration with Shopify's GraphQL Admin API
- Comprehensive Error Handling: Clear error messages for API and authentication issues
Prerequisites
- Node.js (version 16 or higher)
- Shopify Custom App Access Token (see setup instructions below)
Setup
Shopify Access Token
To use this MCP server, you'll need to create a custom app in your Shopify store:
- From your Shopify admin, go to Settings > Apps and sales channels
- Click Develop apps (you may need to enable developer preview first)
- Click Create an app
- Set a name for your app (e.g., "Shopify MCP Server")
- Click Configure Admin API scopes
- Select the following scopes based on your needs:
read_products,write_products(for product, variant, image, and collection management)read_customers,write_customers(for customer management)read_orders,write_orders(for order and draft order management)read_online_store_navigation,write_online_store_navigation(for menu management)
- Click Save
- Click Install app
- Click Install to give the app access to your store data
- After installation, you'll see your Admin API access token
- Copy this token - you'll need it for configuration
Usage with Claude Desktop
To manage Shopify stores, add this to your claude_desktop_config.json:
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": [
"@tzenderman/shopify-mcp",
"--stores",
"[{\"id\":\"store1\",\"domain\":\"store1.myshopify.com\",\"accessToken\":\"token1\"},{\"id\":\"store2\",\"domain\":\"store2.myshopify.com\",\"accessToken\":\"token2\"},{\"id\":\"store3\",\"domain\":\"store3.myshopify.com\",\"accessToken\":\"token3\"}]"
]
}
}
}
Important: Each store needs:
id: A unique identifier for the store (e.g., "main", "eu-store", "store1")domain: The myshopify.com domainaccessToken: The Shopify Admin API access token
All tools require a storeId parameter to specify which store to interact with. Use the list-stores tool to see available stores.
For a single store, use the same format with one store in the array:
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": [
"@tzenderman/shopify-mcp",
"--stores",
"[{\"id\":\"my-store\",\"domain\":\"my-store.myshopify.com\",\"accessToken\":\"<YOUR_ACCESS_TOKEN>\"}]"
]
}
}
}
Locations for the Claude Desktop config file:
- MacOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json
Alternative: Run Locally with Environment Variables
Multi-Store with Environment Variable
Create a .env file with your store configurations:
SHOPIFY_STORES='[{"id":"store1","domain":"store1.myshopify.com","accessToken":"token1"},{"id":"store2","domain":"store2.myshopify.com","accessToken":"token2"}]'
Single Store with Environment Variables
For a single store:
SHOPIFY_ACCESS_TOKEN=your_access_token
MYSHOPIFY_DOMAIN=your-store.myshopify.com
Then run:
npx @tzenderman/shopify-mcp
Direct Installation (Optional)
If you want to install the package globally:
npm install -g @tzenderman/shopify-mcp
Then run it with the multi-store format:
@tzenderman/shopify-mcp --stores='[{"id":"my-store","domain":"my-store.myshopify.com","accessToken":"<YOUR_ACCESS_TOKEN>"}]'
Available Tools
Note: All tools (except list-stores) require a storeId parameter to specify which store to interact with.
Image Upload Best Practices
When uploading product images using the create-product-image tool, you have three options:
-
File Path (Most Token-Efficient): Provide the local file path
- When you drag-and-drop an image into Claude, acknowledge the image but provide the file path instead
- Example:
/Users/username/Downloads/product-photo.jpg - The MCP server reads the file directly, using minimal tokens
-
External URL: Provide a URL to an image hosted elsewhere
- Example:
https://example.com/images/product.jpg - Most efficient if the image is already hosted online
- Example:
-
Base64 (Fallback): Provide base64-encoded data
- Uses significantly more tokens (~33% larger than binary)
- Only recommended when file path is not available
Recommended workflow in Claude Desktop:
User: [drags image into chat]
Claude: "I can see the image. To upload it efficiently, what's the file path?"
User: "/Users/timz/Downloads/product-photo.jpg"
Claude: [uses filePath parameter to upload]
Store Management
list-stores- List all configured stores
- Returns store IDs, domains, and API versions
- No inputs required
Job Management
get-job-status- Check the status of an asynchronous job (e.g., from collection product operations)
- Inputs:
storeId(string, required): The store IDjobId(string, required): Job ID (GID format: gid://shopify/Job/...)
- Returns: Job object with
id,done(boolean), and status message - Use this to poll job completion after async operations like
add-products-to-collectionorremove-products-from-collection
Product Management
-
get-products- Get all products or search by title or SKU from a specific store
- Supports three modes: search by title, search by SKU, or get all products
- Inputs:
storeId(string, required): The store ID to querysearchTitle(string, optional): Search products by title (supports wildcards). Example: 'shirt' finds products with 'shirt' in the titlesearchSku(string, optional): Search products by variant SKU (supports wildcards with ). Examples: 'ABC-123' for exact match, or 'ABC-' to find all SKUs starting with 'ABC-'. When provided, searchTitle is ignoredlimit(number, default: 10): Maximum number of products to return
- Returns:
- When searching by SKU: Products with
matchedVariantsarray containing variants that matched the search - When searching by title or getting all: Products with
variantsarray (first 5 variants per product) searchModefield indicates which mode was used: 'sku', 'title', or 'all'
- When searching by SKU: Products with
-
get-variants-by-skus- Efficiently fetch multiple product variants by their SKUs in a single API call
- Optimized for batch operations like creating draft orders with many line items
- Inputs:
storeId(string, required): The store ID to queryskus(array of strings, required): Array of SKUs to search for (max 250 per request)
- Returns:
variants: Object mapping each SKU to its variant details (variantId, price, inventory, product info)summary: Object withrequested,found, andnotFoundcountsnotFoundSkus: Array of SKUs that were not found in the store
- Example usage: Reduce N API calls to 1 when creating draft orders with multiple products
- Note: Maximum 250 SKUs per request due to GraphQL query limits
-
get-product-by-id- Get a specific product by ID from a specific store
- Inputs:
storeId(string, required): The store ID to queryproductId(string): ID of the product to retrieve
-
create-product- Create new product in a specific store
- Inputs:
storeId(string, required): The store ID to create product intitle(string): Title of the productdescriptionHtml(string, optional): Description of the productvendor(string, optional): Vendor of the productproductType(string, optional): Type of the producttags(array of strings, optional): Tags of the productstatus(string, optional): Status of the product "ACTIVE", "DRAFT", "ARCHIVED". Default "DRAFT"
-
update-product- Update an existing product's information
- Inputs:
storeId(string, required): The store IDid(string, required): Product ID (GID format)title(string, optional): Title of the productdescriptionHtml(string, optional): Description of the productvendor(string, optional): Vendor of the productproductType(string, optional): Type of the producttags(array of strings, optional): Tags of the productstatus(string, optional): Status of the product
-
create-product-variant- Create a new variant for an existing product
- Inputs:
storeId(string, required): The store IDproductId(string, required): Product ID (GID format)price(string, optional): Price of the variantcompareAtPrice(string, optional): Compare at pricesku(string, optional): SKU of the variantbarcode(string, optional): Barcode of the variantinventoryPolicy(enum, optional): "DENY" or "CONTINUE"inventoryQuantities(array, optional): Inventory quantities at locationsoptionValues(array of objects, optional): Variant option values with option names (format:[{optionName: "Size", name: "Large"}])taxable(boolean, optional): Whether the variant is taxable
-
update-product-variant- Update an existing product variant
- Inputs:
storeId(string, required): The store IDproductId(string, required): Product ID (GID format)id(string, required): Variant ID (GID format)price(string, optional): Price of the variantcompareAtPrice(string, optional): Compare at pricesku(string, optional): SKU of the variantbarcode(string, optional): Barcode of the variantinventoryPolicy(enum, optional): "DENY" or "CONTINUE"inventoryQuantities(array, optional): Inventory quantities at locationsoptionValues(array of objects, optional): Variant option values with option namestaxable(boolean, optional): Whether the variant is taxable
-
create-product-image- Create a new image for a product (supports URL, file path, or base64 upload)
- Inputs:
storeId(string, required): The store IDproductId(string, required): Product ID (GID format)src(string, optional): URL of the image (external URL)filePath(string, optional): Local file path to the image (most token-efficient)attachment(string, optional): Base64-encoded image data (for backward compatibility)altText(string, optional): Alt text for the imagefilename(string, optional): Filename (optional, inferred from filePath if not provided)
- Note: Either
src,filePath, orattachmentmust be provided - Recommended: Use
filePathfor best token efficiency. When you drag-and-drop an image into Claude, provide the local file path instead of using the base64 data.
-
update-product-image- Update an existing product image's properties
- Inputs:
storeId(string, required): The store IDproductId(string, required): Product ID (GID format)id(string, required): Image ID (GID format)altText(string, optional): Alt text for the image
-
delete-product-image- Delete a product image
- Inputs:
storeId(string, required): The store IDproductId(string, required): Product ID (GID format)id(string, required): Image ID (GID format)
Collection Management
-
get-collections- Get all collections or search collections from a specific store
- Inputs:
storeId(string, required): The store ID to queryquery(string, optional): Search query to filter collectionslimit(number, default: 10): Number of collections to retrieve
- Returns: Collections with product count, rules, images, and pagination info
-
get-collection-by-id- Get a single collection by ID from a specific store
- Inputs:
storeId(string, required): The store ID to querycollectionId(string, required): Collection ID (GID format: gid://shopify/Collection/...)
- Returns: Full collection details including SEO, products (first 10), and rules
-
create-collection- Create a new collection (manual or automated/smart)
- Inputs:
storeId(string, required): The store IDtitle(string, required): Title of the collectiondescriptionHtml(string, optional): HTML descriptionhandle(string, optional): URL handleruleSet(object, optional): Rules for automated/smart collectionsappliedDisjunctively(boolean): Use OR (true) or AND (false) logicrules(array): Array of rule conditionscolumn(enum): Field to match (TITLE, TYPE, VENDOR, TAG, PRODUCT_METAFIELD_DEFINITION, etc.)relation(enum): Comparison operator (EQUALS, CONTAINS, GREATER_THAN, etc.)condition(string): Value to matchconditionObjectId(string, optional): Required for metafield-based rules
products(array of strings, optional): Product IDs for manual collections (GID format)image(object, optional): Collection imagesrc(string): Source URLaltText(string, optional): Alt text
sortOrder(enum, optional): How products are sorted (BEST_SELLING, MANUAL, PRICE_ASC, etc.)templateSuffix(string, optional): Template suffix
- Note: Collection is unpublished by default. Use
publishablePublishmutation to publish.
-
update-collection- Update an existing collection
- Inputs: Same as create-collection, plus:
id(string, required): Collection ID (GID format)
-
add-products-to-collection- Add products to a manual collection (asynchronous operation)
- Inputs:
storeId(string, required): The store IDid(string, required): Collection ID (GID format)productIds(array of strings, required): Product IDs to add (GID format, up to 250 products)
- Returns: Job object with
idanddonestatus for tracking the async operation - Note: Uses
collectionAddProductsV2mutation which processes asynchronously
-
remove-products-from-collection- Remove products from a manual collection (asynchronous operation)
- Inputs:
storeId(string, required): The store IDid(string, required): Collection ID (GID format)productIds(array of strings, required): Product IDs to remove (GID format, up to 250 products)
- Returns: Job object with
idanddonestatus for tracking the async operation - Note: Only works with manual collections (not smart/automated collections)
Customer Management
-
get-customers- Get customers or search by name/email from a specific store
- Inputs:
storeId(string, required): The store ID to querysearchQuery(optional string): Filter customers by name or emaillimit(optional number, default: 10): Maximum number of customers to return
-
get-customer-by-id- Get a single customer by ID with detailed information
- Inputs:
storeId(string, required): The store ID to querycustomerId(string, required): Customer ID (GID format: gid://shopify/Customer/...)
- Returns: Full customer details including addresses, state, tax exemption, spending history, and recent orders (first 10)
-
create-customer- Create a new customer in a specific store
- Inputs:
storeId(string, required): The store IDfirstName(string, required): Customer's first namelastName(string, required): Customer's last nameemail(string, required): Customer's email addressphone(string, optional): Customer's phone numbertags(array of strings, optional): Tags to associate with the customernote(string, optional): Note about the customertaxExempt(boolean, optional): Whether the customer is exempt from taxesaddresses(array of objects, optional): Customer addresses with address1, address2, city, country, province, zip, etc.metafields(array of objects, optional): Metafields to associate with the customer
-
update-customer- Update a customer's information in a specific store
- Inputs:
storeId(string, required): The store ID to update customer inid(string, required): Shopify customer ID (numeric ID only, like "6276879810626")firstName(string, optional): Customer's first namelastName(string, optional): Customer's last nameemail(string, optional): Customer's email addressphone(string, optional): Customer's phone numbertags(array of strings, optional): Tags to apply to the customernote(string, optional): Note about the customertaxExempt(boolean, optional): Whether the customer is exempt from taxesmetafields(array of objects, optional): Customer metafields for storing additional data
-
get-customer-orders- Get orders for a specific customer from a specific store
- Inputs:
storeId(string, required): The store ID to querycustomerId(string, required): Shopify customer ID (numeric ID only, like "6276879810626")limit(optional number, default: 10): Maximum number of orders to return
Order Management
-
get-orders- Get orders with optional filtering from a specific store
- Inputs:
storeId(string, required): The store ID to querystatus(optional string): Filter by order statuslimit(optional number, default: 10): Maximum number of orders to return
-
get-order-by-id- Get a specific order by ID from a specific store
- Inputs:
storeId(string, required): The store ID to queryorderId(string, required): Full Shopify order ID (e.g., "gid://shopify/Order/6090960994370")
-
update-order- Update an existing order with new information in a specific store
- Inputs:
storeId(string, required): The store ID to update order inid(string, required): Shopify order IDtags(array of strings, optional): New tags for the orderemail(string, optional): Update customer emailnote(string, optional): Order notescustomAttributes(array of objects, optional): Custom attributes for the ordermetafields(array of objects, optional): Order metafieldsshippingAddress(object, optional): Shipping address information
Draft Order Management
-
get-draft-orders- Get all draft orders or search draft orders from a specific store
- Inputs:
storeId(string, required): The store ID to queryquery(string, optional): Search query to filter draft orderslimit(number, default: 10): Number of draft orders to retrieve
- Returns: Draft orders with line items (first 10), customer info, and pagination info
-
get-draft-order-by-id- Get a single draft order by ID from a specific store
- Inputs:
storeId(string, required): The store ID to querydraftOrderId(string, required): Draft Order ID (GID format: gid://shopify/DraftOrder/...)
- Returns: Complete draft order details including line items (first 50), addresses, shipping, discounts, and full pricing breakdown
-
create-draft-order- Create a new draft order
- Inputs:
storeId(string, required): The store IDlineItems(array, required): Line items for the ordercustomerId(string, optional): Customer ID (GID format)email(string, optional): Customer emailphone(string, optional): Customer phoneshippingAddress(object, optional): Shipping addressbillingAddress(object, optional): Billing addressnote(string, optional): Note for the draft order (input uses 'note', response returns 'note2')tags(array of strings, optional): TagstaxExempt(boolean, optional): Tax exemption statusshippingLine(object, optional): Shipping details
-
update-draft-order- Update an existing draft order
- Inputs: Same as create-draft-order, plus:
id(string, required): Draft Order ID (GID format)
Menu Management
-
get-menus- Get all navigation menus from a specific store
- Inputs:
storeId(string, required): The store ID to querylimit(number, default: 10): Number of menus to retrieve
- Returns: Menus with nested items (up to 3 levels) and pagination info
-
get-menu- Get a single navigation menu by ID from a specific store
- Inputs:
storeId(string, required): The store ID to querymenuId(string, required): Menu ID (GID format: gid://shopify/Menu/...)
- Returns: Complete menu structure with nested items (up to 3 levels deep)
-
create-menu- Create a new navigation menu
- Inputs:
storeId(string, required): The store IDtitle(string, required): Title of the menuhandle(string, required): URL handle for the menuitems(array, required): Menu items with nested structure support- Each item must have:
title(string, required): Title of the menu itemtype(enum, required): Type of menu item - "FRONTPAGE", "COLLECTIONS", "COLLECTION", "PRODUCT", "CATALOG", "PAGE", "BLOG", "ARTICLE", "POLICY", "HTTP", "SHOP_POLICY"url(string, optional): URL for the menu item (can be relative or absolute)resourceId(string, optional): Resource ID if linking to a product, collection, etc. (GID format)tags(array of strings, optional): Tags to filter a collectionitems(array, optional): Nested menu items for submenus
- Each item must have:
-
update-menu- Update an existing navigation menu
- Inputs:
storeId(string, required): The store IDid(string, required): Menu ID (GID format)title(string, required): Title of the menuhandle(string, optional): URL handle for the menuitems(array, required): Menu items (replaces all existing items)- Same structure as create-menu items, plus:
id(string, optional): Menu item ID (GID format) - for updating existing items
- Same structure as create-menu items, plus:
-
delete-menu- Delete a navigation menu
- Inputs:
storeId(string, required): The store IDid(string, required): Menu ID (GID format)
Debugging
Viewing MCP Logs
If you encounter issues, check Claude Desktop's MCP logs:
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
Debug Logging
To enable detailed debug logging, set the DEBUG environment variable to true in your Claude Desktop config:
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": [
"@tzenderman/shopify-mcp",
"--stores",
"[{\"id\":\"store1\",\"domain\":\"store1.myshopify.com\",\"accessToken\":\"token1\"}]"
],
"env": {
"DEBUG": "true"
}
}
}
}
Debug logging will show:
- Request start/completion timestamps
- GraphQL query variables
- Detailed error information
- Permission-related errors
Request Timeout Configuration
By default, GraphQL requests timeout after 30 seconds. You can customize this with the GRAPHQL_TIMEOUT_MS environment variable:
{
"mcpServers": {
"shopify": {
"command": "npx",
"args": ["@tzenderman/shopify-mcp", "--stores", "[...]"],
"env": {
"GRAPHQL_TIMEOUT_MS": "60000"
}
}
}
}
Common Issues
Request hangs or times out:
- Check that your Shopify app has the required API scopes (see Installation)
- Verify your access token is valid
- Check network connectivity to Shopify
- Enable
DEBUG=trueto see detailed request logs
Permission errors:
- Errors will indicate which scopes are missing
- Go to Shopify Admin > Settings > Apps and sales channels > [Your App] > Configuration
- Add the required scopes and reinstall the app
API Compliance
This server has been thoroughly validated against the Shopify Admin GraphQL API specification:
- ✅ 35 tools validated - All GraphQL operations comply with current Shopify Admin API
- ✅ API version 2023-07 - Default version, configurable per store
- ✅ Comprehensive validation - All mutations and queries have been verified using Shopify's schema validation tools
Key API Changes Implemented
The following tools have been updated to use the latest Shopify API patterns:
- Product Variants: Uses
productVariantsBulkCreateandproductVariantsBulkUpdatemutations - Product Images: Uses media-based API (
productCreateMedia,productUpdateMedia,productDeleteMedia) - Menu Management: Uses direct mutation arguments with
MenuItemCreateInputandMenuItemUpdateInput - Collections: Supports both manual and automated/smart collections with async operations
Development
To contribute or modify this project:
# Clone the repository
git clone https://github.com/tzenderman/shopify-mcp.git
cd shopify-mcp
# Install dependencies
npm install
# Build the project
npm run build
# Run in development mode
npm run dev
Project Structure
src/index.ts- Main server initialization and tool registrationsrc/stores/- Store management and configuration parsingsrc/tools/- Individual tool implementations for Shopify operations
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
E2B
Using MCP to run code via e2b.