← Back to documentation

Building an AI Shopping Assistant with BuyWhere MCP

By: Blog

Step-by-step tutorial: Create an AI shopping assistant using Claude and BuyWhere's Model Context Protocol. Includes Python code examples and MCP tool call demonstrations.

Building an AI Shopping Assistant with BuyWhere MCP

Learn how to create an intelligent shopping assistant that can query products, compare prices, and generate personalized recommendations using Anthropic's Claude and BuyWhere's Model Context Protocol (MCP). This tutorial provides complete Python code examples and explains each step of the integration process.

Introduction

The Model Context Protocol (MCP) is an open standard that enables seamless integration between AI models and external data sources and tools. BuyWhere provides an MCP server that exposes its agent-native product catalog API as discoverable tools, allowing AI assistants to access structured product data from across Southeast Asian e-commerce platforms.

In this tutorial, we'll build a shopping assistant that:

  1. Queries products by natural language
  2. Compares prices across platforms
  3. Generates personalized gift recommendations
  4. Handles follow-up conversations with context

Prerequisites

Before you begin, ensure you have:

  • Python 3.8+ installed
  • An Anthropic API key (for Claude access)
  • Access to BuyWhere's MCP server (running locally or accessing the hosted version)
  • Basic knowledge of Python and asynchronous programming

Step 1: Setting Up the Environment

First, install the required dependencies:

pip install anthropic mcp[cli] python-dotenv

Create a .env file to store your API keys:

ANTHROPIC_API_KEY=your_anthropic_api_key_here
BUYWHERE_MCP_URL=https://api.buywhere.ai/mcp

Step 2: Understanding BuyWhere's MCP Tools

BuyWhere's hosted MCP server exposes the current public tool set for shopping agents:

  • search_products: Product search with query and filtering inputs
  • get_product: Retrieve product details by ID
  • compare_products: Compare products side by side
  • get_deals: Retrieve deal-oriented product results
  • list_categories: Browse available product categories

Each tool returns structured data that's easy for AI models to consume and act upon.

Let's explore the available tools first:

from mcp import MCPClient
import asyncio

async def list_available_tools():
    client = MCPClient(os.getenv("BUYWHERE_MCP_URL", "https://api.buywhere.ai/mcp"))
    tools = await client.list_tools()
    for tool in tools:
        print(f"- {tool.name}: {tool.description}")

# Run the function
asyncio.run(list_available_tools())

This will output a list of available tools with their descriptions, helping you understand what capabilities are at your disposal.

Step 3: Building the Shopping Assistant Core

We'll create a ShoppingAssistant class that encapsulates our MCP interactions and Claude integration:

import os
import anthropic
from mcp import MCPClient
from typing import List, Dict, Any
from dotenv import load_dotenv

load_dotenv()

class ShoppingAssistant:
    def __init__(self):
        self.anthropic = anthropic.Anthropic(
            api_key=os.getenv("ANTHROPIC_API_KEY")
        )
        self.mcp_client = MCPClient(os.getenv("BUYWHERE_MCP_URL"))
        self.conversation_history = []
    
    async def search_products(self, query: str, limit: int = 10) -> List[Dict]:
        """Search for products using natural language"""
        result = await self.mcp_client.call_tool(
            "search_products",
            {
                "q": query,
                "limit": limit
            }
        )
        return result.content[0].json.get("results", [])
    
    async def compare_prices(self, product_name: str) -> Dict:
        """Compare prices across platforms"""
        result = await self.mcp_client.call_tool(
            "compare_products",
            {
                "query": product_name
            }
        )
        return result.content[0].json
    
    async def get_deals(self, product_name: str) -> Dict:
        """Find deal-oriented product results."""
        result = await self.mcp_client.call_tool(
            "get_deals",
            {
                "q": product_name
            }
        )
        return result.content[0].json

Step 4: Implementing Price Comparison Functionality

