@shoppexio/mcp-commerce-server 0.2.0 → 0.4.0

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.
Files changed (3) hide show
  1. package/README.md +1 -101
  2. package/package.json +1 -1
  3. package/src/server.mjs +39 -18
package/README.md CHANGED
@@ -1,103 +1,3 @@
1
1
  # @shoppexio/mcp-commerce-server
2
2
 
3
- Model Context Protocol server for Shoppex commerce operations.
4
-
5
- Connect Claude Desktop, Claude Code, Cursor, Windsurf, or Codex to your Shoppex store. Read products, orders, customers, and analytics, create payment links, manage coupons, and create or update products — directly from chat.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install -g @shoppexio/mcp-commerce-server
11
- ```
12
-
13
- Or run without installing:
14
-
15
- ```bash
16
- npx -y @shoppexio/mcp-commerce-server
17
- ```
18
-
19
- ## Claude Desktop
20
-
21
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
22
-
23
- ```json
24
- {
25
- "mcpServers": {
26
- "shoppex-commerce": {
27
- "command": "npx",
28
- "args": ["-y", "@shoppexio/mcp-commerce-server"],
29
- "env": {
30
- "SHOPPEX_SHOP_API_KEY": "shx_your_dev_api_key"
31
- }
32
- }
33
- }
34
- }
35
- ```
36
-
37
- Restart Claude Desktop. Tools accept a `shop_api_key` argument on each call; the env var is available for clients that forward env to tool arguments.
38
-
39
- ## Cursor / Windsurf / Other
40
-
41
- Any MCP client with stdio transport works. Set the same env var and point to `shoppex-mcp-commerce-server` as the command.
42
-
43
- ## Tools (12)
44
-
45
- ### Read
46
-
47
- | Tool | Purpose |
48
- |------|---------|
49
- | `products.list` | Search or list products |
50
- | `products.get` | Fetch one product by id or uniqid |
51
- | `orders.list` | List recent orders, optionally filtered |
52
- | `orders.get` | Fetch one order with line items |
53
- | `customers.get` | Fetch a customer by id or email |
54
- | `coupons.list` | List active coupons |
55
- | `analytics.revenue` | Revenue totals for a date range |
56
-
57
- ### Write
58
-
59
- | Tool | Purpose |
60
- |------|---------|
61
- | `products.create` | Create a product (service, serials, dynamic, file) |
62
- | `products.update` | Update a product's price, title, gateways, stock, visibility |
63
- | `coupons.create` | Create a coupon (percentage or fixed discount) |
64
- | `coupons.update` | Update an existing coupon |
65
- | `payment_links.create` | Create a payment link |
66
-
67
- ## Required Scopes
68
-
69
- Your Shoppex Dev API key needs the scopes matching the tools you use (e.g. `products.read`, `products.write`, `orders.read`, `coupons.write`, `analytics.read`, `payment_links.write`).
70
-
71
- Create one at [dashboard.shoppex.io/developer/api](https://dashboard.shoppex.io/developer/api).
72
-
73
- ## Environment Variables
74
-
75
- | Variable | Required | Default |
76
- |----------|----------|---------|
77
- | `SHOPPEX_SHOP_API_KEY` | passed per call, or set here | — |
78
- | `SHOPPEX_API_BASE_URL` | no | `https://api.shoppex.io` |
79
- | `SHOPPEX_DEV_API_TIMEOUT_MS` | no | `10000` |
80
-
81
- ## Example Prompts
82
-
83
- Once connected in Claude Desktop:
84
-
85
- - "Create a Discord Nitro 3-month product for $14.99 paid in crypto."
86
- - "Show me this month's top 10 customers by revenue."
87
- - "Generate a 20% off coupon for my Discord members, valid until end of month."
88
- - "Update the price of product `prd_abc123` to $12.99."
89
- - "Make a payment link for a $50 USDT one-time purchase."
90
-
91
- ## Companion
92
-
93
- Pair with [`@shoppexio/mcp-theme-server`](https://www.npmjs.com/package/@shoppexio/mcp-theme-server) for storefront theme operations.
94
-
95
- ## Docs
96
-
97
- - [Developer API Reference](https://docs.shoppex.io/api-reference/introduction)
98
- - [Quickstart](https://docs.shoppex.io/api-reference/quickstart)
99
- - [Authentication](https://docs.shoppex.io/api-reference/authentication)
100
-
101
- ## License
102
-
103
- Proprietary. © Shoppex.
3
+ Shoppex MCP server that exposes commerce tools over the Shoppex Dev API.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shoppexio/mcp-commerce-server",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Shoppex MCP server for commerce operations over the Dev API",
5
5
  "type": "module",
6
6
  "repository": {
package/src/server.mjs CHANGED
@@ -257,13 +257,29 @@ export class ShoppexCommerceDevApiClient {
257
257
  }
258
258
 
259
259
  const BaseToolSchema = {
260
- shop_api_key: z.string().trim().min(1),
260
+ shop_api_key: z.string().trim().min(1).optional(),
261
261
  api_base_url: z.string().trim().url().optional(),
262
262
  };
263
263
 
264
+ function resolveShopApiKey(explicitValue) {
265
+ if (typeof explicitValue === 'string' && explicitValue.trim()) {
266
+ return explicitValue.trim();
267
+ }
268
+ const fromEnv = process.env.SHOPPEX_SHOP_API_KEY?.trim()
269
+ || process.env.SHOPPEX_API_KEY?.trim()
270
+ || process.env.SHOP_API_KEY?.trim();
271
+ if (!fromEnv) {
272
+ throw new ShoppexCommerceDevApiError(
273
+ 'Missing Shoppex shop API key. Set SHOPPEX_SHOP_API_KEY in the MCP server env, or pass shop_api_key to the tool.',
274
+ { code: 'auth_error', retryable: false },
275
+ );
276
+ }
277
+ return fromEnv;
278
+ }
279
+
264
280
  function createClient(args) {
265
281
  return new ShoppexCommerceDevApiClient({
266
- shopApiKey: args.shop_api_key,
282
+ shopApiKey: resolveShopApiKey(args.shop_api_key),
267
283
  apiBaseUrl: args.api_base_url,
268
284
  });
269
285
  }
@@ -271,7 +287,7 @@ function createClient(args) {
271
287
  export function createCommerceToolCatalog() {
272
288
  return [
273
289
  {
274
- name: 'products.list',
290
+ name: 'products_list',
275
291
  description: 'Search or list products for one Shoppex shop.',
276
292
  inputSchema: {
277
293
  ...BaseToolSchema,
@@ -286,7 +302,7 @@ export function createCommerceToolCatalog() {
286
302
  }),
287
303
  },
288
304
  {
289
- name: 'products.get',
305
+ name: 'products_get',
290
306
  description: 'Fetch one product by Shoppex product id or uniqid.',
291
307
  inputSchema: {
292
308
  ...BaseToolSchema,
@@ -295,7 +311,7 @@ export function createCommerceToolCatalog() {
295
311
  execute: async (args) => createClient(args).productsGet(args.product_id),
296
312
  },
297
313
  {
298
- name: 'orders.list',
314
+ name: 'orders_list',
299
315
  description: 'List recent orders. Optionally filter by status or customer email.',
300
316
  inputSchema: {
301
317
  ...BaseToolSchema,
@@ -310,7 +326,7 @@ export function createCommerceToolCatalog() {
310
326
  }),
311
327
  },
312
328
  {
313
- name: 'orders.get',
329
+ name: 'orders_get',
314
330
  description: 'Fetch one order with line items by id or uniqid.',
315
331
  inputSchema: {
316
332
  ...BaseToolSchema,
@@ -319,7 +335,7 @@ export function createCommerceToolCatalog() {
319
335
  execute: async (args) => createClient(args).ordersGet(args.order_id),
320
336
  },
321
337
  {
322
- name: 'customers.get',
338
+ name: 'customers_get',
323
339
  description: 'Fetch one customer by Shoppex customer id or email.',
324
340
  inputSchema: {
325
341
  ...BaseToolSchema,
@@ -332,7 +348,7 @@ export function createCommerceToolCatalog() {
332
348
  }),
333
349
  },
334
350
  {
335
- name: 'payment_links.create',
351
+ name: 'payment_links_create',
336
352
  description: 'Create a Shoppex payment link.',
337
353
  inputSchema: {
338
354
  ...BaseToolSchema,
@@ -369,7 +385,7 @@ export function createCommerceToolCatalog() {
369
385
  }),
370
386
  },
371
387
  {
372
- name: 'analytics.revenue',
388
+ name: 'analytics_revenue',
373
389
  description: 'Fetch revenue totals for a date range.',
374
390
  inputSchema: {
375
391
  ...BaseToolSchema,
@@ -384,7 +400,7 @@ export function createCommerceToolCatalog() {
384
400
  }),
385
401
  },
386
402
  {
387
- name: 'coupons.list',
403
+ name: 'coupons_list',
388
404
  description: 'List active coupons for a shop.',
389
405
  inputSchema: {
390
406
  ...BaseToolSchema,
@@ -395,7 +411,7 @@ export function createCommerceToolCatalog() {
395
411
  }),
396
412
  },
397
413
  {
398
- name: 'coupons.create',
414
+ name: 'coupons_create',
399
415
  description: 'Create a coupon in Shoppex.',
400
416
  inputSchema: {
401
417
  ...BaseToolSchema,
@@ -422,8 +438,8 @@ export function createCommerceToolCatalog() {
422
438
  }),
423
439
  },
424
440
  {
425
- name: 'coupons.update',
426
- description: 'Update an existing coupon by uniqid. Only provided fields are changed.',
441
+ name: 'coupons_update',
442
+ description: 'Update an existing coupon by uniqid. Only provided fields change.',
427
443
  inputSchema: {
428
444
  ...BaseToolSchema,
429
445
  coupon_id: z.string().trim().min(1),
@@ -450,8 +466,8 @@ export function createCommerceToolCatalog() {
450
466
  },
451
467
  },
452
468
  {
453
- name: 'products.create',
454
- description: 'Create a product. Defaults to a simple digital/service product. For key-based products pass type="SERIALS" and provide the serials array.',
469
+ name: 'products_create',
470
+ description: 'Create a product. Defaults to a simple digital/service product. For key-based products pass type="SERIALS" and a serials array.',
455
471
  inputSchema: {
456
472
  ...BaseToolSchema,
457
473
  title: z.string().trim().min(1).max(128),
@@ -488,8 +504,8 @@ export function createCommerceToolCatalog() {
488
504
  },
489
505
  },
490
506
  {
491
- name: 'products.update',
492
- description: 'Update an existing product by uniqid. Only provided fields are changed.',
507
+ name: 'products_update',
508
+ description: 'Update an existing product by uniqid. Only provided fields change.',
493
509
  inputSchema: {
494
510
  ...BaseToolSchema,
495
511
  product_id: z.string().trim().min(1),
@@ -522,8 +538,13 @@ export function createCommerceToolCatalog() {
522
538
  ];
523
539
  }
524
540
 
541
+ function normalizeToolName(name) {
542
+ return typeof name === 'string' ? name.replace(/\./g, '_') : name;
543
+ }
544
+
525
545
  export async function executeCommerceTool(toolName, args) {
526
- const tool = createCommerceToolCatalog().find((entry) => entry.name === toolName);
546
+ const normalized = normalizeToolName(toolName);
547
+ const tool = createCommerceToolCatalog().find((entry) => entry.name === normalized);
527
548
  if (!tool) {
528
549
  throw new Error(`Unknown tool: ${toolName}`);
529
550
  }