@sellhapi/mcp 0.1.2 → 0.1.3

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.
@@ -305,6 +305,63 @@ Anti-patterns:
305
305
 
306
306
  ---
307
307
 
308
+ ## ENTITY LAYOUT PHILOSOPHY
309
+
310
+ Entities DO NOT have to be displayed as uniform rectangle cards in a grid.
311
+ Choose the layout that fits the business type, visual direction, and the entity's purpose.
312
+ The wireframe is your opportunity to propose the right layout — the user can approve or change it.
313
+
314
+ Layout options by entity type:
315
+
316
+ MEMBERSHIPS — premium tiers deserve premium presentation:
317
+ - Large image tile (full-width image, title + price + CTA below) — ideal for lifestyle/luxury brands
318
+ - Horizontal comparison table — ideal for SaaS-style or tiered feature sets
319
+ - Feature-rich card with expanded benefits checklist — ideal when benefits are the selling point
320
+ - Avoid generic equal-height rectangle cards unless the business explicitly has many tiers
321
+
322
+ SERVICES — editorial presentation conveys quality better than a card grid:
323
+ - Alternating split sections (image left / text + CTA right, alternates per service)
324
+ - Full-width editorial rows with large background image + text overlay
325
+ - Icon + heading + description list for minimalist service studios
326
+ - Grid cards are acceptable only when services are many and uniform (e.g. a menu)
327
+
328
+ EVENTS — presentation should match the energy of the event:
329
+ - Poster-style: large image, event name as headline, date + location below — theatrical feel
330
+ - Horizontal scroll strip: compact cards in a row — good for many events
331
+ - Featured hero card (first event large, rest smaller) — highlights the primary event
332
+ - Calendar or timeline view when date ordering matters most
333
+
334
+ DONATIONS — campaigns are stories, not products:
335
+ - Hero campaign section: full-width image, campaign name, progress bar, donate CTA
336
+ - Stacked editorial rows: image + story side-by-side, alternating
337
+ - Card grid is acceptable when there are multiple parallel campaigns of equal importance
338
+
339
+ APPOINTMENTS — scheduling flows need clarity, not decoration:
340
+ - Service list → select → calendar → time slot: linear step-by-step (most common, best UX)
341
+ - Service cards with inline "Book now" that opens a side panel
342
+ - Minimal: service name + duration + price in a clean list, not a card grid
343
+
344
+ PRODUCTS (homepage teaser) — this is an editorial/marketing section:
345
+ - 2-col editorial layout: large image takes 60% width, product name + price + CTA in remaining 40%
346
+ - 4-col editorial grid with large images and minimal text overlay
347
+ - Featured product hero (one product at full width) + 3 supporting products below
348
+ - NOT the same component or layout as the /products page — it must look visually distinct
349
+
350
+ PRODUCTS (grid/browse page) — standard grid is correct here:
351
+ - 3-col or 4-col responsive grid with image, name, price, Add to Cart
352
+ - Consistent card height, pagination or Load More at bottom
353
+ - This is the browsing context — uniformity and scannability are correct here
354
+
355
+ Key rules:
356
+ - Match layout to visualDirection.layoutPattern if set — it explicitly describes the intended pattern
357
+ - "glassmorphism" or "soft-shadow" cardStyle + premium business → prefer large image tiles, not small cards
358
+ - The wireframe section names you choose (e.g. "featured-membership-tiles", "editorial-services", "campaign-hero")
359
+ signal your layout intent — use descriptive names, not generic ones like "section1"
360
+ - BuildGuard does NOT enforce layout — only data-region attributes and banned JS APIs are checked
361
+ - The visual representation is yours to decide based on brand and context
362
+
363
+ ---
364
+
308
365
  ## UNIVERSAL RULES
309
366
 
310
367
  1. Price display: always (priceKobo / 100).toLocaleString() — prefix with ₦
@@ -5,4 +5,4 @@
5
5
  * apply_wireframe. The AI client generates mid-fidelity wireframes per page,
6
6
  * presents each one to the user for review, then submits the approved set.
7
7
  */
