@swatcha/mcp-server 0.1.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/dist/index.js ADDED
@@ -0,0 +1,590 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
5
+ import { z } from 'zod';
6
+ import { readFileSync } from 'node:fs';
7
+ import { join, dirname } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { SwatchaClient } from './client.js';
10
+ const apiKey = process.env.SWATCHA_API_KEY || process.env.MCP_API_KEY;
11
+ const apiUrl = process.env.SWATCHA_API_URL || process.env.MCP_API_URL || 'http://localhost:3000';
12
+ if (!apiKey) {
13
+ process.stderr.write('Error: SWATCHA_API_KEY environment variable is required\n');
14
+ process.exit(1);
15
+ }
16
+ const client = new SwatchaClient(apiUrl, apiKey);
17
+ // Construct the UI base URL from the API URL (same host, no /api/v1 prefix)
18
+ const appBaseUrl = apiUrl.replace(/\/+$/, '');
19
+ function selectionUrl(id) {
20
+ return `${appBaseUrl}/selections/${id}`;
21
+ }
22
+ function withSelectionUrl(data) {
23
+ if (data && typeof data === 'object' && 'id' in data) {
24
+ return { ...data, url: selectionUrl(data.id) };
25
+ }
26
+ if (Array.isArray(data)) {
27
+ return data.map((item) => item && typeof item === 'object' && 'id' in item
28
+ ? { ...item, url: selectionUrl(item.id) }
29
+ : item);
30
+ }
31
+ return data;
32
+ }
33
+ const server = new McpServer({ name: 'swatcha', version: '0.1.0' }, {
34
+ instructions: `You are helping a construction industry builder manage product selections in Swatcha. Swatcha is a SaaS platform for creating and managing product selections for building projects.
35
+
36
+ Key concepts:
37
+ - A "selection" is a curated list of products for a building project
38
+ - Products belong to suppliers and can be assigned to locations
39
+ - Clients are the builder's customers (homeowners, developers, etc.)
40
+
41
+ Typical workflows:
42
+ 1. Create client → create selection → add products → share URL
43
+ 2. Review supplier invoice → search existing products → create missing → add to selection
44
+ 3. Browse existing selections → update products → change status
45
+
46
+ Image workflow (after creating products from an invoice):
47
+ 1. Check which products have no imageUrl (from create/list responses)
48
+ 2. For each product without an image, call search_product_images with the product name and supplier
49
+ 3. Batch up to 5 products with their candidates into one pick_product_images call
50
+ - If more than 5 products need images, use multiple batches with batchLabel (e.g. "Batch 1 of 3")
51
+ 4. Wait for the user to select or skip in the picker UI
52
+ 5. Parse the selections from the user message and call update_product for each selected image
53
+ 6. If more batches remain, repeat from step 3 with the next batch
54
+ 7. Present final summary with the selection URL
55
+
56
+ First-time user onboarding:
57
+ When the user's first message is general or exploratory, call list_selections.
58
+ If the result is empty, welcome them:
59
+ "Welcome to Swatcha! You don't have any selections yet. Want me to walk you through creating your first one?"
60
+ If they say yes, follow the New Selection Workflow.
61
+
62
+ New Selection Workflow:
63
+ 1. Call list_clients first
64
+ 2. If clients exist, list them and ask: "Who is this for? Pick an existing client or enter a new name."
65
+ If no clients, ask: "Who is this for? (client name)"
66
+ 3. Match to existing client or create new one via create_client
67
+ 4. Ask for a selection name
68
+ 5. Create selection via create_selection, provide the URL
69
+ 6. Ask how to add products:
70
+ "How would you like to add products?
71
+ 1. Upload a product list document (supplier quote, invoice, spreadsheet, etc.)
72
+ 2. Tell me the products one by one"
73
+ 7. Follow the appropriate path (see below)
74
+ 8. After products are added, report image coverage:
75
+ "X of Y products don't have images yet. Want me to search for them?"
76
+ 9. If yes, run image search + batch picker flow
77
+ 10. Present completion summary with URL and next steps:
78
+ "What's next? You can share this link with your client, add more products, or create another selection."
79
+
80
+ Document upload product extraction:
81
+ 1. Read the uploaded document, extract products (name, supplier, SKU, quantity)
82
+ 2. Call list_locations to get existing tenant locations
83
+ 3. Present a numbered list of extracted products for the user to review and edit
84
+ 4. Wait for the user to confirm the list
85
+ 5. For each new location mentioned — call create_location first
86
+ 6. For each supplier — call list_suppliers to check, create_supplier if new
87
+ 7. For each product — call search_products to check if it already exists in the catalog.
88
+ If found, use the existing product ID. Only call create_product if no match exists.
89
+ 8. For each product — call add_product_to_selection with the product ID, locationId, and quantity.
90
+ This creates a selection_product snapshot linking the catalog product to this selection.
91
+ 9. Report results (note which products were existing vs newly created)
92
+
93
+ One-by-one product addition:
94
+ 1. Ask: "What's the product name and supplier?"
95
+ 2. Check list_suppliers for existing match, create_supplier if new
96
+ 3. Call search_products to check if the product already exists in the catalog.
97
+ If found, use the existing product. Only call create_product if no match.
98
+ 4. Add to selection via add_product_to_selection (creates a selection_product snapshot)
99
+ 5. Ask: "Want to add quantity, location, or notes for this product?"
100
+ 6. If yes, handle each (check list_locations for location, create if new, update via update_selection_product)
101
+ 7. Ask: "Want to add another product?"
102
+ 8. Repeat until done
103
+
104
+ Bulk creation guidance:
105
+ When creating multiple products in sequence, wrap each API call in error handling.
106
+ If a call fails, log the error and continue with the remaining products.
107
+ Report both successes and failures at the end.
108
+
109
+ Guidelines:
110
+ - Always provide the selection URL after creating or modifying a selection
111
+ - When processing invoices, check for existing products before creating duplicates
112
+ - Use search_products before create_product to avoid catalog duplicates
113
+ - Use list_suppliers before create_supplier (dedup is automatic, but saves a call)
114
+ - Always include the supplier name when searching for images — it improves relevance
115
+ - If image search returns no results, skip that product and note it in the summary
116
+ - Selection URLs follow the pattern: {base_url}/selections/{id}`,
117
+ });
118
+ // --- Selection tools ---
119
+ server.registerTool('list_selections', {
120
+ description: 'List all product selections for the current tenant. Returns selection name, status, client, and project info.',
121
+ inputSchema: z.object({}),
122
+ }, async () => {
123
+ const result = await client.listSelections();
124
+ return {
125
+ content: [{ type: 'text', text: JSON.stringify(withSelectionUrl(result.data), null, 2) }],
126
+ };
127
+ });
128
+ server.registerTool('get_selection', {
129
+ description: 'Get detailed information about a specific selection, including its products and metadata. Returns a url field for viewing in the Swatcha UI.',
130
+ inputSchema: z.object({
131
+ id: z.string().describe('The UUID of the selection to retrieve'),
132
+ }),
133
+ }, async ({ id }) => {
134
+ const result = await client.getSelection(id);
135
+ return {
136
+ content: [{ type: 'text', text: JSON.stringify(withSelectionUrl(result.data), null, 2) }],
137
+ };
138
+ });
139
+ server.registerTool('create_selection', {
140
+ description: 'Create a new product selection. Requires a client ID (use list_clients to find one). Returns a url field for viewing the selection in the Swatcha UI.',
141
+ inputSchema: z.object({
142
+ name: z.string().describe('Name for the selection (e.g. "Kitchen Fixtures")'),
143
+ clientId: z
144
+ .string()
145
+ .describe('UUID of the client this selection belongs to. Use list_clients to find one.'),
146
+ status: z
147
+ .string()
148
+ .optional()
149
+ .describe('Initial status (defaults to "Draft"). Options: Draft, Under Review, Approved, Complete, Done, Closed, Cancelled'),
150
+ notes: z.string().optional().describe('Optional notes for the selection'),
151
+ siteAddress: z
152
+ .string()
153
+ .optional()
154
+ .describe('Optional site/delivery address for the selection'),
155
+ }),
156
+ }, async ({ name, clientId, status, notes, siteAddress }) => {
157
+ const result = await client.createSelection({
158
+ name,
159
+ clientId,
160
+ status,
161
+ notes,
162
+ siteAddress,
163
+ });
164
+ return {
165
+ content: [{ type: 'text', text: JSON.stringify(withSelectionUrl(result.data), null, 2) }],
166
+ };
167
+ });
168
+ server.registerTool('update_selection', {
169
+ description: 'Update an existing selection. Only provided fields will be changed. Returns a url field for viewing the selection in the Swatcha UI.',
170
+ inputSchema: z.object({
171
+ id: z.string().describe('The UUID of the selection to update'),
172
+ name: z.string().optional().describe('New name for the selection'),
173
+ status: z
174
+ .string()
175
+ .optional()
176
+ .describe('New status. Options: Draft, Under Review, Approved, Complete, Done, Closed, Cancelled'),
177
+ notes: z.string().optional().describe('Updated notes'),
178
+ siteAddress: z.string().optional().describe('Updated site/delivery address'),
179
+ }),
180
+ }, async ({ id, name, status, notes, siteAddress }) => {
181
+ const result = await client.updateSelection(id, {
182
+ name,
183
+ status,
184
+ notes,
185
+ siteAddress,
186
+ });
187
+ return {
188
+ content: [{ type: 'text', text: JSON.stringify(withSelectionUrl(result.data), null, 2) }],
189
+ };
190
+ });
191
+ server.registerTool('delete_selection', {
192
+ description: 'Delete a selection and all its associated products. This action cannot be undone.',
193
+ inputSchema: z.object({
194
+ id: z.string().describe('The UUID of the selection to delete'),
195
+ }),
196
+ }, async ({ id }) => {
197
+ const result = await client.deleteSelection(id);
198
+ return {
199
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
200
+ };
201
+ });
202
+ // --- Selection Product tools ---
203
+ server.registerTool('list_selection_products', {
204
+ description: 'List all products within a specific selection, including quantity, location, and notes.',
205
+ inputSchema: z.object({
206
+ selectionId: z.string().describe('The UUID of the selection'),
207
+ }),
208
+ }, async ({ selectionId }) => {
209
+ const result = await client.listSelectionProducts(selectionId);
210
+ return {
211
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
212
+ };
213
+ });
214
+ server.registerTool('add_product_to_selection', {
215
+ description: 'Add a product to a selection. Product must exist in the catalog first (use create_product or search_products to find one).',
216
+ inputSchema: z.object({
217
+ selectionId: z.string().describe('The UUID of the selection to add the product to'),
218
+ productId: z
219
+ .string()
220
+ .describe('The UUID of the catalog product to add. Use search_products to find products.'),
221
+ quantity: z
222
+ .string()
223
+ .optional()
224
+ .describe('Quantity as a string (e.g. "2", "1 set", "3 boxes")'),
225
+ location: z
226
+ .string()
227
+ .optional()
228
+ .describe('Free-text location within the project (e.g. "Master Bathroom")'),
229
+ locationId: z
230
+ .string()
231
+ .optional()
232
+ .describe('UUID of a predefined location. Use list_locations to find one.'),
233
+ notes: z.string().optional().describe('Notes specific to this product in this selection'),
234
+ }),
235
+ }, async ({ selectionId, productId, quantity, location, locationId, notes }) => {
236
+ const result = await client.addProductToSelection(selectionId, {
237
+ productId,
238
+ quantity,
239
+ location,
240
+ locationId,
241
+ notes,
242
+ });
243
+ const enriched = { ...result.data, selectionUrl: selectionUrl(selectionId) };
244
+ return {
245
+ content: [{ type: 'text', text: JSON.stringify(enriched, null, 2) }],
246
+ };
247
+ });
248
+ server.registerTool('update_selection_product', {
249
+ description: 'Update a product within a selection (quantity, location, or notes).',
250
+ inputSchema: z.object({
251
+ selectionId: z.string().describe('The UUID of the selection'),
252
+ productId: z.string().describe('The UUID of the selection product entry to update'),
253
+ quantity: z.string().optional().describe('Updated quantity'),
254
+ location: z.string().optional().describe('Updated free-text location'),
255
+ locationId: z.string().optional().describe('UUID of a predefined location. Use list_locations to find one.'),
256
+ notes: z.string().optional().describe('Updated notes'),
257
+ }),
258
+ }, async ({ selectionId, productId, quantity, location, locationId, notes }) => {
259
+ const result = await client.updateSelectionProduct(selectionId, productId, {
260
+ quantity,
261
+ location,
262
+ locationId,
263
+ notes,
264
+ });
265
+ return {
266
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
267
+ };
268
+ });
269
+ server.registerTool('remove_product_from_selection', {
270
+ description: 'Remove a product from a selection. The product remains in the catalog.',
271
+ inputSchema: z.object({
272
+ selectionId: z.string().describe('The UUID of the selection'),
273
+ productId: z.string().describe('The UUID of the selection product entry to remove'),
274
+ }),
275
+ }, async ({ selectionId, productId }) => {
276
+ const result = await client.removeProductFromSelection(selectionId, productId);
277
+ return {
278
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
279
+ };
280
+ });
281
+ // --- Product Catalog tools ---
282
+ server.registerTool('search_products', {
283
+ description: 'Search the product catalog by name or SKU. Returns matching products with their details. Use without a query to list all products.',
284
+ inputSchema: z.object({
285
+ query: z
286
+ .string()
287
+ .optional()
288
+ .describe('Search query to filter products by name or SKU. Omit to list all.'),
289
+ }),
290
+ }, async ({ query }) => {
291
+ const result = await client.listProducts(query);
292
+ return {
293
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
294
+ };
295
+ });
296
+ server.registerTool('get_product', {
297
+ description: 'Get detailed information about a specific product from the catalog.',
298
+ inputSchema: z.object({
299
+ id: z.string().describe('The UUID of the product'),
300
+ }),
301
+ }, async ({ id }) => {
302
+ const result = await client.getProduct(id);
303
+ return {
304
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
305
+ };
306
+ });
307
+ server.registerTool('create_product', {
308
+ description: 'Create a new product in the catalog. Use list_suppliers to find a supplier ID, or create_supplier to create one first.',
309
+ inputSchema: z.object({
310
+ name: z.string().describe('Product name (e.g. "Matte Black Basin Mixer")'),
311
+ sku: z.string().optional().describe('Product SKU/model number'),
312
+ price: z.number().optional().describe('Product price in dollars (e.g. 299.99)'),
313
+ supplierId: z
314
+ .string()
315
+ .optional()
316
+ .describe('UUID of the supplier. Use list_suppliers or create_supplier.'),
317
+ imageUrl: z.string().optional().describe('URL to a product image'),
318
+ description: z.string().optional().describe('Product description'),
319
+ }),
320
+ }, async ({ name, sku, price, supplierId, imageUrl, description }) => {
321
+ const result = await client.createProduct({
322
+ name,
323
+ sku,
324
+ price,
325
+ supplierId,
326
+ imageUrl,
327
+ description,
328
+ });
329
+ return {
330
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
331
+ };
332
+ });
333
+ server.registerTool('update_product', {
334
+ description: 'Update an existing product in the catalog. Only provided fields will be changed.',
335
+ inputSchema: z.object({
336
+ id: z.string().describe('The UUID of the product to update'),
337
+ name: z.string().optional().describe('Updated product name'),
338
+ sku: z.string().optional().describe('Updated SKU/model number'),
339
+ price: z.number().optional().describe('Updated price in dollars'),
340
+ supplierId: z.string().optional().describe('Updated supplier UUID'),
341
+ imageUrl: z.string().optional().describe('Updated image URL'),
342
+ }),
343
+ }, async ({ id, name, sku, price, supplierId, imageUrl }) => {
344
+ const result = await client.updateProduct(id, {
345
+ name,
346
+ sku,
347
+ price,
348
+ supplierId,
349
+ imageUrl,
350
+ });
351
+ return {
352
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
353
+ };
354
+ });
355
+ // --- Client tools ---
356
+ server.registerTool('list_clients', {
357
+ description: 'List all clients for the current tenant. Use this to find a client ID before creating a selection.',
358
+ inputSchema: z.object({}),
359
+ }, async () => {
360
+ const result = await client.listClients();
361
+ return {
362
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
363
+ };
364
+ });
365
+ server.registerTool('create_client', {
366
+ description: 'Create a new client. Returns the client with its UUID.',
367
+ inputSchema: z.object({
368
+ name: z.string().describe('Client name (e.g. "Smith Family")'),
369
+ }),
370
+ }, async ({ name }) => {
371
+ const result = await client.createClient({ name });
372
+ return {
373
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
374
+ };
375
+ });
376
+ // --- Supplier tools ---
377
+ server.registerTool('list_suppliers', {
378
+ description: 'List all suppliers for the current tenant. Use this to find a supplier ID when creating products.',
379
+ inputSchema: z.object({}),
380
+ }, async () => {
381
+ const result = await client.listSuppliers();
382
+ return {
383
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
384
+ };
385
+ });
386
+ server.registerTool('create_supplier', {
387
+ description: 'Create a new supplier. If a supplier with the same name already exists, returns the existing supplier (dedup).',
388
+ inputSchema: z.object({
389
+ name: z.string().describe('Supplier name (e.g. "Reece Plumbing")'),
390
+ websiteUrl: z.string().optional().describe('Supplier website URL'),
391
+ }),
392
+ }, async ({ name, websiteUrl }) => {
393
+ const result = await client.createSupplier({ name, websiteUrl });
394
+ return {
395
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
396
+ };
397
+ });
398
+ // --- Location tools ---
399
+ server.registerTool('list_locations', {
400
+ description: 'List all predefined locations for the current tenant (e.g. "Kitchen", "Master Bathroom").',
401
+ inputSchema: z.object({}),
402
+ }, async () => {
403
+ const result = await client.listLocations();
404
+ return {
405
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
406
+ };
407
+ });
408
+ server.registerTool('create_location', {
409
+ description: 'Create a new predefined location. If a location with the same name already exists, returns the existing location (dedup).',
410
+ inputSchema: z.object({
411
+ name: z.string().describe('Location name (e.g. "Ensuite", "Laundry")'),
412
+ }),
413
+ }, async ({ name }) => {
414
+ const result = await client.createLocation({ name });
415
+ return {
416
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
417
+ };
418
+ });
419
+ // --- Quota tool ---
420
+ server.registerTool('get_quota', {
421
+ description: 'Get the current API usage quota for this tenant, including requests used and remaining.',
422
+ inputSchema: z.object({}),
423
+ }, async () => {
424
+ const result = await client.getQuota();
425
+ return {
426
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
427
+ };
428
+ });
429
+ // --- Image Search tool ---
430
+ server.registerTool('search_product_images', {
431
+ description: 'Search for product images by name and optional supplier. Returns candidate images ranked by relevance. Use this to find images for products that have no imageUrl.',
432
+ inputSchema: z.object({
433
+ productName: z.string().describe('Product name to search for'),
434
+ supplier: z.string().optional().describe('Supplier name for relevance ranking'),
435
+ supplierUrl: z.string().optional().describe('Supplier website URL for site-restricted search'),
436
+ }),
437
+ }, async ({ productName, supplier, supplierUrl }) => {
438
+ const result = await client.searchProductImages(productName, { supplier, supplierUrl });
439
+ return {
440
+ content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
441
+ };
442
+ });
443
+ // --- Image Picker (MCP App) ---
444
+ const __filename = fileURLToPath(import.meta.url);
445
+ const __dirname = dirname(__filename);
446
+ const pickerResourceUri = 'ui://swatcha/image-picker.html';
447
+ let pickerHtml = '<html><body>Image picker not built. Run: pnpm build</body></html>';
448
+ try {
449
+ pickerHtml = readFileSync(join(__dirname, '../dist/apps/src/apps/image-picker.html'), 'utf-8');
450
+ }
451
+ catch {
452
+ process.stderr.write('Warning: image-picker.html not found in dist/apps/. Run pnpm build first.\n');
453
+ }
454
+ registerAppResource(server, 'Image Picker', pickerResourceUri, {
455
+ description: 'Interactive image picker for selecting product images',
456
+ _meta: {
457
+ ui: {
458
+ csp: {
459
+ resourceDomains: [
460
+ 'https://encrypted-tbn0.gstatic.com',
461
+ 'https://serpapi.com',
462
+ ],
463
+ },
464
+ },
465
+ },
466
+ }, async () => ({
467
+ contents: [{
468
+ uri: pickerResourceUri,
469
+ mimeType: RESOURCE_MIME_TYPE,
470
+ text: pickerHtml,
471
+ }],
472
+ }));
473
+ const candidateSchema = z.object({
474
+ imageUrl: z.string().describe('Full-size image URL (saved to product)'),
475
+ thumbnailUrl: z.string().describe('Thumbnail URL (displayed in picker)'),
476
+ title: z.string().describe('Image title/alt text'),
477
+ sourceDomain: z.string().describe('Source website domain'),
478
+ sourceUrl: z.string().optional().describe('Source page URL (clickable link in picker)'),
479
+ });
480
+ const productEntrySchema = z.object({
481
+ productId: z.string().describe('UUID of the product'),
482
+ productName: z.string().describe('Product name (shown as row title)'),
483
+ supplier: z.string().optional().describe('Supplier name'),
484
+ candidates: z.array(candidateSchema).describe('Image candidates from search_product_images'),
485
+ });
486
+ registerAppTool(server, 'pick_product_images', {
487
+ title: 'Product Image Picker',
488
+ description: `Display an interactive batch image picker for multiple products. Pass an array of products with their image candidates (from search_product_images). The user selects one image per product or skips, then confirms all selections at once. Batch up to 5 products per call. For more products, call this tool multiple times with the batchLabel indicating progress (e.g. "Batch 1 of 3").`,
489
+ inputSchema: {
490
+ products: z.array(productEntrySchema).min(1).max(10)
491
+ .describe('Array of products with their image candidates (max 10 per batch)'),
492
+ batchLabel: z.string().optional()
493
+ .describe('Progress label shown in the picker (e.g. "Batch 1 of 3 — Products 1-5 of 15")'),
494
+ },
495
+ _meta: {
496
+ ui: { resourceUri: pickerResourceUri },
497
+ },
498
+ }, async ({ products, batchLabel }) => {
499
+ const totalCandidates = products.reduce((sum, p) => sum + p.candidates.length, 0);
500
+ return {
501
+ content: [
502
+ {
503
+ type: 'text',
504
+ text: `Showing image picker for ${products.length} products (${totalCandidates} total candidates). ${batchLabel || ''} The user will select images or skip, then confirm.`,
505
+ },
506
+ ],
507
+ structuredContent: { products, batchLabel },
508
+ };
509
+ });
510
+ // --- Prompts ---
511
+ server.prompt('new-selection', 'New Selection Workflow — guided flow from client through products to images', {
512
+ clientName: z.string().optional().describe('Skip the client question if provided'),
513
+ selectionName: z.string().optional().describe('Skip the selection name question if provided'),
514
+ }, ({ clientName, selectionName }) => ({
515
+ messages: [
516
+ {
517
+ role: 'user',
518
+ content: {
519
+ type: 'text',
520
+ text: `Create a new product selection using the guided workflow:
521
+
522
+ 1. List existing clients and ask who this selection is for — an existing client or a new one
523
+ ${clientName ? `Client: "${clientName}"` : ''}
524
+ ${selectionName ? `Selection name: "${selectionName}"` : ''}
525
+ 2. Ask for a selection name if not provided
526
+ 3. Create the client (if new) and selection
527
+ 4. Provide the selection URL
528
+ 5. Ask how to add products:
529
+ - Upload a product list document (supplier quote, invoice, spreadsheet, etc.)
530
+ - Tell me the products one by one
531
+ 6. After products are added, check for missing images and offer to search
532
+ 7. Present a completion summary with URL and next steps`,
533
+ },
534
+ },
535
+ ],
536
+ }));
537
+ server.prompt('process-product-list', 'Process Product List — upload a document, extract products, confirm, and add to selection', {
538
+ selectionId: z.string().optional().describe('Target selection UUID. If not provided, ask which one.'),
539
+ }, ({ selectionId }) => ({
540
+ messages: [
541
+ {
542
+ role: 'user',
543
+ content: {
544
+ type: 'text',
545
+ text: `Process an uploaded product list document and add the products to a selection.
546
+ ${selectionId ? `Target selection: ${selectionId}` : 'Ask which selection to add products to.'}
547
+
548
+ Steps:
549
+ 1. Read the uploaded document and extract products (name, supplier, SKU, quantity)
550
+ 2. Call list_locations to get existing tenant locations
551
+ 3. Present extracted products as a numbered list for user review and editing
552
+ 4. After confirmation, create new locations, create suppliers, create products, add to selection
553
+ 5. Report results and offer image search for products without images`,
554
+ },
555
+ },
556
+ ],
557
+ }));
558
+ server.prompt('add-product-images', 'Add Product Images — search for and assign images to products missing them', {
559
+ selectionId: z.string().optional().describe('Target selection UUID. If not provided, ask which one.'),
560
+ }, ({ selectionId }) => ({
561
+ messages: [
562
+ {
563
+ role: 'user',
564
+ content: {
565
+ type: 'text',
566
+ text: `Search for and assign images to products that don't have them.
567
+ ${selectionId ? `Target selection: ${selectionId}` : 'Ask which selection to work with.'}
568
+
569
+ Steps:
570
+ 1. Get the selection and identify products without imageUrl
571
+ 2. Report how many products need images
572
+ 3. Search for images in batches of 5 using search_product_images
573
+ 4. Present batch image picker using pick_product_images
574
+ 5. Update products with selected images
575
+ 6. Present summary`,
576
+ },
577
+ },
578
+ ],
579
+ }));
580
+ // --- Start server ---
581
+ async function main() {
582
+ const transport = new StdioServerTransport();
583
+ await server.connect(transport);
584
+ process.stderr.write('Swatcha MCP server started\n');
585
+ }
586
+ main().catch((error) => {
587
+ process.stderr.write(`Fatal error: ${error}\n`);
588
+ process.exit(1);
589
+ });
590
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@swatcha/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP Server for Swatcha - AI agent integration for product selections",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "swatcha-mcp": "./dist/index.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc && INPUT=src/apps/image-picker.html vite build",
13
+ "build:server": "tsc",
14
+ "build:apps": "INPUT=src/apps/image-picker.html vite build",
15
+ "dev": "tsc --watch",
16
+ "start": "node dist/index.js",
17
+ "type-check": "tsc --noEmit"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/ext-apps": "^1.2.0",
21
+ "@modelcontextprotocol/sdk": "^1.27.1",
22
+ "react": "^19.2.4",
23
+ "react-dom": "^19.2.4",
24
+ "zod": "^3.25.76"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.4.0",
28
+ "@types/react": "19.2.6",
29
+ "@types/react-dom": "19.2.2",
30
+ "@vitejs/plugin-react": "^5.1.2",
31
+ "typescript": "^5.5.4",
32
+ "vite": "^7.3.1",
33
+ "vite-plugin-singlefile": "^2.3.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ }
38
+ }