Skip to main content
Glama
wspotter

MCP Art Supply Store

by wspotter

get_low_stock_items

Identify art supplies that need replenishment by finding items at or below reorder levels to prevent stockouts and maintain inventory availability.

Instructions

Get a list of all items that are at or below their reorder level. Critical for preventing stockouts.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
categoryNoOptional: filter by category (Paint, Canvas, Brushes, Drawing, Tools)

Implementation Reference

  • The core handler logic that filters inventory for items at or below reorder level, optionally by category, and returns formatted low stock report.
    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!'
        }]
      };
    }
  • Tool schema definition including name, description, and optional input parameters for category filtering.
      name: 'get_low_stock_items',
      description: 'Get a list of all items that are at or below their reorder level. Critical for preventing stockouts.',
      inputSchema: {
        type: 'object',
        properties: {
          category: { type: 'string', description: 'Optional: filter by category (Paint, Canvas, Brushes, Drawing, Tools)' },
        },
      },
    },
  • src/index.ts:516-518 (registration)
    Registers the tool list handler which includes the get_low_stock_items schema when listing available tools.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return { tools };
    });
  • src/index.ts:521-1509 (registration)
    Registers the tool call handler with switch case dispatching to get_low_stock_items implementation.
    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,
        };
      }
    });
  • Mock inventory data used by get_low_stock_items to determine low stock items based on quantity vs reorderLevel.
      { id: 'SKU001', name: 'Acrylic Paint Set (24 colors)', category: 'Paint', quantity: 45, reorderLevel: 20, price: 34.99, supplier: 'ArtCo Supplies', lastRestocked: '2025-09-28' },
      { id: 'SKU002', name: 'Professional Watercolor Set', category: 'Paint', quantity: 12, reorderLevel: 15, price: 89.99, supplier: 'Premium Art Inc', lastRestocked: '2025-09-15' },
      { id: 'SKU003', name: 'Canvas Panel 16x20"', category: 'Canvas', quantity: 78, reorderLevel: 30, price: 12.99, supplier: 'Canvas Warehouse', lastRestocked: '2025-10-01' },
      { id: 'SKU004', name: 'Synthetic Brush Set (10pc)', category: 'Brushes', quantity: 5, reorderLevel: 10, price: 24.99, supplier: 'BrushMasters Ltd', lastRestocked: '2025-08-20' },
      { id: 'SKU005', name: 'Oil Paint Starter Kit', category: 'Paint', quantity: 23, reorderLevel: 15, price: 65.99, supplier: 'ArtCo Supplies', lastRestocked: '2025-09-25' },
      { id: 'SKU006', name: 'Drawing Pencil Set (12B-6H)', category: 'Drawing', quantity: 34, reorderLevel: 20, price: 18.99, supplier: 'Sketchers Supply', lastRestocked: '2025-09-30' },
      { id: 'SKU007', name: 'Stretched Canvas 24x36"', category: 'Canvas', quantity: 15, reorderLevel: 10, price: 28.99, supplier: 'Canvas Warehouse', lastRestocked: '2025-09-28' },
      { id: 'SKU008', name: 'Palette Knife Set (5pc)', category: 'Tools', quantity: 18, reorderLevel: 12, price: 15.99, supplier: 'ArtTools Direct', lastRestocked: '2025-09-22' },
    ],

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