# Shopify Admin MCP [Health: Active]

**Category:** 🛒 E-Commerce  
**Repository:** https://github.com/A1-x-Tech/mcp-shopify-admin  
**GitHub Stars:** 0  
**npm Downloads (last month):** 1065  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/shopify-admin-mcp

## Description
MCP server for the Shopify Admin API: products, orders, customers, inventory, discounts.

## Tools
Capabilities this server exposes over MCP:

- **get_shop** — Возвращает магазин, к которому привязан сервер: название, myshopifyDomain, основной домен витрины, валюту, тариф (plan), контактный email, часовой пояс, число товаров и список локаций (id локаций нужны инструменту set_inventory). Аргументов не принимает — магазин задан в SHOPIFY_STORE_DOMAIN и не выбирается для отдельного вызова. Как и у всех инструментов здесь, в ответе есть cost: состояние cost-бакета GraphQL (actualQueryCost — сколько стоил запрос, currentlyAvailable/maximumAvailable — остаток и размер бакета, restoreRate — восстановление в секунду).
- **list_products** — Возвращает страницу товаров магазина (id, название, handle, статус, вендор, тип, теги, общий остаток, до 5 вариантов с ценами) плюс count — число товаров под тем же фильтром. Пагинация курсорная: в ответе pageInfo-поля hasNextPage и endCursor, следующий вызов передаёт endCursor в after; параметра "номер страницы" у Shopify нет. query — строка поиска Shopify, например "status:active", "vendor:Nike created_at:>=2026-01-01", "title:*shirt*". Страница first до 250 за один вызов дешевле по cost-бакету, чем много мелких страниц.
- **get_product** — Возвращает один товар целиком: описание (HTML), опции, до 100 вариантов с ценами, остатками, SKU и id inventoryItem (этот id нужен инструменту set_inventory). Принимает числовой id или gid://shopify/Product/<id>. Несуществующий товар — это data: null, а не ошибка. Медиафайлы и метаполя не возвращает — за ними graphql_request.
- **create_product** — Создаёт товар и возвращает его с дефолтным вариантом, который Shopify добавляет сам. Товар НЕ появляется на витрине: созданные через API товары не опубликованы ни в одном канале продаж, и публикация делается отдельной операцией publishablePublish (её здесь нет — только через graphql_request). Статус по умолчанию — ACTIVE, но это не публикация: status: "DRAFT" дополнительно помечает товар черновиком. Цена задаётся следующим вызовом update_variant по id созданного дефолтного варианта (он есть в ответе). Варианты, изображения и остатки этот инструмент не создаёт. Повторный вызов создаст второй такой же товар. Провал приходит как ошибка с userErrors — HTTP-статус Shopify всегда 200.
- **update_product** — Перезаписывает переданные поля товара (название, описание, вендор, тип, теги, статус) и не трогает остальные. tags замещают весь список тегов, а не добавляются к нему. Цены и остатки здесь не меняются — цены через update_variant, остатки через set_inventory. status: DRAFT снимает товар с витрины, ARCHIVED архивирует (обратимо — вернуть можно, снова передав ACTIVE). Провал приходит как ошибка с userErrors.
- **update_variant** — Задаёт цену и/или зачёркнутую цену (compareAtPrice) вариантам одного товара — до 250 вариантов за вызов, каждый элемент variants несёт id варианта и новые значения. Суммы — десятичные строки в валюте магазина ("1999.00"); compareAtPrice: null убирает зачёркнутую цену. Больше ничего в варианте не меняет (SKU, штрихкод, опции — через graphql_request). Требуется id товара-родителя: он есть в ответах list_products и get_product. Провал приходит как ошибка с userErrors.
- **list_orders** — Возвращает страницу заказов, новые первыми (номер, дата, финансовый статус, статус выдачи, сумма, клиент) плюс count под тем же фильтром. Пагинация курсорная: hasNextPage/endCursor в ответе, следующий вызов передаёт endCursor в after. query — строка поиска Shopify: "financial_status:pending", "fulfillment_status:unfulfilled", "created_at:>=2026-08-01", "email:ivan@example.com". Нужен scope read_orders; заказы старше 60 дней требуют ещё read_all_orders — без него они просто не приходят.
- **get_order** — Возвращает один заказ целиком: позиции (до 100), суммы (итог, доставка, возвраты), адрес доставки, заметку, теги, отгрузки с трек-номерами. Принимает числовой id или gid://shopify/Order/<id> — id, не «номер» вида #1001 (номер ищется через list_orders с query "name:#1001"). Несуществующий заказ — это data: null, а не ошибка.
- **cancel_order** — НЕОБРАТИМО отменяет заказ. Два решения обязательны и не имеют значений по умолчанию: refund — вернуть ли деньги покупателю, restock — вернуть ли позиции на склад. notifyCustomer управляет письмом покупателю. Отмена выполняется фоновой задачей: в ответе job, а не обновлённый заказ — итог стоит проверить через get_order. Уже выданный (fulfilled) заказ Shopify отменить не даст — это придёт ошибкой userErrors. Расформировать отмену нельзя; частичные возвраты этот инструмент не делает.
- **list_customers** — Возвращает страницу клиентов (имя, email, телефон, число заказов, потраченная сумма, город) плюс count — число клиентов под тем же фильтром. Пагинация курсорная: hasNextPage/endCursor в ответе, следующий вызов передаёт endCursor в after. query — строка поиска Shopify: "email:ivan@example.com", "phone:+79001234567", "state:enabled", "created_at:>=2026-01-01". Клиентов не создаёт и не меняет — записи с персональными данными изменяются только через graphql_request. Нужен scope read_customers.
- **get_customer** — Возвращает одного клиента целиком: контакты, адреса, заметку, теги и его 10 последних заказов с суммами. Принимает числовой id или gid://shopify/Customer/<id>; клиент по email ищется через list_customers с query "email:...". Несуществующий клиент — это data: null, а не ошибка.
- **list_locations** — Возвращает локации магазина (склады и точки), включая неактивные: id, название, адрес, активность, выполняет ли онлайн-заказы. Именно id локации нужен инструменту set_inventory. У большинства магазинов локаций одна-две, так что страницы по умолчанию хватает.
- **set_inventory** — Устанавливает АБСОЛЮТНЫЙ доступный остаток (available) позиций на локациях — «стало N», не «изменить на N»: повторный вызов с теми же числами ничего не меняет. Каждый элемент quantities несёт inventoryItemId (id inventoryItem варианта — он в ответе get_product, это НЕ id варианта), locationId (из list_locations) и quantity >= 0. reason — из закрытого словаря Shopify, по умолчанию correction. Историю движений не пишет и резервы не трогает. Провал приходит как ошибка с userErrors — например, если позиция не отслеживается (inventory tracking выключен) или не привязана к локации.
- **list_discounts** — Возвращает страницу скидок магазина — промокодных и автоматических: тип (__typename), название, статус, период действия, лимит использований, для кодовых — до 5 кодов и счётчик применений. Пагинация курсорная (hasNextPage/endCursor → after). query — строка поиска Shopify: "status:active", "type:code", "title:BLACKFRIDAY". Ничего не создаёт и не выключает.
- **create_basic_discount** — Создаёт базовую промокодную скидку: один код, процент (percentage, доля 0..1: 0.2 = −20%) ИЛИ фиксированная сумма (amount в валюте магазина) — ровно одно из двух, для всех клиентов на все товары. startsAt по умолчанию — сейчас, то есть код начинает действовать немедленно; отложенный запуск задаётся явным startsAt. usageLimit — общий лимит применений, appliesOncePerCustomer — не больше раза на клиента. Скидки на отдельные коллекции/сегменты, BXGY и бесплатная доставка здесь не создаются (graphql_request), выключение скидки — тоже. Повторный вызов с тем же кодом провалится userErrors: код должен быть уникален.
- **graphql_request** — Выполняет произвольный GraphQL-документ против Admin API магазина — для всего, чему нет отдельного инструмента (метаполя, медиа, коллекции, вебхуки, сегменты, bulk-операции). Токен, магазин и версию API подставляет сервер; переменные — через variables. Помечен destructive, потому что документ может быть мутацией; query безопасен. ВАЖНО: у мутаций Shopify HTTP 200 не значит успех — реальный вердикт в userErrors внутри data, и здесь он возвращается как есть, без интерпретации: поле userErrors нужно проверить самому. Ретраев для мутаций нет (повтор мог бы применить изменение дважды) — вид операции определяется разбором документа, поэтому мутация с фрагментом перед ней тоже не повторяется; THROTTLED повторяется сам после паузы. Стоимость запроса видна в cost ответа — глубокие вложенные выборки стоят дорого, а дороже 1000 очков запрос отклоняется валидатором Shopify.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "shopify-admin-mcp": {
    "command": "npx",
    "args": ["-y","mcp-shopify-admin@latest"],
    "env": {
      "SHOPIFY_STORE_DOMAIN": "",
      "SHOPIFY_CLIENT_ID": "",
      "SHOPIFY_CLIENT_SECRET": "",
      "SHOPIFY_ACCESS_TOKEN": ""
    }
  }
}
```

**Requires environment variables:** `SHOPIFY_STORE_DOMAIN`, `SHOPIFY_CLIENT_ID`, `SHOPIFY_CLIENT_SECRET`, `SHOPIFY_ACCESS_TOKEN` — the values above are empty placeholders; fill in real credentials before running (see the repository for what each one is for).

## Documentation

## What Shopify Admin MCP does

Shopify Admin MCP exposes one Shopify store through the Admin GraphQL API and makes common commerce operations available as MCP tools. It can inspect shop details, locations, products, orders, customers, inventory, and discounts. Supported writes include creating and updating products, changing variant prices, setting inventory quantities, cancelling eligible orders, and creating basic promotional codes.

The server is scoped to the store configured in `SHOPIFY_STORE_DOMAIN`; individual tool calls cannot switch stores. Its `graphql_request` tool extends coverage to Admin API operations without dedicated wrappers, including metafields, media, collections, webhooks, segments, and bulk operations.

## How it works

The server is an npm package launched locally with `npx` and communicates with MCP clients over stdio. It uses either Shopify Dev Dashboard app credentials or an existing Admin access token. With a client ID and secret, it obtains an Admin API token, holds that token in memory, and renews it before Shopify's 24-hour expiry.

List operations use Shopify search syntax and cursor pagination. Responses include `hasNextPage` and `endCursor`; a later call passes the cursor as `after`. Product, order, and customer lookups accept Shopify numeric IDs or the corresponding GraphQL global IDs. Order numbers such as `#1001` must first be located through an order search.

