# Shopify MCP Server (please leave a star if you like!) 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: `shopify-mcp`** **🚀 Command: `shopify-mcp` (NOT `shopify-mcp-server`)** Shopify MCP server ## Features - **Product Management**: Full CRUD for products, variants, and options (8 tools) - **Customer Management**: Full CRUD, merge, and address management (8 tools) - **Order Management**: Smart lookup, cancel, close/open, mark as paid, fulfillment, refunds (10 tools) - **Metafield Management**: Get, set, and delete metafields on any resource (3 tools) - **Inventory Management**: Set absolute inventory quantities at locations (1 tool) - **Tag Management**: Add/remove tags on any taggable resource (1 tool) - **Pagination & Sorting**: Cursor-based pagination and sort keys on all list queries - **Advanced Filtering**: Pass-through Shopify query syntax for all list endpoints - **GraphQL Integration**: Direct integration with Shopify's GraphQL Admin API (2026-01) - **Comprehensive Error Handling**: Clear error messages for API and authentication issues ## Prerequisites 1. Node.js (version 18 or higher) 2. A Shopify store with a custom app (see setup instructions below) ## Setup ### Authentication This server supports two authentication methods: #### Option 1: Client Credentials (Dev Dashboard apps, January 2026+) As of January 1, 2026, new Shopify apps are created in the **Dev Dashboard** and use OAuth client credentials instead of static access tokens. 1. From your Shopify admin, go to **Settings** > **Apps and sales channels** 2. Click **Develop apps** > **Build app in dev dashboard** 3. Create a new app and configure **Admin API scopes**: - `read_products`, `write_products` - `read_customers`, `write_customers` - `read_orders`, `write_orders` 4. Install the app on your store 5. Copy your **Client ID** and **Client Secret** from the app's API credentials The server will automatically exchange these for an access token and refresh it before it expires (tokens are valid for ~24 hours). #### Option 2: Static Access Token (legacy apps) If you have an existing custom app with a static `shpat_` access token, you can still use it directly. ### Usage with Claude Desktop **Client Credentials (recommended):** ```json { "mcpServers": { "shopify": { "command": "npx", "args": [ "shopify-mcp", "--clientId", "", "--clientSecret", "", "--domain", ".myshopify.com" ] } } } ``` **Static Access Token (legacy):** ```json { "mcpServers": { "shopify": { "command": "npx", "args": [ "shopify-mcp", "--accessToken", "", "--domain", ".myshopify.com" ] } } } ``` Locations for the Claude Desktop config file: - MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%/Claude/claude_desktop_config.json` ### Usage with Claude Code **Client Credentials:** ```bash claude mcp add shopify -- npx shopify-mcp \ --clientId YOUR_CLIENT_ID \ --clientSecret YOUR_CLIENT_SECRET \ --domain your-store.myshopify.com ``` **Static Access Token (legacy):** ```bash claude mcp add shopify -- npx shopify-mcp \ --accessToken YOUR_ACCESS_TOKEN \ --domain your-store.myshopify.com ``` ### Alternative: Run Locally with Environment Variables If you prefer to use environment variables instead of command-line arguments: 1. Create a `.env` file with your Shopify credentials: **Client Credentials:** ``` SHOPIFY_CLIENT_ID=your_client_id SHOPIFY_CLIENT_SECRET=your_client_secret MYSHOPIFY_DOMAIN=your-store.myshopify.com ``` **Static Access Token (legacy):** ``` SHOPIFY_ACCESS_TOKEN=your_access_token MYSHOPIFY_DOMAIN=your-store.myshopify.com ``` 2. Run the server with npx: ``` npx shopify-mcp ``` ### Direct Installation (Optional) If you want to install the package globally: ``` npm install -g shopify-mcp ``` Then run it: ``` shopify-mcp --clientId= --clientSecret= --domain=.myshopify.com ``` ### Additional Options - `--apiVersion`: Specify the Shopify API version (default: `2026-01`). Can also be set via `SHOPIFY_API_VERSION` environment variable. **⚠️ Important:** If you see errors about "SHOPIFY_ACCESS_TOKEN environment variable is required" when using command-line arguments, you might have a different package installed. Make sure you're using `shopify-mcp`, not `shopify-mcp-server`. ## Available Tools (31) ### Pagination, Sorting & Filtering All list query tools (`get-products`, `get-customers`, `get-orders`, `get-customer-orders`) support: - **Cursor-based pagination**: `after` / `before` (cursor strings), with `pageInfo` in the response (`hasNextPage`, `hasPreviousPage`, `startCursor`, `endCursor`) - **Sorting**: `sortKey` (enum specific to each resource) and `reverse` (boolean) - **Advanced filtering**: `query` or `searchQuery` parameter accepting [Shopify query syntax](https://shopify.dev/docs/api/usage/search-syntax) ### Product Management (8 tools) 1. **`get-products`** - Get all products or search by title with pagination and sorting - Inputs: - `searchTitle` (string, optional): Filter products by title (wraps in `title:*...*`) - `limit` (number, default: 10): Maximum number of products to return - `query` (string, optional): Raw Shopify query string (e.g. `"status:active vendor:Nike tag:sale"`) - `sortKey` (string, optional): One of `CREATED_AT`, `ID`, `INVENTORY_TOTAL`, `PRODUCT_TYPE`, `PUBLISHED_AT`, `RELEVANCE`, `TITLE`, `UPDATED_AT`, `VENDOR` - `reverse` (boolean, optional): Reverse the sort order - `after` / `before` (string, optional): Pagination cursors 2. **`get-product-by-id`** - Get a specific product by ID with full details including SEO, options, media, variants, and collections - Inputs: - `productId` (string, required): Shopify product GID - Returns: `productType`, `descriptionHtml`, `seo`, `options` (with `optionValues`), `media` (images), `variants`, `collections`, `tags`, `vendor`, price range, inventory 3. **`create-product`** - Create a new product. When using `productOptions`, Shopify registers all option values but only creates one default variant (first value of each option, price $0). Use `manage-product-variants` with `strategy: REMOVE_STANDALONE_VARIANT` afterward to create all real variants with prices. - Inputs: - `title` (string, required): Title of the product - `descriptionHtml` (string, optional): Description with HTML - `handle` (string, optional): URL slug. Auto-generated from title if omitted - `vendor` (string, optional): Vendor of the product - `productType` (string, optional): Type of the product - `tags` (array of strings, optional): Product tags - `status` (string, optional): `"ACTIVE"`, `"DRAFT"`, or `"ARCHIVED"`. Default `"DRAFT"` - `seo` (object, optional): `{ title, description }` for search engines - `metafields` (array of objects, optional): Custom metafields (`namespace`, `key`, `value`, `type`) - `productOptions` (array of objects, optional): Options to create inline, e.g. `[{ name: "Size", values: [{ name: "S" }, { name: "M" }] }]`. Max 3 options. - `collectionsToJoin` (array of strings, optional): Collection GIDs to add the product to 4. **`update-product`** - Update an existing product's fields - Inputs: - `id` (string, required): Shopify product GID - `title` (string, optional): New title - `descriptionHtml` (string, optional): New description - `handle` (string, optional): New URL slug - `vendor` (string, optional): New vendor - `productType` (string, optional): New product type - `tags` (array of strings, optional): New tags (overwrites existing) - `status` (string, optional): `"ACTIVE"`, `"DRAFT"`, or `"ARCHIVED"` - `seo` (object, optional): `{ title, description }` for search engines - `metafields` (array of objects, optional): Metafields to set or update - `collectionsToJoin` (array of strings, optional): Collection GIDs to add the product to - `collectionsToLeave` (array of strings, optional): Collection GIDs to remove the product from - `redirectNewHandle` (boolean, optional): If true, old handle redirects to new handle 5. **`delete-product`** - Delete a product - Inputs: - `id` (string, required): Shopify product GID 6. **`manage-product-options`** - Create, update, or delete product options (e.g. Size, Color) - Inputs: - `productId` (string, required): Shopify product GID - `action` (string, required): `"create"`, `"update"`, or `"delete"` - `variantStrategy` (string, optional): `"LEAVE_AS_IS"` (default) or `"CREATE"` — controls whether new variant combinations are generated when adding options - For `action: "create"`: - `options` (array, required): Options to create, e.g. `[{ name: "Size", values: ["S", "M", "L"] }]` - For `action: "update"`: - `optionId` (string, required): Option GID to update - `name` (string, optional): New name for the option - `position` (number, optional): New position - `valuesToAdd` (array of strings, optional): Values to add - `valuesToDelete` (array of strings, optional): Value GIDs to remove - For `action: "delete"`: - `optionIds` (array of strings, required): Option GIDs to delete 7. **`manage-product-variants`** - Create or update product variants in bulk - Inputs: - `productId` (string, required): Shopify product GID - `strategy` (string, optional): How to handle the default variant when creating. `"DEFAULT"` (removes "Default Title" automatically), `"REMOVE_STANDALONE_VARIANT"` (recommended for full control), or `"PRESERVE_STANDALONE_VARIANT"` - `variants` (array, required): Variants to create or update. Each variant: - `id` (string, optional): Variant GID for updates. Omit to create new - `price` (string, optional): Price, e.g. `"49.00"` - `compareAtPrice` (string, optional): Compare-at price for showing discounts - `sku` (string, optional): SKU (mapped to `inventoryItem.sku`) - `tracked` (boolean, optional): Whether inventory is tracked. Set `false` for print-on-demand - `taxable` (boolean, optional): Whether the variant is taxable - `barcode` (string, optional): Barcode - `weight` (number, optional): Weight of the variant - `weightUnit` (string, optional): `"GRAMS"`, `"KILOGRAMS"`, `"OUNCES"`, or `"POUNDS"` - `optionValues` (array, optional): Option values, e.g. `[{ optionName: "Size", name: "A4" }]` 8. **`delete-product-variants`** - Delete one or more variants from a product - Inputs: - `productId` (string, required): Shopify product GID - `variantIds` (array of strings, required): Variant GIDs to delete ### Customer Management (8 tools) 1. **`get-customers`** - List customers with search, pagination, and sorting - Inputs: - `searchQuery` (string, optional): Freetext or Shopify query syntax (e.g. `"country:US tag:vip orders_count:>5"`) - `limit` (number, default: 10): Maximum number of customers to return - `sortKey` (string, optional): One of `CREATED_AT`, `ID`, `LAST_UPDATE`, `LOCATION`, `NAME`, `ORDERS_COUNT`, `RELEVANCE`, `TOTAL_SPENT`, `UPDATED_AT` - `reverse` (boolean, optional): Reverse the sort order - `after` / `before` (string, optional): Pagination cursors 2. **`get-customer-by-id`** - Get a single customer by ID with full details - Inputs: - `id` (string, required): Shopify customer ID (numeric only, e.g. `"6276879810626"`) - Returns: name, email, phone, addresses, tags, note, tax status, amount spent, order count, metafields 3. **`create-customer`** - Create a new customer - Inputs: - `firstName` (string, optional): Customer's first name - `lastName` (string, optional): Customer's last name - `email` (string, optional): Customer's email address - `phone` (string, optional): Customer's phone number - `tags` (array of strings, optional): Tags to apply - `note` (string, optional): Note about the customer - `taxExempt` (boolean, optional): Whether the customer is exempt from taxes - `metafields` (array of objects, optional): Custom metafields (`namespace`, `key`, `value`, `type`) - `addresses` (array of objects, optional): Customer addresses (`address1`, `address2`, `city`, `provinceCode`, `zip`, `country`, `phone`) 4. **`update-customer`** - Update a customer's information - Inputs: - `id` (string, required): Shopify customer ID (numeric only, e.g. `"6276879810626"`) - `firstName` (string, optional): Customer's first name - `lastName` (string, optional): Customer's last name - `email` (string, optional): Customer's email address - `phone` (string, optional): Customer's phone number - `tags` (array of strings, optional): Tags to apply to the customer - `note` (string, optional): Note about the customer - `taxExempt` (boolean, optional): Whether the customer is exempt from taxes - `emailMarketingConsent` (object, optional): Email marketing consent settings - `marketingState` (string, required): `"NOT_SUBSCRIBED"`, `"SUBSCRIBED"`, `"UNSUBSCRIBED"`, or `"PENDING"` - `consentUpdatedAt` (string, optional): ISO 8601 timestamp - `marketingOptInLevel` (string, optional): `"SINGLE_OPT_IN"`, `"CONFIRMED_OPT_IN"`, or `"UNKNOWN"` - `metafields` (array of objects, optional): Customer metafields 5. **`delete-customer`** - Delete a customer - Inputs: - `id` (string, required): Shopify customer ID (numeric only, e.g. `"6276879810626"`) 6. **`customer-merge`** - Merge two customer records into one - Inputs: - `customerOneId` (string, required): GID of the first customer - `customerTwoId` (string, required): GID of the second customer - `overrideFields` (object, optional): Override which fields to keep from which customer (firstName, lastName, email, phone, defaultAddress, note, tags) 7. **`manage-customer-address`** - Create, update, or delete a customer's mailing address - Inputs: - `customerId` (string, required): Customer GID - `action` (string, required): `"create"`, `"update"`, or `"delete"` - `addressId` (string, optional): Address GID (required for update/delete) - `address` (object, optional): Address fields (required for create/update): `address1`, `address2`, `city`, `company`, `countryCode`, `firstName`, `lastName`, `phone`, `provinceCode`, `zip` - `setAsDefault` (boolean, optional): Set as customer's default address ### Order Management (10 tools) 1. **`get-orders`** - Get orders with filtering, pagination, and sorting - Inputs: - `status` (string, optional): `"any"`, `"open"`, `"closed"`, or `"cancelled"`. Default `"any"` - `limit` (number, default: 10): Maximum number of orders to return - `query` (string, optional): Raw Shopify query string (e.g. `"financial_status:paid fulfillment_status:shipped tag:rush"`) - `sortKey` (string, optional): One of `CREATED_AT`, `ORDER_NUMBER`, `TOTAL_PRICE`, `FINANCIAL_STATUS`, `FULFILLMENT_STATUS`, `UPDATED_AT`, `CUSTOMER_NAME`, `PROCESSED_AT`, `ID`, `RELEVANCE` - `reverse` (boolean, optional): Reverse the sort order - `after` / `before` (string, optional): Pagination cursors 2. **`get-order-by-id`** - Get a specific order by ID with smart lookup — accepts order name (`#77235` or `77235`), numeric ID (`8054938337547`), or full GID (`gid://shopify/Order/...`) - Inputs: - `orderId` (string, required): Order name, numeric ID, or full GID - Returns: pricing, customer, shipping/billing addresses, line items, tags, notes, metafields, cancel reason, return status, discount codes, PO number, timestamps 3. **`update-order`** - Update an existing order - Inputs: - `id` (string, required): Shopify order GID - `tags` (array of strings, optional): New tags for the order - `email` (string, optional): Update customer email on the order - `note` (string, optional): Order notes - `phone` (string, optional): Phone number for the order - `poNumber` (string, optional): Purchase order number - `customAttributes` (array of objects, optional): Custom key-value attributes - `metafields` (array of objects, optional): Order metafields - `shippingAddress` (object, optional): Shipping address fields 4. **`get-customer-orders`** - Get orders for a specific customer with pagination and sorting - Inputs: - `customerId` (string, required): Shopify customer ID (numeric only, e.g. `"6276879810626"`) - `limit` (number, default: 10): Maximum number of orders to return - `sortKey` (string, optional): Same sort keys as `get-orders` - `reverse` (boolean, optional): Reverse the sort order - `after` / `before` (string, optional): Pagination cursors 5. **`order-cancel`** - Cancel an order with options for refunding, restocking, and customer notification. **Irreversible.** - Inputs: - `orderId` (string, required): Order GID - `reason` (string, required): `"CUSTOMER"`, `"DECLINED"`, `"FRAUD"`, `"INVENTORY"`, `"OTHER"`, or `"STAFF"` - `restock` (boolean, required): Whether to restock inventory - `notifyCustomer` (boolean, default: false): Notify the customer - `staffNote` (string, optional): Internal note - `refund` (boolean, optional): Refund to original payment method 6. **`order-close-open`** - Close or reopen an order - Inputs: - `orderId` (string, required): Order GID - `action` (string, required): `"close"` or `"open"` 7. **`order-mark-as-paid`** - Mark an order as paid (for manual/offline payments) - Inputs: - `orderId` (string, required): Order GID 8. **`create-fulfillment`** - Create a fulfillment (mark items as shipped) with optional tracking - Inputs: - `lineItemsByFulfillmentOrder` (array, required): Fulfillment orders and line items to fulfill - `trackingInfo` (object, optional): `{ number, url, company }` tracking details - `notifyCustomer` (boolean, default: false): Send shipping notification 9. **`refund-create`** - Create a full or partial refund with optional restocking - Inputs: - `orderId` (string, required): Order GID - `refundLineItems` (array, optional): Line items to refund with `lineItemId`, `quantity`, `restockType` (`CANCEL`/`RETURN`/`NO_RESTOCK`), `locationId` - `shipping` (object, optional): `{ amount, fullRefund }` shipping refund - `note` (string, optional): Refund note - `notify` (boolean, optional): Send refund notification 10. **`create-draft-order`** - Create a draft order for phone/chat sales, invoicing, or wholesale - Inputs: - `lineItems` (array, required): Product variants (`variantId`) or custom items (`title` + price). Max 499 - `customerId` (string, optional): Customer GID - `email`, `phone`, `note`, `tags`, `poNumber` (optional) - `shippingAddress`, `billingAddress` (objects, optional) - `appliedDiscount` (object, optional): `{ title, value, valueType }` order-level discount ### Draft Order Management (1 tool) 1. **`complete-draft-order`** - Complete a draft order, converting it into a real order - Inputs: - `draftOrderId` (string, required): Draft order GID - `paymentGatewayId` (string, optional): Payment gateway GID ### Metafield Management (3 tools) 1. **`get-metafields`** - Get metafields for any Shopify resource (products, orders, customers, variants, collections, etc.) - Inputs: - `ownerId` (string, required): GID of any resource - `namespace` (string, optional): Filter by namespace - `first` (number, default: 25): Number of metafields to return - `after` (string, optional): Pagination cursor 2. **`set-metafields`** - Set metafields on any Shopify resource. Creates or updates up to 25 metafields atomically - Inputs: - `metafields` (array, required): Metafields to set, each with `ownerId`, `key`, `value`, and optional `namespace`, `type` 3. **`delete-metafields`** - Delete metafields from any Shopify resource - Inputs: - `metafields` (array, required): Metafields to delete, each with `ownerId`, `namespace`, `key` ### Inventory Management (1 tool) 1. **`inventory-set-quantities`** - Set absolute inventory quantities for items at specific locations - Inputs: - `reason` (string, required): Reason for change (e.g. `"correction"`, `"cycle_count_available"`) - `name` (string, required): `"available"` or `"on_hand"` - `quantities` (array, required): Items with `inventoryItemId`, `locationId`, `quantity` ### Tag Management (1 tool) 1. **`manage-tags`** - Add or remove tags on any taggable resource (orders, products, customers, draft orders, articles) - Inputs: - `id` (string, required): GID of the resource - `tags` (array of strings, required): Tags to add or remove - `action` (string, required): `"add"` or `"remove"` ### Order Query Filter Reference The `get-orders` tool's `query` parameter supports [Shopify search syntax](https://shopify.dev/docs/api/usage/search-syntax): | Filter | Example | |--------|---------| | `name` | `name:#77235` | | `created_at` | `created_at:>2024-01-01` or `created_at:2024-01-01..2024-03-31` | | `updated_at` | `updated_at:>2024-06-01` | | `financial_status` | `financial_status:paid` | | `fulfillment_status` | `fulfillment_status:shipped` | | `status` | `status:open` | | `email` | `email:customer@example.com` | | `tag` / `tag_not` | `tag:vip tag_not:wholesale` | | `discount_code` | `discount_code:SUMMER20` | | `sku` | `sku:PROD-001` | | `risk_level` | `risk_level:high` | | `gateway` | `gateway:shopify_payments` | | `test` | `test:true` | ## Debugging If you encounter issues, check Claude Desktop's MCP logs: ``` tail -n 20 -f ~/Library/Logs/Claude/mcp*.log ``` ## License MIT