8
- export declare const WIREFRAME_SCHEMA = "\n# SellHapi Wireframe Schema\n\nWireframes are mid-fidelity HTML page layouts \u2014 one per storefront page.\nThey are the USER'S checkpoint before code is written: present each page\nwireframe in the conversation, collect feedback, revise if needed, then\ncall apply_wireframe only after the user approves the full set.\n\n---\n\n## Data shape\n\n```\n{ [pageSlug: string]: htmlString }\n```\n\n- Each key is a page slug that MUST match one of the slugs in designDirection.pages\n- Each value is a valid HTML string for that page's mid-fidelity wireframe\n- All pages from designDirection.pages should be included (missing pages means no wireframe guidance for code generation on that page)\n\n---\n\n## What a wireframe IS\n\nMid-fidelity structural HTML. It communicates:\n- Which sections appear on the page and in what order\n- What content each section contains (headings, CTAs, placeholder data)\n- Navigation structure (links, cart icon, CTA button)\n- Footer structure (columns, links)\n- Which runtime hook each section will use\n\nIt does NOT include:\n- Real CSS (use only inline style for basic layout structure if needed)\n- JavaScript or React\n- Actual product/service data (use descriptive placeholders)\n- Final colour values or fonts (those come from designDirection.visualDirection)\n\n---\n\n## Structure rules\n\n### Navigation \u2014 MANDATORY on every page\n```html\n<nav>\n <div class=\"nav-logo\">[Business Name]</div>\n <ul class=\"nav-links\">\n <li><a href=\"#/home\">Home</a></li>\n <li><a href=\"#/shop\">Shop</a></li>\n <!-- one <li> per page in designDirection.pages -->\n </ul>\n <!-- If physical_products or digital_products in capabilityIds: -->\n <button class=\"nav-cart\">Cart (0)</button>\n <button class=\"nav-cta\">[Primary CTA]</button>\n</nav>\n```\n\n- Navigation HTML must be **identical across all pages** \u2014 copy verbatim after the first page\n- Highlight the current page's link as active (add class=\"active\" to that <li>)\n- Cart icon only when capability includes physical_products or digital_products\n\n### Footer \u2014 MANDATORY on every page\n```html\n<footer>\n <div class=\"footer-col\">\n <div class=\"footer-logo\">[Business Name]</div>\n <p>[tagline]</p>\n </div>\n <div class=\"footer-col\">\n <h4>NAVIGATE</h4>\n <ul><!-- one <li> per page --></ul>\n </div>\n <div class=\"footer-col\">\n <h4>RESOURCES</h4>\n <ul><!-- relevant links for this business type --></ul>\n </div>\n <div class=\"footer-col\">\n <h4>CONNECT</h4>\n <!-- social platform links -->\n </div>\n <div class=\"footer-bottom\">\u00A9 [year] [Business Name]. All rights reserved.</div>\n</footer>\n```\n\n- Footer HTML must be **identical across all pages** \u2014 copy verbatim after the first page\n\n### Sections\nEach section gets a wrapper with a comment and data-hook attribute:\n\n```html\n<!-- Hero Section -->\n<section data-section=\"hero\" data-hook=\"none\">\n <h1>[Headline \u2014 use the business tagline]</h1>\n <p>[Supporting copy]</p>\n <button>[Primary CTA]</button>\n <div class=\"hero-image\">[Hero image placeholder]</div>\n</section>\n\n<!-- Product Grid Section -->\n<section data-section=\"product-grid\" data-hook=\"useProducts\">\n <h2>Our Products</h2>\n <div class=\"product-grid\">\n <div class=\"product-card\">\n <div class=\"product-image\">[Product image]</div>\n <h3>[Product name]</h3>\n <p>[Price in \u20A6]</p>\n <button>Add to Cart</button>\n </div>\n <!-- repeat 2 more placeholder cards -->\n </div>\n</section>\n\n<!-- Testimonials Section -->\n<section data-section=\"testimonials\" data-hook=\"useContentTestimonials\">\n <h2>What Customers Say</h2>\n <div class=\"testimonials-grid\">\n <blockquote>[Testimonial 1]</blockquote>\n <blockquote>[Testimonial 2]</blockquote>\n <blockquote>[Testimonial 3]</blockquote>\n </div>\n</section>\n```\n\n---\n\n## data-hook values by capability\n\nUse these exact hook names in data-hook attributes so code generation\nmatches the correct runtime hook:\n\n| Section type | data-hook |\n|-------------------------------|---------------------------------|\n| Product listing / grid | useProducts |\n| Product collections | useProductCollections |\n| Single collection | useCollection |\n| Category sections | useSections |\n| Service listings | useServiceListings |\n| Appointment booking | useBookAppointment |\n| Available dates | useAvailableDates |\n| Events listing | useEvents |\n| Donation campaigns | useDonationCampaigns |\n| Membership tiers | useMemberships |\n| Content images | useContentImages |\n| Testimonials | useContentTestimonials |\n| FAQs | useContentFaqs |\n| Team members | useContentTeam |\n| Stats / social proof | useContentStats |\n| Feature highlights | useContentFeatures |\n| Contact / enquiry form | useSubmitForm |\n| Listings (classifieds/jobs) | useListings |\n| Non-data sections (hero, about, footer, nav) | none |\n\n---\n\n## Presenting wireframes to the user\n\nBefore calling apply_wireframe, show each page to the user like this:\n\n```\n\uD83D\uDCC4 HOME PAGE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n[NAV] Logo | Home \u00B7 Shop \u00B7 About \u00B7 Contact [Cart] [Shop Now]\n\n[HERO]\n \"Authentic Nigerian fashion for the bold\"\n Subheading + CTA button\n Full-width hero image\n\n[FEATURED PRODUCTS] (useProducts)\n 3-column product grid \u2014 6 products\n Each card: image, name, price, Add to Cart\n\n[COLLECTIONS] (useProductCollections)\n 4 collection tiles with cover images\n\n[TESTIMONIALS] (useContentTestimonials)\n 3 customer quotes in a row\n\n[NEWSLETTER]\n Email capture form\n\n[FOOTER] 4-column footer\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nDoes this structure look right? Any sections to add, remove, or reorder?\n```\n\nWait for explicit user approval before proceeding to apply_wireframe.\nIf the user requests changes, update the affected page(s) and show again.\n\n---\n\n## Submission\n\nOnce ALL pages are approved by the user:\n\n```\napply_wireframe(projectId, {\n \"home\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"shop\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"about\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"contact\": \"<nav>...</nav><main>...</main><footer>...</footer>\"\n})\n```\n\nReturns: `{ pageCount: 4, slugs: [\"home\", \"shop\", \"about\", \"contact\"] }`\n\nAfter this, proceed to generate React code using the wireframe as your\nstructural reference. The wireframe defines WHAT to build \u2014 runtime-hooks\nand build-rules define HOW to build it in React.\n";
8
+ export declare const WIREFRAME_SCHEMA = "\n# SellHapi Wireframe Schema\n\nWireframes are mid-fidelity HTML page layouts \u2014 one per storefront page.\nThey are the USER'S checkpoint before code is written: present each page\nwireframe in the conversation, collect feedback, revise if needed, then\ncall apply_wireframe only after the user approves the full set.\n\n---\n\n## Data shape\n\n```\n{ [pageSlug: string]: htmlString }\n```\n\n- Each key is a page slug that MUST match one of the slugs in designDirection.pages\n- Each value is a valid HTML string for that page's mid-fidelity wireframe\n- All pages from designDirection.pages should be included (missing pages means no wireframe guidance for code generation on that page)\n\n---\n\n## What a wireframe IS\n\nMid-fidelity structural HTML. It communicates:\n- Which sections appear on the page and in what order\n- What content each section contains (headings, CTAs, placeholder data)\n- Navigation structure (links, cart icon, CTA button)\n- Footer structure (columns, links)\n- Which runtime hook each section will use\n\nIt does NOT include:\n- Real CSS (use only inline style for basic layout structure if needed)\n- JavaScript or React\n- Actual product/service data (use descriptive placeholders)\n- Final colour values or fonts (those come from designDirection.visualDirection)\n\n---\n\n## Structure rules\n\n### Navigation \u2014 MANDATORY on every page\n```html\n<nav>\n <div class=\"nav-logo\">[Business Name]</div>\n <ul class=\"nav-links\">\n <li><a href=\"#/home\">Home</a></li>\n <li><a href=\"#/shop\">Shop</a></li>\n <!-- one <li> per page in designDirection.pages -->\n </ul>\n <!-- If physical_products or digital_products in capabilityIds: -->\n <button class=\"nav-cart\">Cart (0)</button>\n <button class=\"nav-cta\">[Primary CTA]</button>\n</nav>\n```\n\n- Navigation HTML must be **identical across all pages** \u2014 copy verbatim after the first page\n- Highlight the current page's link as active (add class=\"active\" to that <li>)\n- Cart icon only when capability includes physical_products or digital_products\n\n### Footer \u2014 MANDATORY on every page\n```html\n<footer>\n <div class=\"footer-col\">\n <div class=\"footer-logo\">[Business Name]</div>\n <p>[tagline]</p>\n </div>\n <div class=\"footer-col\">\n <h4>NAVIGATE</h4>\n <ul><!-- one <li> per page --></ul>\n </div>\n <div class=\"footer-col\">\n <h4>RESOURCES</h4>\n <ul><!-- relevant links for this business type --></ul>\n </div>\n <div class=\"footer-col\">\n <h4>CONNECT</h4>\n <!-- social platform links -->\n </div>\n <div class=\"footer-bottom\">\u00A9 [year] [Business Name]. All rights reserved.</div>\n</footer>\n```\n\n- Footer HTML must be **identical across all pages** \u2014 copy verbatim after the first page\n\n### Sections\nEach section gets a wrapper with a comment and data-hook attribute:\n\n```html\n<!-- Hero Section -->\n<section data-section=\"hero\" data-hook=\"none\">\n <h1>[Headline \u2014 use the business tagline]</h1>\n <p>[Supporting copy]</p>\n <button>[Primary CTA]</button>\n <div class=\"hero-image\">[Hero image placeholder]</div>\n</section>\n\n<!-- Product Grid Section -->\n<section data-section=\"product-grid\" data-hook=\"useProducts\">\n <h2>Our Products</h2>\n <div class=\"product-grid\">\n <div class=\"product-card\">\n <div class=\"product-image\">[Product image]</div>\n <h3>[Product name]</h3>\n <p>[Price in \u20A6]</p>\n <button>Add to Cart</button>\n </div>\n <!-- repeat 2 more placeholder cards -->\n </div>\n</section>\n\n<!-- Testimonials Section -->\n<section data-section=\"testimonials\" data-hook=\"useContentTestimonials\">\n <h2>What Customers Say</h2>\n <div class=\"testimonials-grid\">\n <blockquote>[Testimonial 1]</blockquote>\n <blockquote>[Testimonial 2]</blockquote>\n <blockquote>[Testimonial 3]</blockquote>\n </div>\n</section>\n```\n\n---\n\n## data-hook values by capability\n\nUse these exact hook names in data-hook attributes so code generation\nmatches the correct runtime hook:\n\n| Section type | data-hook |\n|-------------------------------|---------------------------------|\n| Product listing / grid | useProducts |\n| Product collections | useProductCollections |\n| Single collection | useCollection |\n| Category sections | useSections |\n| Service listings | useServiceListings |\n| Appointment booking | useBookAppointment |\n| Available dates | useAvailableDates |\n| Events listing | useEvents |\n| Donation campaigns | useDonationCampaigns |\n| Membership tiers | useMemberships |\n| Content images | useContentImages |\n| Testimonials | useContentTestimonials |\n| FAQs | useContentFaqs |\n| Team members | useContentTeamMembers |\n| Stats / social proof | useContentStats |\n| Feature highlights | useContentFeatures |\n| Contact / enquiry form | useSubmitForm |\n| Listings (classifieds/jobs) | useListings |\n| Non-data sections (hero, about, footer, nav) | none |\n\n---\n\n## Presenting wireframes to the user\n\nBefore calling apply_wireframe, show each page to the user like this:\n\n```\n\uD83D\uDCC4 HOME PAGE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n[NAV] Logo | Home \u00B7 Shop \u00B7 About \u00B7 Contact [Cart] [Shop Now]\n\n[HERO]\n \"Authentic Nigerian fashion for the bold\"\n Subheading + CTA button\n Full-width hero image\n\n[FEATURED PRODUCTS] (useProducts)\n 3-column product grid \u2014 6 products\n Each card: image, name, price, Add to Cart\n\n[COLLECTIONS] (useProductCollections)\n 4 collection tiles with cover images\n\n[TESTIMONIALS] (useContentTestimonials)\n 3 customer quotes in a row\n\n[NEWSLETTER]\n Email capture form\n\n[FOOTER] 4-column footer\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nDoes this structure look right? Any sections to add, remove, or reorder?\n```\n\nWait for explicit user approval before proceeding to apply_wireframe.\nIf the user requests changes, update the affected page(s) and show again.\n\n---\n\n## Submission\n\nOnce ALL pages are approved by the user:\n\n```\napply_wireframe(projectId, {\n \"home\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"shop\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"about\": \"<nav>...</nav><main>...</main><footer>...</footer>\",\n \"contact\": \"<nav>...</nav><main>...</main><footer>...</footer>\"\n})\n```\n\nReturns: `{ pageCount: 4, slugs: [\"home\", \"shop\", \"about\", \"contact\"] }`\n\nAfter this, proceed to generate React code using the wireframe as your\nstructural reference. The wireframe defines WHAT to build \u2014 runtime-hooks\nand build-rules define HOW to build it in React.\n";
@@ -152,7 +152,7 @@ matches the correct runtime hook:
152
152
  | Content images | useContentImages |
