karrito-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 ADDED
@@ -0,0 +1,119 @@
1
+ # karrito-mcp
2
+
3
+ MCP server for [Karrito](https://karrito.shop) — the digital catalog builder for WhatsApp sellers in LATAM.
4
+
5
+ Connect your AI assistant (Claude, Cursor, Windsurf) to Karrito and manage your catalog, search public stores, and get platform information without leaving your editor.
6
+
7
+ ## Installation
8
+
9
+ ### Quick start (npx)
10
+
11
+ ```bash
12
+ npx karrito-mcp
13
+ ```
14
+
15
+ ### Claude Code
16
+
17
+ ```bash
18
+ claude mcp add karrito -- npx karrito-mcp
19
+ ```
20
+
21
+ ### Claude Desktop (`claude_desktop_config.json`)
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "karrito": {
27
+ "command": "npx",
28
+ "args": ["karrito-mcp"],
29
+ "env": {
30
+ "KARRITO_API_KEY": "your-api-key-here"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Cursor / Windsurf
38
+
39
+ Add to your MCP configuration:
40
+
41
+ ```json
42
+ {
43
+ "karrito": {
44
+ "command": "npx",
45
+ "args": ["karrito-mcp"],
46
+ "env": {
47
+ "KARRITO_API_KEY": "your-api-key-here"
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ ## Configuration
54
+
55
+ | Variable | Required | Description |
56
+ |----------|----------|-------------|
57
+ | `KARRITO_API_KEY` | For authenticated tools | Your Karrito API key from [Settings > API](https://karrito.shop/settings/api) |
58
+ | `KARRITO_API_URL` | No | Custom API URL (default: `https://karrito.shop`) |
59
+
60
+ ## Resources (5)
61
+
62
+ Static data about Karrito — no authentication required.
63
+
64
+ | Resource | URI | Description |
65
+ |----------|-----|-------------|
66
+ | Pricing | `karrito://pricing` | Plans, prices, and features comparison |
67
+ | Features | `karrito://features` | Complete feature list (core, pro, upcoming) |
68
+ | Niches | `karrito://niches` | All 50 available store niches |
69
+ | Competitors | `karrito://competitors` | 19 competitors compared with Karrito advantages |
70
+ | Currencies | `karrito://currencies` | 6 supported LATAM currencies |
71
+
72
+ ## Tools (5)
73
+
74
+ | Tool | Auth | Description |
75
+ |------|------|-------------|
76
+ | `search_catalogs` | No | Search public catalogs by keyword |
77
+ | `get_niche_info` | No | Get info about a specific niche |
78
+ | `list_my_products` | Yes | List products in your catalog |
79
+ | `create_product` | Yes | Create a new product |
80
+ | `list_my_orders` | Yes | List orders from your store |
81
+
82
+ ## Usage examples
83
+
84
+ ### Browse public catalogs
85
+
86
+ > "Search for bakery catalogs on Karrito"
87
+
88
+ The assistant will use `search_catalogs` with query "bakery" to find matching stores.
89
+
90
+ ### Explore niches
91
+
92
+ > "What niches does Karrito support for food businesses?"
93
+
94
+ The assistant will use `get_niche_info` to search food-related niches.
95
+
96
+ ### Manage your catalog
97
+
98
+ > "List all my products and add a new one called 'Chocolate Cake' at $15"
99
+
100
+ The assistant will use `list_my_products` and `create_product` (requires `KARRITO_API_KEY`).
101
+
102
+ ### Compare platforms
103
+
104
+ > "How does Karrito compare to Shopify and TiendaNube?"
105
+
106
+ The assistant will read the `karrito://competitors` resource.
107
+
108
+ ## Development
109
+
110
+ ```bash
111
+ git clone https://github.com/curetcore/karrito-mcp
112
+ cd karrito-mcp
113
+ npm install
114
+ npm run dev
115
+ ```
116
+
117
+ ## License
118
+
119
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
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 { KarritoApiClient } from './lib/api-client.js';
5
+ // Resources
6
+ import { register as registerPricing } from './resources/pricing.js';
7
+ import { register as registerFeatures } from './resources/features.js';
8
+ import { register as registerNiches } from './resources/niches.js';
9
+ import { register as registerCompetitors } from './resources/competitors.js';
10
+ import { register as registerCurrencies } from './resources/currencies.js';
11
+ // Tools
12
+ import { register as registerCatalogTools } from './tools/catalog.js';
13
+ import { register as registerProductTools } from './tools/products.js';
14
+ import { register as registerOrderTools } from './tools/orders.js';
15
+ const server = new McpServer({
16
+ name: 'karrito',
17
+ version: '1.0.0',
18
+ });
19
+ const client = new KarritoApiClient();
20
+ // Register static resources (public, no auth needed)
21
+ registerPricing(server);
22
+ registerFeatures(server);
23
+ registerNiches(server);
24
+ registerCompetitors(server);
25
+ registerCurrencies(server);
26
+ // Register tools
27
+ registerCatalogTools(server, client);
28
+ registerProductTools(server, client);
29
+ registerOrderTools(server, client);
30
+ // Connect via stdio
31
+ async function main() {
32
+ const transport = new StdioServerTransport();
33
+ await server.connect(transport);
34
+ console.error('Karrito MCP Server running on stdio');
35
+ }
36
+ main().catch((error) => {
37
+ console.error('Fatal error:', error);
38
+ process.exit(1);
39
+ });
@@ -0,0 +1,23 @@
1
+ interface ApiOptions {
2
+ apiKey?: string;
3
+ timeout?: number;
4
+ }
5
+ export declare class KarritoApiClient {
6
+ private baseUrl;
7
+ private apiKey;
8
+ private timeout;
9
+ constructor(options?: ApiOptions);
10
+ get hasApiKey(): boolean;
11
+ private request;
12
+ searchCatalogs(query?: string): Promise<unknown>;
13
+ checkSlug(slug: string): Promise<{
14
+ available: boolean;
15
+ }>;
16
+ listProducts(limit?: number, offset?: number): Promise<unknown>;
17
+ getProduct(id: string): Promise<unknown>;
18
+ createProduct(data: Record<string, unknown>): Promise<unknown>;
19
+ listCategories(limit?: number, offset?: number): Promise<unknown>;
20
+ listOrders(limit?: number, offset?: number, status?: string): Promise<unknown>;
21
+ getOrder(id: string): Promise<unknown>;
22
+ }
23
+ export {};
@@ -0,0 +1,73 @@
1
+ const BASE_URL = process.env.KARRITO_API_URL ?? 'https://karrito.shop';
2
+ export class KarritoApiClient {
3
+ baseUrl;
4
+ apiKey;
5
+ timeout;
6
+ constructor(options = {}) {
7
+ this.baseUrl = BASE_URL;
8
+ this.apiKey = options.apiKey ?? process.env.KARRITO_API_KEY;
9
+ this.timeout = options.timeout ?? 10_000;
10
+ }
11
+ get hasApiKey() {
12
+ return Boolean(this.apiKey);
13
+ }
14
+ async request(path, options = {}) {
15
+ const headers = {
16
+ 'Content-Type': 'application/json',
17
+ 'User-Agent': 'karrito-mcp/1.0.0',
18
+ };
19
+ if (this.apiKey) {
20
+ headers['Authorization'] = `Bearer ${this.apiKey}`;
21
+ }
22
+ const controller = new AbortController();
23
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
24
+ try {
25
+ const response = await fetch(`${this.baseUrl}${path}`, {
26
+ ...options,
27
+ headers: { ...headers, ...options.headers },
28
+ signal: controller.signal,
29
+ });
30
+ if (!response.ok) {
31
+ const error = await response.json().catch(() => ({
32
+ error: response.statusText,
33
+ }));
34
+ throw new Error(`Karrito API error ${response.status}: ${error.error}`);
35
+ }
36
+ return response.json();
37
+ }
38
+ finally {
39
+ clearTimeout(timeoutId);
40
+ }
41
+ }
42
+ // --- Public endpoints (no auth) ---
43
+ async searchCatalogs(query) {
44
+ const params = query ? `?q=${encodeURIComponent(query)}` : '';
45
+ return this.request(`/api/v1/stores${params}`);
46
+ }
47
+ async checkSlug(slug) {
48
+ return this.request(`/api/check-slug?slug=${encodeURIComponent(slug)}`);
49
+ }
50
+ // --- Authenticated endpoints ---
51
+ async listProducts(limit = 50, offset = 0) {
52
+ return this.request(`/api/v1/products?limit=${limit}&offset=${offset}`);
53
+ }
54
+ async getProduct(id) {
55
+ return this.request(`/api/v1/products/${id}`);
56
+ }
57
+ async createProduct(data) {
58
+ return this.request('/api/v1/products', {
59
+ method: 'POST',
60
+ body: JSON.stringify(data),
61
+ });
62
+ }
63
+ async listCategories(limit = 50, offset = 0) {
64
+ return this.request(`/api/v1/categories?limit=${limit}&offset=${offset}`);
65
+ }
66
+ async listOrders(limit = 50, offset = 0, status) {
67
+ const statusParam = status ? `&status=${status}` : '';
68
+ return this.request(`/api/v1/orders?limit=${limit}&offset=${offset}${statusParam}`);
69
+ }
70
+ async getOrder(id) {
71
+ return this.request(`/api/v1/orders/${id}`);
72
+ }
73
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function register(server: McpServer): void;
@@ -0,0 +1,47 @@
1
+ const COMPETITORS_DATA = {
2
+ summary: 'Karrito is the only catalog builder designed specifically for WhatsApp sellers in LATAM. No payment gateway required — customers order via WhatsApp.',
3
+ competitors: [
4
+ { name: 'Shopify', region: 'Global', whatsappNative: false, pricing: '$29+/mo', commission: '2%+', latamFocus: false, freeplan: '3-day trial' },
5
+ { name: 'TiendaNube', region: 'LATAM', whatsappNative: false, pricing: '$9+/mo', commission: '2%', latamFocus: true, freeplan: 'Yes (limited)' },
6
+ { name: 'Mercado Shops', region: 'LATAM', whatsappNative: false, pricing: 'Free', commission: '6-13%', latamFocus: true, freeplan: 'Yes' },
7
+ { name: 'WooCommerce', region: 'Global', whatsappNative: false, pricing: 'Free (hosting extra)', commission: '0%', latamFocus: false, freeplan: 'Yes' },
8
+ { name: 'Wix', region: 'Global', whatsappNative: false, pricing: '$17+/mo', commission: '0%', latamFocus: false, freeplan: 'Yes (with ads)' },
9
+ { name: 'Ecwid', region: 'Global', whatsappNative: false, pricing: '$25+/mo', commission: '0%', latamFocus: false, freeplan: 'Yes (5 products)' },
10
+ { name: 'Square Online', region: 'US-focused', whatsappNative: false, pricing: 'Free', commission: '2.9%', latamFocus: false, freeplan: 'Yes' },
11
+ { name: 'Jumpseller', region: 'LATAM', whatsappNative: false, pricing: '$19+/mo', commission: '0%', latamFocus: true, freeplan: '14-day trial' },
12
+ { name: 'Kyte', region: 'Brazil', whatsappNative: true, pricing: '$8+/mo', commission: '0%', latamFocus: true, freeplan: 'Yes (limited)' },
13
+ { name: 'CatalogApp', region: 'India', whatsappNative: true, pricing: '$5+/mo', commission: '0%', latamFocus: false, freeplan: 'Yes (limited)' },
14
+ { name: 'Linktree', region: 'Global', whatsappNative: false, pricing: '$5+/mo', commission: '0%', latamFocus: false, freeplan: 'Yes' },
15
+ { name: 'WhatsApp Business Catalog', region: 'Global', whatsappNative: true, pricing: 'Free', commission: '0%', latamFocus: false, freeplan: 'Yes' },
16
+ { name: 'GoDaddy', region: 'Global', whatsappNative: false, pricing: '$10+/mo', commission: '0%', latamFocus: false, freeplan: '30-day trial' },
17
+ { name: 'Zyro/Hostinger', region: 'Global', whatsappNative: false, pricing: '$3+/mo', commission: '0%', latamFocus: false, freeplan: 'No' },
18
+ { name: 'Empretienda', region: 'Argentina', whatsappNative: true, pricing: '$9+/mo', commission: '0%', latamFocus: true, freeplan: 'Yes (limited)' },
19
+ { name: 'Pedidos Ya Market', region: 'LATAM', whatsappNative: false, pricing: 'Free', commission: '15-25%', latamFocus: true, freeplan: 'Yes' },
20
+ { name: 'Rappi Market', region: 'LATAM', whatsappNative: false, pricing: 'Free', commission: '20-30%', latamFocus: true, freeplan: 'Yes' },
21
+ { name: 'Instagram Shop', region: 'Global', whatsappNative: false, pricing: 'Free', commission: '5%', latamFocus: false, freeplan: 'Yes' },
22
+ { name: 'Facebook Shops', region: 'Global', whatsappNative: false, pricing: 'Free', commission: '5%', latamFocus: false, freeplan: 'Yes' },
23
+ ],
24
+ karritoAdvantages: [
25
+ '0% commission on all plans, forever',
26
+ 'WhatsApp-native checkout — customers order via message, no payment gateway needed',
27
+ 'Built for LATAM: multi-currency (DOP, MXN, COP, ARS, CLP, USD), Spanish-first',
28
+ 'Mobile-first design — optimized for the 90%+ mobile traffic in LATAM',
29
+ 'Lifetime plan at $499 — no recurring fees ever',
30
+ 'No technical knowledge required — set up in under 5 minutes',
31
+ 'SEO-optimized catalog pages with structured data',
32
+ ],
33
+ };
34
+ export function register(server) {
35
+ server.resource('competitors', 'karrito://competitors', {
36
+ description: 'Competitive analysis: 19 competitors compared with Karrito advantages',
37
+ mimeType: 'application/json',
38
+ }, async (uri) => ({
39
+ contents: [
40
+ {
41
+ uri: uri.href,
42
+ text: JSON.stringify(COMPETITORS_DATA, null, 2),
43
+ mimeType: 'application/json',
44
+ },
45
+ ],
46
+ }));
47
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function register(server: McpServer): void;
@@ -0,0 +1,26 @@
1
+ const CURRENCIES_DATA = {
2
+ supported: [
3
+ { code: 'DOP', name: 'Peso dominicano', symbol: 'RD$', country: 'Republica Dominicana', decimalPlaces: 2 },
4
+ { code: 'MXN', name: 'Peso mexicano', symbol: '$', country: 'Mexico', decimalPlaces: 2 },
5
+ { code: 'COP', name: 'Peso colombiano', symbol: '$', country: 'Colombia', decimalPlaces: 0 },
6
+ { code: 'ARS', name: 'Peso argentino', symbol: '$', country: 'Argentina', decimalPlaces: 2 },
7
+ { code: 'CLP', name: 'Peso chileno', symbol: '$', country: 'Chile', decimalPlaces: 0 },
8
+ { code: 'USD', name: 'US Dollar', symbol: '$', country: 'United States / International', decimalPlaces: 2 },
9
+ ],
10
+ default: 'DOP',
11
+ notes: 'Currency is set per store. Prices display with the local symbol and formatting. No currency conversion is performed — sellers set prices in their local currency.',
12
+ };
13
+ export function register(server) {
14
+ server.resource('currencies', 'karrito://currencies', {
15
+ description: 'Supported currencies in Karrito — 6 LATAM currencies with formatting details',
16
+ mimeType: 'application/json',
17
+ }, async (uri) => ({
18
+ contents: [
19
+ {
20
+ uri: uri.href,
21
+ text: JSON.stringify(CURRENCIES_DATA, null, 2),
22
+ mimeType: 'application/json',
23
+ },
24
+ ],
25
+ }));
26
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function register(server: McpServer): void;
@@ -0,0 +1,44 @@
1
+ const FEATURES_DATA = {
2
+ core: [
3
+ { name: 'Digital catalog', description: 'Beautiful product catalog with categories, images, and variants' },
4
+ { name: 'WhatsApp checkout', description: 'Customers order via WhatsApp message — no payment gateway needed' },
5
+ { name: 'Custom slug', description: 'Your store at karrito.shop/your-name or custom domain' },
6
+ { name: 'Mobile-first', description: 'Optimized for mobile browsers where 90%+ LATAM traffic comes from' },
7
+ { name: 'Multi-currency', description: 'DOP, MXN, COP, ARS, CLP, USD supported natively' },
8
+ { name: 'Product variants', description: 'Size, color, flavor — any variant type (Pro+)' },
9
+ { name: 'Categories', description: 'Organize products with drag-and-drop categories' },
10
+ { name: 'Product images', description: 'Up to 5 images per product with automatic optimization' },
11
+ { name: 'Store customization', description: 'Logo, banner, colors, and social links' },
12
+ { name: 'SEO optimized', description: 'Each catalog is a fully indexed page with structured data' },
13
+ ],
14
+ pro: [
15
+ { name: 'Analytics dashboard', description: 'Views, clicks, orders, top products, conversion funnel' },
16
+ { name: 'Custom domain', description: 'Use your own domain (e.g., tienda.tudominio.com)' },
17
+ { name: 'Remove branding', description: 'No "Powered by Karrito" badge' },
18
+ { name: 'Priority support', description: 'WhatsApp support with <4h response time' },
19
+ { name: 'Bulk import', description: 'Import products via CSV' },
20
+ { name: 'Order history', description: 'Track and manage customer orders' },
21
+ ],
22
+ upcoming: [
23
+ { name: 'AI product descriptions', description: 'Generate compelling product descriptions with AI' },
24
+ { name: 'Instagram sync', description: 'Import products from Instagram posts' },
25
+ { name: 'Multi-store', description: 'Manage multiple catalogs from one account' },
26
+ { name: 'Delivery zones', description: 'Configure delivery areas and fees' },
27
+ { name: 'Payment links', description: 'Accept card payments via Stripe/MercadoPago' },
28
+ ],
29
+ url: 'https://karrito.shop/features',
30
+ };
31
+ export function register(server) {
32
+ server.resource('features', 'karrito://features', {
33
+ description: 'Complete list of Karrito features — core, pro, and upcoming',
34
+ mimeType: 'application/json',
35
+ }, async (uri) => ({
36
+ contents: [
37
+ {
38
+ uri: uri.href,
39
+ text: JSON.stringify(FEATURES_DATA, null, 2),
40
+ mimeType: 'application/json',
41
+ },
42
+ ],
43
+ }));
44
+ }
@@ -0,0 +1,8 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const NICHES_DATA: {
3
+ slug: string;
4
+ name: string;
5
+ description: string;
6
+ emoji: string;
7
+ }[];
8
+ export declare function register(server: McpServer): void;
@@ -0,0 +1,66 @@
1
+ export const NICHES_DATA = [
2
+ { slug: 'reposteria', name: 'Reposteria', description: 'Cakes, cupcakes, cookies, and custom desserts', emoji: 'cake' },
3
+ { slug: 'comida-casera', name: 'Comida casera', description: 'Home-cooked meals, meal prep, and lunch delivery', emoji: 'pot' },
4
+ { slug: 'ropa-mujer', name: 'Ropa de mujer', description: 'Women\'s clothing, dresses, accessories', emoji: 'dress' },
5
+ { slug: 'ropa-hombre', name: 'Ropa de hombre', description: 'Men\'s clothing, streetwear, casual wear', emoji: 'shirt' },
6
+ { slug: 'zapatos', name: 'Zapatos', description: 'Sneakers, heels, sandals, boots', emoji: 'shoe' },
7
+ { slug: 'cosmeticos', name: 'Cosmeticos', description: 'Makeup, skincare, beauty products', emoji: 'lipstick' },
8
+ { slug: 'joyeria', name: 'Joyeria', description: 'Handmade jewelry, earrings, necklaces, bracelets', emoji: 'ring' },
9
+ { slug: 'accesorios', name: 'Accesorios', description: 'Phone cases, bags, sunglasses, watches', emoji: 'bag' },
10
+ { slug: 'plantas', name: 'Plantas', description: 'Indoor plants, succulents, pots, and gardening supplies', emoji: 'plant' },
11
+ { slug: 'velas-aromas', name: 'Velas y aromas', description: 'Scented candles, essential oils, diffusers', emoji: 'candle' },
12
+ { slug: 'artesanias', name: 'Artesanias', description: 'Handmade crafts, pottery, macrame, woodwork', emoji: 'art' },
13
+ { slug: 'mascotas', name: 'Mascotas', description: 'Pet food, accessories, toys, grooming', emoji: 'paw' },
14
+ { slug: 'fitness', name: 'Fitness', description: 'Supplements, workout gear, activewear', emoji: 'dumbbell' },
15
+ { slug: 'tecnologia', name: 'Tecnologia', description: 'Gadgets, phone accessories, cables, chargers', emoji: 'phone' },
16
+ { slug: 'papeleria', name: 'Papeleria', description: 'Stationery, notebooks, planners, stickers', emoji: 'pencil' },
17
+ { slug: 'jugos-batidos', name: 'Jugos y batidos', description: 'Fresh juices, smoothies, acai bowls', emoji: 'cup' },
18
+ { slug: 'panaderia', name: 'Panaderia', description: 'Bread, pastries, empanadas, pan de bono', emoji: 'bread' },
19
+ { slug: 'cafeteria', name: 'Cafeteria', description: 'Specialty coffee, beans, brewing equipment', emoji: 'coffee' },
20
+ { slug: 'snacks', name: 'Snacks', description: 'Chips, nuts, dried fruit, candy, chocolates', emoji: 'candy' },
21
+ { slug: 'helados', name: 'Helados', description: 'Ice cream, paletas, frozen yogurt', emoji: 'icecream' },
22
+ { slug: 'salsas-condimentos', name: 'Salsas y condimentos', description: 'Hot sauce, seasonings, marinades', emoji: 'bottle' },
23
+ { slug: 'bebidas', name: 'Bebidas', description: 'Craft beverages, kombucha, agua fresca', emoji: 'drink' },
24
+ { slug: 'bebe', name: 'Bebe', description: 'Baby clothing, toys, accessories, diapers', emoji: 'baby' },
25
+ { slug: 'hogar', name: 'Hogar', description: 'Home decor, kitchenware, organization', emoji: 'home' },
26
+ { slug: 'limpieza', name: 'Limpieza', description: 'Eco cleaning products, detergents, supplies', emoji: 'spray' },
27
+ { slug: 'farmacia', name: 'Farmacia', description: 'OTC medicine, vitamins, health supplies', emoji: 'pill' },
28
+ { slug: 'electrónica', name: 'Electronica', description: 'Electronics, components, repairs', emoji: 'chip' },
29
+ { slug: 'ferreteria', name: 'Ferreteria', description: 'Hardware, tools, construction materials', emoji: 'hammer' },
30
+ { slug: 'libreria', name: 'Libreria', description: 'Books, e-books, educational materials', emoji: 'book' },
31
+ { slug: 'deportes', name: 'Deportes', description: 'Sports equipment, jerseys, outdoor gear', emoji: 'ball' },
32
+ { slug: 'musica', name: 'Musica', description: 'Instruments, vinyl, music accessories', emoji: 'guitar' },
33
+ { slug: 'fotografia', name: 'Fotografia', description: 'Photography prints, frames, camera gear', emoji: 'camera' },
34
+ { slug: 'flores', name: 'Flores', description: 'Flower arrangements, bouquets, event decor', emoji: 'flower' },
35
+ { slug: 'eventos', name: 'Eventos', description: 'Party supplies, decorations, invitations', emoji: 'balloon' },
36
+ { slug: 'regalos', name: 'Regalos', description: 'Gift boxes, personalized gifts, hampers', emoji: 'gift' },
37
+ { slug: 'imprenta', name: 'Imprenta', description: 'Business cards, flyers, banners, signage', emoji: 'printer' },
38
+ { slug: 'uniformes', name: 'Uniformes', description: 'Work uniforms, school uniforms, scrubs', emoji: 'vest' },
39
+ { slug: 'telas', name: 'Telas', description: 'Fabrics, sewing supplies, patterns', emoji: 'scissors' },
40
+ { slug: 'cuidado-personal', name: 'Cuidado personal', description: 'Shampoo, soap, grooming, natural products', emoji: 'soap' },
41
+ { slug: 'suplementos', name: 'Suplementos', description: 'Protein, vitamins, health supplements', emoji: 'supplement' },
42
+ { slug: 'optica', name: 'Optica', description: 'Eyeglasses, contact lenses, sunglasses', emoji: 'glasses' },
43
+ { slug: 'peluqueria', name: 'Peluqueria', description: 'Hair products, tools, salon supplies', emoji: 'hairdryer' },
44
+ { slug: 'tatuajes', name: 'Tatuajes', description: 'Tattoo supplies, aftercare, flash designs', emoji: 'needle' },
45
+ { slug: 'ceramica', name: 'Ceramica', description: 'Handmade ceramics, mugs, plates, vases', emoji: 'vase' },
46
+ { slug: 'bordados', name: 'Bordados', description: 'Embroidery, patches, custom textile art', emoji: 'thread' },
47
+ { slug: 'frutas-verduras', name: 'Frutas y verduras', description: 'Fresh produce, organic fruits, vegetables', emoji: 'apple' },
48
+ { slug: 'carniceria', name: 'Carniceria', description: 'Fresh meat, cuts, sausages, marinated meats', emoji: 'meat' },
49
+ { slug: 'mariscos', name: 'Mariscos', description: 'Fresh seafood, shrimp, fish, ceviche', emoji: 'shrimp' },
50
+ { slug: 'lacteos', name: 'Lacteos', description: 'Cheese, yogurt, milk, artisan dairy', emoji: 'cheese' },
51
+ { slug: 'licores', name: 'Licores', description: 'Wines, spirits, craft beer, mixers', emoji: 'wine' },
52
+ ];
53
+ export function register(server) {
54
+ server.resource('niches', 'karrito://niches', {
55
+ description: 'All 50 available niches for Karrito stores in LATAM — slug, name, and description',
56
+ mimeType: 'application/json',
57
+ }, async (uri) => ({
58
+ contents: [
59
+ {
60
+ uri: uri.href,
61
+ text: JSON.stringify({ niches: NICHES_DATA, total: NICHES_DATA.length }, null, 2),
62
+ mimeType: 'application/json',
63
+ },
64
+ ],
65
+ }));
66
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function register(server: McpServer): void;
@@ -0,0 +1,56 @@
1
+ const PRICING_DATA = {
2
+ plans: [
3
+ {
4
+ name: 'Free',
5
+ price: 0,
6
+ billing: 'forever',
7
+ products: 10,
8
+ categories: 3,
9
+ variants: false,
10
+ analytics: false,
11
+ customDomain: false,
12
+ removeBranding: false,
13
+ },
14
+ {
15
+ name: 'Pro',
16
+ price: 29,
17
+ billing: 'monthly',
18
+ yearlyPrice: 290,
19
+ products: 500,
20
+ categories: 50,
21
+ variants: true,
22
+ analytics: true,
23
+ customDomain: true,
24
+ removeBranding: true,
25
+ },
26
+ {
27
+ name: 'Lifetime',
28
+ price: 499,
29
+ billing: 'one-time',
30
+ products: 'unlimited',
31
+ categories: 'unlimited',
32
+ variants: true,
33
+ analytics: true,
34
+ customDomain: true,
35
+ removeBranding: true,
36
+ },
37
+ ],
38
+ commissions: 'Never. 0% on all plans.',
39
+ trial: '14-day free Pro trial for all new users',
40
+ refund: '7-day money-back guarantee on Pro and Lifetime',
41
+ url: 'https://karrito.shop/pricing',
42
+ };
43
+ export function register(server) {
44
+ server.resource('pricing', 'karrito://pricing', {
45
+ description: 'Karrito pricing plans, features comparison, and billing details',
46
+ mimeType: 'application/json',
47
+ }, async (uri) => ({
48
+ contents: [
49
+ {
50
+ uri: uri.href,
51
+ text: JSON.stringify(PRICING_DATA, null, 2),
52
+ mimeType: 'application/json',
53
+ },
54
+ ],
55
+ }));
56
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { KarritoApiClient } from '../lib/api-client.js';
3
+ export declare function register(server: McpServer, client: KarritoApiClient): void;
@@ -0,0 +1,67 @@
1
+ import { z } from 'zod';
2
+ import { NICHES_DATA } from '../resources/niches.js';
3
+ export function register(server, client) {
4
+ // --- search_catalogs (public, no auth) ---
5
+ server.tool('search_catalogs', 'Search public Karrito catalogs by keyword. No authentication required.', {
6
+ query: z.string().min(1).max(100).describe('Search query — store name, product, or niche'),
7
+ }, async ({ query }) => {
8
+ try {
9
+ const data = await client.searchCatalogs(query);
10
+ return {
11
+ content: [
12
+ {
13
+ type: 'text',
14
+ text: JSON.stringify(data, null, 2),
15
+ },
16
+ ],
17
+ };
18
+ }
19
+ catch (error) {
20
+ const message = error instanceof Error ? error.message : 'Unknown error';
21
+ return {
22
+ content: [{ type: 'text', text: `Error searching catalogs: ${message}` }],
23
+ isError: true,
24
+ };
25
+ }
26
+ });
27
+ // --- get_niche_info (public, static data) ---
28
+ server.tool('get_niche_info', 'Get information about a specific Karrito niche by slug or name. Returns niche details from the 50 available niches. No authentication required.', {
29
+ niche: z.string().min(1).max(50).describe('Niche slug (e.g., "reposteria") or partial name to search'),
30
+ }, async ({ niche }) => {
31
+ const query = niche.toLowerCase();
32
+ // Busqueda exacta por slug
33
+ const exactMatch = NICHES_DATA.find((n) => n.slug === query);
34
+ if (exactMatch) {
35
+ return {
36
+ content: [
37
+ {
38
+ type: 'text',
39
+ text: JSON.stringify(exactMatch, null, 2),
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ // Busqueda parcial por nombre o descripcion
45
+ const partialMatches = NICHES_DATA.filter((n) => n.slug.includes(query) ||
46
+ n.name.toLowerCase().includes(query) ||
47
+ n.description.toLowerCase().includes(query));
48
+ if (partialMatches.length === 0) {
49
+ return {
50
+ content: [
51
+ {
52
+ type: 'text',
53
+ text: `No niches found matching "${niche}". Use the karrito://niches resource to see all 50 available niches.`,
54
+ },
55
+ ],
56
+ };
57
+ }
58
+ return {
59
+ content: [
60
+ {
61
+ type: 'text',
62
+ text: JSON.stringify({ matches: partialMatches, total: partialMatches.length }, null, 2),
63
+ },
64
+ ],
65
+ };
66
+ });
67
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { KarritoApiClient } from '../lib/api-client.js';
3
+ export declare function register(server: McpServer, client: KarritoApiClient): void;
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ export function register(server, client) {
3
+ // --- list_my_orders (auth required) ---
4
+ server.tool('list_my_orders', 'List orders from your Karrito store. Requires KARRITO_API_KEY environment variable.', {
5
+ limit: z.number().min(1).max(100).default(50).describe('Max orders to return (1-100)'),
6
+ offset: z.number().min(0).default(0).describe('Pagination offset'),
7
+ status: z
8
+ .enum(['pending', 'confirmed', 'delivered', 'cancelled'])
9
+ .optional()
10
+ .describe('Filter by order status'),
11
+ }, async ({ limit, offset, status }) => {
12
+ if (!client.hasApiKey) {
13
+ return {
14
+ content: [
15
+ {
16
+ type: 'text',
17
+ text: 'Authentication required. Set the KARRITO_API_KEY environment variable with your Karrito API key. You can generate one at https://karrito.shop/settings/api',
18
+ },
19
+ ],
20
+ isError: true,
21
+ };
22
+ }
23
+ try {
24
+ const data = await client.listOrders(limit, offset, status);
25
+ return {
26
+ content: [
27
+ {
28
+ type: 'text',
29
+ text: JSON.stringify(data, null, 2),
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ catch (error) {
35
+ const message = error instanceof Error ? error.message : 'Unknown error';
36
+ return {
37
+ content: [{ type: 'text', text: `Error listing orders: ${message}` }],
38
+ isError: true,
39
+ };
40
+ }
41
+ });
42
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { KarritoApiClient } from '../lib/api-client.js';
3
+ export declare function register(server: McpServer, client: KarritoApiClient): void;
@@ -0,0 +1,83 @@
1
+ import { z } from 'zod';
2
+ export function register(server, client) {
3
+ // --- list_my_products (auth required) ---
4
+ server.tool('list_my_products', 'List products in your Karrito catalog. Requires KARRITO_API_KEY environment variable.', {
5
+ limit: z.number().min(1).max(100).default(50).describe('Max products to return (1-100)'),
6
+ offset: z.number().min(0).default(0).describe('Pagination offset'),
7
+ }, async ({ limit, offset }) => {
8
+ if (!client.hasApiKey) {
9
+ return {
10
+ content: [
11
+ {
12
+ type: 'text',
13
+ text: 'Authentication required. Set the KARRITO_API_KEY environment variable with your Karrito API key. You can generate one at https://karrito.shop/settings/api',
14
+ },
15
+ ],
16
+ isError: true,
17
+ };
18
+ }
19
+ try {
20
+ const data = await client.listProducts(limit, offset);
21
+ return {
22
+ content: [
23
+ {
24
+ type: 'text',
25
+ text: JSON.stringify(data, null, 2),
26
+ },
27
+ ],
28
+ };
29
+ }
30
+ catch (error) {
31
+ const message = error instanceof Error ? error.message : 'Unknown error';
32
+ return {
33
+ content: [{ type: 'text', text: `Error listing products: ${message}` }],
34
+ isError: true,
35
+ };
36
+ }
37
+ });
38
+ // --- create_product (auth required) ---
39
+ server.tool('create_product', 'Create a new product in your Karrito catalog. Requires KARRITO_API_KEY environment variable.', {
40
+ name: z.string().min(1).max(200).describe('Product name'),
41
+ price: z.number().min(0).describe('Product price in store currency'),
42
+ description: z.string().max(2000).optional().describe('Product description'),
43
+ categoryId: z.string().optional().describe('Category ID to assign the product to'),
44
+ imageUrl: z.string().url().optional().describe('Product image URL'),
45
+ }, async ({ name, price, description, categoryId, imageUrl }) => {
46
+ if (!client.hasApiKey) {
47
+ return {
48
+ content: [
49
+ {
50
+ type: 'text',
51
+ text: 'Authentication required. Set the KARRITO_API_KEY environment variable with your Karrito API key. You can generate one at https://karrito.shop/settings/api',
52
+ },
53
+ ],
54
+ isError: true,
55
+ };
56
+ }
57
+ try {
58
+ const productData = { name, price };
59
+ if (description)
60
+ productData.description = description;
61
+ if (categoryId)
62
+ productData.categoryId = categoryId;
63
+ if (imageUrl)
64
+ productData.imageUrl = imageUrl;
65
+ const data = await client.createProduct(productData);
66
+ return {
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: JSON.stringify(data, null, 2),
71
+ },
72
+ ],
73
+ };
74
+ }
75
+ catch (error) {
76
+ const message = error instanceof Error ? error.message : 'Unknown error';
77
+ return {
78
+ content: [{ type: 'text', text: `Error creating product: ${message}` }],
79
+ isError: true,
80
+ };
81
+ }
82
+ });
83
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "karrito-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Karrito — digital catalog builder for WhatsApp sellers in LATAM",
5
+ "bin": {
6
+ "karrito-mcp": "./dist/index.js"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "type": "module",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "karrito",
18
+ "whatsapp",
19
+ "catalog",
20
+ "latam",
21
+ "ecommerce",
22
+ "model-context-protocol"
23
+ ],
24
+ "author": "Ronaldo Paulino",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.12.0",
28
+ "zod": "^3.25.0"
29
+ },
30
+ "devDependencies": {
31
+ "tsx": "^4.19.0",
32
+ "typescript": "^5.8.0"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md"
37
+ ],
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/curetcore/karrito-mcp"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ }
45
+ }