Skip to main content
Glama

Superprecio MCP Server

by bunkerapps
functional-demo.tsβ€’11.1 kB
/** * Functional Demo: Complete Shopping List Workflow * * This demonstrates all V2 features with mock data * Run with: npx ts-node tests/functional-demo.ts */ // Mock API client class MockSuperPrecioApiClient { private lists: any[] = []; private alerts: any[] = []; private nextListId = 1; private nextAlertId = 1; // Mock supermarket data (5 supermarkets in Argentina) private mockSupermarkets = [ { id: 1, name: 'Carrefour', logo: 'carrefour.png' }, { id: 2, name: 'Disco', logo: 'disco.png' }, { id: 3, name: 'Jumbo', logo: 'jumbo.png' }, { id: 4, name: 'Dia', logo: 'dia.png' }, { id: 5, name: 'Coto', logo: 'coto.png' }, ]; // Mock product prices by supermarket private mockPrices: Record<string, Record<string, number>> = { 'leche descremada': { Carrefour: 850, Disco: 920, Jumbo: 880, Dia: 790, Coto: 870 }, 'pan lactal': { Carrefour: 450, Disco: 480, Jumbo: 460, Dia: 420, Coto: 465 }, 'arroz integral': { Carrefour: 620, Disco: 680, Jumbo: 650, Dia: 600, Coto: 640 }, 'aceite girasol': { Carrefour: 1200, Disco: 1350, Jumbo: 1280, Dia: 1150, Coto: 1300 }, 'azucar': { Carrefour: 380, Disco: 420, Jumbo: 400, Dia: 350, Coto: 390 }, 'cafe torrado': { Carrefour: 950, Disco: 1020, Jumbo: 980, Dia: 890, Coto: 960 }, 'yerba mate': { Carrefour: 1100, Disco: 1200, Jumbo: 1150, Dia: 1050, Coto: 1120 }, }; async createShoppingList(data: any) { const list = { id: this.nextListId++, name: data.name, description: data.description || null, items: (data.items || []).map((item: any, index: number) => ({ id: index + 1, productName: item.productName, quantity: item.quantity || 1, })), createdAt: new Date().toISOString(), }; this.lists.push(list); return { success: true, data: list }; } async addItemsToList(listId: number, items: any[]) { const list = this.lists.find((l) => l.id === listId); if (!list) return { success: false, message: 'List not found' }; const newItems = items.map((item, index) => ({ id: list.items.length + index + 1, productName: item.productName, quantity: item.quantity || 1, })); list.items.push(...newItems); return { success: true, data: list, addedItems: newItems.length }; } async optimizeShoppingList(listId: number) { const list = this.lists.find((l) => l.id === listId); if (!list) return { success: false, message: 'List not found' }; const results: Record<string, any> = {}; this.mockSupermarkets.forEach((market) => { results[market.name] = { marketName: market.name, total: 0, items: [], foundItems: 0, }; }); list.items.forEach((item: any) => { const productName = item.productName.toLowerCase(); const prices = this.mockPrices[productName]; if (prices) { Object.keys(prices).forEach((marketName) => { const unitPrice = prices[marketName]; const totalPrice = unitPrice * item.quantity; results[marketName].total += totalPrice; results[marketName].foundItems++; results[marketName].items.push({ productName: item.productName, quantity: item.quantity, unitPrice, totalPrice, }); }); } }); const ranked = Object.values(results) .filter((r: any) => r.foundItems > 0) .sort((a: any, b: any) => a.total - b.total); const bestMarket = ranked[0]; const worstMarket = ranked[ranked.length - 1]; const savings = worstMarket.total - bestMarket.total; const savingsPercent = ((savings / worstMarket.total) * 100).toFixed(1); return { success: true, listName: list.name, totalItems: list.items.length, bestMarket: { name: bestMarket.marketName, total: parseFloat(bestMarket.total.toFixed(2)), foundItems: bestMarket.foundItems, items: bestMarket.items, }, savings: { amount: parseFloat(savings.toFixed(2)), percentage: parseFloat(savingsPercent), comparedTo: worstMarket.marketName, }, allMarkets: ranked.map((r: any) => ({ name: r.marketName, total: parseFloat(r.total.toFixed(2)), })), }; } async createPriceAlert(data: any) { const alert = { id: this.nextAlertId++, productName: data.productName, targetPrice: data.targetPrice, currentPrice: null, }; this.alerts.push(alert); return { success: true, data: alert }; } async checkPriceAlerts() { const results = this.alerts.map((alert) => { const productName = alert.productName.toLowerCase(); const prices = this.mockPrices[productName]; if (prices) { const lowestPrice = Math.min(...Object.values(prices)); const marketWithLowestPrice = Object.keys(prices).find( (k) => prices[k] === lowestPrice )!; alert.currentPrice = lowestPrice; const isTriggered = lowestPrice <= alert.targetPrice; return { productName: alert.productName, targetPrice: alert.targetPrice, currentPrice: lowestPrice, isTriggered, bestMarket: marketWithLowestPrice, priceDifference: lowestPrice - alert.targetPrice, }; } return { productName: alert.productName, targetPrice: alert.targetPrice, error: 'Product not found', }; }); const triggeredCount = results.filter((r) => r.isTriggered).length; return { success: true, checked: this.alerts.length, triggered: triggeredCount, results, }; } } // Main demo function async function runDemo() { console.log('\n' + '='.repeat(70)); console.log('πŸš€ SUPERPRECIO MCP V2 - FUNCTIONAL DEMO'); console.log('='.repeat(70)); const client = new MockSuperPrecioApiClient(); let listId: number; // Step 1: Create Shopping List console.log('\nπŸ“ STEP 1: Creating shopping list...\n'); const createResponse = await client.createShoppingList({ name: 'Compra Semanal', description: 'Lista para la semana', items: [ { productName: 'Leche Descremada', quantity: 2 }, { productName: 'Pan Lactal', quantity: 1 }, { productName: 'Arroz Integral', quantity: 1 }, ], }); listId = createResponse.data.id; console.log(`βœ… Shopping list created:`); console.log(` ID: ${createResponse.data.id}`); console.log(` Name: ${createResponse.data.name}`); console.log(` Items: ${createResponse.data.items.length}`); createResponse.data.items.forEach((item: any, i: number) => { console.log(` ${i + 1}. ${item.productName} (x${item.quantity})`); }); // Step 2: Add More Items console.log('\nβž• STEP 2: Adding more items...\n'); const addResponse = await client.addItemsToList(listId, [ { productName: 'Aceite Girasol', quantity: 1 }, { productName: 'Azucar', quantity: 1 }, { productName: 'Cafe Torrado', quantity: 1 }, { productName: 'Yerba Mate', quantity: 2 }, ]); console.log(`βœ… Items added: ${addResponse.addedItems}`); console.log(` Total items in list: ${addResponse.data.items.length}`); // Step 3: Optimize Shopping List (THE STAR!) console.log('\nπŸ”₯ STEP 3: OPTIMIZING SHOPPING LIST...\n'); const optimizeResponse = await client.optimizeShoppingList(listId); console.log('━'.repeat(70)); console.log(`πŸ† BEST SUPERMARKET: ${optimizeResponse.bestMarket.name}`); console.log(`πŸ’΅ Total: $${optimizeResponse.bestMarket.total.toLocaleString('es-AR')}`); console.log(`βœ… Found: ${optimizeResponse.bestMarket.foundItems}/${optimizeResponse.totalItems} items`); console.log('━'.repeat(70)); console.log(`\nπŸ’° YOUR SAVINGS:`); console.log(` Amount: $${optimizeResponse.savings.amount.toLocaleString('es-AR')}`); console.log(` Percentage: ${optimizeResponse.savings.percentage}%`); console.log(` vs. ${optimizeResponse.savings.comparedTo}`); console.log('\nπŸ“Š ALL SUPERMARKETS (sorted by price):'); optimizeResponse.allMarkets.forEach((market: any, i: number) => { const badge = i === 0 ? 'πŸ†' : i === optimizeResponse.allMarkets.length - 1 ? '❌' : ' '; console.log(` ${badge} ${i + 1}. ${market.name.padEnd(12)} $${market.total.toLocaleString('es-AR').padStart(8)}`); }); console.log(`\nπŸ›’ DETAILED BREAKDOWN AT ${optimizeResponse.bestMarket.name}:`); optimizeResponse.bestMarket.items.forEach((item: any, i: number) => { console.log(` ${i + 1}. ${item.productName.padEnd(20)} Qty: ${item.quantity} x $${item.unitPrice.toString().padStart(6)} = $${item.totalPrice.toString().padStart(6)}`); }); // Step 4: Set Price Alert console.log('\nπŸ”” STEP 4: Setting price alert...\n'); const alertResponse = await client.createPriceAlert({ productName: 'Aceite Girasol', targetPrice: 1000, }); console.log(`βœ… Price alert created:`); console.log(` Product: ${alertResponse.data.productName}`); console.log(` Target Price: $${alertResponse.data.targetPrice}`); console.log(` ID: ${alertResponse.data.id}`); // Step 5: Check Alerts console.log('\nπŸ” STEP 5: Checking price alerts...\n'); const checkResponse = await client.checkPriceAlerts(); console.log(`Alerts checked: ${checkResponse.checked}`); console.log(`Alerts triggered: ${checkResponse.triggered}\n`); checkResponse.results.forEach((result: any) => { if (result.error) { console.log(` ❌ ${result.productName}: ${result.error}`); } else { console.log(` ${result.isTriggered ? 'πŸŽ‰' : 'πŸ”'} ${result.productName}`); console.log(` Target: $${result.targetPrice}`); console.log(` Current: $${result.currentPrice} (${result.bestMarket})`); console.log(` Status: ${result.isTriggered ? 'TRIGGERED! πŸŽ‰' : 'Monitoring'}`); console.log(` Difference: ${result.priceDifference >= 0 ? '+' : ''}$${result.priceDifference}`); } }); // Final Summary console.log('\n' + '='.repeat(70)); console.log('πŸ“Š FINAL SUMMARY'); console.log('='.repeat(70)); console.log(`\nβœ… Shopping List: "${optimizeResponse.listName}"`); console.log(` Items: ${optimizeResponse.totalItems}`); console.log(`\nπŸ† Best Supermarket: ${optimizeResponse.bestMarket.name}`); console.log(` Total Cost: $${optimizeResponse.bestMarket.total.toLocaleString('es-AR')}`); console.log(` Your Savings: $${optimizeResponse.savings.amount.toLocaleString('es-AR')} (${optimizeResponse.savings.percentage}%)`); console.log(`\nπŸ”” Price Alerts:`); console.log(` Active: ${checkResponse.checked}`); console.log(` Triggered: ${checkResponse.triggered}`); console.log('\n' + '='.repeat(70)); console.log('βœ… DEMO COMPLETED SUCCESSFULLY!'); console.log('πŸŽ‰ All MCP V2 features are working perfectly!'); console.log('='.repeat(70) + '\n'); } // Run the demo runDemo().catch((error) => { console.error('❌ Demo failed:', error); process.exit(1); });

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/bunkerapps/superprecio_mcp'

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