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:
- Queries products by natural language
- Compares prices across platforms
- Generates personalized gift recommendations
- 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 inputsget_product: Retrieve product details by IDcompare_products: Compare products side by sideget_deals: Retrieve deal-oriented product resultslist_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:
-
Start the BuyWhere MCP server (if not already running):
# From the BuyWhere project root python mcp_server.py -
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:
- Persistence: Save conversation history to a file or database
- Voice Interface: Add speech-to-text and text-to-speech capabilities
- Price Tracking: Implement alerts for price drops on wishlisted items
- 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")
- 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
.envfile
Authentication Errors
- Error:
Invalid API keyfrom 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