Skip to main content
Glama
wspotter

MCP Art Supply Store

by wspotter

compare_supplier_prices

Compare prices and terms across multiple suppliers for specific art supply products to identify cost-effective purchasing options.

Instructions

Compare prices and terms across suppliers for a specific product or category.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
productNameYesProduct name or category

Implementation Reference

  • Handler function for 'compare_supplier_prices' tool. Filters inventory by product name or category, groups products by supplier, and generates a price comparison report including lead times.
    case 'compare_supplier_prices': {
      const productName = String(args?.productName || '').toLowerCase();
      const products = storeData.inventory.filter(i =>
        i.name.toLowerCase().includes(productName) ||
        i.category.toLowerCase().includes(productName)
      );
      
      if (products.length === 0) {
        return { content: [{ type: 'text', text: `No products found matching "${args?.productName}"` }] };
      }
      
      const supplierMap = new Map();
      products.forEach(p => {
        if (!supplierMap.has(p.supplier)) {
          supplierMap.set(p.supplier, []);
        }
        supplierMap.get(p.supplier).push(p);
      });
      
      return {
        content: [{
          type: 'text',
          text: `πŸ’² Price Comparison for "${args?.productName}":\n\n${Array.from(supplierMap.entries()).map(([supplier, items]) => {
            const supplierInfo = storeData.suppliers.find(s => s.name === supplier);
            return `${supplier}:\n${items.map((item: any) => `β€’ ${item.name} - $${item.price}`).join('\n')}\nLead Time: ${supplierInfo?.leadTime || 'N/A'}`;
          }).join('\n\n')}`
        }]
      };
    }
  • Tool schema definition including name, description, and input schema requiring 'productName' parameter.
    {
      name: 'compare_supplier_prices',
      description: 'Compare prices and terms across suppliers for a specific product or category.',
      inputSchema: {
        type: 'object',
        properties: {
          productName: { type: 'string', description: 'Product name or category' },
        },
        required: ['productName'],
      },
    },
  • src/index.ts:516-518 (registration)
    Registration of the ListToolsRequestHandler which returns the array of all tools including 'compare_supplier_prices'.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return { tools };
    });
  • src/index.ts:521-1509 (registration)
    Registration of the CallToolRequestHandler which dispatches to specific tool handlers via switch, including the case for 'compare_supplier_prices'.
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      try {
        switch (name) {
          // INVENTORY MANAGEMENT
          // VIP DATASET GENERATION TOOLS
          case 'vip_generate_dataset':
          case 'vip_check_status':
          case 'vip_list_datasets':
          case 'vip_get_dataset_info':
          case 'vip_stop_pipeline':
          case 'vip_validate_config':
          case 'vip_health_check': {
            const result = await handleVIPTool(name, args);
            return {
              content: [{
                type: 'text',
                text: result
              }]
            };
          }
    
    
          // UNIVERSAL DAILY TASK TOOLS
          case 'create_task':
          case 'list_tasks':
          case 'complete_task':
          case 'update_task':
          case 'get_daily_agenda':
          case 'schedule_event':
          case 'list_upcoming_events':
          case 'set_reminder':
          case 'get_today_schedule':
          case 'create_note':
          case 'search_notes':
          case 'tag_note':
          case 'log_expense':
          case 'get_expense_summary':
          case 'categorize_expenses':
          case 'generate_daily_summary':
          case 'export_data':
          case 'create_alert':
          case 'list_alerts': {
            const result = await handleUniversalTool(name, args);
            return {
              content: [{
                type: 'text',
                text: JSON.stringify(result, null, 2)
              }]
            };
          }
          case 'check_inventory': {
            const search = String(args?.search || '').toLowerCase();
            const results = storeData.inventory.filter(item =>
              item.name.toLowerCase().includes(search) ||
              item.id.toLowerCase().includes(search) ||
              item.category.toLowerCase().includes(search)
            );
            return {
              content: [{
                type: 'text',
                text: results.length > 0
                  ? `Found ${results.length} item(s):\n\n${results.map(item => 
                      `${item.name} (${item.id})\n- Category: ${item.category}\n- Stock: ${item.quantity} units${item.quantity <= item.reorderLevel ? ' ⚠️ LOW STOCK' : ''}\n- Price: $${item.price}\n- Supplier: ${item.supplier}\n- Last Restocked: ${item.lastRestocked}`
                    ).join('\n\n')}`
                  : `No items found matching "${args?.search}"`
              }]
            };
          }
    
          case 'get_low_stock_items': {
            const category = args?.category ? String(args.category) : null;
            let lowStockItems = storeData.inventory.filter(item => item.quantity <= item.reorderLevel);
            if (category) {
              lowStockItems = lowStockItems.filter(item => item.category.toLowerCase() === category.toLowerCase());
            }
            return {
              content: [{
                type: 'text',
                text: lowStockItems.length > 0
                  ? `⚠️ ${lowStockItems.length} item(s) need reordering:\n\n${lowStockItems.map(item =>
                      `${item.name} (${item.id})\n- Current: ${item.quantity} | Reorder Level: ${item.reorderLevel}\n- Need to order: ${item.reorderLevel * 2 - item.quantity} units\n- Supplier: ${item.supplier}`
                    ).join('\n\n')}`
                  : 'βœ… All items are adequately stocked!'
              }]
            };
          }
    
          case 'update_stock': {
            const sku = String(args?.sku || '');
            const quantity = Number(args?.quantity || 0);
            const reason = String(args?.reason || 'manual update');
            const item = storeData.inventory.find(i => i.id === sku);
            
            if (!item) {
              return { content: [{ type: 'text', text: `❌ Product ${sku} not found` }] };
            }
            
            const oldQty = item.quantity;
            item.quantity = quantity;
            const diff = quantity - oldQty;
            
            return {
              content: [{
                type: 'text',
                text: `βœ… Stock updated for ${item.name}\n- Previous: ${oldQty} units\n- New: ${quantity} units\n- Change: ${diff > 0 ? '+' : ''}${diff} units\n- Reason: ${reason}\n- ${quantity <= item.reorderLevel ? '⚠️ Now below reorder level!' : 'Stock level OK'}`
              }]
            };
          }
    
          case 'search_products': {
            const query = String(args?.query || '').toLowerCase();
            const filterBy = args?.filterBy ? String(args.filterBy) : null;
            
            let results = storeData.inventory.filter(item =>
              item.name.toLowerCase().includes(query) ||
              item.category.toLowerCase().includes(query)
            );
            
            return {
              content: [{
                type: 'text',
                text: `Found ${results.length} product(s):\n\n${results.map(item =>
                  `πŸ“¦ ${item.name}\n- SKU: ${item.id} | Price: $${item.price}\n- Category: ${item.category} | Stock: ${item.quantity}\n- Supplier: ${item.supplier}`
                ).join('\n\n')}`
              }]
            };
          }
    
          // CUSTOMER MANAGEMENT
          case 'lookup_customer': {
            const identifier = String(args?.identifier || '').toLowerCase();
            const customer = storeData.customers.find(c =>
              c.name.toLowerCase().includes(identifier) ||
              c.email.toLowerCase().includes(identifier) ||
              c.phone.includes(identifier) ||
              c.id.toLowerCase() === identifier
            );
            
            if (!customer) {
              return { content: [{ type: 'text', text: `❌ Customer not found: "${args?.identifier}"` }] };
            }
            
            return {
              content: [{
                type: 'text',
                text: `πŸ‘€ ${customer.name} (${customer.id})\n\nπŸ“§ ${customer.email}\nπŸ“± ${customer.phone}\n\nπŸ’° Total Spent: $${customer.totalSpent.toFixed(2)}\n⭐ Loyalty Points: ${customer.loyaltyPoints} (β‰ˆ $${(customer.loyaltyPoints / 10).toFixed(2)} credit)\nπŸ“… Last Visit: ${customer.lastVisit}\n🎨 Preferences: ${customer.preferences.join(', ')}`
              }]
            };
          }
    
          case 'update_loyalty_points': {
            const customerId = String(args?.customerId || '');
            const points = Number(args?.points || 0);
            const reason = String(args?.reason || 'adjustment');
            const customer = storeData.customers.find(c => c.id === customerId);
            
            if (!customer) {
              return { content: [{ type: 'text', text: `❌ Customer ${customerId} not found` }] };
            }
            
            const oldPoints = customer.loyaltyPoints;
            customer.loyaltyPoints += points;
            
            return {
              content: [{
                type: 'text',
                text: `βœ… Loyalty points updated for ${customer.name}\n- Previous: ${oldPoints} points\n- Change: ${points > 0 ? '+' : ''}${points} points\n- New Balance: ${customer.loyaltyPoints} points (β‰ˆ $${(customer.loyaltyPoints / 10).toFixed(2)} credit)\n- Reason: ${reason}`
              }]
            };
          }
    
          case 'get_customer_recommendations': {
            const customerId = String(args?.customerId || '');
            const customer = storeData.customers.find(c => c.id === customerId);
            
            if (!customer) {
              return { content: [{ type: 'text', text: `❌ Customer ${customerId} not found` }] };
            }
            
            const recommendations = storeData.inventory.filter(item =>
              customer.preferences.some(pref => 
                item.name.toLowerCase().includes(pref.toLowerCase()) ||
                item.category.toLowerCase().includes(pref.toLowerCase())
              )
            ).slice(0, 5);
            
            return {
              content: [{
                type: 'text',
                text: `🎯 Personalized recommendations for ${customer.name}:\n\nBased on preferences: ${customer.preferences.join(', ')}\n\n${recommendations.map(item =>
                  `β€’ ${item.name} - $${item.price}\n  ${item.quantity} in stock`
                ).join('\n')}`
              }]
            };
          }
    
          case 'get_top_customers': {
            const sortBy = String(args?.sortBy || 'spending');
            const limit = Number(args?.limit || 10);
            
            const sorted = [...storeData.customers].sort((a, b) =>
              sortBy === 'loyalty_points' ? b.loyaltyPoints - a.loyaltyPoints : b.totalSpent - a.totalSpent
            ).slice(0, limit);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ† Top ${limit} Customers by ${sortBy === 'loyalty_points' ? 'Loyalty Points' : 'Total Spending'}:\n\n${sorted.map((c, i) =>
                  `${i + 1}. ${c.name}\n   ${sortBy === 'loyalty_points' ? `${c.loyaltyPoints} points` : `$${c.totalSpent.toFixed(2)} spent`} | Last visit: ${c.lastVisit}`
                ).join('\n\n')}`
              }]
            };
          }
    
          // SALES & ANALYTICS
          case 'get_daily_sales': {
            const date = String(args?.date || '2025-10-03');
            const salesData = storeData.sales.find(s => s.date === date);
            
            if (!salesData) {
              return { content: [{ type: 'text', text: `No sales data found for ${date}` }] };
            }
            
            return {
              content: [{
                type: 'text',
                text: `πŸ“Š Sales Report for ${salesData.date}\n\nπŸ’΅ Revenue: $${salesData.revenue.toFixed(2)}\nπŸ›’ Transactions: ${salesData.transactions}\nπŸ“ˆ Avg Transaction: $${(salesData.revenue / salesData.transactions).toFixed(2)}\nπŸ† Top Seller: ${salesData.topItem}`
              }]
            };
          }
    
          case 'get_sales_report': {
            const startDate = String(args?.startDate || '');
            const endDate = String(args?.endDate || '');
            
            const periodSales = storeData.sales.filter(s => s.date >= startDate && s.date <= endDate);
            const totalRevenue = periodSales.reduce((sum, s) => sum + s.revenue, 0);
            const totalTransactions = periodSales.reduce((sum, s) => sum + s.transactions, 0);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ“Š Sales Report: ${startDate} to ${endDate}\n\nπŸ’° Total Revenue: $${totalRevenue.toFixed(2)}\nπŸ›’ Total Transactions: ${totalTransactions}\nπŸ“ˆ Average Transaction: $${(totalRevenue / totalTransactions).toFixed(2)}\nπŸ“… Days in Period: ${periodSales.length}\nπŸ“Š Daily Average: $${(totalRevenue / periodSales.length).toFixed(2)}`
              }]
            };
          }
    
          case 'get_best_sellers': {
            const category = args?.category ? String(args.category) : null;
            const period = String(args?.period || 'week');
            
            let items = storeData.inventory;
            if (category) {
              items = items.filter(i => i.category.toLowerCase() === category.toLowerCase());
            }
            
            const bestSellers = items.sort((a, b) => b.price - a.price).slice(0, 5);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ† Best Sellers${category ? ` in ${category}` : ''} (${period}):\n\n${bestSellers.map((item, i) =>
                  `${i + 1}. ${item.name}\n   Price: $${item.price} | In stock: ${item.quantity}`
                ).join('\n\n')}`
              }]
            };
          }
    
          case 'calculate_profit_margin': {
            const sku = String(args?.sku || '');
            const costPrice = Number(args?.costPrice || 0);
            const item = storeData.inventory.find(i => i.id === sku);
            
            if (!item) {
              return { content: [{ type: 'text', text: `❌ Product ${sku} not found` }] };
            }
            
            const profit = item.price - costPrice;
            const margin = (profit / item.price) * 100;
            
            return {
              content: [{
                type: 'text',
                text: `πŸ’° Profit Analysis: ${item.name}\n\n- Selling Price: $${item.price}\n- Cost Price: $${costPrice.toFixed(2)}\n- Profit per Unit: $${profit.toFixed(2)}\n- Profit Margin: ${margin.toFixed(1)}%\n- Potential Revenue (current stock): $${(item.quantity * profit).toFixed(2)}`
              }]
            };
          }
    
          // SUPPLIER & ORDERING
          case 'get_supplier_info': {
            const supplierName = String(args?.supplierName || '').toLowerCase();
            const supplier = storeData.suppliers.find(s =>
              s.name.toLowerCase().includes(supplierName) ||
              s.id.toLowerCase() === supplierName
            );
            
            if (!supplier) {
              return { content: [{ type: 'text', text: `❌ Supplier not found: "${args?.supplierName}"` }] };
            }
            
            const supplierProducts = storeData.inventory.filter(i => i.supplier === supplier.name);
            
            return {
              content: [{
                type: 'text',
                text: `🏒 ${supplier.name} (${supplier.id})\n\nπŸ“§ ${supplier.contact}\nπŸ“± ${supplier.phone}\n⏱️ Lead Time: ${supplier.leadTime}\nπŸ’΅ Minimum Order: $${supplier.minOrder}\n\nπŸ“¦ Products from this supplier: ${supplierProducts.length}\n${supplierProducts.slice(0, 5).map(p => `β€’ ${p.name}`).join('\n')}`
              }]
            };
          }
    
          case 'create_purchase_order': {
            const supplier = String(args?.supplier || '');
            const autoInclude = Boolean(args?.autoIncludeLowStock);
            
            const supplierInfo = storeData.suppliers.find(s => s.name.toLowerCase().includes(supplier.toLowerCase()));
            
            if (!supplierInfo) {
              return { content: [{ type: 'text', text: `❌ Supplier not found: "${supplier}"` }] };
            }
            
            const supplierProducts = storeData.inventory.filter(i => i.supplier === supplierInfo.name);
            const lowStock = autoInclude ? supplierProducts.filter(i => i.quantity <= i.reorderLevel) : [];
            
            const orderTotal = lowStock.reduce((sum, item) => sum + (item.price * (item.reorderLevel * 2 - item.quantity)), 0);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ“ Purchase Order Created\n\n🏒 Supplier: ${supplierInfo.name}\nπŸ“… Date: ${new Date().toISOString().split('T')[0]}\n⏱️ Expected Delivery: ${supplierInfo.leadTime}\n\n${lowStock.length > 0 ? `Items to Order:\n${lowStock.map(item =>
                  `β€’ ${item.name} (${item.id})\n  Order Qty: ${item.reorderLevel * 2 - item.quantity} | Est. Cost: $${(item.price * (item.reorderLevel * 2 - item.quantity) * 0.6).toFixed(2)}`
                ).join('\n\n')}\n\nπŸ’° Estimated Total: $${(orderTotal * 0.6).toFixed(2)}` : 'No items below reorder level for this supplier.'}`
              }]
            };
          }
    
          case 'compare_supplier_prices': {
            const productName = String(args?.productName || '').toLowerCase();
            const products = storeData.inventory.filter(i =>
              i.name.toLowerCase().includes(productName) ||
              i.category.toLowerCase().includes(productName)
            );
            
            if (products.length === 0) {
              return { content: [{ type: 'text', text: `No products found matching "${args?.productName}"` }] };
            }
            
            const supplierMap = new Map();
            products.forEach(p => {
              if (!supplierMap.has(p.supplier)) {
                supplierMap.set(p.supplier, []);
              }
              supplierMap.get(p.supplier).push(p);
            });
            
            return {
              content: [{
                type: 'text',
                text: `πŸ’² Price Comparison for "${args?.productName}":\n\n${Array.from(supplierMap.entries()).map(([supplier, items]) => {
                  const supplierInfo = storeData.suppliers.find(s => s.name === supplier);
                  return `${supplier}:\n${items.map((item: any) => `β€’ ${item.name} - $${item.price}`).join('\n')}\nLead Time: ${supplierInfo?.leadTime || 'N/A'}`;
                }).join('\n\n')}`
              }]
            };
          }
    
          // SCHEDULING & OPERATIONS
          case 'check_appointments': {
            const date = String(args?.date || new Date().toISOString().split('T')[0]);
            const appointments = storeData.appointments.filter(a => a.date === date);
            
            return {
              content: [{
                type: 'text',
                text: appointments.length > 0
                  ? `πŸ“… Appointments for ${date}:\n\n${appointments.map(apt =>
                      `⏰ ${apt.time} - ${apt.service}\nπŸ‘€ Customer: ${apt.customerName}\n⏱️ Duration: ${apt.duration}`
                    ).join('\n\n')}`
                  : `No appointments scheduled for ${date}`
              }]
            };
          }
    
          case 'book_appointment': {
            const customerName = String(args?.customerName || '');
            const service = String(args?.service || '');
            const date = String(args?.date || '');
            const time = String(args?.time || '');
            
            const newApt = {
              id: `APT${String(storeData.appointments.length + 1).padStart(3, '0')}`,
              customerName,
              service,
              date,
              time,
              duration: service.toLowerCase().includes('workshop') ? '2 hours' : '30 min'
            };
            
            storeData.appointments.push(newApt);
            
            return {
              content: [{
                type: 'text',
                text: `βœ… Appointment Booked!\n\nπŸ“… ${date} at ${time}\nπŸ‘€ ${customerName}\n🎨 Service: ${service}\n⏱️ Duration: ${newApt.duration}\n🎫 Confirmation: ${newApt.id}`
              }]
            };
          }
    
          case 'get_employee_schedule': {
            const date = String(args?.date || new Date().toLocaleDateString('en-US', { weekday: 'long' }));
            
            return {
              content: [{
                type: 'text',
                text: `πŸ‘₯ Employee Schedule:\n\n${storeData.employees.map(emp =>
                  `${emp.name} - ${emp.role}\nπŸ“… ${emp.shift}\nπŸ’΅ Rate: $${emp.hourlyRate}/hr`
                ).join('\n\n')}`
              }]
            };
          }
    
          case 'calculate_labor_cost': {
            const startDate = String(args?.startDate || '');
            const endDate = String(args?.endDate || '');
            
            const days = Math.ceil((new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24));
            const totalCost = storeData.employees.reduce((sum, emp) => sum + (emp.hourlyRate * 40 * days / 7), 0);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ’° Labor Cost Analysis\nπŸ“… Period: ${startDate} to ${endDate} (${days} days)\n\n${storeData.employees.map(emp =>
                  `${emp.name}: $${(emp.hourlyRate * 40 * days / 7).toFixed(2)}`
                ).join('\n')}\n\nπŸ’΅ Total Labor Cost: $${totalCost.toFixed(2)}\nπŸ“Š Daily Average: $${(totalCost / days).toFixed(2)}`
              }]
            };
          }
    
          // PRICING & PROMOTIONS
          case 'calculate_discount': {
            const sku = String(args?.sku || '');
            const discountType = String(args?.discountType || 'percentage');
            const discountValue = Number(args?.discountValue || 0);
            const quantity = Number(args?.quantity || 1);
            
            const item = storeData.inventory.find(i => i.id === sku);
            if (!item) {
              return { content: [{ type: 'text', text: `❌ Product ${sku} not found` }] };
            }
            
            let finalPrice = item.price;
            let discount = 0;
            
            switch (discountType) {
              case 'percentage':
                discount = item.price * (discountValue / 100);
                finalPrice = item.price - discount;
                break;
              case 'fixed':
                discount = discountValue;
                finalPrice = item.price - discount;
                break;
              case 'loyalty':
                discount = discountValue / 10;
                finalPrice = item.price - discount;
                break;
              case 'bulk':
                if (quantity >= 5) {
                  discount = item.price * 0.15;
                  finalPrice = item.price - discount;
                }
                break;
            }
            
            return {
              content: [{
                type: 'text',
                text: `πŸ’² Price Calculation: ${item.name}\n\n- Original Price: $${item.price}\n- Discount Type: ${discountType}\n- Discount Amount: $${discount.toFixed(2)}\n- Final Price: $${finalPrice.toFixed(2)}\n- Quantity: ${quantity}\n- Total: $${(finalPrice * quantity).toFixed(2)}`
              }]
            };
          }
    
          case 'suggest_bundle': {
            const baseSku = String(args?.baseSku || '');
            const baseItem = storeData.inventory.find(i => i.id === baseSku);
            
            if (!baseItem) {
              return { content: [{ type: 'text', text: `❌ Product ${baseSku} not found` }] };
            }
            
            const complementary = storeData.inventory
              .filter(i => i.category === baseItem.category || i.id !== baseSku)
              .slice(0, 3);
            
            const bundlePrice = baseItem.price + complementary.reduce((sum, item) => sum + item.price, 0);
            const bundleDiscount = bundlePrice * 0.15;
            
            return {
              content: [{
                type: 'text',
                text: `🎁 Suggested Bundle:\n\nπŸ“¦ Base Item:\nβ€’ ${baseItem.name} - $${baseItem.price}\n\nβž• Add to Bundle:\n${complementary.map(item =>
                  `β€’ ${item.name} - $${item.price}`
                ).join('\n')}\n\nπŸ’° Bundle Price:\n- Individual Total: $${bundlePrice.toFixed(2)}\n- Bundle Discount (15%): -$${bundleDiscount.toFixed(2)}\n- Bundle Price: $${(bundlePrice - bundleDiscount).toFixed(2)}\nπŸ’΅ Customer Saves: $${bundleDiscount.toFixed(2)}`
              }]
            };
          }
    
          // REPORTING & INSIGHTS
          case 'generate_eod_report': {
            const date = String(args?.date || '2025-10-03');
            const salesData = storeData.sales.find(s => s.date === date);
            const lowStock = storeData.inventory.filter(i => i.quantity <= i.reorderLevel);
            const appointments = storeData.appointments.filter(a => a.date === date);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ“‹ End of Day Report - ${date}\n\nπŸ’° SALES SUMMARY:\n- Revenue: $${salesData?.revenue.toFixed(2) || '0.00'}\n- Transactions: ${salesData?.transactions || 0}\n- Avg Transaction: $${salesData ? (salesData.revenue / salesData.transactions).toFixed(2) : '0.00'}\n\n⚠️ ACTION ITEMS:\n- ${lowStock.length} items need reordering\n- ${appointments.length} appointments completed\n\nπŸ“Š KEY METRICS:\n- Top Seller: ${salesData?.topItem || 'N/A'}\n- Inventory Alerts: ${lowStock.length}\n\nβœ… CLOSING TASKS:\nβ–‘ Count cash drawer\nβ–‘ Review low stock report\nβ–‘ Confirm tomorrow's appointments\nβ–‘ Lock up and set alarm`
              }]
            };
          }
    
          case 'get_inventory_value': {
            const valueType = String(args?.valueType || 'retail');
            const category = args?.category ? String(args.category) : null;
            
            let items = storeData.inventory;
            if (category) {
              items = items.filter(i => i.category.toLowerCase() === category.toLowerCase());
            }
            
            const retailValue = items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
            const costValue = retailValue * 0.6; // Assume 40% markup
            
            return {
              content: [{
                type: 'text',
                text: `πŸ’Ž Inventory Valuation${category ? ` - ${category}` : ''}\n\nπŸ“¦ Total Items: ${items.length}\nπŸ“Š Total Units: ${items.reduce((sum, i) => sum + i.quantity, 0)}\n\nπŸ’° Value at Cost: $${costValue.toFixed(2)}\nπŸ’΅ Value at Retail: $${retailValue.toFixed(2)}\nπŸ“ˆ Potential Profit: $${(retailValue - costValue).toFixed(2)}`
              }]
            };
          }
    
          case 'forecast_demand': {
            const sku = String(args?.sku || '');
            const period = String(args?.period || 'month');
            const item = storeData.inventory.find(i => i.id === sku);
            
            if (!item) {
              return { content: [{ type: 'text', text: `❌ Product ${sku} not found` }] };
            }
            
            const baselineSales = 50;
            const periodMultiplier = period === 'week' ? 0.25 : period === 'month' ? 1 : 3;
            const forecast = Math.round(baselineSales * periodMultiplier);
            
            return {
              content: [{
                type: 'text',
                text: `πŸ“ˆ Demand Forecast: ${item.name}\n\nπŸ“… Period: Next ${period}\nπŸ“Š Forecasted Sales: ~${forecast} units\nπŸ“¦ Current Stock: ${item.quantity} units\n\n${item.quantity < forecast ? `⚠️ WARNING: Current stock may not meet demand!\nπŸ’‘ Recommended order: ${forecast - item.quantity + item.reorderLevel} units` : 'βœ… Current stock sufficient for forecasted demand'}`
              }]
            };
          }
    
          // SOCIAL MEDIA MANAGEMENT
          case 'post_to_social_media': {
            if (!socialMediaManager.isConfigured()) {
              return {
                content: [{
                  type: 'text',
                  text: `⚠️ Social media not configured yet!\n\nTo use this feature:\n1. Create a Facebook Business account\n2. Create a Facebook App\n3. Get your access tokens\n4. Add them to your .env file\n\nSee FACEBOOK_INSTAGRAM_SETUP.md for detailed instructions.`
                }]
              };
            }
    
            const platforms = String(args?.platforms || 'facebook').toLowerCase().split(',').map(p => p.trim());
            const message = String(args?.message || '');
            const imageUrl = args?.imageUrl ? String(args.imageUrl) : undefined;
            const hashtags = args?.hashtags ? String(args.hashtags).split(',').map(h => h.trim()) : undefined;
            const scheduleTime = args?.scheduleTime ? String(args.scheduleTime) : undefined;
    
            const results = [];
            
            for (const platform of platforms) {
              if (platform === 'facebook' || platform === 'both') {
                const result = await socialMediaManager.postToFacebook({
                  platform: 'facebook',
                  message,
                  imageUrl,
                  scheduledTime: scheduleTime
                });
                results.push(result);
              }
              
              if (platform === 'instagram' || platform === 'both') {
                const result = await socialMediaManager.postToInstagram({
                  platform: 'instagram',
                  message,
                  imageUrl,
                  hashtags
                });
                results.push(result);
              }
            }
    
            const successCount = results.filter(r => r.success).length;
            const failedResults = results.filter(r => !r.success);
    
            return {
              content: [{
                type: 'text',
                text: `πŸ“± Social Media Post Results\n\nβœ… ${successCount}/${results.length} successful\n\n${results.map(r =>
                  r.success 
                    ? `βœ“ ${r.platform}: Posted${r.scheduledTime ? ` (scheduled for ${r.scheduledTime})` : ''}\n  Post ID: ${r.postId}`
                    : `βœ— ${r.platform}: Failed - ${r.error}`
                ).join('\n\n')}${failedResults.length > 0 ? '\n\nπŸ’‘ Tip: Check your API tokens and permissions if posts failed.' : ''}`
              }]
            };
          }
    
          case 'generate_post_ideas': {
            const theme = String(args?.theme || '');
            const productsArg = String(args?.products || '');
            const count = Number(args?.count || 5);
            
            const products = productsArg.split(',').map(p => p.trim());
            const ideas = socialMediaManager.generatePostIdeas(theme, products);
    
            return {
              content: [{
                type: 'text',
                text: `πŸ’‘ Post Ideas - ${theme}\n\n${ideas.slice(0, count).map((idea, i) =>
                  `${i + 1}. ${idea}`
                ).join('\n\n')}\n\n✨ Pro tip: Customize these ideas with your store's personality and current promotions!`
              }]
            };
          }
    
          case 'schedule_weekly_posts': {
            const startDate = String(args?.startDate || '');
            const postsPerDay = Number(args?.postsPerDay || 1);
            const focusProducts = String(args?.focusProducts || '');
            
            const products = focusProducts ? focusProducts.split(',').map(p => p.trim()) : ['Acrylic Paint', 'Brushes', 'Canvas'];
            const postTypes = ['product_feature', 'behind_the_scenes', 'customer_spotlight', 'tip_of_the_day', 'promotion'];
            
            const schedule = [];
            const start = new Date(startDate);
            
            for (let day = 0; day < 7; day++) {
              const currentDate = new Date(start);
              currentDate.setDate(start.getDate() + day);
              const dateStr = currentDate.toISOString().split('T')[0];
              const dayName = currentDate.toLocaleDateString('en-US', { weekday: 'long' });
              
              for (let post = 0; post < postsPerDay; post++) {
                const postType = postTypes[Math.floor(Math.random() * postTypes.length)];
                const product = products[Math.floor(Math.random() * products.length)];
                
                schedule.push({
                  date: dateStr,
                  day: dayName,
                  time: post === 0 ? '10:00 AM' : post === 1 ? '2:00 PM' : '6:00 PM',
                  type: postType,
                  suggestion: `${postType.replace('_', ' ').toUpperCase()}: Feature ${product}`
                });
              }
            }
    
            return {
              content: [{
                type: 'text',
                text: `πŸ“… Weekly Posting Schedule\nπŸ“ Week of ${startDate}\n\n${schedule.map(s =>
                  `${s.day}, ${s.date} @ ${s.time}\n  ${s.suggestion}`
                ).join('\n\n')}\n\nπŸ’‘ Use 'generate_post_ideas' for specific content, then 'post_to_social_media' to publish!`
              }]
            };
          }
    
          case 'get_social_analytics': {
            if (!socialMediaManager.isConfigured()) {
              return {
                content: [{
                  type: 'text',
                  text: `⚠️ Social media not configured. See FACEBOOK_INSTAGRAM_SETUP.md for setup instructions.`
                }]
              };
            }
    
            const platform = String(args?.platform || 'facebook');
            const period = Number(args?.period || 7);
    
            try {
              if (platform.toLowerCase() === 'facebook') {
                const analytics = await socialMediaManager.getFacebookAnalytics(period);
                
                return {
                  content: [{
                    type: 'text',
                    text: `πŸ“Š Facebook Analytics - ${analytics.period}\n\nπŸ“ˆ Performance Metrics:\n  πŸ‘₯ Reach: ${analytics.metrics.reach.toLocaleString()}\n  πŸ‘οΈ Impressions: ${analytics.metrics.impressions.toLocaleString()}\n  πŸ’¬ Engagement: ${analytics.metrics.engagement.toLocaleString()}\n  ⭐ Followers: ${analytics.metrics.followers.toLocaleString()}\n\nπŸ† Top Posts:\n${analytics.topPosts.map((post, i) =>
                      `${i + 1}. ${post.content}\n   ❀️ ${post.likes} | πŸ’¬ ${post.comments} | πŸ”„ ${post.shares}`
                    ).join('\n\n')}\n\nπŸ’‘ Insight: Post more content like your top performers to boost engagement!`
                  }]
                };
              } else {
                return {
                  content: [{
                    type: 'text',
                    text: `πŸ“Š Instagram Analytics coming soon! Currently only Facebook analytics are available.`
                  }]
                };
              }
            } catch (error: any) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Failed to fetch analytics: ${error.message}`
                }]
              };
            }
          }
    
          case 'get_new_comments': {
            if (!socialMediaManager.isConfigured()) {
              return {
                content: [{
                  type: 'text',
                  text: `⚠️ Social media not configured. See FACEBOOK_INSTAGRAM_SETUP.md for setup instructions.`
                }]
              };
            }
    
            const sinceHours = Number(args?.sinceHours || 24);
            
            try {
              const comments = await socialMediaManager.getFacebookComments(sinceHours);
              
              if (comments.length === 0) {
                return {
                  content: [{
                    type: 'text',
                    text: `βœ… No new comments in the last ${sinceHours} hours. All caught up!`
                  }]
                };
              }
    
              return {
                content: [{
                  type: 'text',
                  text: `πŸ’¬ New Comments (Last ${sinceHours} hours)\n\n${comments.map((comment, i) =>
                    `${i + 1}. From ${comment.from} on ${comment.platform}\n   "${comment.text}"\n   πŸ• ${new Date(comment.timestamp).toLocaleString()}`
                  ).join('\n\n')}\n\nπŸ’‘ Use 'suggest_comment_reply' to get AI-powered reply suggestions!`
                }]
              };
            } catch (error: any) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Failed to fetch comments: ${error.message}`
                }]
              };
            }
          }
    
          case 'suggest_comment_reply': {
            const commentText = String(args?.commentText || '');
            const tone = String(args?.tone || 'friendly');
            
            if (!commentText) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Please provide the comment text to reply to.`
                }]
              };
            }
    
            const suggestions = socialMediaManager.generateCommentReplySuggestions(commentText);
    
            return {
              content: [{
                type: 'text',
                text: `πŸ’¬ Reply Suggestions (${tone} tone)\n\nOriginal comment: "${commentText}"\n\n${suggestions.map((suggestion, i) =>
                  `${i + 1}. ${suggestion}`
                ).join('\n\n')}\n\n✨ Feel free to customize these replies to match your store's voice!`
              }]
            };
          }
    
          case 'generate_hashtags': {
            const postTopic = String(args?.postTopic || '');
            const includeLocation = Boolean(args?.includeLocation ?? true);
            const count = Number(args?.count || 15);
            
            if (!postTopic) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Please provide a post topic to generate hashtags.`
                }]
              };
            }
    
            const hashtags = socialMediaManager.generateHashtags(postTopic, includeLocation);
    
            return {
              content: [{
                type: 'text',
                text: `#️⃣ Hashtag Suggestions for "${postTopic}"\n\n${hashtags.slice(0, count).map(tag => `#${tag}`).join(' ')}\n\nπŸ“‹ Copy-paste ready: ${hashtags.slice(0, count).map(tag => `#${tag}`).join(' ')}\n\nπŸ’‘ Pro tip: Use 10-15 hashtags per post for maximum reach without looking spammy!`
              }]
            };
          }
    
          case 'get_instagram_story_ideas': {
            const occasion = String(args?.occasion || 'daily');
            const productsArg = args?.products ? String(args.products) : '';
            
            const storyIdeas = [
              `πŸ“Έ Behind the counter: Show off new ${productsArg || 'art supplies'} that just arrived!`,
              `🎨 Quick tip: Demo how to use ${productsArg || 'one of your products'} in 15 seconds`,
              `❓ Poll: "What's your favorite art medium?" with product stickers`,
              `⏰ Countdown sticker: "${occasion}" sale starts in...`,
              `🌟 Customer spotlight: Share a tagged photo of customer artwork (with permission)`,
              `πŸ’― This or That: Show two products and let followers vote`,
              `🎯 Link sticker: "New blog post: Top 5 ${productsArg || 'art supplies'} for beginners"`,
              `πŸ“¦ Unboxing: Quick reveal of what's in today's shipment`
            ];
    
            return {
              content: [{
                type: 'text',
                text: `πŸ“± Instagram Story Ideas - ${occasion}\n\n${storyIdeas.map((idea, i) =>
                  `${i + 1}. ${idea}`
                ).join('\n\n')}\n\n✨ Remember: Stories are temporary, so have fun and be authentic!`
              }]
            };
          }
    
          case 'create_product_campaign': {
            const productSku = String(args?.productSku || '');
            const duration = Number(args?.duration || 7);
            const platforms = String(args?.platforms || 'both');
            
            const product = storeData.inventory.find(p => p.id === productSku);
            
            if (!product) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Product ${productSku} not found in inventory.`
                }]
              };
            }
    
            const campaignPosts = [
              {
                day: 1,
                type: 'Announcement',
                content: `πŸŽ‰ Introducing: ${product.name}! Perfect for ${product.category.toLowerCase()} artists. $${product.price} - Available now!`
              },
              {
                day: 3,
                type: 'Feature Highlight',
                content: `✨ Why ${product.name}? Let us show you what makes this ${product.category} essential for your creative toolkit!`
              },
              {
                day: 5,
                type: 'Customer Testimonial',
                content: `⭐ "Love the ${product.name}!" - Hear what our customers are saying about this amazing product!`
              },
              {
                day: duration,
                type: 'Last Chance',
                content: `⏰ Don't miss out! Get your ${product.name} today while supplies last. Only ${product.quantity} in stock!`
              }
            ];
    
            return {
              content: [{
                type: 'text',
                text: `🎯 Product Campaign: ${product.name}\nπŸ“… Duration: ${duration} days\nπŸ“± Platforms: ${platforms}\nπŸ’° Price: $${product.price}\n\nπŸ“‹ Campaign Schedule:\n\n${campaignPosts.filter(p => p.day <= duration).map(post =>
                  `Day ${post.day} - ${post.type}\n${post.content}`
                ).join('\n\n')}\n\nπŸ’‘ Use 'post_to_social_media' to publish each post, and 'generate_hashtags' for maximum reach!`
              }]
            };
          }
    
          case 'analyze_post_performance': {
            const postId = String(args?.postId || '');
            const compareToAverage = Boolean(args?.compareToAverage ?? true);
            
            if (!postId) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Please provide a post ID to analyze.`
                }]
              };
            }
    
            // Mock analysis (real implementation would call Meta Graph API)
            const mockAnalysis = {
              postId,
              reach: 2340,
              impressions: 3120,
              engagement: 187,
              likes: 156,
              comments: 23,
              shares: 8,
              engagementRate: 8.0,
              accountAverage: {
                reach: 1850,
                engagementRate: 5.5
              }
            };
    
            const performance = mockAnalysis.engagementRate > mockAnalysis.accountAverage.engagementRate ? 'πŸ“ˆ Above' : 'πŸ“‰ Below';
    
            return {
              content: [{
                type: 'text',
                text: `πŸ“Š Post Performance Analysis\nπŸ†” Post ID: ${postId}\n\nπŸ“ˆ Metrics:\n  πŸ‘₯ Reach: ${mockAnalysis.reach.toLocaleString()}\n  πŸ‘οΈ Impressions: ${mockAnalysis.impressions.toLocaleString()}\n  πŸ’¬ Engagement: ${mockAnalysis.engagement} (${mockAnalysis.engagementRate}%)\n  ❀️ Likes: ${mockAnalysis.likes}\n  πŸ’¬ Comments: ${mockAnalysis.comments}\n  πŸ”„ Shares: ${mockAnalysis.shares}\n\n${compareToAverage ? `πŸ“Š vs Account Average:\n  ${performance} average (${mockAnalysis.engagementRate}% vs ${mockAnalysis.accountAverage.engagementRate}%)\n  Reach ${mockAnalysis.reach > mockAnalysis.accountAverage.reach ? '+' : ''}${((mockAnalysis.reach / mockAnalysis.accountAverage.reach - 1) * 100).toFixed(1)}%\n\n` : ''}πŸ’‘ Insight: ${mockAnalysis.engagementRate > 7 ? 'Great post! Create more content like this.' : 'Try experimenting with different content types or posting times.'}`
              }]
            };
          }
    
          case 'auto_respond_common_questions': {
            const enable = Boolean(args?.enable ?? false);
            const questionTypes = String(args?.questionTypes || 'hours,location,stock');
            
            const types = questionTypes.split(',').map(t => t.trim());
    
            return {
              content: [{
                type: 'text',
                text: `πŸ€– Auto-Response Settings ${enable ? 'ENABLED' : 'DISABLED'}\n\n${enable ? 'βœ… Will auto-respond to:\n' + types.map(type =>
                  `  β€’ ${type.charAt(0).toUpperCase() + type.slice(1)} questions`
                ).join('\n') : '❌ Auto-responses are disabled'}\n\nβš™οΈ Note: Auto-responses help provide quick answers, but always review and personalize when possible!\n\nπŸ’‘ This is a mock feature. In production, this would integrate with Facebook's Messenger API for automated responses.`
              }]
            };
          }
    
          case 'track_competitor_activity': {
            const competitors = String(args?.competitors || '');
            const metrics = String(args?.metrics || 'posts,engagement');
            
            if (!competitors) {
              return {
                content: [{
                  type: 'text',
                  text: `❌ Please provide competitor page names to track.`
                }]
              };
            }
    
            const competitorList = competitors.split(',').map(c => c.trim());
            const metricsList = metrics.split(',').map(m => m.trim());
    
            // Mock competitor data
            const mockData = competitorList.map(comp => ({
              name: comp,
              postsThisWeek: Math.floor(Math.random() * 10) + 3,
              avgEngagement: Math.floor(Math.random() * 200) + 50,
              recentPromotion: Math.random() > 0.5 ? 'Yes - Sale on brushes' : 'No recent promotions'
            }));
    
            return {
              content: [{
                type: 'text',
                text: `πŸ” Competitor Activity Tracking\nπŸ“Š Metrics: ${metricsList.join(', ')}\n\n${mockData.map(comp =>
                  `πŸ“ ${comp.name}\n  πŸ“ Posts this week: ${comp.postsThisWeek}\n  πŸ’¬ Avg engagement: ${comp.avgEngagement}\n  🎯 Promotions: ${comp.recentPromotion}`
                ).join('\n\n')}\n\nπŸ’‘ Note: This is a demonstration feature. In production, this would track public competitor pages to help you stay competitive.`
              }]
            };
          }
    
          default:
            throw new Error(`Unknown tool: ${name}`);
        }
      } catch (error: any) {
        return {
          content: [{
            type: 'text',
            text: `❌ Error executing ${name}: ${error.message}`
          }],
          isError: true,
        };
      }
    });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wspotter/mcpart'

If you have feedback or need assistance with the MCP directory API, please join our Discord server