Shopify MCP Manager
# Shopify MCP Manager
An MCP (Model Context Protocol) server for fully managing a Shopify store through AI assistants like Cursor or Claude Desktop.
## Architecture
```
┌─────────────────┐ stdio ┌──────────────────┐ GraphQL ┌──────────────┐
│ Cursor / Claude │◄──────────────►│ MCP Server │◄────────────►│ Shopify API │
│ (MCP Client) │ │ (Node.js) │ │ Admin API │
└─────────────────┘ └──────────────────┘ └──────────────┘
│
▼
┌──────────────────┐
│ token-store.json │
│ (Access Token) │
└──────────────────┘
```
### OAuth Flow
```
┌──────────┐ 1. /auth/start ┌──────────────────┐
│ Browser │◄────────────────────►│ OAuth Server │
│ │ │ (localhost:3847) │
└─────┬─────┘ └──────────────────┘
│ ▲
│ 2. Redirect to Shopify │ 5. Save token
▼ │
┌──────────────┐ 3. Authorize ┌──────────────────────────────┐
│ Shopify │───────────────►│ Cloudflare Worker │
│ Grant Screen│ 4. Callback │ (your-oauth-callback. │
└──────────────┘ + Auth Code │ workers.dev) │
│ │ │
│ Redirect to localhost:3847 │
│ /callback │
└──────────────────────────────┘
```
## Prerequisites
- Node.js >= 18
- A Shopify App (created in the [Dev Dashboard](https://partners.shopify.com/))
- A Cloudflare Worker for URL redirect (OAuth callback)
## Quick Start
### 1. Install dependencies
```bash
npm install
```
### 2. Configuration
Copy `.env.example` to `.env` and fill in your values:
```bash
cp .env.example .env
```
Required values from the Shopify Dev Dashboard:
- **SHOPIFY_API_KEY** → Client ID of your app
- **SHOPIFY_API_SECRET** → Client Secret of your app
- **SHOPIFY_DOMAIN** → Your myshopify.com domain
- **SHOPIFY_REDIRECT_URL** → Your Cloudflare Worker callback URL
### 3. Configure Shopify App
In the Shopify Dev Dashboard under your app:
1. Set **App URL** to your Cloudflare Worker domain (e.g. `https://your-oauth-callback.workers.dev`)
2. Add **Allowed redirection URLs**:
- `https://your-oauth-callback.workers.dev/callback`
### 4. Configure Cloudflare Worker
Your Cloudflare Worker must redirect OAuth callbacks from Shopify to your local server.
Example Worker:
```typescript
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
// OAuth callback from Shopify → Redirect to local server
if (url.pathname === "/callback") {
const localUrl = `http://localhost:3847/callback${url.search}`;
return Response.redirect(localUrl, 302);
}
// App URL request from Shopify → Redirect to local server
if (url.searchParams.has("shop")) {
const localUrl = `http://localhost:3847${url.pathname}${url.search}`;
return Response.redirect(localUrl, 302);
}
return new Response("Shopify OAuth Endpoint active.", { status: 200 });
},
};
```
### 5. Run OAuth
```bash
npm run oauth
```
This starts a local server and opens the browser. Log in to Shopify and grant the permissions. The access token is automatically saved to `token-store.json`.
### 6. Configure MCP Server in Cursor
Add the following to your Cursor configuration (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"shopify-manager": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/src/mcp-server.js"],
"env": {
"SHOPIFY_DOMAIN": "your-store.myshopify.com",
"SHOPIFY_API_VERSION": "2026-01"
}
}
}
}
```
## Available Tools (30+)
### Shop Management
| Tool | Description |
|------|-------------|
| `shop_info` | Shop basics (name, domain, plan, currency) |
| `shop_locales` | Configured languages |
| `shop_policies` | Privacy, terms of service, refund policies |
| `available_shipping_countries` | Shipping destinations |
### Products
| Tool | Description |
|------|-------------|
| `list_products` | List products with filtering & pagination |
| `get_product` | Product details with variants & images |
| `create_product` | Create a new product |
| `update_product` | Update a product |
| `delete_product` | Delete a product |
| `list_collections` | List collections |
### Orders
| Tool | Description |
|------|-------------|
| `list_orders` | List orders with filtering |
| `get_order` | Order details |
| `update_order` | Update an order |
| `cancel_order` | Cancel an order |
| `create_draft_order` | Create a draft order |
### Customers
| Tool | Description |
|------|-------------|
| `list_customers` | List customers |
| `get_customer` | Customer details |
| `create_customer` | Create a new customer |
| `update_customer` | Update a customer |
| `delete_customer` | Delete a customer |
### Inventory
| Tool | Description |
|------|-------------|
| `list_locations` | List locations |
| `get_inventory_levels` | Show inventory levels |
| `adjust_inventory` | Adjust inventory |
| `get_product_inventory` | Full product inventory |
### Discounts
| Tool | Description |
|------|-------------|
| `list_discount_codes` | List discount codes |
| `create_basic_discount` | Create a discount code |
| `list_automatic_discounts` | List automatic discounts |
### Analytics
| Tool | Description |
|------|-------------|
| `get_order_count` | Count orders |
| `get_product_count` | Count products |
| `get_customer_count` | Count customers |
| `shop_dashboard_summary` | Dashboard overview |
| `graphql_query` | Run arbitrary GraphQL queries |
## OAuth Flow Details
The OAuth 2.0 Authorization Code Grant flow works as follows:
1. **Initiation**: User starts the OAuth flow via `http://localhost:3847/auth/start`
2. **Redirect to Shopify**: The app redirects the user to Shopify's authorization page with:
- `client_id` (App API Key)
- `scope` (requested permissions)
- `redirect_uri` (Cloudflare Worker URL)
- `state` (nonce for CSRF protection)
3. **User authorizes**: The store owner grants the requested permissions
4. **Callback**: Shopify sends an authorization code to the redirect_uri
5. **Cloudflare Worker**: Redirects the callback to the local OAuth server
6. **Security checks**:
- HMAC verification (message authenticity from Shopify)
- State/nonce comparison (CSRF protection)
- Shop domain validation
7. **Token exchange**: The authorization code is exchanged for an access token via `POST https://{shop}/admin/oauth/access_token`
8. **Persistence**: The token is saved to `token-store.json`
## Security Notes
- **Never** commit `token-store.json` or `.env` (both are in `.gitignore`)
- The `SHOPIFY_API_SECRET` is confidential
- Access tokens have the permissions of the configured scopes
- If you suspect token compromise: rotate the token via the Shopify Dev Dashboard
## License
MIT
TDQS
Scored across 32 tools
Most tools have a clear resource-action distinction (products, orders, customers), but there is some overlap between inventory tools (get_inventory_levels vs get_product_inventory) and count tools vs shop_dashboard_summary. Descriptions help clarify, but a few could cause misselection.
The dominant pattern is verb_noun (list_*, get_*, create_*, update_*, delete_*), but exceptions like shop_info, available_shipping_countries, and graphql_query break the pattern. Also, get_product_inventory and get_inventory_levels invert the noun order, creating minor inconsistency.
With 32 tools, this exceeds the 25+ threshold considered 'too many' in the calibration. While Shopify has many domains, the count feels heavy; some tools like get_product_count, get_order_count, and get_customer_count could be consolidated into a single metrics tool.
Core resources (products, orders, customers) have solid CRUD coverage, but collections are only listable, discounts lack update/delete, normal order creation is missing (only draft), and variant-level management is absent. These are notable gaps for a Shopify management server.