153
153
  | Testimonials | useContentTestimonials |
154
154
  | FAQs | useContentFaqs |
155
- | Team members | useContentTeam |
155
+ | Team members | useContentTeamMembers |
156
156
  | Stats / social proof | useContentStats |
157
157
  | Feature highlights | useContentFeatures |
158
158
  | Contact / enquiry form | useSubmitForm |
@@ -1,9 +1,6 @@
1
1
  /**
2
- * Commerce tools — read-only access to products, services, events, memberships, donations, appointments.
3
- *
4
- * All URLs point to /api/mcp/* (API key auth). Write endpoints are not yet
5
- * available on the MCP route layer — create tools will be added when backend
6
- * write proxies are shipped.
2
+ * Commerce tools — read and write access to products, services, events,
3
+ * memberships, donations, appointments, and forms.
7
4
  */
8
5
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
6
  export declare function registerCommerceTools(server: McpServer): void;
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
  /**
3
- * Commerce tools — read-only access to products, services, events, memberships, donations, appointments.
4
- *
5
- * All URLs point to /api/mcp/* (API key auth). Write endpoints are not yet
6
- * available on the MCP route layer — create tools will be added when backend
7
- * write proxies are shipped.
3
+ * Commerce tools — read and write access to products, services, events,
4
+ * memberships, donations, appointments, and forms.
8
5
  */