Let's implement a function that helps users find the best deal for a product they're interested in:

    async def find_best_deal(self, product_query: str) -> str:
        """Find and format the best deal for a product"""
        # Search for the product
        search_results = await self.search_products(product_query, limit=5)
        
        if not search_results:
            return f"I couldn't find any products matching '{product_query}'."
        
        # Get the first result for price comparison
        top_product = search_results[0]
        product_name = top_product.get("title", "")
        
        # Compare prices across platforms
        comparison = await self.compare_prices(product_name)
        
        # Format the response
        response = f"# Price Comparison for {product_name}\n\n"
        
        if comparison.get("results"):
            best_deal = comparison.get("best_deal")
            if best_deal:
                response += f"## πŸ† Best Deal\n"
                response += f"- **Platform**: {best_deal.get('source', 'Unknown').title()}\n"
                response += f"- **Price**: {best_deal.get('currency', 'SGD')} {best_deal.get('price', 0):.2f}\n"
                response += f"- **Rating**: {best_deal.get('rating', 'N/A')}/5 ({best_deal.get('review_count', 0)} reviews)\n"
                response += f"- **Availability**: {'In Stock' if best_deal.get('is_available') else 'Out of Stock'}\n"
                response += f"- **Link**: {best_deal.get('url', '#')}\n\n"
            
            response += "## πŸ“Š All Options\n"
            for i, option in enumerate(comparison["results"][:5], 1):
                response += f"{i}. **{option.get('source', 'Unknown').title()}**: "
                response += f"{option.get('currency', 'SGD')} {option.get('price', 0):.2f} "
                response += f"(Rating: {option.get('rating', 'N/A')}/5)\n"
        else:
            response += "No price comparison data available.\n"
        
        return response

Step 5: Adding Personalized Recommendations

Now let's add functionality to generate personalized gift recommendations based on user preferences:

    async def get_gift_recommendations(self, recipient_profile: str, budget: float) -> str:
        """Generate gift recommendations based on recipient profile and budget"""
        # Search for products matching the recipient's interests
        search_results = await self.search_products(
            recipient_profile, 
            limit=10
        )
        
        # Filter by budget
        affordable_items = [
            item for item in search_results 
            if item.get("price", float('inf')) <= budget
        ]
        
        if not affordable_items:
            return f"I couldn't find any items under {budget} SGD matching '{recipient_profile}'."
        
        # Sort by rating (highest first)
        affordable_items.sort(
            key=lambda x: x.get("rating", 0), 
            reverse=True
        )
        
        # Format recommendations
        response = f"# Gift Recommendations for {recipient_profile}\n"
        response += f"## Budget: {budget} SGD\n\n"
        
        for i, item in enumerate(affordable_items[:5], 1):
            response += f"## {i}. {item.get('title', 'Unknown Product')}\n"
            response += f"- **Platform**: {item.get('source', 'Unknown').title()}\n"
            response += f"- **Price**: {item.get('currency', 'SGD')} {item.get('price', 0):.2f} SGD\n"
            response += f"- **Rating**: {item.get('rating', 'N/A')}/5 "
            response += f"({item.get('review_count', 0)} reviews)\n"
            response += f"- **Brand**: {item.get('brand', 'N/A')}\n"
            response += f"- **Category**: {item.get('category', 'N/A')}\n"
            response += f"- **Link**: {item.get('url', '#')}\n\n"
            
            # Add highlights if available
            highlights = item.get("metadata", {}).get("rating", {}).get("rateCount", {})
            if highlights:
                response += f"- **Rating Breakdown**: "
                response += f"{highlights.get('five', 0)}⭐ {highlights.get('four', 0)}⭐ "
                response += f"{highlights.get('three', 0)}⭐ {highlights.get('two', 0)}⭐ "
                response += f"{highlights.get('one', 0)}⭐\n\n"
        
        return response

Step 6: Integrating with Claude

Now we'll connect our shopping assistant to Claude using the Model Context Protocol. This allows Claude to call our MCP tools directly:

    async def process_with_claude(self, user_message: str) -> str:
        """Process a user message using Claude with access to MCP tools"""
        # Add user message to conversation history
        self.conversation_history.append({"role": "user", "content": user_message})
        
        # Define available tools for Claude
        tools = [
            {
                "name": "search_products",
                "description": "Search for products using natural language queries",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "The search query"},
                        "limit": {"type": "integer", "description": "Number of results to return (default: 10)"}
                    },
                    "required": ["query"]
                }
            },
            {
                "name": "compare_prices",
                "description": "Compare prices for a product across different platforms",
                "input_schema": {
                    "type": "object",
                    "properties": {
                        "product_name": {"type": "string", "description": "The product name to compare"},
                        "currency": {"type": "string", "description": "Target currency (default: SGD)"}
                    },
                    "required": ["product_name"]
                }
            }
        ]
        
        # Get response from Claude with tool access
        response = self.anthropic.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=1000,
            messages=self.conversation_history,
            tools=tools
        )
        
        # Process Claude's response
        assistant_message = {"role": "assistant", "content": []}
        
        for block in response.content:
            if block.type == "text":
                assistant_message["content"].append({
                    "type": "text",
                    "text": block.text
                })
            elif block.type == "tool_use":
                # Execute the requested MCP tool
                tool_result = await self.mcp_client.call_tool(
                    block.name,
                    block.input
                )
                
                # Add the tool use and result to the conversation
                assistant_message["content"].append({
                    "type": "tool_use",
                    "id": block.id,
                    "name": block.name,
                    "input": block.input
                })
                
                assistant_message["content"].append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": tool_result.content[0].text if tool_result.content else "No result"
                })
        
        # Add assistant's response to conversation history
        self.conversation_history.append(assistant_message)
        
        # Extract text content for return
        text_blocks = [block for block in assistant_message["content"] if block.get("type") == "text"]
        return " ".join([block["text"] for block in text_blocks])

