@shoppexio/mcp-commerce-server 0.6.0 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shoppexio/mcp-commerce-server",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Shoppex MCP server for commerce operations over the Dev API",
5
5
  "type": "module",
6
6
  "repository": {
@@ -34,6 +34,8 @@
34
34
  "files": [
35
35
  "bin",
36
36
  "src/server.mjs",
37
+ "src/prompts.mjs",
38
+ "src/resources.mjs",
37
39
  "src/index.d.ts",
38
40
  "README.md"
39
41
  ],
@@ -0,0 +1,168 @@
1
+ /**
2
+ * MCP Prompts for Shoppex — curated multi-tool workflows that merchants
3
+ * invoke by name in their MCP client. Each prompt returns a user-message
4
+ * with a full instruction block that primes the LLM to run a pre-planned
5
+ * sequence of tool calls.
6
+ *
7
+ * Registration via `server.registerPrompt(name, {title, description, argsSchema}, cb)`.
8
+ */
9
+
10
+ import * as z from 'zod/v4';
11
+
12
+ function text(body) {
13
+ return { messages: [{ role: 'user', content: { type: 'text', text: body } }] };
14
+ }
15
+
16
+ export function registerShoppexPrompts(server) {
17
+ server.registerPrompt(
18
+ 'shoppex_daily_brief',
19
+ {
20
+ title: 'Daily brief',
21
+ description:
22
+ 'Summarise today\'s shop health: revenue, orders, failed payments, open tickets, new disputes. Produces an actionable morning brief.',
23
+ },
24
+ () => text(`Give me a concise morning brief for my Shoppex shop. Follow this order:
25
+
26
+ 1. Call analytics_revenue for the current month.
27
+ 2. Call orders_list with limit=10 to see the most recent orders.
28
+ 3. Call invoices_list with status="pending", limit=5.
29
+ 4. Call disputes_list with limit=5 (only flag if status=open).
30
+ 5. Call tickets_list with status="open", limit=5.
31
+
32
+ Return a short markdown briefing with these sections:
33
+ - **Revenue today / MTD** (use currency from the analytics response)
34
+ - **Latest orders** (3 most recent, one line each)
35
+ - **Attention items** — pending invoices over 24h, open disputes, open tickets
36
+ - **Suggested next action** — one sentence, concrete
37
+
38
+ Keep it under 150 words. Do not invent numbers — if a tool returned 0 items, say so.`),
39
+ );
40
+
41
+ server.registerPrompt(
42
+ 'shoppex_launch_product',
43
+ {
44
+ title: 'Launch a product',
45
+ description:
46
+ 'End-to-end product launch: create the product, generate a launch coupon, and return a ready-to-send Discord/Telegram announcement.',
47
+ argsSchema: {
48
+ product_name: z.string().min(1),
49
+ price: z.string().min(1),
50
+ coupon_percent: z.string().min(1).optional(),
51
+ },
52
+ },
53
+ ({ product_name, price, coupon_percent }) => text(`Launch a new product called "${product_name}" priced at $${price}. Work in this order:
54
+
55
+ 1. Call products_create with { title: "${product_name}", price: ${price}, type: "SERVICE" }. Capture the returned uniqid.
56
+ 2. ${coupon_percent ? `Call coupons_create with { code: "LAUNCH${Math.round(Math.random() * 999)}", discount_value: ${coupon_percent}, discount_type: "PERCENTAGE" }.` : 'Skip coupon unless the user explicitly asks for one.'}
57
+ 3. Call payment_links_create for the new product so we have a single shareable checkout URL. Use name="${product_name} launch", type="PRODUCT", gateways=["STRIPE","CRYPTO"].
58
+
59
+ After the tools run, produce:
60
+ - A short confirmation in markdown ("Created …").
61
+ - A ready-to-post Discord launch blurb (2-3 sentences, casual tone, include the payment link and the coupon code if created).
62
+
63
+ Do NOT invent the uniqid or URL — use what the tools returned.`),
64
+ );
65
+
66
+ server.registerPrompt(
67
+ 'shoppex_fraud_check',
68
+ {
69
+ title: 'Fraud check',
70
+ description:
71
+ 'Investigate suspicious orders: look at recent high-value orders, match them against the blacklist, and propose block/refund actions.',
72
+ },
73
+ () => text(`Run a fraud-risk scan on the shop. Work in this order:
74
+
75
+ 1. Call orders_list with limit=30.
76
+ 2. Call disputes_list with limit=20.
77
+ 3. Call blacklist_list with limit=50.
78
+
79
+ Analyse the data and answer:
80
+ - Any order whose customer email or IP is already on the blacklist? (exact match)
81
+ - Any order with an unusually high value vs. the shop's typical order size?
82
+ - Any order with a recent dispute against the same customer email?
83
+ - Any order from a country/IP cluster that has disputes (>=2 in the last 30 days)?
84
+
85
+ Return a markdown report:
86
+ - **Risk score**: low / medium / high (overall)
87
+ - **Flagged orders** (table: order id, customer, reason, suggested action)
88
+ - **Recommended blacklist adds** (email/ip/country with reason)
89
+
90
+ Do not execute block/refund automatically. End with: "Want me to add these to the blacklist? Confirm one-by-one."`),
91
+ );
92
+
93
+ server.registerPrompt(
94
+ 'shoppex_weekly_recap',
95
+ {
96
+ title: 'Weekly recap',
97
+ description:
98
+ 'Seven-day performance recap: revenue, top products, customer additions, operational health. Designed for founder/team standups.',
99
+ },
100
+ () => text(`Give me a 7-day recap for the shop. Work in this order:
101
+
102
+ 1. Call analytics_revenue for the last 7 days.
103
+ 2. Call orders_list with limit=50 (to estimate order volume).
104
+ 3. Call products_list with limit=20 to know the catalog.
105
+ 4. Call customers_list with limit=20 (most recent signups).
106
+ 5. Call invoices_list with status="paid", limit=20.
107
+
108
+ Return a markdown recap with:
109
+ - **Revenue (7d)** + YoY trend if data allows
110
+ - **Top 3 products by order count**
111
+ - **New customers this week** (count + 2-3 notable emails if VIP-like)
112
+ - **Operational signals** (pending invoices, failed payments if visible)
113
+ - **Focus for next week** — one concrete initiative
114
+
115
+ Tone: factual, founder-facing, under 250 words.`),
116
+ );
117
+
118
+ server.registerPrompt(
119
+ 'shoppex_customer_care',
120
+ {
121
+ title: 'Customer care',
122
+ description:
123
+ 'Look up a customer end-to-end: orders, invoices, subscriptions, licenses, tickets. Returns a full timeline plus a draft reply.',
124
+ argsSchema: {
125
+ email: z.string().email(),
126
+ },
127
+ },
128
+ ({ email }) => text(`Look up the full history for customer "${email}". Work in this order:
129
+
130
+ 1. Call customers_get with email="${email}".
131
+ 2. Call orders_list with customer_email="${email}", limit=20.
132
+ 3. Call invoices_list with customer_email="${email}", limit=10.
133
+ 4. Call licenses_list (then filter locally by the customer's id).
134
+ 5. Call subscriptions_list (then filter locally by the customer's id).
135
+
136
+ Return a markdown report:
137
+ - **Summary** (customer name/email, total spend, first-seen / last-seen)
138
+ - **Timeline** (orders + tickets chronologically)
139
+ - **Open issues** (active disputes, unresolved tickets, failed payments)
140
+ - **Draft reply** — a ready-to-send support message that addresses likely concerns, signed as the shop
141
+
142
+ Keep the draft reply polite, short, and actionable. Do not invent details the tools didn't return.`),
143
+ );
144
+
145
+ server.registerPrompt(
146
+ 'shoppex_theme_refresh',
147
+ {
148
+ title: 'Theme refresh',
149
+ description:
150
+ 'Guided mini-review of the shop\'s active theme: structure, sections, recent changes, publish readiness.',
151
+ },
152
+ () => text(`Do a theme-refresh review. Work in this order:
153
+
154
+ 1. Call theme_list to find the active theme for this shop (is_active=true).
155
+ 2. Call theme_inspect on the active theme to get sections, settings, tokens.
156
+ 3. Call theme_diff on the active theme to see draft vs. published state.
157
+ 4. Call theme_latest_run on the active theme to see the last build health.
158
+
159
+ Return a markdown report:
160
+ - **Active theme** (name, scheme, version)
161
+ - **Section inventory** (list of sections + page count)
162
+ - **Draft status** (any pending changes? any build errors?)
163
+ - **Publish readiness** — safe to publish? what risks?
164
+ - **Suggested improvements** — 2-3 concrete section-level tweaks (e.g. "Add a testimonials section above footer"). Keep them specific.
165
+
166
+ Format: founder-facing, under 200 words.`),
167
+ );
168
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * MCP Resources for Shoppex — cacheable read-only context documents the
3
+ * client can attach to a conversation (e.g. Claude Desktop "Attach" menu).
4
+ * Each resource fetches fresh data on read and returns JSON text.
5
+ *
6
+ * Registration via `server.registerResource(name, uri, { title, description, mimeType }, async () => ({ contents: [...] }))`.
7
+ */
8
+
9
+ import { ShoppexCommerceDevApiClient } from './server.mjs';
10
+
11
+ function resolveShopApiKey() {
12
+ const fromEnv = process.env.SHOPPEX_SHOP_API_KEY?.trim()
13
+ || process.env.SHOPPEX_API_KEY?.trim()
14
+ || process.env.SHOP_API_KEY?.trim();
15
+ if (!fromEnv) {
16
+ throw new Error('Shoppex resources require SHOPPEX_SHOP_API_KEY to be set.');
17
+ }
18
+ return fromEnv;
19
+ }
20
+
21
+ function buildClient() {
22
+ return new ShoppexCommerceDevApiClient({
23
+ shopApiKey: resolveShopApiKey(),
24
+ apiBaseUrl: process.env.SHOPPEX_API_BASE_URL?.trim()
25
+ || process.env.API_URL?.trim()
26
+ || 'https://api.shoppex.io',
27
+ });
28
+ }
29
+
30
+ function jsonResource(uri, value) {
31
+ return {
32
+ contents: [
33
+ {
34
+ uri,
35
+ mimeType: 'application/json',
36
+ text: JSON.stringify(value, null, 2),
37
+ },
38
+ ],
39
+ };
40
+ }
41
+
42
+ export function registerShoppexResources(server) {
43
+ server.registerResource(
44
+ 'shoppex_products_catalog',
45
+ 'shoppex://products',
46
+ {
47
+ title: 'Product catalog',
48
+ description: 'Current product catalog for the authenticated shop (up to 50 products, includes variants).',
49
+ mimeType: 'application/json',
50
+ },
51
+ async (uri) => {
52
+ const data = await buildClient().productsList({ limit: 50 });
53
+ return jsonResource(uri.href, data ?? []);
54
+ },
55
+ );
56
+
57
+ server.registerResource(
58
+ 'shoppex_recent_orders',
59
+ 'shoppex://orders/recent',
60
+ {
61
+ title: 'Recent orders',
62
+ description: '50 most recent orders across all statuses.',
63
+ mimeType: 'application/json',
64
+ },
65
+ async (uri) => {
66
+ const data = await buildClient().ordersList({ limit: 50 });
67
+ return jsonResource(uri.href, data ?? []);
68
+ },
69
+ );
70
+
71
+ server.registerResource(
72
+ 'shoppex_analytics_summary',
73
+ 'shoppex://analytics/summary',
74
+ {
75
+ title: 'Analytics summary',
76
+ description: 'Month-to-date revenue totals and recent trends.',
77
+ mimeType: 'application/json',
78
+ },
79
+ async (uri) => {
80
+ const data = await buildClient().analyticsRevenue({ currency: 'USD' });
81
+ return jsonResource(uri.href, data ?? {});
82
+ },
83
+ );
84
+
85
+ server.registerResource(
86
+ 'shoppex_categories',
87
+ 'shoppex://categories',
88
+ {
89
+ title: 'Category tree',
90
+ description: 'Full product category list for the shop.',
91
+ mimeType: 'application/json',
92
+ },
93
+ async (uri) => {
94
+ const data = await buildClient().categoriesList();
95
+ return jsonResource(uri.href, data ?? []);
96
+ },
97
+ );
98
+
99
+ server.registerResource(
100
+ 'shoppex_open_tickets',
101
+ 'shoppex://tickets/open',
102
+ {
103
+ title: 'Open support tickets',
104
+ description: 'Tickets currently in status=open for the shop.',
105
+ mimeType: 'application/json',
106
+ },
107
+ async (uri) => {
108
+ const data = await buildClient().ticketsList({ limit: 50, status: 'open' });
109
+ return jsonResource(uri.href, data ?? []);
110
+ },
111
+ );
112
+ }
package/src/server.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import * as z from 'zod/v4';
4
+ import { registerShoppexPrompts } from './prompts.mjs';
5
+ import { registerShoppexResources } from './resources.mjs';
4
6
 
5
7
  const DEV_API_TIMEOUT_MS = Number.parseInt(process.env.SHOPPEX_DEV_API_TIMEOUT_MS ?? '10000', 10);
6
8
 
@@ -1162,7 +1164,7 @@ export async function executeCommerceTool(toolName, args) {
1162
1164
  export function createCommerceMcpServer() {
1163
1165
  const server = new McpServer({
1164
1166
  name: 'shoppex-commerce',
1165
- version: '0.1.0',
1167
+ version: '0.7.0',
1166
1168
  });
1167
1169
 
1168
1170
  for (const tool of createCommerceToolCatalog()) {
@@ -1175,6 +1177,9 @@ export function createCommerceMcpServer() {
1175
1177
  });
1176
1178
  }
1177
1179
 
1180
+ registerShoppexResources(server);
1181
+ registerShoppexPrompts(server);
1182
+
1178
1183
  return server;
1179
1184
  }
1180
1185