@sellhapi/mcp 0.1.3 → 0.1.5
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/dist/server.js +2 -0
- package/dist/tools/analytics.d.ts +5 -0
- package/dist/tools/analytics.js +22 -0
- package/dist/tools/commerce.js +67 -3
- package/dist/tools/studio.js +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -12,6 +12,7 @@ const studio_js_1 = require("./tools/studio.js");
|
|
|
12
12
|
const commerce_js_1 = require("./tools/commerce.js");
|
|
13
13
|
const content_js_1 = require("./tools/content.js");
|
|
14
14
|
const intelligence_js_1 = require("./tools/intelligence.js");
|
|
15
|
+
const analytics_js_1 = require("./tools/analytics.js");
|
|
15
16
|
const index_js_1 = require("./resources/index.js");
|
|
16
17
|
function createMcpServer() {
|
|
17
18
|
const server = new mcp_js_1.McpServer({
|
|
@@ -22,6 +23,7 @@ function createMcpServer() {
|
|
|
22
23
|
(0, commerce_js_1.registerCommerceTools)(server);
|
|
23
24
|
(0, content_js_1.registerContentTools)(server);
|
|
24
25
|
(0, intelligence_js_1.registerIntelligenceTools)(server);
|
|
26
|
+
(0, analytics_js_1.registerAnalyticsTools)(server);
|
|
25
27
|
(0, index_js_1.registerResources)(server);
|
|
26
28
|
return server;
|
|
27
29
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Analytics tools — read-only access to pre-computed capability metrics.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerAnalyticsTools = registerAnalyticsTools;
|
|
7
|
+
const v4_1 = require("zod/v4");
|
|
8
|
+
const client_js_1 = require("../client.js");
|
|
9
|
+
const util_js_1 = require("../util.js");
|
|
10
|
+
function registerAnalyticsTools(server) {
|
|
11
|
+
server.registerTool("get_analytics", {
|
|
12
|
+
title: "Get Analytics",
|
|
13
|
+
description: "Get pre-computed analytics for this vendor. Returns revenue, transaction counts, and other metrics per capability for a given period. Use this to answer questions like 'what's my revenue this month', 'which capability earns the most', or 'how many orders have I had'. Metrics are computed on a schedule — call this before making business recommendations.",
|
|
14
|
+
annotations: { readOnlyHint: true },
|
|
15
|
+
inputSchema: {
|
|
16
|
+
period: v4_1.z.enum(["7d", "30d", "90d"]).optional().default("30d").describe("Time period for metrics (default: 30d)"),
|
|
17
|
+
},
|
|
18
|
+
}, async ({ period }) => (0, util_js_1.safeCall)(async () => {
|
|
19
|
+
const data = await (0, client_js_1.get)(`/api/mcp/analytics?period=${period}`);
|
|
20
|
+
return JSON.stringify(data, null, 2);
|
|
21
|
+
}));
|
|
22
|
+
}
|
package/dist/tools/commerce.js
CHANGED
|
@@ -72,10 +72,58 @@ function registerCommerceTools(server) {
|
|
|
72
72
|
const data = await (0, client_js_1.get)("/api/mcp/appointments/services");
|
|
73
73
|
return JSON.stringify(data.services, null, 2);
|
|
74
74
|
}));
|
|
75
|
+
// ── Discounts ─────────────────────────────────────────────────────────────
|
|
76
|
+
server.registerTool("list_discounts", {
|
|
77
|
+
title: "List Discounts",
|
|
78
|
+
description: "List all active discounts for this vendor. Returns id, name, code, discountType, value, scope, usage count, and expiry. Use this to check existing discounts before creating new ones.",
|
|
79
|
+
annotations: { readOnlyHint: true },
|
|
80
|
+
}, async () => (0, util_js_1.safeCall)(async () => {
|
|
81
|
+
const data = await (0, client_js_1.get)("/api/mcp/discounts");
|
|
82
|
+
return JSON.stringify(data.discounts, null, 2);
|
|
83
|
+
}));
|
|
84
|
+
server.registerTool("create_discount", {
|
|
85
|
+
title: "Create Discount",
|
|
86
|
+
description: "Create a discount code or automatic discount. For percentage discounts, value is 1–100 (e.g. 20 = 20% off). For fixed discounts, value is in kobo (₦1 = 100 kobo) — the API converts to Naira internally. minimumOrderKobo is also in kobo. scope 'all_products' applies sitewide. 'specific_products' and 'specific_categories' require editing via the dashboard after creation. code is optional — omit for automatic (no-code) discounts.",
|
|
87
|
+
inputSchema: {
|
|
88
|
+
name: v4_1.z.string().describe("Internal discount name e.g. 'Lagos Launch 20% Off'"),
|
|
89
|
+
discountType: v4_1.z.enum(["percentage", "fixed"]).describe("percentage = % off, fixed = fixed Naira amount off"),
|
|
90
|
+
value: v4_1.z.number().describe("For percentage: 1–100. For fixed: amount in kobo (₦1 = 100 kobo)."),
|
|
91
|
+
code: v4_1.z.string().optional().describe("Discount code customers enter at checkout (e.g. 'LAUNCH20'). Omit for automatic discount."),
|
|
92
|
+
description: v4_1.z.string().optional().describe("Internal description"),
|
|
93
|
+
scope: v4_1.z.enum(["all_products", "specific_products", "specific_categories"]).optional().default("all_products").describe("Which products this applies to. specific_products/specific_categories require assigning products in the dashboard after creation."),
|
|
94
|
+
usageLimit: v4_1.z.number().int().min(1).optional().describe("Maximum total uses. Omit for unlimited."),
|
|
95
|
+
minimumOrderKobo: v4_1.z.number().int().min(0).optional().describe("Minimum cart total in kobo to qualify for this discount."),
|
|
96
|
+
expiresAt: v4_1.z.string().optional().describe("Expiry datetime — ISO 8601 string. Omit for no expiry."),
|
|
97
|
+
startsAt: v4_1.z.string().optional().describe("Start datetime — ISO 8601 string. Omit to activate immediately."),
|
|
98
|
+
},
|
|
99
|
+
}, async (input) => (0, util_js_1.safeCall)(async () => {
|
|
100
|
+
const data = await (0, client_js_1.post)("/api/mcp/discounts", input);
|
|
101
|
+
return JSON.stringify(data, null, 2);
|
|
102
|
+
}));
|
|
103
|
+
// ── Categories ────────────────────────────────────────────────────────────
|
|
104
|
+
server.registerTool("list_categories", {
|
|
105
|
+
title: "List Categories",
|
|
106
|
+
description: "List all product categories for this vendor. Call this before create_product or update_product to get valid categoryId values. Returns id, name, description for each category.",
|
|
107
|
+
annotations: { readOnlyHint: true },
|
|
108
|
+
}, async () => (0, util_js_1.safeCall)(async () => {
|
|
109
|
+
const data = await (0, client_js_1.get)("/api/mcp/categories");
|
|
110
|
+
return JSON.stringify(data.categories, null, 2);
|
|
111
|
+
}));
|
|
112
|
+
server.registerTool("create_category", {
|
|
113
|
+
title: "Create Category",
|
|
114
|
+
description: "Create a product category. Returns the new category id — use it immediately in create_product or update_product. Returns a 409 conflict (with the existing id) if a category with the same name already exists — use that id instead of creating a duplicate.",
|
|
115
|
+
inputSchema: {
|
|
116
|
+
name: v4_1.z.string().describe("Category name e.g. 'Clothing', 'Baked Goods'"),
|
|
117
|
+
description: v4_1.z.string().optional().describe("Optional description"),
|
|
118
|
+
},
|
|
119
|
+
}, async (input) => (0, util_js_1.safeCall)(async () => {
|
|
120
|
+
const data = await (0, client_js_1.post)("/api/mcp/categories", input);
|
|
121
|
+
return JSON.stringify(data, null, 2);
|
|
122
|
+
}));
|
|
75
123
|
// ── Write: Create product ─────────────────────────────────────────────────
|
|
76
124
|
server.registerTool("create_product", {
|
|
77
125
|
title: "Create Product",
|
|
78
|
-
description: "Create a physical or digital product. Call list_capabilities first to confirm the relevant capability (physical_products or digital_products) is active. Prices must be in kobo (₦1 = 100 kobo). imageUrl is optional
|
|
126
|
+
description: "Create a physical or digital product. Call list_capabilities first to confirm the relevant capability (physical_products or digital_products) is active. Call list_categories first to get a valid categoryId — supplying an invalid categoryId returns a 400 error. Prices must be in kobo (₦1 = 100 kobo). imageUrl is optional.",
|
|
79
127
|
inputSchema: {
|
|
80
128
|
name: v4_1.z.string().describe("Product name"),
|
|
81
129
|
description: v4_1.z.string().optional().describe("Product description"),
|
|
@@ -83,11 +131,27 @@ function registerCommerceTools(server) {
|
|
|
83
131
|
type: v4_1.z.enum(["physical", "digital"]).optional().default("physical").describe("Product type — physical (default) or digital"),
|
|
84
132
|
stock: v4_1.z.number().int().min(0).optional().describe("Initial stock quantity (0 = out of stock). Omit for untracked stock."),
|
|
85
133
|
imageUrl: v4_1.z.string().optional().describe("External image URL for the product"),
|
|
134
|
+
categoryId: v4_1.z.string().uuid().optional().describe("Category ID from list_categories. Omit if no category applies."),
|
|
86
135
|
},
|
|
87
136
|
}, async (input) => (0, util_js_1.safeCall)(async () => {
|
|
88
137
|
const data = await (0, client_js_1.post)("/api/mcp/products", input);
|
|
89
138
|
return JSON.stringify(data, null, 2);
|
|
90
139
|
}));
|
|
140
|
+
// ── Write: Update product ─────────────────────────────────────────────────
|
|
141
|
+
server.registerTool("update_product", {
|
|
142
|
+
title: "Update Product",
|
|
143
|
+
description: "Update an existing product's name, description, category, or image. Call list_products to get the productId, list_categories to get a valid categoryId. Only fields provided are updated — omitted fields stay unchanged. Pass categoryId: null to remove the category.",
|
|
144
|
+
inputSchema: {
|
|
145
|
+
productId: v4_1.z.string().uuid().describe("Product ID from list_products"),
|
|
146
|
+
name: v4_1.z.string().optional().describe("New product name"),
|
|
147
|
+
description: v4_1.z.string().optional().describe("New product description"),
|
|
148
|
+
categoryId: v4_1.z.string().uuid().nullable().optional().describe("Category ID from list_categories, or null to remove category"),
|
|
149
|
+
imageUrl: v4_1.z.string().nullable().optional().describe("New image URL, or null to clear"),
|
|
150
|
+
},
|
|
151
|
+
}, async ({ productId, ...rest }) => (0, util_js_1.safeCall)(async () => {
|
|
152
|
+
const data = await (0, client_js_1.patch)(`/api/mcp/products/${productId}`, rest);
|
|
153
|
+
return JSON.stringify(data, null, 2);
|
|
154
|
+
}));
|
|
91
155
|
// ── Write: Create event ───────────────────────────────────────────────────
|
|
92
156
|
server.registerTool("create_event", {
|
|
93
157
|
title: "Create Event",
|
|
@@ -181,13 +245,13 @@ function registerCommerceTools(server) {
|
|
|
181
245
|
// ── Write: Create form ───────────────────────────────────────────────────
|
|
182
246
|
server.registerTool("create_form", {
|
|
183
247
|
title: "Create Form",
|
|
184
|
-
description: "Create a published storefront form. Returns the form ID — use it in useContentForm(formId) and useSubmitForm(formId) in storefront code. Call list_capabilities first to confirm content capability is active. Field types: text, email, phone, textarea, select, checkbox, date, number.",
|
|
248
|
+
description: "Create a published storefront form. Returns the form ID — use it in useContentForm(formId) and useSubmitForm(formId) in storefront code. Call list_capabilities first to confirm content capability is active. Field types: text, email, phone, textarea, select, radio, checkbox, date, number, file.",
|
|
185
249
|
inputSchema: {
|
|
186
250
|
title: v4_1.z.string().describe("Form name e.g. 'Contact Us'"),
|
|
187
251
|
description: v4_1.z.string().optional(),
|
|
188
252
|
fields: v4_1.z.array(v4_1.z.object({
|
|
189
253
|
label: v4_1.z.string().describe("Field label shown to the user"),
|
|
190
|
-
type: v4_1.z.enum(["text", "email", "phone", "textarea", "select", "checkbox", "date", "number"]).describe("Field input type"),
|
|
254
|
+
type: v4_1.z.enum(["text", "email", "phone", "textarea", "select", "radio", "checkbox", "date", "number", "file"]).describe("Field input type"),
|
|
191
255
|
required: v4_1.z.boolean().optional().default(false),
|
|
192
256
|
placeholder: v4_1.z.string().optional(),
|
|
193
257
|
options: v4_1.z.array(v4_1.z.string()).optional().describe("Options for select fields"),
|
package/dist/tools/studio.js
CHANGED
|
@@ -124,7 +124,7 @@ function registerStudioTools(server) {
|
|
|
124
124
|
// ── Push code (zero credits) ───────────────────────────────────────────────
|
|
125
125
|
server.registerTool("push_code", {
|
|
126
126
|
title: "Push Code",
|
|
127
|
-
description: "Push client-generated React code to a project. Runs BuildGuard validation + esbuild bundling and returns a preview URL. ZERO AI credit cost — you generate the code, SellHapi only builds it. CRITICAL RULES: (1) import ONLY from @sellhapi/studio-runtime and react — NO external packages; (2) every top-level JSX section must have data-region, data-label, data-scope attributes; (3)
|
|
127
|
+
description: "Push client-generated React code to a project. Runs BuildGuard validation + esbuild bundling and returns a preview URL. ZERO AI credit cost — you generate the code, SellHapi only builds it. CRITICAL RULES: (1) import ONLY from @sellhapi/studio-runtime and react — NO external packages; (2) every top-level JSX section must have data-region, data-label, data-scope attributes; (3) use inline React style objects for ALL styling — Tailwind is NOT available; (4) NO localStorage/sessionStorage for state management — EXCEPTION: window.location.href IS required and allowed for payment redirects (all commerce hooks return { paymentLink } — redirect with window.location.href = result.paymentLink); (5) prices via priceKobo / 100 — never hardcode currency. Call get_build_rules or get_runtime_hooks for full reference.",
|
|
128
128
|
inputSchema: {
|
|
129
129
|
projectId: v4_1.z.string().describe("Studio project ID"),
|
|
130
130
|
files: v4_1.z.record(v4_1.z.string(), v4_1.z.string()).describe("Map of filename → code content. Must include App.tsx as entry point."),
|