Step 7: Creating an Interactive Interface

Let's create a simple command-line interface to interact with our shopping assistant:

async def main():
    """Run an interactive shopping assistant session"""
    assistant = ShoppingAssistant()
    
    print("πŸ›’ Welcome to the BuyWhere AI Shopping Assistant!")
    print("I can help you find products, compare prices, and get recommendations.")
    print("Type 'quit' to exit.\n")
    
    while True:
        user_input = input("\nYou: ").strip()
        
        if user_input.lower() in ['quit', 'exit', 'bye']:
            print("Thanks for shopping! Goodbye!")
            break
        
        if not user_input:
            continue
        
        try:
            # Process the user's request
            response = await assistant.process_with_claude(user_input)
            print(f"\nAssistant: {response}")
        except Exception as e:
            print(f"\nError: {str(e)}")
            print("Please try again or rephrase your request.")

if __name__ == "__main__":
    asyncio.run(main())

Step 8: Running the Assistant

To run your shopping assistant:

  1. Start the BuyWhere MCP server (if not already running):

    # From the BuyWhere project root
    python mcp_server.py
    
  2. Run your assistant:

    python shopping_assistant.py
    

Example Interactions

Here are some example conversations you can have with your assistant:

Example 1: Price Comparison

You: I want to buy a Sony WH-1000XM5 headphones. Where can I get the best price?
Assistant: [Searches for the product, compares prices across Lazada, Shopee, Amazon.sg, etc.]
Assistant: The best price for Sony WH-1000XM5 headphones is on Shopee at SGD 398.00, which is 15% below the average price of SGD 468.00.

Example 2: Gift Recommendations

You: I need a gift for my girlfriend who loves skincare, budget is SGD 100.
Assistant: [Searches for skincare products under SGD 100, sorts by rating]
Assistant: Based on your girlfriend's interest in skincare and your SGD 100 budget, I recommend:
1. The Face Shop Rice Water Bright Light Cleansing Oil (SGD 22.90) - 4.8/5 rating
2. Innisfree Green Tea Seed Serum (SGD 34.00) - 4.7/5 rating
3. Laneige Water Sleeping Mask (SGD 42.00) - 4.9/5 rating

Example 3: Follow-up Conversation

You: Show me more details about the Laneige Water Sleeping Mask.
Assistant: [Provides detailed specifications, availability across platforms, and recent price trends]

Advanced Features to Explore

Once you have the basic assistant working, consider enhancing it with:

  1. Persistence: Save conversation history to a file or database
  2. Voice Interface: Add speech-to-text and text-to-speech capabilities
  3. Price Tracking: Implement alerts for price drops on wishlisted items
  4. Multi-turn Reasoning: Chain multiple tool calls for complex queries (e.g., "Find me a wireless printer under SGD 200 that has good reviews and is available for same-day delivery")
  5. User Profiles: Store user preferences and shopping history for more personalized recommendations

Troubleshooting Common Issues

Connection Problems

  • Error: Failed to connect to MCP server
  • Solution: Ensure the BuyWhere MCP server is running and accessible at the URL specified in your .env file

Authentication Errors

  • Error: Invalid API key from Anthropic
  • Solution: Verify your ANTHROPIC_API_KEY in the .env file is correct and has sufficient credits

Tool Execution Errors

  • Error: Tool not found: search_products
  • Solution: Check that you're connected to the current BuyWhere MCP endpoint and confirm the live tool list at https://api.buywhere.ai/mcp

Rate Limiting

  • Error: Too many requests
  • Solution: Implement exponential backoff in your tool calls or cache frequent queries

Conclusion

You've now built a functional AI shopping assistant that leverages BuyWhere's MCP to access structured product data from across Southeast Asian e-commerce platforms. By combining Claude's natural language understanding with structured product data through MCP, you've created an assistant that can help users make informed shopping decisions quickly and easily.

The modular design of this assistant makes it easy to extend with additional features like price tracking, wish lists, or integration with messaging platforms. As you continue to develop your AI shopping assistant, remember that the quality of your data sources is paramountβ€”which is why BuyWhere's focus on clean, structured, agent-ready data makes it an ideal foundation for AI-powered commerce applications.

Happy coding, and may your shopping assistant always find the best deals!

Word count: approximately 1,500