Safe-write Shopify operations: plan-before-execute writes with out-of-band approval and audit.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent โ or use 1-click editor setup below.
๐ก Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
An agent can read and modify a Shopify store without being able to cause an unrecoverable accident. The safety layer is the differentiator: every write previews before it commits, large or irreversible changes require out-of-band human approval, and every action is recorded to a tamper-evident hash-chained audit file.
The two-phase pattern (preview โ token โ execute) is the core discipline. Every write tool:
approvalRequiredAboveItems (default 25) or containing always-gated operations wait for human approval at the token-bearing URL the server prints on startup (e.g. http://127.0.0.1:4319/?token=<token>)STATE_CHANGED), then applies mutations per-item with a full success/failure ledgerA plan whose manifest exceeds hardMaxItems (default 250) is refused outright โ no token, no approval path.
Irreversible operations (cancel_order, refund_order) always require approval regardless of item count and cannot be rolled back. Reversible operations (price changes, inventory adjustments) support rollback within a configurable window (default 24 hours).
The risk is not a malicious agent โ the agent is trusted to author correct GraphQL. The risk is a trusted-but-fallible agent: syntactically perfect, well-formed operations whose scope is the problem.
The killer scenario โ a syntactically perfect bulk reprice with a misplaced decimal:
A 500-product bulk update that runs without preview-and-approve, or where the agent's price calculation contains a typo, produces exactly the wrong result at scale. Approval would catch it: a human sees "change 500 prices from $X to $1.50" and flags theไธๅฏนๅฒ. Without approval, or without the preview that makes the damage visible before it happens, the error lands silently in Shopify.
Three mechanisms carry the safety guarantee:
1. Preview-first, computed-diff. Every write tool reads current state and computes the manifest ({ref, before, after} pairs) without calling any mutation. A STATE_CHANGED re-read at execute time refuses the write if the world moved since preview. The blast radius is visible before anything changes.
2. Approval gating above the threshold. Plans touching >= approvalRequiredAboveItems items (default 25) require human approval. The threshold is sized for "is this large enough to warrant a human eye?" โ meaningful for bulk value changes; irrelevant for one-item operations (which get unconditional approval for irreversible ops instead).
3. Plan token bound to exact manifest. The token is a SHA-256 fingerprint of the exact previewed manifest โ not an opaque ID. Swapping in a wider set of items or a different price at execute time produces a different fingerprint and is refused as STATEMENT_MISMATCH.
Rollback provides recovery for reversible mistakes (wrong price, wrong inventory level) within the rollback window. It does not recover from the irreversible operations: a cancelled order stays cancelled, a refunded payment stays refunded.
Set the required environment variable and point Claude Desktop at the server (see Configuration below). node dist/index.js starts the localhost approval UI alongside the MCP stdio server.
Demo: the step-by-step walkthrough script (store-wide reprice refused โ approval-gated reprice โ one-call rollback โ hash-chained audit) is in docs/demo-runbook.md.
Configuration file (default config.json in the working directory, or path via SHOPIFY_CONFIG):
| Field | Type | Default | Description |
|---|---|---|---|
shopify.storeDomain | string | (required) | MyShopify domain, e.g. "my-store.myshopify.com" |
shopify.apiVersion | string | "2026-04" | Pinned quarterly Admin API version |
shopify.adminToken | string | (env only) | Admin API token โ never in config file, only SHOPIFY_ADMIN_TOKEN env var |
plans.planTtlMs | positive int | 60000 | How long a plan token stays valid (ms). Overridable: SHOPIFY_PLAN_TTL_MS |
plans.approvalRequiredAboveItems | positive int | 25 | Plans touching this many items require human approval. Overridable: SHOPIFY_APPROVAL_REQUIRED_ABOVE_ITEMS |
plans.hardMaxItems | positive int | 250 | Plans exceeding this item count are refused outright. Overridable: SHOPIFY_HARD_MAX_ITEMS |
plans.maxPriceChangePct | positive int | 30 | Price changes exceeding this % require approval. Overridable: SHOPIFY_MAX_PRICE_CHANGE_PCT |
plans.rollbackTtlMs | positive int | 86400000 | Rollback window (ms, default 24h). Overridable: SHOPIFY_ROLLBACK_TTL_MS |
approvalServer.enabled | boolean | true | Start localhost approval UI alongside MCP server. Overridable: SHOPIFY_APPROVAL_SERVER_ENABLED |
approvalServer.port | positive int | 4319 | Port for localhost approval UI (127.0.0.1 only). Overridable: SHOPIFY_APPROVAL_SERVER_PORT |
approvalServer.requireAuth | boolean | true | Require the per-session bearer token on every approval-server route. Set false to fall back to pre-0.4.0 behavior (not recommended). Overridable: SHOPIFY_APPROVAL_SERVER_REQUIRE_AUTH |
approvalServer.authToken | string? | (env only) | Explicit bearer token for the approval server โ never in config file, only SHOPIFY_APPROVAL_SERVER_AUTH_TOKEN env var. Unset means a random token is generated per start and printed once on stderr. |
protectedTags | string[] | ["do-not-touch"] | Tags that plans may never modify. Overridable: SHOPIFY_PROTECTED_TAGS (comma-separated) |
callerId | string | "unknown" | Identity recorded on every audit row. Overridable: SHOPIFY_CALLER_ID |
Invariant: plans.hardMaxItems must be >= plans.approvalRequiredAboveItems. The loader throws if violated.
All config fields are overridable by environment variables (precedence: env > config file > default). SHOPIFY_ADMIN_TOKEN is required and only ever read from the environment.
search_productsSearch products by title, SKU, vendor, or tag. Returns products with variants, current prices, and per-location inventory levels.
Arguments:
| Field | Type | Description |
|---|---|---|
title | string? | Matches products whose title contains the term (Shopify fuzzy search) |
sku | string? | Matches products with a variant whose SKU equals the term |
vendor | string? | Matches products from this vendor |
tag | string? | Matches products carrying this tag |
first | positive int? | Page size passed to Admin API (default 50) |
Returns: products[] with id, title, vendor, tags, variants (each with id, sku, price, inventoryItemId, inventoryLevels), plus flags.protected / flags.protectedTags indicating whether the product carries a protected tag.
Safety properties: Pure read โ zero mutation calls. Protected-tagged products are returned (never filtered out) so a later write plan that touches them is refused.
list_ordersList orders filtered by financial status, fulfillment status, and date range.
Arguments:
| Field | Type | Description |
|---|---|---|
financialStatus | FinancialStatus? | "pending" | "authorized" | "partially_paid" | "paid" | "partially_refunded" | "refunded" | "voided" |
fulfillmentStatus | FulfillmentStatus? | "fulfilled" | "partial" | "unfulfilled" |
createdAfter | ISO-8601 string? | Orders created at or after this datetime |
createdBefore | ISO-8601 string? | Orders created at or before this datetime |
first | positive int? | Page size (default 250) |
Returns: orders[] with id, name, financialStatus, fulfillmentStatus, totalPrice, lineItems[].
Safety properties: Pure read โ zero mutation calls.
All write tools go through preview โ token โ (approval) โ execute.
update_inventorySet absolute inventory quantities at a named location for multiple inventory items. Preview reads current levels; execute calls inventorySetQuantities.
Arguments:
No reviews yet โ be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/shopify-operations-mcp)<a href="https://allmcps.com/mcp/shopify-operations-mcp"><img src="https://allmcps.com/api/badge/shopify-operations-mcp?style=directory" alt="Shopify Operations MCP on AllMCPs" /></a>