epicmerch-mcp 1.0.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 +182 -0
- package/manifest.json +17 -0
- package/package.json +64 -0
- package/skills/epicmerch-auth.md +78 -0
- package/skills/epicmerch-merchant-agent.md +74 -0
- package/skills/epicmerch-merchant.md +46 -0
- package/skills/epicmerch-migrate.md +62 -0
- package/skills/epicmerch-orders.md +153 -0
- package/skills/epicmerch-products.md +95 -0
- package/skills/epicmerch-stripe.md +64 -0
- package/skills/epicmerch.md +389 -0
- package/smithery.yaml +6 -0
- package/src/adapters/mcp.js +76 -0
- package/src/adapters/openapi.js +97 -0
- package/src/auth.js +118 -0
- package/src/client.js +81 -0
- package/src/index.js +67 -0
- package/src/install.js +269 -0
- package/src/login.js +149 -0
- package/src/logout.js +30 -0
- package/src/prompts/index.js +59 -0
- package/src/refresh.js +73 -0
- package/src/resources/examples/auth.md +31 -0
- package/src/resources/examples/orders.md +27 -0
- package/src/resources/examples/payments.md +23 -0
- package/src/resources/examples/products.md +22 -0
- package/src/resources/overview.md +26 -0
- package/src/resources/sdk-guide.md +341 -0
- package/src/status.js +22 -0
- package/src/token-store.js +52 -0
- package/src/tools/_examples.js +352 -0
- package/src/tools/developer.js +65 -0
- package/src/tools/merchant.js +618 -0
- package/src/tools/scaffold.js +278 -0
- package/src/tools/session.js +44 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// src/tools/scaffold.js
|
|
2
|
+
const TEMPLATES = {
|
|
3
|
+
react: {
|
|
4
|
+
auth: [
|
|
5
|
+
{
|
|
6
|
+
path: 'src/lib/epicmerch.js',
|
|
7
|
+
content: `import EpicMerch from 'epicmerch';
|
|
8
|
+
|
|
9
|
+
export const store = new EpicMerch({
|
|
10
|
+
apiKey: import.meta.env.VITE_API_KEY,
|
|
11
|
+
...(import.meta.env.VITE_API_URL && { baseUrl: import.meta.env.VITE_API_URL }),
|
|
12
|
+
});
|
|
13
|
+
`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
path: 'src/components/Login.jsx',
|
|
17
|
+
content: `import { useState } from 'react';
|
|
18
|
+
import { store } from '../lib/epicmerch';
|
|
19
|
+
|
|
20
|
+
export default function Login({ onLogin }) {
|
|
21
|
+
const [phone, setPhone] = useState('');
|
|
22
|
+
const [otp, setOtp] = useState('');
|
|
23
|
+
const [step, setStep] = useState('phone');
|
|
24
|
+
|
|
25
|
+
const sendOtp = async () => {
|
|
26
|
+
await store.auth.sendOtp(phone, 'phone');
|
|
27
|
+
setStep('otp');
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const verify = async () => {
|
|
31
|
+
const result = await store.auth.verifyOtp(phone, otp, {});
|
|
32
|
+
if (result.token) {
|
|
33
|
+
store.setCustomerToken(result.token);
|
|
34
|
+
localStorage.setItem('customerInfo', JSON.stringify(result));
|
|
35
|
+
onLogin(result);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
{step === 'phone' ? (
|
|
42
|
+
<>
|
|
43
|
+
<input value={phone} onChange={e => setPhone(e.target.value)} placeholder="+919876543210" />
|
|
44
|
+
<button onClick={sendOtp}>Send OTP</button>
|
|
45
|
+
</>
|
|
46
|
+
) : (
|
|
47
|
+
<>
|
|
48
|
+
<input value={otp} onChange={e => setOtp(e.target.value)} placeholder="Enter OTP" />
|
|
49
|
+
<button onClick={verify}>Verify</button>
|
|
50
|
+
</>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
`,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
|
|
59
|
+
products: [
|
|
60
|
+
{
|
|
61
|
+
path: 'src/components/ProductCard.jsx',
|
|
62
|
+
content: `export default function ProductCard({ product, onAddToCart }) {
|
|
63
|
+
return (
|
|
64
|
+
<div className="product-card">
|
|
65
|
+
<img src={product.images?.[0]} alt={product.name} />
|
|
66
|
+
<h3>{product.name}</h3>
|
|
67
|
+
<p>₹{product.price}</p>
|
|
68
|
+
<button onClick={() => onAddToCart(product._id)}>Add to Cart</button>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
`,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
path: 'src/components/ProductList.jsx',
|
|
76
|
+
content: `import { useEffect, useState } from 'react';
|
|
77
|
+
import { store } from '../lib/epicmerch';
|
|
78
|
+
import ProductCard from './ProductCard';
|
|
79
|
+
|
|
80
|
+
export default function ProductList() {
|
|
81
|
+
const [products, setProducts] = useState([]);
|
|
82
|
+
const [category, setCategory] = useState(undefined);
|
|
83
|
+
const [categories, setCategories] = useState([]);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
store.categories.list().then(setCategories);
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
store.products.list({ type: category, limit: 12 }).then(d => setProducts(d.products));
|
|
91
|
+
}, [category]);
|
|
92
|
+
|
|
93
|
+
const addToCart = async (productId) => {
|
|
94
|
+
await store.cart.add(productId, 1);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div>
|
|
99
|
+
<div>
|
|
100
|
+
{categories.map(c => (
|
|
101
|
+
<button key={c} onClick={() => setCategory(c === 'All' ? undefined : c)}>{c}</button>
|
|
102
|
+
))}
|
|
103
|
+
</div>
|
|
104
|
+
<div className="product-grid">
|
|
105
|
+
{products.map(p => <ProductCard key={p._id} product={p} onAddToCart={addToCart} />)}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
`,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
|
|
114
|
+
orders: [
|
|
115
|
+
{
|
|
116
|
+
path: 'src/components/Cart.jsx',
|
|
117
|
+
content: `import { useEffect, useState } from 'react';
|
|
118
|
+
import { store } from '../lib/epicmerch';
|
|
119
|
+
|
|
120
|
+
export default function Cart({ onCheckout }) {
|
|
121
|
+
const [cart, setCart] = useState({ items: [] });
|
|
122
|
+
|
|
123
|
+
useEffect(() => { store.cart.get().then(setCart); }, []);
|
|
124
|
+
|
|
125
|
+
const remove = async (productId) => {
|
|
126
|
+
await store.cart.remove(productId);
|
|
127
|
+
store.cart.get().then(setCart);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const total = cart.items?.reduce((sum, i) => sum + i.price * i.qty, 0) ?? 0;
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<div>
|
|
134
|
+
{cart.items?.map(item => (
|
|
135
|
+
<div key={item.productId}>
|
|
136
|
+
<span>{item.name} x{item.qty}</span>
|
|
137
|
+
<span>₹{item.price * item.qty}</span>
|
|
138
|
+
<button onClick={() => remove(item.productId)}>Remove</button>
|
|
139
|
+
</div>
|
|
140
|
+
))}
|
|
141
|
+
<p>Total: ₹{total}</p>
|
|
142
|
+
<button onClick={onCheckout}>Checkout</button>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
`,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
path: 'src/components/Checkout.jsx',
|
|
150
|
+
content: `import { useState } from 'react';
|
|
151
|
+
import { store } from '../lib/epicmerch';
|
|
152
|
+
|
|
153
|
+
export default function Checkout({ cart, onSuccess }) {
|
|
154
|
+
const [address, setAddress] = useState({ street: '', city: '', postalCode: '', country: 'India' });
|
|
155
|
+
|
|
156
|
+
const placeOrder = async () => {
|
|
157
|
+
const total = cart.items.reduce((s, i) => s + i.price * i.qty, 0);
|
|
158
|
+
const { orderId } = await store.orders.create({
|
|
159
|
+
orderItems: cart.items.map(i => ({ productId: i.productId, qty: i.qty, price: i.price })),
|
|
160
|
+
shippingAddress: address,
|
|
161
|
+
paymentMethod: 'Razorpay',
|
|
162
|
+
totalPrice: total,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const config = await store.payment.getConfig();
|
|
166
|
+
const { razorpayOrderId } = await store.payment.createOrder(total * 100, orderId);
|
|
167
|
+
|
|
168
|
+
const rzp = new window.Razorpay({
|
|
169
|
+
key: config.razorpayKeyId,
|
|
170
|
+
order_id: razorpayOrderId,
|
|
171
|
+
amount: total * 100,
|
|
172
|
+
handler: async (response) => {
|
|
173
|
+
await store.payment.verify({ ...response, orderId });
|
|
174
|
+
await store.cart.clear();
|
|
175
|
+
onSuccess(orderId);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
rzp.open();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div>
|
|
183
|
+
<input placeholder="Street" onChange={e => setAddress(a => ({ ...a, street: e.target.value }))} />
|
|
184
|
+
<input placeholder="City" onChange={e => setAddress(a => ({ ...a, city: e.target.value }))} />
|
|
185
|
+
<input placeholder="Postal Code" onChange={e => setAddress(a => ({ ...a, postalCode: e.target.value }))} />
|
|
186
|
+
<button onClick={placeOrder}>Place Order</button>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
`,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
path: 'src/components/OrderHistory.jsx',
|
|
194
|
+
content: `import { useEffect, useState } from 'react';
|
|
195
|
+
import { store } from '../lib/epicmerch';
|
|
196
|
+
|
|
197
|
+
export default function OrderHistory() {
|
|
198
|
+
const [orders, setOrders] = useState([]);
|
|
199
|
+
|
|
200
|
+
useEffect(() => { store.orders.list().then(setOrders); }, []);
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div>
|
|
204
|
+
{orders.map(order => (
|
|
205
|
+
<div key={order._id}>
|
|
206
|
+
<span>Order #{order._id.slice(-6)}</span>
|
|
207
|
+
<span>{order.status}</span>
|
|
208
|
+
<span>₹{order.totalPrice}</span>
|
|
209
|
+
</div>
|
|
210
|
+
))}
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
`,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
|
|
218
|
+
envExample: {
|
|
219
|
+
path: '.env.example',
|
|
220
|
+
content: `VITE_API_KEY=your_epicmerch_api_key_here\n# VITE_API_URL=http://localhost:5001/api\n`,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
function getFrameworkTemplates(framework) {
|
|
226
|
+
if (!TEMPLATES[framework]) {
|
|
227
|
+
throw new Error(`Framework "${framework}" not supported. Supported: ${Object.keys(TEMPLATES).join(', ')}`);
|
|
228
|
+
}
|
|
229
|
+
return TEMPLATES[framework];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function scaffoldTools() {
|
|
233
|
+
return {
|
|
234
|
+
async store_scaffold_auth({ framework = 'react' } = {}) {
|
|
235
|
+
try {
|
|
236
|
+
const t = getFrameworkTemplates(framework);
|
|
237
|
+
return { content: [{ type: 'text', text: JSON.stringify(t.auth, null, 2) }] };
|
|
238
|
+
} catch (err) {
|
|
239
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
async store_scaffold_products({ framework = 'react' } = {}) {
|
|
244
|
+
try {
|
|
245
|
+
const t = getFrameworkTemplates(framework);
|
|
246
|
+
return { content: [{ type: 'text', text: JSON.stringify(t.products, null, 2) }] };
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
async store_scaffold_orders({ framework = 'react' } = {}) {
|
|
253
|
+
try {
|
|
254
|
+
const t = getFrameworkTemplates(framework);
|
|
255
|
+
return { content: [{ type: 'text', text: JSON.stringify(t.orders, null, 2) }] };
|
|
256
|
+
} catch (err) {
|
|
257
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
async store_scaffold_full({ framework = 'react' } = {}) {
|
|
262
|
+
try {
|
|
263
|
+
const t = getFrameworkTemplates(framework);
|
|
264
|
+
const files = [...t.auth, ...t.products, ...t.orders, t.envExample];
|
|
265
|
+
return { content: [{ type: 'text', text: JSON.stringify(files, null, 2) }] };
|
|
266
|
+
} catch (err) {
|
|
267
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const scaffoldToolDefs = [
|
|
274
|
+
{ name: 'store_scaffold_auth', description: 'Generate auth integration files (SDK init + Login component) for a framework. Returns [{path, content}] — write these files to the project.', schema: { framework: { type: 'string', description: 'react (default)' } } },
|
|
275
|
+
{ name: 'store_scaffold_products', description: 'Generate product catalog components (ProductList, ProductCard) for a framework.', schema: { framework: { type: 'string' } } },
|
|
276
|
+
{ name: 'store_scaffold_orders', description: 'Generate cart + order management components (Cart, Checkout, OrderHistory) for a framework.', schema: { framework: { type: 'string' } } },
|
|
277
|
+
{ name: 'store_scaffold_full', description: 'Generate a complete EpicMerch-integrated storefront scaffold (auth + products + orders + .env.example).', schema: { framework: { type: 'string' } } },
|
|
278
|
+
];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export function sessionTools(session) {
|
|
2
|
+
return {
|
|
3
|
+
async store_list_stores(_args) {
|
|
4
|
+
const stores = session.listStores();
|
|
5
|
+
const lines = stores.map(s => `- ${s.name}${s.active ? ' (active)' : ''}`).join('\n');
|
|
6
|
+
return { content: [{ type: 'text', text: `Configured stores:\n${lines}` }] };
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
async store_switch({ name }) {
|
|
10
|
+
try {
|
|
11
|
+
session.switch(name);
|
|
12
|
+
return { content: [{ type: 'text', text: `Switched to store: ${name}` }] };
|
|
13
|
+
} catch (err) {
|
|
14
|
+
return { isError: true, content: [{ type: 'text', text: err.message }] };
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async store_add({ name, apiKey }) {
|
|
19
|
+
session.addStore(name, apiKey);
|
|
20
|
+
return { content: [{ type: 'text', text: `Store "${name}" added. Call store_switch to activate it.` }] };
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const sessionToolDefs = [
|
|
26
|
+
{
|
|
27
|
+
name: 'store_list_stores',
|
|
28
|
+
description: 'List all configured EpicMerch stores and which is currently active.',
|
|
29
|
+
schema: {},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'store_switch',
|
|
33
|
+
description: 'Switch the active store. All subsequent tool calls will use this store\'s credentials.',
|
|
34
|
+
schema: { name: { type: 'string', description: 'Store name as configured in EPICMERCH_STORES' } },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'store_add',
|
|
38
|
+
description: 'Add a new EpicMerch store to the session without restarting.',
|
|
39
|
+
schema: {
|
|
40
|
+
name: { type: 'string', description: 'Store name' },
|
|
41
|
+
apiKey: { type: 'string', description: 'EpicMerch API key for this store' },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|