Building a Shopify MCP Server with Claude: Complete Tutorial

Model Context Protocol (MCP) servers let you extend Claude's capabilities with custom tools and data sources. A Shopify MCP server is a bridge between Claude and your Shopify store—giving Claude real-time access to orders, products, inventory, and customers. You can then automate customer service, product recommendations, bulk operations, and strategic analysis without touching the Shopify admin dashboard.

This guide walks you through building, testing, and deploying a Shopify MCP server that Claude can call.

What Is MCP and Why Shopify?

MCP is Anthropic's open standard for connecting Claude to external tools and data. Think of it as a standardized API layer. You build an MCP server; Claude discovers its capabilities; Claude calls them when needed.

The use cases for a Shopify MCP are straightforward:

  • Customer service automation — Claude reads an order, reviews order history, and drafts a personalized refund response
  • Product recommendations — Claude analyzes purchase history and current inventory to recommend the next product
  • Bulk operations — Tag 500 customers by purchase behavior; update 1000 product descriptions with SEO keywords
  • Strategic analysis — "Which products have inventory over-stock?" "What's our customer LTV by cohort?"

Traditional APIs require you to write code in Python or Node.js and deploy it somewhere. MCP servers can run locally (on your laptop or server) or deployed as Lambda functions. Claude calls them in real time.

Architecture: How Claude Talks to Your Shopify Store

Claude (Claude Code or API)
    ↓