Every result includes GraphQL cost information, including the request cost and the remaining query bucket. Shopify mutation failures are reported through `userErrors`, even when the HTTP response status is 200. Arbitrary GraphQL mutations are marked destructive and are not automatically retried; throttled requests can be retried after a delay.

## Setup and configuration

Use Node.js 20 or newer, a Shopify store domain, and Admin API credentials. The recommended configuration uses a Shopify Dev Dashboard app whose app and store belong to the same Shopify organization. A legacy ready-made token from a custom app can be supplied instead.

Example launch command:

```bash
npx -y mcp-shopify-admin@latest
```

Configure the process in an MCP client with these environment variables:

- `SHOPIFY_STORE_DOMAIN` — the store domain, such as `my-store.myshopify.com`.
- `SHOPIFY_CLIENT_ID` and `SHOPIFY_CLIENT_SECRET` — credentials for the recommended token exchange flow.
- `SHOPIFY_ACCESS_TOKEN` — an alternative to the client ID and secret when using an existing token.

The package includes setup examples for Codex, Claude Code, Claude Desktop local configurations, Cursor, and VS Code. Browser-only ChatGPT and Claude web sessions cannot start this local stdio process directly.

## Tools and capabilities

The dedicated tools cover the following areas:

- Read shop information, locations, products, orders, customers, and discounts.
- Search products, orders, and customers using Shopify query syntax.
- Create products and update product fields or variant prices.
- Set absolute available inventory quantities for inventory items at locations.
- Cancel orders with explicit refund and restock decisions, then inspect the background job result through `get_order`.
- Create basic percentage or fixed-amount discount codes.
- Send custom Admin GraphQL queries or mutations with variables.

Product creation adds a default variant but does not publish the product, set its price, create media, or add inventory. Publication requires a separate Shopify operation through `graphql_request`. Inventory updates use the inventory item ID, not the variant ID, and set the final available quantity rather than applying a delta.

## Limitations and notes

Order cancellation is irreversible, cannot handle fulfilled orders, and does not support partial refunds. Older orders require the `read_all_orders` scope in addition to `read_orders`; customer operations require `read_customers`.

The dedicated discount tool creates only basic, store-wide code discounts. Collection or segment targeting, buy-one-get-one offers, free shipping, and disabling discounts require custom GraphQL operations. Customer records are read-only through the dedicated tools.

GraphQL queries are subject to Shopify's cost limits, and a request costing more than 1,000 points is rejected by Shopify's validator. Deep nested selections can consume the cost bucket quickly. For mutations, callers should inspect `userErrors` rather than treating HTTP 200 as success.

_Full upstream README: https://allmcps.com/mcp/shopify-admin-mcp/readme_

