@shoppexio/mcp-commerce-server 0.7.0 → 0.8.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.
- package/README.md +109 -39
- package/package.json +2 -2
- package/src/server.mjs +122 -66
package/README.md
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Model Context Protocol server for Shoppex commerce operations.
|
|
4
4
|
|
|
5
|
-
Connect Claude Desktop, Claude Code, Cursor, Windsurf, or Codex to your Shoppex store
|
|
5
|
+
Connect Claude Desktop, Claude Code, Cursor, Windsurf, or Codex to your Shoppex store — manage products, orders, customers, coupons, payment links, subscriptions, tickets, licenses, blacklist, analytics, and more. 51 tools, 5 resources, 6 workflow prompts.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
+
The fastest way is the one-shot installer:
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
|
-
|
|
12
|
+
npx @shoppexio/mcp-shoppex install --api-key shx_your_dev_api_key
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
Or
|
|
15
|
+
That installs both commerce and theme MCPs. Or install commerce standalone:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
|
|
18
|
+
npm install -g @shoppexio/mcp-commerce-server
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
## Claude Desktop
|
|
@@ -34,63 +36,131 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
|
34
36
|
}
|
|
35
37
|
```
|
|
36
38
|
|
|
37
|
-
Restart Claude Desktop.
|
|
39
|
+
Restart Claude Desktop.
|
|
38
40
|
|
|
39
|
-
## Cursor / Windsurf /
|
|
41
|
+
## Cursor / Windsurf / Claude Code
|
|
40
42
|
|
|
41
|
-
Any MCP client with stdio transport works. Set the same env var and point to `shoppex-mcp-commerce-server` as the command
|
|
43
|
+
Any MCP client with stdio transport works. Set the same env var and point to `shoppex-mcp-commerce-server` as the command — or use the `@shoppexio/cli` helper: `shoppex mcp install --client cursor|windsurf|claude-code`.
|
|
42
44
|
|
|
43
|
-
## Tools (
|
|
45
|
+
## Tools (51)
|
|
44
46
|
|
|
45
|
-
###
|
|
47
|
+
### Products
|
|
48
|
+
- `products_list` — search or list products
|
|
49
|
+
- `products_get` — fetch one by id/uniqid
|
|
50
|
+
- `products_create` — create (service, serials, dynamic, file)
|
|
51
|
+
- `products_update` — price, title, gateways, stock, visibility
|
|
52
|
+
- `products_delete` — soft-delete
|
|
53
|
+
- `products_duplicate` — clone
|
|
54
|
+
- `products_upload_serials` — bulk-add license keys
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
+
### Orders
|
|
57
|
+
- `orders_list` — list, filter by status/email
|
|
58
|
+
- `orders_get` — fetch one with line items
|
|
59
|
+
- `orders_update` — notes, internal notes
|
|
60
|
+
- `orders_fulfill` — mark delivered
|
|
56
61
|
|
|
57
|
-
###
|
|
62
|
+
### Customers
|
|
63
|
+
- `customers_list` — list with filter expressions
|
|
64
|
+
- `customers_get` — fetch by id or email
|
|
65
|
+
- `customers_wallet_credit` — credit wallet balance
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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 |
|
|
67
|
+
### Invoices
|
|
68
|
+
- `invoices_list` — filter by status, customer
|
|
69
|
+
- `invoices_get` — fetch one
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
### Coupons
|
|
72
|
+
- `coupons_list` — list active
|
|
73
|
+
- `coupons_get` — fetch one
|
|
74
|
+
- `coupons_create` — percentage or fixed
|
|
75
|
+
- `coupons_update` — update any field
|
|
76
|
+
- `coupons_delete` — remove
|
|
68
77
|
|
|
69
|
-
|
|
78
|
+
### Payment Links
|
|
79
|
+
- `payment_links_list` / `_get` / `_update` / `_delete` / `_toggle`
|
|
80
|
+
- `payment_links_create` — one-click checkout URLs
|
|
70
81
|
|
|
71
|
-
|
|
82
|
+
### Categories
|
|
83
|
+
- `categories_list` / `_create` / `_update`
|
|
72
84
|
|
|
73
|
-
|
|
85
|
+
### Webhooks
|
|
86
|
+
- `webhooks_list` / `_create`
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
### Tickets (support inbox)
|
|
89
|
+
- `tickets_list` / `_get` / `_create` / `_reply` / `_close`
|
|
90
|
+
|
|
91
|
+
### Disputes
|
|
92
|
+
- `disputes_list` / `_get`
|
|
93
|
+
|
|
94
|
+
### Licenses
|
|
95
|
+
- `licenses_list` / `_get` / `_update` (revoke/extend/reset HWID locks)
|
|
96
|
+
|
|
97
|
+
### Subscriptions
|
|
98
|
+
- `subscriptions_list` / `_cancel`
|
|
99
|
+
|
|
100
|
+
### Affiliates
|
|
101
|
+
- `affiliates_list`
|
|
102
|
+
|
|
103
|
+
### Blacklist
|
|
104
|
+
- `blacklist_list` / `_add` / `_remove`
|
|
105
|
+
|
|
106
|
+
### Analytics
|
|
107
|
+
- `analytics_revenue` — revenue totals
|
|
108
|
+
- `analytics_reports_list` — custom reports
|
|
109
|
+
- `analytics_report_generate` — re-generate a report
|
|
110
|
+
|
|
111
|
+
## Resources (5)
|
|
80
112
|
|
|
81
|
-
|
|
113
|
+
Claude Desktop surfaces these as attachable context documents. Drag them into any chat to ground the conversation in live shop data:
|
|
82
114
|
|
|
83
|
-
|
|
115
|
+
| URI | What |
|
|
116
|
+
|------|------|
|
|
117
|
+
| `shoppex://products` | Full product catalog with variants |
|
|
118
|
+
| `shoppex://orders/recent` | Last 50 orders |
|
|
119
|
+
| `shoppex://analytics/summary` | MTD revenue snapshot |
|
|
120
|
+
| `shoppex://categories` | Category tree |
|
|
121
|
+
| `shoppex://tickets/open` | Open support tickets |
|
|
122
|
+
|
|
123
|
+
## Prompts (6)
|
|
124
|
+
|
|
125
|
+
Pre-built workflows available as slash commands:
|
|
126
|
+
|
|
127
|
+
| Prompt | What it does |
|
|
128
|
+
|--------|--------------|
|
|
129
|
+
| `/shoppex_daily_brief` | Morning summary: revenue, orders, attention items |
|
|
130
|
+
| `/shoppex_launch_product` | End-to-end product launch (args: product_name, price) |
|
|
131
|
+
| `/shoppex_fraud_check` | Suspicious-orders scan + blacklist suggestions |
|
|
132
|
+
| `/shoppex_weekly_recap` | 7-day performance recap |
|
|
133
|
+
| `/shoppex_customer_care` | Full customer timeline + draft reply (args: email) |
|
|
134
|
+
| `/shoppex_theme_refresh` | Active-theme structural review |
|
|
135
|
+
|
|
136
|
+
## Example prompts
|
|
84
137
|
|
|
85
138
|
- "Create a Discord Nitro 3-month product for $14.99 paid in crypto."
|
|
86
139
|
- "Show me this month's top 10 customers by revenue."
|
|
87
140
|
- "Generate a 20% off coupon for my Discord members, valid until end of month."
|
|
88
141
|
- "Update the price of product `prd_abc123` to $12.99."
|
|
89
|
-
- "
|
|
142
|
+
- "Refund customer alice@example.com for invoice `inv_xyz`."
|
|
143
|
+
- "Are there any fraud patterns in the last 48h?"
|
|
144
|
+
- `/shoppex_daily_brief`
|
|
145
|
+
|
|
146
|
+
## Environment Variables
|
|
147
|
+
|
|
148
|
+
| Variable | Required | Default |
|
|
149
|
+
|----------|----------|---------|
|
|
150
|
+
| `SHOPPEX_SHOP_API_KEY` | yes (or passed per call) | — |
|
|
151
|
+
| `SHOPPEX_API_BASE_URL` | no | `https://api.shoppex.io` |
|
|
152
|
+
| `SHOPPEX_DEV_API_TIMEOUT_MS` | no | `10000` |
|
|
153
|
+
|
|
154
|
+
Create an API key at [dashboard.shoppex.io/developer/api](https://dashboard.shoppex.io/developer/api).
|
|
90
155
|
|
|
91
156
|
## Companion
|
|
92
157
|
|
|
93
|
-
Pair with [`@shoppexio/mcp-theme-server`](https://www.npmjs.com/package/@shoppexio/mcp-theme-server) for storefront theme operations.
|
|
158
|
+
Pair with [`@shoppexio/mcp-theme-server`](https://www.npmjs.com/package/@shoppexio/mcp-theme-server) for storefront theme operations including `theme_ai_apply` (natural-language theme editing).
|
|
159
|
+
|
|
160
|
+
## Agent Templates
|
|
161
|
+
|
|
162
|
+
Paste-ready agent personalities (customer care, product launch, fraud investigator, analyst, theme editor):
|
|
163
|
+
[`docs/agents/`](https://github.com/ShoppexIO/shoppex/tree/main/docs/agents)
|
|
94
164
|
|
|
95
165
|
## Docs
|
|
96
166
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoppexio/mcp-commerce-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Shoppex MCP server for commerce operations over the Dev API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
50
|
-
"zod": "^4.
|
|
50
|
+
"zod": "^4.3.6"
|
|
51
51
|
}
|
|
52
52
|
}
|
package/src/server.mjs
CHANGED
|
@@ -435,9 +435,15 @@ export class ShoppexCommerceDevApiClient {
|
|
|
435
435
|
}
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
+
// SECURITY: `api_base_url` is intentionally NOT a tool argument.
|
|
439
|
+
// The Shoppex shop API bearer token is attached to every request, so the
|
|
440
|
+
// destination origin must never be chosen by an (untrusted) tool caller —
|
|
441
|
+
// that would allow exfiltrating the credential to an attacker-controlled host
|
|
442
|
+
// (SSRF / credential disclosure, CWE-918/CWE-200). The API base URL is resolved
|
|
443
|
+
// solely from server-side env (`SHOPPEX_API_BASE_URL`/`API_URL`) via
|
|
444
|
+
// `resolveBaseUrl`, which the operator controls, not the caller.
|
|
438
445
|
const BaseToolSchema = {
|
|
439
446
|
shop_api_key: z.string().trim().min(1).optional(),
|
|
440
|
-
api_base_url: z.string().trim().url().optional(),
|
|
441
447
|
};
|
|
442
448
|
|
|
443
449
|
function resolveShopApiKey(explicitValue) {
|
|
@@ -457,9 +463,10 @@ function resolveShopApiKey(explicitValue) {
|
|
|
457
463
|
}
|
|
458
464
|
|
|
459
465
|
function createClient(args) {
|
|
466
|
+
// Do not pass any caller-supplied base URL here. The destination origin is
|
|
467
|
+
// resolved from server env only (see BaseToolSchema security note).
|
|
460
468
|
return new ShoppexCommerceDevApiClient({
|
|
461
469
|
shopApiKey: resolveShopApiKey(args.shop_api_key),
|
|
462
|
-
apiBaseUrl: args.api_base_url,
|
|
463
470
|
});
|
|
464
471
|
}
|
|
465
472
|
|
|
@@ -761,39 +768,43 @@ export function createCommerceToolCatalog() {
|
|
|
761
768
|
},
|
|
762
769
|
{
|
|
763
770
|
name: 'categories_create',
|
|
764
|
-
description: 'Create a product category.',
|
|
771
|
+
description: 'Create a product category. Fields match POST /dev/v1/categories.',
|
|
765
772
|
inputSchema: {
|
|
766
773
|
...BaseToolSchema,
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
774
|
+
title: z.string().trim().min(1).max(64),
|
|
775
|
+
unlisted: z.boolean().optional(),
|
|
776
|
+
products_bound: z.array(z.string().trim().min(1)).optional(),
|
|
777
|
+
groups_bound: z.array(z.string().trim().min(1)).optional(),
|
|
778
|
+
sort_priority: z.number().int().optional(),
|
|
771
779
|
},
|
|
772
780
|
execute: async (args) => {
|
|
773
|
-
const body = {
|
|
774
|
-
if (args.
|
|
775
|
-
if (args.
|
|
776
|
-
if (args.
|
|
781
|
+
const body = { title: args.title };
|
|
782
|
+
if (args.unlisted !== undefined) body.unlisted = args.unlisted;
|
|
783
|
+
if (args.products_bound !== undefined) body.products_bound = args.products_bound;
|
|
784
|
+
if (args.groups_bound !== undefined) body.groups_bound = args.groups_bound;
|
|
785
|
+
if (args.sort_priority !== undefined) body.sort_priority = args.sort_priority;
|
|
777
786
|
return createClient(args).categoriesCreate(body);
|
|
778
787
|
},
|
|
779
788
|
},
|
|
780
789
|
{
|
|
781
790
|
name: 'categories_update',
|
|
782
|
-
description: 'Update a category by
|
|
791
|
+
description: 'Update a category by uniqid. Only provided fields change. Uses the same field shape as categories_create.',
|
|
783
792
|
inputSchema: {
|
|
784
793
|
...BaseToolSchema,
|
|
785
794
|
category_id: z.string().trim().min(1),
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
795
|
+
title: z.string().trim().min(1).max(64).optional(),
|
|
796
|
+
unlisted: z.boolean().optional(),
|
|
797
|
+
products_bound: z.array(z.string().trim().min(1)).optional(),
|
|
798
|
+
groups_bound: z.array(z.string().trim().min(1)).optional(),
|
|
799
|
+
sort_priority: z.number().int().optional(),
|
|
790
800
|
},
|
|
791
801
|
execute: async (args) => {
|
|
792
802
|
const body = {};
|
|
793
|
-
if (args.
|
|
794
|
-
if (args.
|
|
795
|
-
if (args.
|
|
796
|
-
if (args.
|
|
803
|
+
if (args.title !== undefined) body.title = args.title;
|
|
804
|
+
if (args.unlisted !== undefined) body.unlisted = args.unlisted;
|
|
805
|
+
if (args.products_bound !== undefined) body.products_bound = args.products_bound;
|
|
806
|
+
if (args.groups_bound !== undefined) body.groups_bound = args.groups_bound;
|
|
807
|
+
if (args.sort_priority !== undefined) body.sort_priority = args.sort_priority;
|
|
797
808
|
return createClient(args).categoriesUpdate(args.category_id, body);
|
|
798
809
|
},
|
|
799
810
|
},
|
|
@@ -899,18 +910,20 @@ export function createCommerceToolCatalog() {
|
|
|
899
910
|
},
|
|
900
911
|
},
|
|
901
912
|
{
|
|
902
|
-
name: '
|
|
903
|
-
description: '
|
|
913
|
+
name: 'orders_set_affiliate',
|
|
914
|
+
description: 'Attribute an order to an affiliate after the fact. Backed by PATCH /dev/v1/orders/:id which is the affiliate-attribution endpoint. Provide one of affiliate_code, referral_code, or affiliate_id (pass null to clear an existing attribution).',
|
|
904
915
|
inputSchema: {
|
|
905
916
|
...BaseToolSchema,
|
|
906
917
|
order_id: z.string().trim().min(1),
|
|
907
|
-
|
|
908
|
-
|
|
918
|
+
affiliate_code: z.string().trim().optional().nullable(),
|
|
919
|
+
referral_code: z.string().trim().optional().nullable(),
|
|
920
|
+
affiliate_id: z.string().trim().optional().nullable(),
|
|
909
921
|
},
|
|
910
922
|
execute: async (args) => {
|
|
911
923
|
const body = {};
|
|
912
|
-
if (args.
|
|
913
|
-
if (args.
|
|
924
|
+
if (args.affiliate_code !== undefined) body.affiliate_code = args.affiliate_code;
|
|
925
|
+
if (args.referral_code !== undefined) body.referral_code = args.referral_code;
|
|
926
|
+
if (args.affiliate_id !== undefined) body.affiliate_id = args.affiliate_id;
|
|
914
927
|
return createClient(args).ordersUpdate(args.order_id, body);
|
|
915
928
|
},
|
|
916
929
|
},
|
|
@@ -930,19 +943,22 @@ export function createCommerceToolCatalog() {
|
|
|
930
943
|
},
|
|
931
944
|
{
|
|
932
945
|
name: 'customers_wallet_credit',
|
|
933
|
-
description: 'Credit a customer wallet balance. Useful for refunds, goodwill credits, or promo grants.',
|
|
946
|
+
description: 'Credit a customer wallet balance. Useful for refunds, goodwill credits, or promo grants. Amount is a decimal string with up to 2 decimal places (e.g. "5.00"). Wallet currency is fixed to the shop default.',
|
|
934
947
|
inputSchema: {
|
|
935
948
|
...BaseToolSchema,
|
|
936
949
|
customer_id: z.string().trim().min(1),
|
|
937
|
-
amount: z.
|
|
938
|
-
|
|
939
|
-
|
|
950
|
+
amount: z.string().regex(/^\d+(\.\d{1,2})?$/, 'Amount must be a positive decimal string (e.g. "5.00")'),
|
|
951
|
+
type: z.enum(['CREDIT', 'PROMO', 'ADJUSTMENT']).optional(),
|
|
952
|
+
description: z.string().max(500).optional(),
|
|
953
|
+
expires_at: z.string().datetime().optional(),
|
|
954
|
+
},
|
|
955
|
+
execute: async (args) => {
|
|
956
|
+
const body = { amount: args.amount };
|
|
957
|
+
if (args.type !== undefined) body.type = args.type;
|
|
958
|
+
if (args.description !== undefined) body.description = args.description;
|
|
959
|
+
if (args.expires_at !== undefined) body.expires_at = args.expires_at;
|
|
960
|
+
return createClient(args).customersWalletCredit(args.customer_id, body);
|
|
940
961
|
},
|
|
941
|
-
execute: async (args) => createClient(args).customersWalletCredit(args.customer_id, {
|
|
942
|
-
amount: args.amount,
|
|
943
|
-
currency: args.currency,
|
|
944
|
-
reason: args.reason,
|
|
945
|
-
}),
|
|
946
962
|
},
|
|
947
963
|
{
|
|
948
964
|
name: 'coupons_get',
|
|
@@ -970,26 +986,65 @@ export function createCommerceToolCatalog() {
|
|
|
970
986
|
},
|
|
971
987
|
{
|
|
972
988
|
name: 'payment_links_update',
|
|
973
|
-
description: 'Update a payment link by uniqid.
|
|
989
|
+
description: 'Update a payment link by uniqid. The backend expects a full create-style payload, so this tool reads the existing link, merges your overrides, and sends the merged result. Pass only the fields you want to change — the rest are preserved from the current link.',
|
|
974
990
|
inputSchema: {
|
|
975
991
|
...BaseToolSchema,
|
|
976
992
|
link_id: z.string().trim().min(1),
|
|
977
993
|
name: z.string().trim().min(1).max(255).optional(),
|
|
994
|
+
type: z.enum(['PRODUCT', 'SUBSCRIPTION', 'SUBSCRIPTION_V2', 'LICENSE', 'PAY_WHAT_YOU_WANT', 'FIXED_PRICE']).optional(),
|
|
978
995
|
description: z.string().max(255).optional().nullable(),
|
|
996
|
+
active: z.boolean().optional(),
|
|
979
997
|
price: z.number().positive().optional(),
|
|
980
998
|
currency: z.string().trim().min(3).max(8).optional(),
|
|
981
999
|
gateways: z.array(z.string().trim().min(1)).optional(),
|
|
982
|
-
|
|
1000
|
+
product_ids: z.array(z.string().trim().min(1)).optional(),
|
|
1001
|
+
cta: z.enum(['PAY', 'BOOK', 'DONATE', 'SUBSCRIBE']).optional(),
|
|
1002
|
+
allow_discount_code: z.boolean().optional(),
|
|
1003
|
+
require_customer_address: z.boolean().optional(),
|
|
1004
|
+
require_customer_phone: z.boolean().optional(),
|
|
1005
|
+
show_confirmation_page: z.boolean().optional(),
|
|
1006
|
+
return_url: z.string().trim().url().optional().nullable(),
|
|
983
1007
|
},
|
|
984
1008
|
execute: async (args) => {
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
if (
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1009
|
+
const client = createClient(args);
|
|
1010
|
+
const existing = await client.paymentLinksGet(args.link_id);
|
|
1011
|
+
if (!existing || typeof existing !== 'object') {
|
|
1012
|
+
throw new ShoppexCommerceDevApiError(
|
|
1013
|
+
`payment_links_update: payment link ${args.link_id} not found.`,
|
|
1014
|
+
{ code: 'not_found', retryable: false },
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
const cur = existing;
|
|
1018
|
+
const body = {
|
|
1019
|
+
uniqid: cur.uniqid ?? args.link_id,
|
|
1020
|
+
name: args.name ?? cur.name,
|
|
1021
|
+
type: args.type ?? cur.type,
|
|
1022
|
+
description: args.description !== undefined ? args.description : cur.description ?? null,
|
|
1023
|
+
status: args.active !== undefined ? args.active : cur.status,
|
|
1024
|
+
price: args.price !== undefined ? args.price : cur.price,
|
|
1025
|
+
currency: args.currency ?? cur.currency ?? 'USD',
|
|
1026
|
+
gateways: args.gateways !== undefined
|
|
1027
|
+
? args.gateways.join(',')
|
|
1028
|
+
: Array.isArray(cur.gateways) ? cur.gateways.join(',') : (cur.gateways ?? ''),
|
|
1029
|
+
products_ids: args.product_ids !== undefined
|
|
1030
|
+
? args.product_ids.join(',')
|
|
1031
|
+
: Array.isArray(cur.products_ids) ? cur.products_ids.join(',') : (cur.products_ids ?? ''),
|
|
1032
|
+
cta: args.cta ?? cur.cta ?? 'PAY',
|
|
1033
|
+
discount_code_allowed: args.allow_discount_code !== undefined
|
|
1034
|
+
? args.allow_discount_code
|
|
1035
|
+
: (cur.discount_code_allowed ?? false),
|
|
1036
|
+
customer_address_required: args.require_customer_address !== undefined
|
|
1037
|
+
? args.require_customer_address
|
|
1038
|
+
: (cur.customer_address_required ?? false),
|
|
1039
|
+
customer_phone_required: args.require_customer_phone !== undefined
|
|
1040
|
+
? args.require_customer_phone
|
|
1041
|
+
: (cur.customer_phone_required ?? false),
|
|
1042
|
+
show_confirmation_page: args.show_confirmation_page !== undefined
|
|
1043
|
+
? args.show_confirmation_page
|
|
1044
|
+
: (cur.show_confirmation_page ?? true),
|
|
1045
|
+
return_url: args.return_url !== undefined ? args.return_url : cur.return_url ?? null,
|
|
1046
|
+
};
|
|
1047
|
+
return client.paymentLinksUpdate(args.link_id, body);
|
|
993
1048
|
},
|
|
994
1049
|
},
|
|
995
1050
|
{
|
|
@@ -1029,22 +1084,21 @@ export function createCommerceToolCatalog() {
|
|
|
1029
1084
|
},
|
|
1030
1085
|
{
|
|
1031
1086
|
name: 'tickets_create',
|
|
1032
|
-
description: 'Create a new support ticket.
|
|
1087
|
+
description: 'Create a new support ticket. Email is the customer email; title is short (max 30 chars); message is the opening body. Optionally link an invoice.',
|
|
1033
1088
|
inputSchema: {
|
|
1034
1089
|
...BaseToolSchema,
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
customer_email: z.string().trim().email().optional(),
|
|
1090
|
+
email: z.string().trim().min(1),
|
|
1091
|
+
title: z.string().trim().min(2).max(30),
|
|
1092
|
+
message: z.string().trim().min(2).max(2000),
|
|
1039
1093
|
invoice_id: z.string().trim().min(1).optional(),
|
|
1040
|
-
order_id: z.string().trim().min(1).optional(),
|
|
1041
1094
|
},
|
|
1042
1095
|
execute: async (args) => {
|
|
1043
|
-
const body = {
|
|
1044
|
-
|
|
1045
|
-
|
|
1096
|
+
const body = {
|
|
1097
|
+
email: args.email,
|
|
1098
|
+
title: args.title,
|
|
1099
|
+
message: args.message,
|
|
1100
|
+
};
|
|
1046
1101
|
if (args.invoice_id !== undefined) body.invoice_id = args.invoice_id;
|
|
1047
|
-
if (args.order_id !== undefined) body.order_id = args.order_id;
|
|
1048
1102
|
return createClient(args).ticketsCreate(body);
|
|
1049
1103
|
},
|
|
1050
1104
|
},
|
|
@@ -1114,21 +1168,23 @@ export function createCommerceToolCatalog() {
|
|
|
1114
1168
|
},
|
|
1115
1169
|
{
|
|
1116
1170
|
name: 'licenses_update',
|
|
1117
|
-
description: 'Update a license (
|
|
1171
|
+
description: 'Update a license: set status (ACTIVE/SUSPENDED/REVOKED/EXPIRED), change the hardware-id binding, allowlist IPs, change activation limit, or update the expiry. Set status="REVOKED" to revoke access.',
|
|
1118
1172
|
inputSchema: {
|
|
1119
1173
|
...BaseToolSchema,
|
|
1120
1174
|
license_id: z.string().trim().min(1),
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1175
|
+
status: z.enum(['ACTIVE', 'SUSPENDED', 'REVOKED', 'EXPIRED']).optional(),
|
|
1176
|
+
hardware_id: z.string().trim().optional().nullable(),
|
|
1177
|
+
allowed_ips: z.array(z.string().trim().min(1)).optional().nullable(),
|
|
1178
|
+
max_uses: z.number().int().min(1).optional().nullable(),
|
|
1179
|
+
expires_at: z.string().trim().optional().nullable(),
|
|
1125
1180
|
},
|
|
1126
1181
|
execute: async (args) => {
|
|
1127
|
-
const body = {};
|
|
1128
|
-
if (args.
|
|
1129
|
-
if (args.
|
|
1130
|
-
if (args.
|
|
1131
|
-
if (args.
|
|
1182
|
+
const body = { id: args.license_id };
|
|
1183
|
+
if (args.status !== undefined) body.status = args.status;
|
|
1184
|
+
if (args.hardware_id !== undefined) body.hardware_id = args.hardware_id;
|
|
1185
|
+
if (args.allowed_ips !== undefined) body.allowed_ips = args.allowed_ips;
|
|
1186
|
+
if (args.max_uses !== undefined) body.max_uses = args.max_uses;
|
|
1187
|
+
if (args.expires_at !== undefined) body.expires_at = args.expires_at;
|
|
1132
1188
|
return createClient(args).licensesUpdate(args.license_id, body);
|
|
1133
1189
|
},
|
|
1134
1190
|
},
|
|
@@ -1164,7 +1220,7 @@ export async function executeCommerceTool(toolName, args) {
|
|
|
1164
1220
|
export function createCommerceMcpServer() {
|
|
1165
1221
|
const server = new McpServer({
|
|
1166
1222
|
name: 'shoppex-commerce',
|
|
1167
|
-
version: '0.
|
|
1223
|
+
version: '0.8.0',
|
|
1168
1224
|
});
|
|
1169
1225
|
|
|
1170
1226
|
for (const tool of createCommerceToolCatalog()) {
|