MCP Client (Claude's local tool runner)
    ↓
Your MCP Server (Python/Node.js)
    ↓
Shopify Admin API / Storefront API
    ↓
Your Shopify Store Data (orders, products, customers, inventory)

The MCP server acts as a translator: Claude sends a request ("Get orders from the last 7 days"); the MCP server converts that into a Shopify GraphQL query; Shopify returns data; the MCP server formats it for Claude.

Step 1: Set Up Your Shopify Admin API Credentials

You need a Shopify Admin API key to authenticate. Here's how:

  1. Log into your Shopify admin
  2. Go to SettingsApps and integrationsDevelop apps
  3. Click Create an app
  4. Name it "Claude MCP Server"
  5. Select Admin API permissions. Request these scopes:
    • read_orders
    • read_products
    • read_customers
    • write_orders (if you want to update orders)
    • write_products (if you want to update products)
    • write_inventory (if you want to manage inventory)
  6. Copy your API Access Token and Store URL (e.g., mystore.myshopify.com)

Store these in a .env file:

SHOPIFY_STORE_URL=mystore.myshopify.com
SHOPIFY_API_KEY=shpat_xxxxxxxxxxxxx
SHOPIFY_API_VERSION=2026-01

Step 2: Build Your MCP Server

Here's a minimal Python MCP server using the mcp library:

import os
import json
import httpx
from typing import Any
from mcp.server import Server, RequestContext
from mcp.types import Tool, TextContent, ToolResponse

# Initialize MCP server
server = Server("shopify-mcp")

# Load credentials from .env
SHOPIFY_STORE_URL = os.getenv("SHOPIFY_STORE_URL")
SHOPIFY_API_KEY = os.getenv("SHOPIFY_API_KEY")
SHOPIFY_API_VERSION = os.getenv("SHOPIFY_API_VERSION", "2026-01")

SHOPIFY_URL = f"https://{SHOPIFY_STORE_URL}/admin/api/{SHOPIFY_API_VERSION}/graphql.json"

def run_shopify_query(query: str, variables: dict = None) -> dict:
    """Execute a GraphQL query against Shopify Admin API."""
    headers = {
        "X-Shopify-Access-Token": SHOPIFY_API_KEY,
        "Content-Type": "application/json",
    }
    payload = {
        "query": query,
        "variables": variables or {}
    }
    
    response = httpx.post(SHOPIFY_URL, json=payload, headers=headers)
    response.raise_for_status()
    data = response.json()
    
    if "errors" in data:
        raise Exception(f"Shopify GraphQL error: {data['errors']}")
    
    return data["data"]

@server.call_tool()
def get_recent_orders(days: int = 7) -> str:
    """Fetch orders from the last N days."""
    query = """
    query GetRecentOrders($query: String!) {
        orders(first: 50, query: $query) {
            edges {
                node {
                    id
                    name
                    email
                    totalPriceSet {
                        shopMoney {
                            amount
                            currencyCode
                        }
                    }
                    createdAt
                    displayFulfillmentStatus
                    lineItems(first: 5) {
                        edges {
                            node {
                                title
                                quantity
                            }
                        }
                    }
                }
            }
        }
    }
    """
    
    variables = {
        "query": f"created:>={days}d"
    }
    
    result = run_shopify_query(query, variables)
    return json.dumps(result, indent=2)

@server.call_tool()
def get_product_by_handle(handle: str) -> str:
    """Fetch product details by handle (URL slug)."""
    query = """
    query GetProduct($handle: String!) {
        productByHandle(handle: $handle) {
            id
            title
            description
            totalInventory
            priceRange {
                minVariantPrice {
                    amount
                    currencyCode
                }
                maxVariantPrice {
                    amount
                    currencyCode
                }
            }
            variants(first: 10) {
                edges {
                    node {
                        id
                        title
                        sku
                        inventoryQuantity
                        price
                    }
                }
            }
        }
    }
    """
    
    variables = {"handle": handle}
    result = run_shopify_query(query, variables)
    return json.dumps(result, indent=2)

@server.call_tool()
def get_customer(email: str) -> str:
    """Fetch customer by email."""
    query = """
    query GetCustomer($email: String!) {
        customers(first: 1, query: $email) {
            edges {
                node {
                    id
                    email
                    firstName
                    lastName
                    lifetimeValue {
                        amount
                        currencyCode
                    }
                    ordersCount
                    createdAt
                    lastOrder {
                        createdAt
                        totalPriceSet {
                            shopMoney {
                                amount
                            }
                        }
                    }
                }
            }
        }
    }
    """
    
    variables = {"email": email}
    result = run_shopify_query(query, variables)
    return json.dumps(result, indent=2)

if __name__ == "__main__":
    server.run()

Step 3: Register Tools with Claude

Once your MCP server is running, Claude needs to discover its tools. Add this to your Claude Code config (or Claude API settings):

{
  "mcpServers": {
    "shopify": {
      "command": "python",
      "args": ["/path/to/shopify_mcp.py"],
      "env": {
        "SHOPIFY_STORE_URL": "mystore.myshopify.com",
        "SHOPIFY_API_KEY": "shpat_xxxxx"
      }
    }
  }
}

Claude will now see three tools:

  1. get_recent_orders — Fetch recent orders
  2. get_product_by_handle — Fetch product details
  3. get_customer — Fetch customer info

Step 4: Query from Claude

Now you can ask Claude questions and it will use your MCP server:

Claude Code Prompt:
"What's our average order value from the last 7 days? Show me the top 5 products by order count."

Claude's Internal Logic:
1. Calls get_recent_orders(days=7)
2. Parses the order data
3. Calculates average order value
4. Counts product occurrences
5. Returns analysis

Advanced Patterns

Pattern 1: Bulk Customer Tagging by Behavior

Ask Claude: "Tag all customers who spent over $500 in the last 30 days with 'high-value'"

Claude would:

  1. Call get_recent_orders(days=30) to fetch all orders
  2. Aggregate by customer email
  3. Filter customers with total spend > $500
  4. Call a custom tag_customer() tool to apply the "high-value" tag

Pattern 2: Inventory Alerts

Ask Claude: "Which products have less than 5 units in stock?"

Claude would:

  1. Call a custom list_all_products() tool (you'd need to build this)
  2. Filter by inventory quantity
  3. Return a formatted list with product names, SKUs, and stock levels

Pattern 3: Customer Service Automation

Ask Claude: "I have a refund request from [email protected] for order #1234. Should we approve it? Draft a response."

Claude would:

  1. Call get_customer(email="[email protected]")
  2. Call a custom get_order(id="1234") tool
  3. Analyze purchase history and order details
  4. Draft a personalized response

Deployment Options

Option 1: Local Development (Free)

Run the MCP server on your laptop. Works for manual requests but not scalable for production.

Option 2: AWS Lambda (Serverless)

Deploy your MCP server as a Lambda function. Cost: ~$0.20/million requests (negligible for most use cases).

Option 3: Docker Container

Containerize your MCP server and deploy to AWS ECS, Google Cloud Run, or DigitalOcean App Platform. Cost: $5–$30/month depending on traffic.

Common Pitfalls

Pitfall 1: Rate Limiting

Shopify Admin API has rate limits (2 requests/second for most plans). If Claude makes 10 requests in quick succession, you'll hit the limit. Solution: Add exponential backoff retry logic.

Pitfall 2: GraphQL Complexity

Each Shopify GraphQL query has a complexity score. Too many nested fields = error. Solution: Keep queries focused (query only fields you need).

Pitfall 3: API Permissions

If Claude asks for something your API key doesn't have permission for, it fails silently. Solution: Regularly audit your scopes. Only request what you need.

The Tenten Shopify MCP

Tenten has built a production-grade Shopify MCP server used by Shopify Plus partners for:

  • Customer service automation (reduce response time by 60%)
  • Bulk product updates (update 1000 product descriptions in 5 minutes)
  • Inventory analysis (identify over-stock and under-stock patterns)
  • Strategic cohort analysis (LTV by acquisition channel, repeat purchase rate by product)

Our MCP server includes authentication, error handling, rate limit management, and caching. We can customize it for your specific use cases.


Ready to Automate Your Shopify Operations with Claude?

Building an MCP server requires understanding both Shopify's API and Claude's tool calling conventions. Tenten specializes in Shopify API architecture, MCP development, and Claude integration for Shopify Plus merchants. We can build a custom MCP server tailored to your operational needs.

Contact Tenten for an MCP development consultation at tenten.co/contact.


Editorial Note

This tutorial draws on Tenten's production deployments of Shopify MCP servers for Shopify Plus partners. Code examples use Python 3.10+ and the mcp library (Anthropic). Shopify API version 2026-01 (current as of April 2026).