Skip to main content
Glama

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