shopify-multi-store
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OPT_OUT_INSTRUMENTATION | No | Set to 'true' to turn off Shopify skill telemetry. | |
| SHOPIFY_MULTI_STORE_CONFIG | No | Path to the configuration file. Default: ~/.config/codex-shopify-multi-store/stores.json |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| shopify_graphql_schemaC | Explore the Admin GraphQL schema for this store's API version. |
| shopify_validate_graphql_codeblocksB | Validate Admin GraphQL operations against this store's API version without executing them. |
| shopify_create_productA | Create a product with options, variants and images, and optionally add it to a manual collection. Defaults to status DRAFT and to dryRun:true, which previews the input without creating anything. |
| shopify_update_productA | Update product fields, variants, media and tags. dryRun:true (the default) returns the current product and the change without applying it; dryRun:false applies it and returns before and after. Tags: addTags and removeTags change only the named tags; replaceTags replaces all tags. A status of ARCHIVED or DRAFT takes the product off every sales channel. |
| shopify_create_collectionA | Create a manual collection (optional productIds) or a smart collection (ruleSet). Pass publicationIds to publish to explicitly selected channels. Defaults to dryRun:true, which previews the input without creating anything. |
| shopify_update_collectionA | Update collection fields, rules or image, and add products to a manual collection (addProductIds). dryRun:true (the default) returns the current collection and the change without applying it; dryRun:false applies it and returns before and after. |
| shopify_set_inventoryA | Set available inventory at one location using compare-and-set protection: compareQuantity must equal the current available quantity. Read inventory first (shopify_get resource inventory). dryRun:true (the default) checks and previews without changing anything. |
| shopify_create_discountB | Create a percentage discount code with an explicit start date and customer audience. Defaults to dryRun:true, which resolves segments and previews the discount without creating it. |
| shopify_upload_imageA | Upload a local image file or an HTTPS image to Shopify Files, wait for processing, and return its CDN URL (check it later with shopify_get resource uploaded_image). Defaults to dryRun:true, which previews the upload without sending anything. |
| shopify_update_pricesA | Set price, compareAtPrice and/or unit cost for up to 250 SKUs on one store (store) or the same list on several stores in parallel (stores). Resolves each SKU to the variants whose SKU matches exactly (Shopify search is a prefix match) and groups writes by product. A SKU shared by several variants is skipped unless allowDuplicates:true. Duplicate SKU rows with conflicting values are rejected before any write; identical duplicates are collapsed. After a write, verifies each variant with a separate read-back query and reports per-item outcome (applied, applied_unverified, rejected, not_found, ambiguous, unknown, skipped, mismatch) and a store status (ok, unverified, partial, failed, unknown). Large results are trimmed, never dropped: status, counts and every item that did not apply are always returned. Defaults to dryRun:true. |
| shopify_metafieldsA | Set (metafieldsSet) and/or delete (metafieldsDelete) up to 25 metafields each, for any owner GID. Read them with shopify_get resource metafields. Defaults to dryRun:true. |
| shopify_redirectsA | Create and/or delete up to 100 URL redirects each, with a per-redirect outcome (applied, rejected or unknown) and a store status. List them with shopify_search resource redirects. Requires write_online_store_navigation. Defaults to dryRun:true. |
| shopify_update_orderA | Update order note, email, shipping address and tags (orderUpdate). dryRun:true (the default) returns the current order and the change without applying it; dryRun:false applies it and returns before and after. Tags: addTags and removeTags change only the named tags; replaceTags replaces all tags. Requires write_orders. |
| shopify_tagsA | Add and/or remove tags on a product, order, customer or draft order by GID (tagsAdd/tagsRemove). Defaults to dryRun:true. |
| shopify_update_customerA | Update customer note, email and tags (customerUpdate). dryRun:true (the default) returns the current customer and the change without applying it; dryRun:false applies it and returns before and after. Tags: addTags and removeTags change only the named tags; replaceTags replaces all tags. Email marketing consent is out of scope. Requires write_customers. |
| shopify_create_fulfillmentA | Fulfill the remaining quantities of an order's OPEN and IN_PROGRESS fulfillment orders with optional tracking. notifyCustomer defaults to false. Requires read_merchant_managed_fulfillment_orders and write_merchant_managed_fulfillment_orders (Shopify reports any other missing scope, such as for fulfillment orders assigned to a fulfillment service). Defaults to dryRun:true. |
| shopify_check_accessA | For one or many stores, report the shop identity and granted Admin API access scopes, compare them against every tool's requirement (see src/scope-requirements.ts; tools with several resources or reports are listed as tool:resource), and report missing scopes and which tools would fail. Omit stores to check every configured store. |
| shopify_searchA | List or search one kind of record with cursor pagination, on one store (store) or several in parallel (stores; each store returns its own result and cursor). Resources:
|
| shopify_getA | Read one record by GID from one store. Follow each returned cursor independently. Resources:
|
| shopify_reportA | Run one read-only report across selected stores; each store returns its own result and completeness indicators. Reports:
|
| shopify_search_docs_chunksA | Search Shopify documentation and return source links. No store credentials are sent. |
| shopify_find_actionsA | Search every Shopify Admin API mutation (hundreds of write actions, most without a dedicated tool) by keyword and optional category. Returns each action's name, one-line description, category, whether it is destructive, which dedicated tools already cover it, and a scope hint. Next: shopify_describe_action for the full signature, then shopify_run_action. |
| shopify_describe_actionA | Full signature of one Admin API mutation: arguments with types, the expanded input object fields (required markers, enum values, descriptions), the payload fields, a ready-to-edit GraphQL document with a default selection, a variables template with the required fields, a scope hint, and whether it is destructive (then shopify_run_action needs confirm set to the mutation name). |
| shopify_run_actionA | Run any Shopify Admin API mutation on one to one hundred stores. Give a mutation name (a default document is built) or a full single-mutation document, plus variables shared by every store and/or variablesByStore (IDs differ per store). dryRun (the default) validates the document and variables against each store's API version and looks up every record ID in the variables and the document; nothing is changed. The preview says whether it is complete: targets chosen by a search, saved search, filter, or "all" flag, more than 250 IDs, or IDs that do not resolve make it incomplete, and then applying also needs acknowledgeIncompletePreview: true. dryRun false applies it; every ID is looked up again first, and IDs that do not resolve refuse the apply unless acknowledgeIncompletePreview is true. Destructive actions (delete, cancel, refund and similar) need confirm set to the mutation name. Mutations are never retried automatically. On a hosted server in per-user mode, Shopify limits this to what your own staff account may do. |
| shopify_list_storesA | List every Shopify Admin store that remains connected to this plugin. On a hosted server in per-user mode, lists only the stores you have connected with your own Shopify account and names the others with a link to connect them. This tool does not expose access tokens. |
| shopify_get_shop_infoA | Get identity and account information from one named Shopify Admin store. Use this tool before a sensitive change to make sure that the selected store is correct. |
| shopify_graphql_queryA | Run one read-only GraphQL Admin API query against one named store. Use cursor pagination and request only necessary fields. |
| shopify_graphql_query_manyA | Run the same read-only GraphQL Admin API query across multiple named stores in parallel. Each store returns its own success or error result. |
| shopify_graphql_mutationA | Run one GraphQL Admin API mutation against one named store. Set confirm to true only after the user authorizes the exact store and change. Destructive mutations (see shopify_describe_action; some are destructive only with certain arguments, such as a product status of ARCHIVED or notifyCustomer true) need confirm set to the mutation name instead, and denylisted mutations are refused, exactly as in shopify_run_action. The result reports each top-level mutation field as applied, rejected, or unknown, and the store as applied, rejected, partial, or unknown; after partial or unknown, retry only the rejected fields in a new document. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 29 tools
The typed per-resource tools (create_product, update_order, search, get) are distinct, but the generic escape hatches overlap heavily: shopify_run_action, shopify_graphql_mutation, shopify_graphql_query, and shopify_graphql_query_many all run arbitrary GraphQL, and shopify_get/search/report also read data. Descriptions do draw boundaries (run_action=multi-store any mutation, graphql_mutation=single store, graphql_query=read-only), so an attentive agent can choose, but the surface is confusable.
Every tool carries the shopify_ prefix in snake_case with a mostly predictable verb_noun pattern (shopify_create_product, shopify_update_order, shopify_list_stores, shopify_search). A few deviate to noun-only forms (shopify_metafields, shopify_redirects, shopify_tags), and the graphql_* cluster differs, but overall it is highly readable and consistent.
29 tools is on the heavy side, though the scope (the full Shopify Admin API across multiple stores) partly justifies it and the find/describe/run pipeline generalizes away hundreds of mutations. A few entries (e.g. graphql_query vs graphql_query_many, run_action vs graphql_mutation) could be consolidated, making it somewhat over-provisioned.
The surface covers the core commerce lifecycle (products, collections, orders, customers, inventory, discounts, fulfillments, metafields, redirects, tags) plus a rich reporting layer and read/search tools. Crucially, shopify_run_action with find/describe provides a universal escape hatch for any mutation not covered directly, leaving no real dead ends.