9
6
  Object.defineProperty(exports, "__esModule", { value: true });
10
7
  exports.registerCommerceTools = registerCommerceTools;
8
+ const v4_1 = require("zod/v4");
11
9
  const client_js_1 = require("../client.js");
12
10
  const util_js_1 = require("../util.js");
13
11
  function registerCommerceTools(server) {
@@ -74,6 +72,134 @@ function registerCommerceTools(server) {
74
72
  const data = await (0, client_js_1.get)("/api/mcp/appointments/services");
75
73
  return JSON.stringify(data.services, null, 2);
76
74
  }));
75
+ // ── Write: Create product ─────────────────────────────────────────────────
76
+ server.registerTool("create_product", {
77
+ 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 — use an external URL if the vendor has one, or omit it.",
79
+ inputSchema: {
80
+ name: v4_1.z.string().describe("Product name"),
81
+ description: v4_1.z.string().optional().describe("Product description"),
82
+ priceKobo: v4_1.z.number().int().min(0).describe("Price in kobo (₦1 = 100 kobo)"),
83
+ type: v4_1.z.enum(["physical", "digital"]).optional().default("physical").describe("Product type — physical (default) or digital"),
84
+ stock: v4_1.z.number().int().min(0).optional().describe("Initial stock quantity (0 = out of stock). Omit for untracked stock."),
85
+ imageUrl: v4_1.z.string().optional().describe("External image URL for the product"),
86
+ },
87
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
88
+ const data = await (0, client_js_1.post)("/api/mcp/products", input);
89
+ return JSON.stringify(data, null, 2);
90
+ }));
91
+ // ── Write: Create event ───────────────────────────────────────────────────
92
+ server.registerTool("create_event", {
93
+ title: "Create Event",
94
+ description: "Create an event with optional ticket types in a single call. Events are created as draft — they become visible on the storefront when published from the dashboard. Call list_capabilities first to confirm events capability is active.",
95
+ inputSchema: {
96
+ title: v4_1.z.string().describe("Event title"),
97
+ description: v4_1.z.string().optional().describe("Event description"),
98
+ startsAt: v4_1.z.string().describe("Start datetime — ISO 8601 string e.g. '2025-03-15T10:00:00'"),
99
+ endsAt: v4_1.z.string().describe("End datetime — ISO 8601 string"),
100
+ location: v4_1.z.string().optional().describe("Venue or location name"),
101
+ imageUrl: v4_1.z.string().optional().describe("Event cover image URL"),
102
+ tickets: v4_1.z.array(v4_1.z.object({
103
+ name: v4_1.z.string().describe("Ticket type name e.g. 'General Admission'"),
104
+ priceKobo: v4_1.z.number().int().min(0).describe("Ticket price in kobo (0 = free)"),
105
+ capacity: v4_1.z.number().int().min(1).describe("Total number of tickets available"),
106
+ maxPerOrder: v4_1.z.number().int().optional().describe("Max tickets per order"),
107
+ description: v4_1.z.string().optional(),
108
+ })).optional().default([]).describe("Ticket types to create inline with the event"),
109
+ },
110
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
111
+ const data = await (0, client_js_1.post)("/api/mcp/events", input);
112
+ return JSON.stringify(data, null, 2);
113
+ }));
114
+ // ── Write: Create membership tier ─────────────────────────────────────────
115
+ server.registerTool("create_membership_tier", {
116
+ title: "Create Membership Tier",
117
+ description: "Create a membership tier with benefits list and billing period. Call list_capabilities first to confirm memberships capability is active. Prices in kobo.",
118
+ inputSchema: {
119
+ name: v4_1.z.string().describe("Tier name e.g. 'Gold Member'"),
120
+ description: v4_1.z.string().optional().describe("Tier description"),
121
+ priceKobo: v4_1.z.number().int().min(0).describe("Price in kobo per billing period"),
122
+ billingPeriod: v4_1.z.enum(["monthly", "yearly", "one_time"]).optional().default("monthly"),
123
+ benefits: v4_1.z.array(v4_1.z.string()).optional().describe("List of benefits e.g. ['Free delivery', 'Early access to drops']"),
124
+ imageUrl: v4_1.z.string().optional().describe("Tier cover image URL"),
125
+ maxMembers: v4_1.z.number().int().optional().describe("Maximum members for this tier (null = unlimited)"),
126
+ },
127
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
128
+ const data = await (0, client_js_1.post)("/api/mcp/memberships/tiers", input);
129
+ return JSON.stringify(data, null, 2);
130
+ }));
131
+ // ── Write: Create donation campaign ───────────────────────────────────────
132
+ server.registerTool("create_donation_campaign", {
133
+ title: "Create Donation Campaign",
134
+ description: "Create a fundraising campaign. Campaigns are live immediately after creation. Call list_capabilities first to confirm donations capability is active.",
135
+ inputSchema: {
136
+ title: v4_1.z.string().describe("Campaign title"),
137
+ description: v4_1.z.string().optional().describe("Campaign story / description"),
138
+ goalAmountKobo: v4_1.z.number().int().optional().describe("Fundraising goal in kobo (omit for open-ended campaigns)"),
139
+ imageUrl: v4_1.z.string().optional().describe("Campaign cover image URL"),
140
+ endsAt: v4_1.z.string().optional().describe("Campaign end date — ISO 8601 string (omit for no end date)"),
141
+ presetAmounts: v4_1.z.array(v4_1.z.number().int().min(0)).optional().describe("Preset donation amount options in kobo e.g. [500000, 1000000, 2000000]"),
142
+ },
143
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
144
+ const data = await (0, client_js_1.post)("/api/mcp/donations/campaigns", input);
145
+ return JSON.stringify(data, null, 2);
146
+ }));
147
+ // ── Write: Create appointment service ────────────────────────────────────
148
+ server.registerTool("create_appointment_service", {
149
+ title: "Create Appointment Service",
150
+ description: "Create a bookable appointment service. Note: staff members and their weekly schedules must be set up in the Appointments dashboard before customers can book. Call list_capabilities first to confirm appointments capability is active.",
151
+ inputSchema: {
152
+ name: v4_1.z.string().describe("Service name e.g. 'Hair Consultation'"),
153
+ description: v4_1.z.string().optional(),
154
+ durationMinutes: v4_1.z.number().int().min(1).describe("Service duration in minutes"),
155
+ priceKobo: v4_1.z.number().int().min(0).describe("Price in kobo"),
156
+ imageUrl: v4_1.z.string().optional(),
157
+ bufferMinutes: v4_1.z.number().int().min(0).optional().describe("Buffer time between bookings in minutes (default 0)"),
158
+ maxConcurrentBookings: v4_1.z.number().int().min(1).optional().describe("Max simultaneous bookings for this service (default 1)"),
159
+ },
160
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
161
+ const data = await (0, client_js_1.post)("/api/mcp/appointments/services", input);
162
+ return JSON.stringify(data, null, 2);
163
+ }));
164
+ // ── Write: Create service listing ────────────────────────────────────────
165
+ server.registerTool("create_service_listing", {
166
+ title: "Create Service Listing",
167
+ description: "Create a service listing (freelance/agency-style services with a coverImage, description, and purchase flow). Different from appointment services — service listings are for deliverable-based work like design, photography, consulting. Call list_capabilities first to confirm services capability is active.",
168
+ inputSchema: {
169
+ title: v4_1.z.string().describe("Listing title e.g. 'Brand Identity Package'"),
170
+ description: v4_1.z.string().optional(),
171
+ priceKobo: v4_1.z.number().int().min(0).describe("Price in kobo"),
172
+ category: v4_1.z.string().optional().describe("Service category e.g. 'Design', 'Photography'"),
173
+ coverImageUrl: v4_1.z.string().optional(),
174
+ duration: v4_1.z.string().optional().describe("Delivery timeframe label e.g. '3–5 days'"),
175
+ deliveryTime: v4_1.z.string().optional().describe("Delivery time e.g. '7 days'"),
176
+ },
177
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
178
+ const data = await (0, client_js_1.post)("/api/mcp/service-listings", input);
179
+ return JSON.stringify(data, null, 2);
180
+ }));
181
+ // ── Write: Create form ───────────────────────────────────────────────────
182
+ server.registerTool("create_form", {
183
+ 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.",
185
+ inputSchema: {
186
+ title: v4_1.z.string().describe("Form name e.g. 'Contact Us'"),
187
+ description: v4_1.z.string().optional(),
188
+ fields: v4_1.z.array(v4_1.z.object({
189
+ 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"),
191
+ required: v4_1.z.boolean().optional().default(false),
192
+ placeholder: v4_1.z.string().optional(),
193
+ options: v4_1.z.array(v4_1.z.string()).optional().describe("Options for select fields"),
194
+ })).describe("Form fields in order"),
195
+ submitButtonText: v4_1.z.string().optional().describe("Submit button label (default: 'Submit')"),
196
+ successMessage: v4_1.z.string().optional().describe("Message shown after successful submission"),
197
+ storefrontPurpose: v4_1.z.enum(["contact", "waitlist", "enquiry", "feedback", "application"]).optional().describe("Semantic purpose — helps the storefront and Studio identify this form"),
198
+ },
199
+ }, async (input) => (0, util_js_1.safeCall)(async () => {
200
+ const data = await (0, client_js_1.post)("/api/mcp/content/forms", input);
201
+ return JSON.stringify(data, null, 2);
202
+ }));
77
203
  // ── Capabilities ───────────────────────────────────────────────────────────
