shopify-store-mcp 1.0.2 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,44 +6,99 @@
6
6
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)
8
8
 
9
- A Model Context Protocol (MCP) server that connects to **live Shopify stores** via the Admin and Storefront APIs. Unlike documentation-only MCPs, this server enables AI agents to perform real operations on your store.
9
+ A Model Context Protocol (MCP) server that connects to **live Shopify stores** via the Admin and Storefront APIs. Unlike documentation-only MCPs, this server enables AI agents to perform **real operations** on your store.
10
+
11
+ ## Why This MCP?
12
+
13
+ | Feature | Shopify Store MCP | [Shopify Dev MCP](https://shopify.dev/docs/apps/build/devmcp) |
14
+ |---------|-------------------|---------------------------------------------------------------|
15
+ | Execute GraphQL queries | ✅ Real API calls | ❌ Documentation only |
16
+ | Modify store data | ✅ Full CRUD | ❌ No |
17
+ | Upload files | ✅ Yes | ❌ No |
18
+ | Bulk operations | ✅ Yes | ❌ No |
19
+ | API documentation | ❌ No | ✅ Yes |
20
+ | Schema introspection | ❌ No | ✅ Yes |
21
+
22
+ > **Important:** For the best experience, use **both** this MCP and the official [Shopify Dev MCP](https://shopify.dev/docs/apps/build/devmcp) together. The Dev MCP helps your AI agent understand Shopify's API schemas and documentation, while this MCP executes the actual operations on your store.
10
23
 
11
24
  ## Features
12
25
 
13
- - **Universal GraphQL Access** - Execute any Admin API query or mutation via `run_graphql_query`
14
- - **Smart Multi-Step Tools** - File uploads, bulk operations, metaobject upserts with automatic polling
15
- - **Rate Limiting** - Respects Shopify's plan-based rate limits (Standard/Advanced/Plus/Enterprise)
16
- - **Operation Logging** - SQLite database tracks all operations for debugging and history
17
- - **Schema Discovery** - Explore your store's metafield definitions and metaobject types
26
+ - **Universal GraphQL Access** Execute any Admin API query or mutation via `run_graphql_query`
27
+ - **Smart Multi-Step Tools** File uploads, bulk operations, metaobject upserts with automatic polling
28
+ - **Rate Limiting** Respects Shopify's plan-based rate limits (Standard/Advanced/Plus/Enterprise)
29
+ - **Operation Logging** SQLite database tracks all operations for debugging and history
30
+ - **Schema Discovery** Explore your store's metafield definitions and metaobject types
18
31
 
19
- ## Setup
32
+ ## Prerequisites
20
33
 
21
- ### Prerequisites
34
+ 1. **Node.js 18+**
35
+ 2. **Shopify store** with a [custom app](https://help.shopify.com/en/manual/apps/app-types/custom-apps)
36
+ 3. **Admin API access token** — Create a custom app in Shopify Admin → Settings → Apps and development channels → Develop apps
22
37
 
23
- 1. A Shopify store with a [custom app](https://help.shopify.com/en/manual/apps/app-types/custom-apps)
24
- 2. Admin API access token with required scopes
25
- 3. Node.js 18+
38
+ ## Installation
26
39
 
27
- ### Installation
40
+ <details>
41
+ <summary><strong>Cursor</strong></summary>
28
42
 
29
- ```bash
30
- npm install -g shopify-store-mcp
43
+ ### Quick Install
44
+
45
+ [![Install in Cursor](https://img.shields.io/badge/Install%20in-Cursor-blue?style=for-the-badge&logo=cursor)](https://cursor.com/install-mcp?name=shopify-store-mcp&config=eyJtY3BTZXJ2ZXJzIjp7InNob3BpZnktc3RvcmUtbWNwIjp7ImNvbW1hbmQiOiJucHgiLCJhcmdzIjpbIi15Iiwic2hvcGlmeS1zdG9yZS1tY3AiXSwiZW52Ijp7IlNIT1BJRllfU1RPUkVfVVJMIjoieW91ci1zdG9yZS5teXNob3BpZnkuY29tIiwiU0hPUElGWV9BQ0NFU1NfVE9LRU4iOiJzaHBhdF94eHh4eHh4eHh4eHh4eHh4eHh4eHgifX19fQ==)
46
+
47
+ After installing, edit the configuration to add your actual store credentials.
48
+
49
+ ### Manual Configuration
50
+
51
+ Add to your Cursor MCP settings (`~/.cursor/mcp.json`):
52
+
53
+ ```json
54
+ {
55
+ "mcpServers": {
56
+ "shopify-store-mcp": {
57
+ "command": "npx",
58
+ "args": ["-y", "shopify-store-mcp"],
59
+ "env": {
60
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
61
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
62
+ }
63
+ }
64
+ }
65
+ }
31
66
  ```
32
67
 
33
- Or run directly with npx:
68
+ <details>
69
+ <summary>Windows Configuration</summary>
34
70
 
35
- ```bash
36
- npx shopify-store-mcp
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "shopify-store-mcp": {
75
+ "command": "cmd",
76
+ "args": ["/k", "npx", "-y", "shopify-store-mcp"],
77
+ "env": {
78
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
79
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
80
+ }
81
+ }
82
+ }
83
+ }
37
84
  ```
38
85
 
39
- ## Usage with Claude Desktop or Cursor
86
+ </details>
87
+
88
+ </details>
89
+
90
+ <details>
91
+ <summary><strong>Claude Desktop</strong></summary>
40
92
 
41
- Add the following to your MCP configuration:
93
+ Add to your Claude Desktop config:
94
+
95
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
96
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
42
97
 
43
98
  ```json
44
99
  {
45
100
  "mcpServers": {
46
- "shopify-store": {
101
+ "shopify-store-mcp": {
47
102
  "command": "npx",
48
103
  "args": ["-y", "shopify-store-mcp"],
49
104
  "env": {
@@ -55,12 +110,13 @@ Add the following to your MCP configuration:
55
110
  }
56
111
  ```
57
112
 
58
- On Windows, use this configuration:
113
+ <details>
114
+ <summary>Windows Configuration</summary>
59
115
 
60
116
  ```json
61
117
  {
62
118
  "mcpServers": {
63
- "shopify-store": {
119
+ "shopify-store-mcp": {
64
120
  "command": "cmd",
65
121
  "args": ["/k", "npx", "-y", "shopify-store-mcp"],
66
122
  "env": {
@@ -72,15 +128,131 @@ On Windows, use this configuration:
72
128
  }
73
129
  ```
74
130
 
131
+ </details>
132
+
133
+ </details>
134
+
135
+ <details>
136
+ <summary><strong>Claude Code (CLI)</strong></summary>
137
+
138
+ Add to your Claude Code settings (`~/.claude/settings.json`):
139
+
140
+ ```json
141
+ {
142
+ "mcpServers": {
143
+ "shopify-store-mcp": {
144
+ "command": "npx",
145
+ "args": ["-y", "shopify-store-mcp"],
146
+ "env": {
147
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
148
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
149
+ }
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ </details>
156
+
157
+ <details>
158
+ <summary><strong>VS Code (Copilot)</strong></summary>
159
+
160
+ Add to your VS Code settings (`settings.json`):
161
+
162
+ ```json
163
+ {
164
+ "mcp.servers": {
165
+ "shopify-store-mcp": {
166
+ "command": "npx",
167
+ "args": ["-y", "shopify-store-mcp"],
168
+ "env": {
169
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
170
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
171
+ }
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ </details>
178
+
179
+ <details>
180
+ <summary><strong>Windsurf</strong></summary>
181
+
182
+ Add to your Windsurf MCP config (`~/.windsurf/mcp.json`):
183
+
184
+ ```json
185
+ {
186
+ "mcpServers": {
187
+ "shopify-store-mcp": {
188
+ "command": "npx",
189
+ "args": ["-y", "shopify-store-mcp"],
190
+ "env": {
191
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
192
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
193
+ }
194
+ }
195
+ }
196
+ }
197
+ ```
198
+
199
+ </details>
200
+
201
+ <details>
202
+ <summary><strong>Other MCP Clients</strong></summary>
203
+
204
+ For any MCP-compatible client, use:
205
+
206
+ ```bash
207
+ npx -y shopify-store-mcp
208
+ ```
209
+
210
+ With environment variables:
211
+ - `SHOPIFY_STORE_URL` — Your store's myshopify.com domain
212
+ - `SHOPIFY_ACCESS_TOKEN` — Admin API access token
213
+
214
+ </details>
215
+
216
+ ## Recommended: Add Shopify Dev MCP
217
+
218
+ For the best AI agent experience, also add the official **[Shopify Dev MCP](https://shopify.dev/docs/apps/build/devmcp)**. It provides:
219
+
220
+ - API documentation search
221
+ - GraphQL schema introspection
222
+ - Query validation
223
+ - Up-to-date Shopify API knowledge
224
+
225
+ This helps your AI agent know **what queries to write** before executing them with this MCP.
226
+
227
+ ```json
228
+ {
229
+ "mcpServers": {
230
+ "shopify-store-mcp": {
231
+ "command": "npx",
232
+ "args": ["-y", "shopify-store-mcp"],
233
+ "env": {
234
+ "SHOPIFY_STORE_URL": "your-store.myshopify.com",
235
+ "SHOPIFY_ACCESS_TOKEN": "shpat_xxxxxxxxxxxxxxxxxxxxx"
236
+ }
237
+ },
238
+ "shopify-dev-mcp": {
239
+ "command": "npx",
240
+ "args": ["-y", "@shopify/dev-mcp@latest"]
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
75
246
  ## Environment Variables
76
247
 
77
248
  | Variable | Required | Default | Description |
78
249
  |----------|----------|---------|-------------|
79
- | `SHOPIFY_STORE_URL` | Yes | - | Store's myshopify.com domain |
80
- | `SHOPIFY_ACCESS_TOKEN` | Yes | - | Admin API access token |
81
- | `SHOPIFY_STOREFRONT_ACCESS_TOKEN` | No | - | Storefront API token |
82
- | `SHOPIFY_API_VERSION` | No | `2025-01` | API version |
250
+ | `SHOPIFY_STORE_URL` | Yes | | Store's myshopify.com domain |
251
+ | `SHOPIFY_ACCESS_TOKEN` | Yes | | Admin API access token |
252
+ | `SHOPIFY_STOREFRONT_ACCESS_TOKEN` | No | | Storefront API token |
253
+ | `SHOPIFY_API_VERSION` | No | `2026-01` | API version (or `unstable` for bleeding edge) |
83
254
  | `SHOPIFY_TIER` | No | `STANDARD` | Rate limit tier |
255
+ | `MCP_LOG_OPERATIONS` | No | `true` | Enable operation logging |
84
256
 
85
257
  ## Available Tools
86
258
 
@@ -88,17 +260,20 @@ On Windows, use this configuration:
88
260
 
89
261
  | Tool | Description |
90
262
  |------|-------------|
91
- | `get_shop_info` | Retrieve store configuration and settings |
92
- | `run_graphql_query` | Execute any GraphQL query or mutation |
263
+ | `get_shop_info` | Retrieve store configuration, plan info, and settings |
264
+ | `run_graphql_query` | **Universal tool** — Execute any GraphQL query or mutation |
93
265
 
94
266
  ### Smart Tools
95
267
 
268
+ Multi-step workflows that handle complexity automatically:
269
+
96
270
  | Tool | Description |
97
271
  |------|-------------|
98
- | `upload_file` | Upload file from URL, poll until ready, return CDN URL |
99
- | `bulk_export` | Start bulk query, poll completion, return JSONL download URL |
100
- | `bulk_import` | Staged upload + bulk mutation with automatic polling |
272
+ | `upload_file` | Upload file (URL, local path, or base64) → poll until ready return CDN URL |
273
+ | `bulk_export` | Start bulk query poll completion return JSONL download URL |
274
+ | `bulk_import` | Staged upload bulk mutation poll completion |
101
275
  | `upsert_metaobject` | Create or update metaobject by handle (idempotent) |
276
+ | `delete_metaobject` | Delete metaobject by ID or type+handle |
102
277
  | `schema_discover` | Discover metafield definitions and metaobject types |
103
278
 
104
279
  ### Infrastructure Tools
@@ -107,20 +282,20 @@ On Windows, use this configuration:
107
282
  |------|-------------|
108
283
  | `configure` | Set rate limit tier (manual or auto-detect from shop plan) |
109
284
  | `get_history` | Query past operations for debugging |
110
- | `get_stats` | Aggregated usage statistics |
285
+ | `get_stats` | Aggregated usage statistics (calls, errors, response times) |
111
286
 
112
287
  ## Rate Limiting
113
288
 
114
- The server respects Shopify's rate limits based on your shop plan:
289
+ The server automatically respects Shopify's rate limits based on your shop plan:
115
290
 
116
291
  | Tier | Requests/sec | Plans |
117
292
  |------|--------------|-------|
118
- | STANDARD | 1 | Basic, Development, Lite |
119
- | ADVANCED | 2 | Advanced |
120
- | PLUS | 5 | Shopify Plus |
121
- | ENTERPRISE | 10 | Commerce Components |
293
+ | `STANDARD` | 1 | Basic, Development, Lite |
294
+ | `ADVANCED` | 2 | Advanced |
295
+ | `PLUS` | 5 | Shopify Plus |
296
+ | `ENTERPRISE` | 10 | Commerce Components |
122
297
 
123
- Use the `configure` tool to set your tier manually or auto-detect from your shop plan.
298
+ Use the `configure` tool to set your tier or auto-detect from your shop plan.
124
299
 
125
300
  ## Available Prompts
126
301
 
@@ -144,35 +319,43 @@ Use the `configure` tool to set your tier manually or auto-detect from your shop
144
319
  ## Development
145
320
 
146
321
  ```bash
322
+ # Clone the repo
323
+ git clone https://github.com/Brahim-Benzarti/Shopify_store-MCP.git
324
+ cd Shopify_store-MCP
325
+
147
326
  # Install dependencies
148
327
  npm install
149
328
 
150
329
  # Build
151
330
  npm run build
152
331
 
153
- # Run with inspector
332
+ # Run with MCP Inspector
154
333
  npm run inspect
155
334
 
156
335
  # Watch mode
157
336
  npm run dev
158
- ```
159
-
160
- ### Database
161
337
 
162
- The server uses SQLite for operation logging and configuration. The database is automatically created at `~/.shopify-mcp/mcp.db`.
163
-
164
- ```bash
165
338
  # View database
166
339
  npm run db:studio
167
340
  ```
168
341
 
342
+ ### Database
343
+
344
+ The server uses SQLite for operation logging and configuration. Database is automatically created at `~/.shopify-mcp/mcp.db`.
345
+
169
346
  ## Security
170
347
 
171
- - Never commit your `.env` file or access tokens
172
- - Use environment variables or MCP config for credentials
173
- - Access tokens should have minimal required scopes
174
- - The server logs operations locally for debugging (disable with `MCP_LOG_OPERATIONS=false`)
348
+ - **Never commit** your `.env` file or access tokens
349
+ - Use **environment variables** or MCP config for credentials
350
+ - Access tokens should have **minimal required scopes**
351
+ - Operations are logged locally for debugging (disable with `MCP_LOG_OPERATIONS=false`)
175
352
 
176
353
  ## License
177
354
 
178
- ISC
355
+ [ISC](LICENSE)
356
+
357
+ ## Related
358
+
359
+ - [Shopify Dev MCP](https://shopify.dev/docs/apps/build/devmcp) — Official Shopify MCP for API documentation
360
+ - [Shopify Admin API](https://shopify.dev/docs/api/admin-graphql) — GraphQL API reference
361
+ - [Model Context Protocol](https://modelcontextprotocol.io/) — MCP specification
package/dist/config.js CHANGED
@@ -16,7 +16,7 @@ export function loadConfig() {
16
16
  const adminAccessToken = process.env.SHOPIFY_ACCESS_TOKEN;
17
17
  const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;
18
18
  const customerAccessToken = process.env.SHOPIFY_CUSTOMER_ACCESS_TOKEN;
19
- const apiVersion = process.env.SHOPIFY_API_VERSION || "2025-01";
19
+ const apiVersion = process.env.SHOPIFY_API_VERSION || "2026-01";
20
20
  const bugReportEnabled = process.env.SHOPIFY_MCP_BUG_REPORTS === "true";
21
21
  const bugReportBaseDir = process.env.SHOPIFY_MCP_BUG_REPORT_DIR;
22
22
  if (!storeDomain) {
package/dist/errors.js CHANGED
@@ -59,7 +59,7 @@ export function formatGraphQLErrors(response) {
59
59
  };
60
60
  }
61
61
  export function formatUserErrors(userErrors) {
62
- const lines = userErrors.map((e) => `- ${e.field.join(".")}: ${e.message}`);
62
+ const lines = userErrors.map((e) => `- ${e.field?.join(".") || "general"}: ${e.message}`);
63
63
  return {
64
64
  content: [
65
65
  {
@@ -14,12 +14,22 @@ export declare const BULK_OPERATION_RUN_QUERY = "#graphql\n mutation BulkOperat
14
14
  */
15
15
  export declare const BULK_OPERATION_RUN_MUTATION = "#graphql\n mutation BulkOperationRunMutation($mutation: String!, $stagedUploadPath: String!) {\n bulkOperationRunMutation(mutation: $mutation, stagedUploadPath: $stagedUploadPath) {\n bulkOperation {\n id\n status\n url\n objectCount\n }\n userErrors {\n field\n message\n }\n }\n }\n";
16
16
  /**
17
- * Get current bulk operation status
18
- * Only one bulk operation can run at a time per app
17
+ * Get current bulk operation status (for queries)
18
+ * Deprecated in 2026-01, use GET_BULK_OPERATION_BY_ID instead
19
19
  */
20
20
  export declare const GET_CURRENT_BULK_OPERATION = "#graphql\n query GetCurrentBulkOperation {\n currentBulkOperation {\n id\n type\n status\n query\n url\n rootObjectCount\n objectCount\n fileSize\n partialDataUrl\n errorCode\n createdAt\n completedAt\n }\n }\n";
21
21
  /**
22
- * Get a specific bulk operation by ID
22
+ * Get current bulk MUTATION operation status
23
+ * Required for polling mutation status in versions < 2026-01
24
+ */
25
+ export declare const GET_CURRENT_BULK_MUTATION = "#graphql\n query GetCurrentBulkMutation {\n currentBulkOperation(type: MUTATION) {\n id\n type\n status\n url\n objectCount\n fileSize\n partialDataUrl\n errorCode\n createdAt\n completedAt\n }\n }\n";
26
+ /**
27
+ * Get a specific bulk operation by ID (API version 2026-01+)
28
+ * Use this for polling both queries and mutations
29
+ */
30
+ export declare const GET_BULK_OPERATION_BY_ID = "#graphql\n query GetBulkOperationById($id: ID!) {\n bulkOperation(id: $id) {\n id\n type\n status\n url\n objectCount\n fileSize\n partialDataUrl\n errorCode\n createdAt\n completedAt\n }\n }\n";
31
+ /**
32
+ * Get a specific bulk operation by ID (legacy node query)
23
33
  */
24
34
  export declare const GET_BULK_OPERATION = "#graphql\n query GetBulkOperation($id: ID!) {\n node(id: $id) {\n ... on BulkOperation {\n id\n type\n status\n query\n url\n rootObjectCount\n objectCount\n fileSize\n partialDataUrl\n errorCode\n createdAt\n completedAt\n }\n }\n }\n";
25
35
  /**
@@ -46,8 +46,8 @@ export const BULK_OPERATION_RUN_MUTATION = `#graphql
46
46
  }
47
47
  `;
48
48
  /**
49
- * Get current bulk operation status
50
- * Only one bulk operation can run at a time per app
49
+ * Get current bulk operation status (for queries)
50
+ * Deprecated in 2026-01, use GET_BULK_OPERATION_BY_ID instead
51
51
  */
52
52
  export const GET_CURRENT_BULK_OPERATION = `#graphql
53
53
  query GetCurrentBulkOperation {
@@ -68,7 +68,47 @@ export const GET_CURRENT_BULK_OPERATION = `#graphql
68
68
  }
69
69
  `;
70
70
  /**
71
- * Get a specific bulk operation by ID
71
+ * Get current bulk MUTATION operation status
72
+ * Required for polling mutation status in versions < 2026-01
73
+ */
74
+ export const GET_CURRENT_BULK_MUTATION = `#graphql
75
+ query GetCurrentBulkMutation {
76
+ currentBulkOperation(type: MUTATION) {
77
+ id
78
+ type
79
+ status
80
+ url
81
+ objectCount
82
+ fileSize
83
+ partialDataUrl
84
+ errorCode
85
+ createdAt
86
+ completedAt
87
+ }
88
+ }
89
+ `;
90
+ /**
91
+ * Get a specific bulk operation by ID (API version 2026-01+)
92
+ * Use this for polling both queries and mutations
93
+ */
94
+ export const GET_BULK_OPERATION_BY_ID = `#graphql
95
+ query GetBulkOperationById($id: ID!) {
96
+ bulkOperation(id: $id) {
97
+ id
98
+ type
99
+ status
100
+ url
101
+ objectCount
102
+ fileSize
103
+ partialDataUrl
104
+ errorCode
105
+ createdAt
106
+ completedAt
107
+ }
108
+ }
109
+ `;
110
+ /**
111
+ * Get a specific bulk operation by ID (legacy node query)
72
112
  */
73
113
  export const GET_BULK_OPERATION = `#graphql
74
114
  query GetBulkOperation($id: ID!) {
@@ -172,6 +172,134 @@ tag:vip orders_count:>3
172
172
  If a tool returns a 403 error, it likely means your custom app is missing the required scope. Update your app's API access scopes in:
173
173
 
174
174
  **Shopify Admin → Settings → Apps and sales channels → Develop apps → [Your App] → Configuration**
175
+ `,
176
+ },
177
+ ],
178
+ }));
179
+ // Smart Tools Reference
180
+ server.registerResource("smart-tools", "shopify://docs/smart-tools", {
181
+ title: "Smart Tools Reference",
182
+ description: "Reference guide for smart multi-step tools that handle complex workflows automatically.",
183
+ mimeType: "text/markdown",
184
+ }, async () => ({
185
+ contents: [
186
+ {
187
+ uri: "shopify://docs/smart-tools",
188
+ mimeType: "text/markdown",
189
+ text: `# Smart Tools Reference
190
+
191
+ Smart tools handle complex multi-step workflows automatically, including polling and staged uploads.
192
+
193
+ ## upload_file
194
+
195
+ Upload files to Shopify with automatic status polling. Returns the final CDN URL when ready.
196
+
197
+ ### Mode 1: External URL
198
+ Shopify fetches the file from a publicly accessible URL.
199
+
200
+ \`\`\`json
201
+ {
202
+ "url": "https://example.com/image.jpg",
203
+ "alt": "Product image"
204
+ }
205
+ \`\`\`
206
+
207
+ ### Mode 2: Local File Path (Recommended for large files)
208
+ Read file directly from disk. MIME type is auto-detected.
209
+
210
+ \`\`\`json
211
+ {
212
+ "filePath": "/path/to/document.pdf",
213
+ "alt": "Product manual"
214
+ }
215
+ \`\`\`
216
+
217
+ ### Mode 3: Base64 Content (Small files only, < 5MB)
218
+ For small files when you already have the content encoded.
219
+
220
+ \`\`\`json
221
+ {
222
+ "content": "iVBORw0KGgoAAAANSUhEUgAA...",
223
+ "filename": "photo.jpg",
224
+ "mimeType": "image/jpeg"
225
+ }
226
+ \`\`\`
227
+
228
+ **Required for Mode 3:** \`content\`, \`filename\`, \`mimeType\`
229
+
230
+ ### Content Types
231
+ - \`IMAGE\` - jpg, png, gif, webp, svg
232
+ - \`VIDEO\` - mp4, mov, webm
233
+ - \`FILE\` - pdf, documents, other files
234
+
235
+ ## bulk_export
236
+
237
+ Export large datasets to JSONL format.
238
+
239
+ \`\`\`json
240
+ {
241
+ "query": "{ products { edges { node { id title } } } }"
242
+ }
243
+ \`\`\`
244
+
245
+ Returns a download URL for the JSONL file when complete.
246
+
247
+ ## bulk_import
248
+
249
+ Import data via bulk mutations.
250
+
251
+ \`\`\`json
252
+ {
253
+ "mutation": "mutation($input: ProductInput!) { productUpdate(input: $input) { product { id } } }",
254
+ "jsonlUrl": "https://example.com/data.jsonl"
255
+ }
256
+ \`\`\`
257
+
258
+ ## upsert_metaobject
259
+
260
+ Create or update a metaobject by handle (idempotent).
261
+
262
+ \`\`\`json
263
+ {
264
+ "type": "color_swatch",
265
+ "handle": "navy-blue",
266
+ "fields": [
267
+ { "key": "name", "value": "Navy Blue" },
268
+ { "key": "hex", "value": "#000080" }
269
+ ]
270
+ }
271
+ \`\`\`
272
+
273
+ ## delete_metaobject
274
+
275
+ Delete a metaobject by ID or by type+handle.
276
+
277
+ \`\`\`json
278
+ {
279
+ "id": "gid://shopify/Metaobject/123456789"
280
+ }
281
+ \`\`\`
282
+
283
+ Or by type and handle:
284
+
285
+ \`\`\`json
286
+ {
287
+ "type": "color_swatch",
288
+ "handle": "navy-blue"
289
+ }
290
+ \`\`\`
291
+
292
+ ## schema_discover
293
+
294
+ Discover custom schema definitions in the store.
295
+
296
+ \`\`\`json
297
+ {
298
+ "includeMetafields": true,
299
+ "includeMetaobjects": true,
300
+ "metafieldOwnerTypes": ["PRODUCT", "VARIANT"]
301
+ }
302
+ \`\`\`
175
303
  `,
176
304
  },
177
305
  ],
@@ -1,3 +1,3 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { AdminApiClient } from "../shopify-client.js";
3
- export declare function registerGraphQLTools(server: McpServer, client: AdminApiClient): void;
3
+ export declare function registerGraphQLTools(server: McpServer, client: AdminApiClient, storeDomain: string): void;
@@ -1,6 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { formatSuccessResponse, formatGraphQLErrors, formatErrorResponse, } from "../errors.js";
3
- export function registerGraphQLTools(server, client) {
3
+ import { enqueue } from "../queue.js";
4
+ import { logOperation } from "../logger.js";
5
+ export function registerGraphQLTools(server, client, storeDomain) {
4
6
  server.registerTool("run_graphql_query", {
5
7
  title: "Run GraphQL Query",
6
8
  description: "Execute any GraphQL query or mutation against the Shopify Admin API. " +
@@ -24,16 +26,45 @@ export function registerGraphQLTools(server, client) {
24
26
  openWorldHint: true,
25
27
  },
26
28
  }, async ({ query, variables }) => {
29
+ const startTime = Date.now();
27
30
  try {
28
- const response = await client.request(query, {
31
+ const response = await enqueue(() => client.request(query, {
29
32
  variables: variables,
30
- });
33
+ }));
31
34
  if (response.errors) {
35
+ await logOperation({
36
+ storeDomain,
37
+ toolName: "run_graphql_query",
38
+ query,
39
+ variables,
40
+ response,
41
+ success: false,
42
+ errorMessage: "GraphQL errors",
43
+ durationMs: Date.now() - startTime,
44
+ });
32
45
  return formatGraphQLErrors(response);
33
46
  }
47
+ await logOperation({
48
+ storeDomain,
49
+ toolName: "run_graphql_query",
50
+ query,
51
+ variables,
52
+ response: response.data,
53
+ success: true,
54
+ durationMs: Date.now() - startTime,
55
+ });
34
56
  return formatSuccessResponse(response.data);
35
57
  }
36
58
  catch (error) {
59
+ await logOperation({
60
+ storeDomain,
61
+ toolName: "run_graphql_query",
62
+ query,
63
+ variables,
64
+ success: false,
65
+ errorMessage: error instanceof Error ? error.message : String(error),
66
+ durationMs: Date.now() - startTime,
67
+ });
37
68
  return formatErrorResponse(error);
38
69
  }
39
70
  });