78
204
  server.registerTool("list_capabilities", {
79
205
  title: "List Capabilities",
@@ -9,6 +9,8 @@ const client_js_1 = require("../client.js");
9
9
  const util_js_1 = require("../util.js");
10
10
  const runtime_hooks_js_1 = require("../resources/runtime-hooks.js");
11
11
  const build_rules_js_1 = require("../resources/build-rules.js");
12
+ const design_direction_schema_js_1 = require("../resources/design-direction-schema.js");
13
+ const wireframe_schema_js_1 = require("../resources/wireframe-schema.js");
12
14
  function registerStudioTools(server) {
13
15
  // ── List projects ──────────────────────────────────────────────────────────
14
16
  server.registerTool("list_projects", {
@@ -52,13 +54,13 @@ function registerStudioTools(server) {
52
54
  step: 1,
53
55
  tool: "apply_design_direction",
54
56
  required: true,
55
- description: "Generate and store a full DesignDirection — colors, fonts, pages, business context. Do this NOW before anything else. Read sellhapi://design-direction-schema for the exact shape. Present the direction summary to the user (palette, pages, mood) and get confirmation before calling apply_design_direction. Alternatively use set_design_direction to let SellHapi's Claude generate it (costs credits).",
57
+ description: "BEFORE generating any direction JSON, have a SHORT design conversation with the user. Ask: (1) preferred brand colors — or let the AI suggest based on the business type; (2) font style — modern/minimal, editorial/serif, warm/handcrafted, bold/display, playful; (3) if physical_products is active: which display modes to use (product grid / collections / bundles / category sections); (4) overall mood / reference brands they like. Then generate the DesignDirection JSON and present a summary (palette, fonts, pages, mood) for user confirmation before calling apply_design_direction. The design_direction_schema in required_reading has the full shape. Alternatively use set_design_direction to let SellHapi's Claude generate it (costs credits).",
56
58
  },
57
59
  {
58
60
  step: 2,
59
61
  tool: "apply_wireframe",
60
62
  required: false,
61
- description: "Optional but recommended. Generate mid-fidelity HTML wireframes for each page, present them section-by-section to the user, collect feedback, then store the approved wireframes. Read sellhapi://wireframe-schema first.",
63
+ description: "Optional but recommended. Generate mid-fidelity HTML wireframes for each page, present them section-by-section to the user, collect feedback, then store the approved wireframes. The wireframe_schema in required_reading has full conventions and data-hook reference.",
62
64
  },
63
65
  {
64
66
  step: 3,
@@ -75,7 +77,9 @@ function registerStudioTools(server) {
75
77
  ],
76
78
  },
77
79
  required_reading: {
78
- instruction: "Read build_rules and runtime_hooks in full before generating any storefront code. Violating build_rules causes push_code to fail with a BuildGuard error.",
80
+ instruction: "Read ALL four documents below before generating any storefront code. design_direction_schema and wireframe_schema must be read before Step 1. build_rules and runtime_hooks must be read before Step 3 (push_code). Violating build_rules causes push_code to fail with a BuildGuard error.",
81
+ design_direction_schema: design_direction_schema_js_1.DESIGN_DIRECTION_SCHEMA,
82
+ wireframe_schema: wireframe_schema_js_1.WIREFRAME_SCHEMA,
79
83
  build_rules: build_rules_js_1.BUILD_RULES,
80
84
  runtime_hooks: runtime_hooks_js_1.RUNTIME_HOOKS,
81
85
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellhapi/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "SellHapi MCP server — build and manage SellHapi storefronts from AI tools",
5
5
  "bin": {
6
6
  "sellhapi-mcp": "./dist/index.js"