diff --git a/mcp/README.md b/mcp/README.md new file mode 100644 index 0000000..2d36871 --- /dev/null +++ b/mcp/README.md @@ -0,0 +1,270 @@ +# MCP Tools + +This directory contains Model Context Protocol (MCP) tools that can be used by AI assistants and agents. + +## Available Tools + +### 1. Weather Tool (`weather_tool/`) + +Get weather information for any city. + +**Features**: +- Current weather data +- Temperature, wind speed, conditions +- Uses Open-Meteo API (no API key required) + +**Tools**: +- `get_weather(city: str)` - Get weather info for a city + +### 2. Movie Tool (`movie_tool/`) + +Get movie information and reviews from OMDb. + +**Features**: +- Movie details (plot, ratings, actors, awards) +- Full plot summaries +- Uses OMDb API + +**Tools**: +- `get_full_plot(movie_title: str)` - Get full plot summary +- `get_movie_details(movie_title: str)` - Get full movie details + +**Requirements**: +- OMDB_API_KEY environment variable + +### 3. Slack Tool (`slack_tool/`) + +Interact with Slack workspaces. + +**Features**: +- List channels +- Get channel history +- Optional fine-grained authorization + +**Tools**: +- `get_channels()` - Lists all public and private channels +- `get_channel_history(channel_id: str, limit: int)` - Fetches recent messages + +**Requirements**: +- SLACK_BOT_TOKEN environment variable +- Optional: ADMIN_SLACK_BOT_TOKEN for fine-grained auth + +### 4. GitHub Tool (`github_tool/`) + +Interact with GitHub repositories (written in Go). + +**Features**: +- Repository management +- Issue tracking +- Pull request operations + +**Requirements**: +- GitHub authentication token + +### 5. Shopping Agent (`shopping_tool/`) ⭐ NEW + +AI-powered shopping recommendations using LangChain, LangGraph, OpenAI, and SerpAPI. + +**Features**: +- Natural language query understanding +- Real-time product search across retailers +- AI-curated recommendations with reasoning +- Budget-aware suggestions +- Multi-step LangGraph workflow + +**Tools**: +- `recommend_products(query: str, maxResults: int)` - Get AI-powered product recommendations +- `search_products(query: str, maxResults: int)` - Raw product search + +**Requirements**: +- OPENAI_API_KEY environment variable +- SERPAPI_API_KEY environment variable + +**Example Usage**: +```bash +curl -X POST http://localhost:8000/tools/recommend_products \ + -H "Content-Type: application/json" \ + -d '{ + "query": "I want to buy a scarf for 40 dollars", + "maxResults": 5 + }' +``` + +**Technologies**: +- FastMCP - MCP server framework +- OpenAI GPT-4o-mini - Natural language understanding/generation +- SerpAPI - Product search across retailers + +**Documentation**: +- [README.md](shopping_agent/README.md) - Full documentation +- [QUICKSTART.md](shopping_agent/QUICKSTART.md) - Quick start guide +- [ARCHITECTURE.md](shopping_agent/ARCHITECTURE.md) - Architecture details + +## Getting Started + +### General Setup + +All MCP tools follow a similar pattern: + +1. **Install dependencies**: +```bash +cd +uv pip install -e . +``` + +2. **Configure environment variables**: +```bash +export API_KEY="your-api-key-here" +``` + +3. **Run the server**: +```bash +python .py +``` + +4. **Test the server**: +```bash +curl http://localhost:8000/health +``` + +### Docker Deployment + +Each tool includes a Dockerfile for containerized deployment: + +```bash +cd +docker build -t -mcp . +docker run -p 8000:8000 -e API_KEY="your-key" -mcp +``` + +## MCP Protocol + +All tools expose functionality via the Model Context Protocol (MCP), which allows AI assistants to discover and use these tools programmatically. + +### Key Features + +- **Tool Discovery**: Tools are self-describing with metadata +- **Type Safety**: Strong typing for parameters and returns +- **Documentation**: Built-in documentation for each tool +- **Error Handling**: Standardized error responses +- **Transport**: HTTP transport support (streamable HTTP optional) + +### Tool Annotations + +Tools use annotations to describe their behavior: +- `readOnlyHint`: Indicates if the tool only reads data +- `destructiveHint`: Warns if the tool modifies or deletes data +- `idempotentHint`: Indicates if repeated calls have the same effect + +## Framework Comparison + +| Tool | Language | Framework | Key Library | +|------|----------|-----------|-------------| +| Weather | Python | FastMCP | requests | +| Movie | Python | FastMCP | requests + OMDb | +| Slack | Python | FastMCP | slack_sdk | +| GitHub | Go | Custom | GitHub API | +| Shopping Agent | Python | FastMCP | SerpAPI | + +## Advanced Example: Shopping Agent Architecture + +The Shopping Agent demonstrates an advanced MCP tool with: + +``` +User Query + ↓ +SerpAPI Search + ↓ +Structured Response +## Creating Your Own MCP Tool + +### Basic Template + +```python +import os +from fastmcp import FastMCP + +mcp = FastMCP("My Tool") + +@mcp.tool(annotations={"readOnlyHint": True}) +def my_function(param: str) -> str: + """Tool description""" + # Your logic here + return result + +def run_server(): + transport = os.getenv("MCP_TRANSPORT", "http") + host = os.getenv("HOST", "0.0.0.0") + port = int(os.getenv("PORT", "8000")) + mcp.run(transport=transport, host=host, port=port) + +if __name__ == "__main__": + run_server() +``` + +### Best Practices + +1. **Environment Variables**: Use env vars for API keys and configuration +2. **Error Handling**: Return structured error responses +3. **Logging**: Use appropriate log levels +4. **Documentation**: Include docstrings for all tools +5. **Type Hints**: Use type hints for parameters and returns +6. **Testing**: Provide test clients or scripts +7. **Docker**: Include Dockerfile for deployment +8. **README**: Comprehensive documentation + +## Common Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| HOST | Server host address | 0.0.0.0 | +| PORT | Server port | 8000 | +| MCP_TRANSPORT | Transport protocol | http | +| LOG_LEVEL | Logging level | INFO | + +## Troubleshooting + +### Server Won't Start + +1. Check API keys are set +2. Verify port 8000 is available +3. Check Python version (3.10+) +4. Review logs for errors + +### Tool Returns Errors + +1. Verify API keys are valid +2. Check API quota limits +3. Review request parameters +4. Check network connectivity + +### Import Errors + +1. Install dependencies: `uv pip install -e .` +2. Verify Python version +3. Check for conflicting packages + +## Contributing + +When adding new MCP tools: + +1. Follow the existing structure +2. Use FastMCP framework (or document why not) +3. Include comprehensive README +4. Add Dockerfile +5. Provide test client +6. Document all tools and parameters +7. Use environment variables for secrets +8. Add logging and error handling + +## Resources + +- [FastMCP Documentation](https://github.com/jlowin/fastmcp) +- [Model Context Protocol Spec](https://modelcontextprotocol.io/) +- [LangChain Documentation](https://python.langchain.com/) +- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) + +## License + +See the repository's LICENSE file for details. + diff --git a/mcp/github_tool/README.md b/mcp/github_tool/README.md index ed62880..bde8f80 100644 --- a/mcp/github_tool/README.md +++ b/mcp/github_tool/README.md @@ -137,7 +137,7 @@ After adding the new env vars, apply to Kagenti using `kubectl apply -n team1 -f Now that the environment variables are available, start an instance of the tool - Browse to http://kagenti-ui.localtest.me:8080/Import_New_Tool -- Select namespace (e.g. `team1`) +- Select namespace - Set the Target Port to 9090 - Specify Subfolder `mcp/github_tool` - Click "Build & Deploy New Tool" to deploy. diff --git a/mcp/shopping_tool/.gitignore b/mcp/shopping_tool/.gitignore new file mode 100644 index 0000000..fb88bd5 --- /dev/null +++ b/mcp/shopping_tool/.gitignore @@ -0,0 +1,58 @@ +# API Keys and Secrets - NEVER COMMIT THESE! +.env +.env.local +.env.*.local +config.sh +*.key +*.pem + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual Environments +venv/ +ENV/ +env/ +.venv + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Logs +*.log + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# uv +uv.lock + diff --git a/mcp/shopping_tool/ARCHITECTURE.md b/mcp/shopping_tool/ARCHITECTURE.md new file mode 100644 index 0000000..b0865f7 --- /dev/null +++ b/mcp/shopping_tool/ARCHITECTURE.md @@ -0,0 +1,455 @@ +# Shopping Agent Architecture + +## System Overview + +The Shopping Agent is an MCP (Model Context Protocol) server that uses SerpAPI to provide product search capabilities. The server returns structured product data, and the calling agent (your AI) provides intelligent analysis and recommendations. + +## Design Philosophy + +**Separation of Concerns:** +- **MCP Server**: Provides data (product search results) +- **AI Agent**: Provides intelligence (analysis and recommendations) + +This architecture follows the principle that MCP servers should be lightweight data providers, while AI agents handle complex reasoning and decision-making. + +## High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Client Application │ +│ (Any MCP-compatible client) │ +└────────────────────────────────┬────────────────────────────────────┘ + │ HTTP/MCP Protocol + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ Shopping Agent MCP Server │ +│ (FastMCP Framework) │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌───────────────────┐ ┌──────────────────┐ │ +│ │ recommend_products│ │ search_products │ │ +│ │ @mcp.tool │ │ @mcp.tool │ │ +│ └─────────┬─────────┘ └─────────┬────────┘ │ +│ │ │ │ +│ └──────────────┬───────────────┘ │ +│ ▼ │ +│ ┌──────────────────────────┐ │ +│ │ SerpAPI Integration │ │ +│ │ (Product Search Only) │ │ +│ └──────────┬───────────────┘ │ +│ │ │ +└───────────────────────┼──────────────────────────────────────────────┘ + │ + ▼ + ┌─────────┐ + │ SerpAPI │ + │ API │ + └─────────┘ + + ↓ + Returns structured product data to agent + ↓ +┌─────────────────────────────────────────────────────────────────────┐ +│ AI Agent (Your Client) │ +│ Analyzes data & provides reasoning │ +│ │ +│ • Evaluates products against user requirements │ +│ • Considers budget constraints │ +│ • Provides recommendation scores │ +│ • Explains reasoning for each recommendation │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## Component Details + +### 1. FastMCP Server Layer + +**Purpose**: Exposes product search tools via Model Context Protocol + +**Components**: +- `FastMCP("Shopping Agent")`: MCP server instance +- Tool decorators with proper annotations +- HTTP transport support (MCP Inspector compatible) +- Environment-based configuration + +**Key Features**: +- RESTful API endpoints for tools +- Tool metadata and documentation +- Error handling and validation +- Logging and monitoring + +### 2. Tool Implementations + +#### recommend_products Tool + +``` +Input: "I want to buy a scarf for 40 dollars" + ↓ + [SerpAPI Search] + ↓ + [Parse Results] + ↓ +Output: Structured product data (JSON) +``` + +**Process**: +1. Receives natural language query +2. Constructs optimized search query for shopping +3. Queries SerpAPI for product listings +4. Parses raw results into structured format +5. Returns JSON with product names, prices, descriptions, URLs + +**No AI reasoning at this level** - just data retrieval and structuring. + +#### search_products Tool + +``` +Input: "wireless headphones" + ↓ + [SerpAPI Search] + ↓ +Output: Raw search results +``` + +**Process**: +1. Receives search query +2. Queries SerpAPI +3. Returns raw results for lower-level access + +## Data Flow + +### Request Flow + +``` +1. User asks AI agent for product recommendations + ↓ +2. AI agent calls recommend_products MCP tool + ↓ +3. MCP server validates parameters + ↓ +4. MCP server searches SerpAPI + ↓ +5. MCP server parses results into structured format + ↓ +6. MCP server returns JSON with product data + ↓ +7. AI agent receives product data + ↓ +8. AI agent analyzes products: + - Evaluates match to user requirements + - Considers budget constraints + - Compares features and value + - Generates reasoning for each product + - Ranks products by suitability + ↓ +9. AI agent presents recommendations to user with reasoning +``` + +### Example Data Flow + +**User Query:** +``` +"I want to buy a scarf for 40 dollars" +``` + +**MCP Server Response:** +```json +{ + "query": "I want to buy a scarf for 40 dollars", + "products": [ + { + "name": "Winter Wool Scarf", + "price": "$38.99", + "description": "100% merino wool, various colors", + "url": "https://example.com/product1" + }, + { + "name": "Cashmere Blend Scarf", + "price": "$35.99", + "description": "Soft cashmere blend, multiple patterns", + "url": "https://example.com/product2" + } + ], + "count": 2, + "note": "These are search results. The agent should analyze and provide reasoning." +} +``` + +**AI Agent Analysis & Response to User:** +``` +I found 2 great scarves within your $40 budget: + +1. **Winter Wool Scarf - $38.99** ⭐ Score: 9/10 + This is an excellent choice. The 100% merino wool provides superior warmth + and quality. At $38.99, it's well within your budget and offers great value. + Merino wool is naturally breathable and soft against skin. + +2. **Cashmere Blend Scarf - $35.99** ⭐ Score: 8/10 + A more affordable luxury option. The cashmere blend provides softness and + warmth at a lower price point ($35.99). The multiple pattern options give + you style flexibility. Great value if you want a touch of cashmere without + the high price. + +My top recommendation is the Winter Wool Scarf for its superior quality and warmth. +``` + +## Integration Points + +### External APIs + +#### SerpAPI +- **Usage**: Real-time product search across retailers +- **Calls per request**: 1 +- **Authentication**: API key via environment variable +- **Results**: Aggregated product listings + + + +## Error Handling + +### Error Flow + +``` +Try: + Validate input parameters + ↓ + Execute SerpAPI search + ↓ + Parse results + ↓ + Return structured data +Except APIError: + Log error + Return {"error": "API error message"} +Except ValidationError: + Log error + Return {"error": "Validation error message"} +Except Exception: + Log with traceback + Return {"error": "Generic error message"} +``` + +### Error Types + +1. **API Key Errors**: Missing or invalid SERPAPI_API_KEY +2. **API Quota Errors**: SerpAPI rate limits exceeded +3. **Network Errors**: Connection failures +4. **Parsing Errors**: Invalid search results format +5. **Validation Errors**: Invalid parameters (max_results bounds, etc.) + +## Performance Characteristics + +### Latency Breakdown + +``` +Total Request Time: ~2-4 seconds + ├── Search Products: ~2-3 seconds (SerpAPI) + └── Parse Results: ~0.5-1 second (local processing) +``` + +**Note**: The AI agent's analysis time is additional and depends on the agent's LLM speed. + +### Optimization Strategies + +1. **Efficient Parsing**: Lightweight result parsing +2. **Result Limiting**: max_results parameter (default 10, max 20 for recommend_products) +3. **Simple Processing**: No complex AI processing on server side +4. **Stateless Design**: No session management overhead + +## Scalability + +### Horizontal Scaling + +``` +Load Balancer + ↓ +┌───────────┬───────────┬───────────┐ +│ Instance 1│ Instance 2│ Instance 3│ +└───────────┴───────────┴───────────┘ +``` + +### Considerations + +- Stateless design (no session storage) +- Independent request processing +- External API rate limits (SerpAPI) +- Docker containerization for easy deployment +- Lightweight processing (no AI model loading) + +## Security + +### API Key Management + +``` +Environment Variables + └── SERPAPI_API_KEY (required) + • Never logged or exposed + • Loaded from environment only + • Validated at startup +``` + +### Input Validation + +- Query length limits +- max_results bounds checking (10 default, 20 max for recommend_products, 100 max for search_products) +- Parameter type validation +- Error message sanitization + +## Monitoring and Logging + +### Log Levels + +``` +DEBUG: Detailed execution flow +INFO: Search queries and result counts +WARNING: API issues or parsing problems +ERROR: Failures and exceptions +``` + +### Key Metrics + +- Request count +- Response times +- SerpAPI call counts +- Error rates +- Search result quality + +## Deployment Architecture + +### Docker Deployment + +``` +Docker Container + ├── Python 3.10+ + ├── uv package manager + ├── Application code + ├── Dependencies (FastMCP, LangChain Community, SerpAPI) + └── Environment configuration + +Exposed: + └── Port 8000 (HTTP) + +Environment: + ├── SERPAPI_API_KEY (required) + ├── HOST (default: 0.0.0.0) + ├── PORT (default: 8000) + ├── MCP_TRANSPORT (default: http) + ├── MCP_JSON_RESPONSE (default: true) + └── LOG_LEVEL (default: INFO) +``` + +### Production Setup + +``` +┌─────────────────┐ +│ Load Balancer │ +└────────┬────────┘ + │ + ┌────┴────┬────────┐ + ▼ ▼ ▼ +┌────────┐ ┌────────┐ ┌────────┐ +│Container│ │Container│ │Container│ +│ #1 │ │ #2 │ │ #3 │ +└────────┘ └────────┘ └────────┘ +``` + +## Agent Integration Guide + +### Recommended System Prompt for AI Agents + +When using this MCP server, configure your AI agent with a system prompt like: + +``` +When users ask for product recommendations: + +1. Use the recommend_products tool to search for products based on their query +2. Analyze each returned product considering: + - How well it matches the user's specific requirements + - Whether the price fits within their stated budget + - The value proposition (quality vs. price) + - Any specific features or constraints mentioned + - Availability and retailer reputation + +3. For each relevant product, provide: + - A clear explanation of why it's a good match + - A recommendation score (1-10 scale) + - Any important caveats or considerations + - Comparison with other options + +4. Rank products by how well they meet the user's needs +5. Present the top 3-5 recommendations with detailed reasoning +6. Provide direct purchase links for convenience + +Always explain your reasoning transparently so users understand why you're +recommending specific products. +``` + +### Example Agent Conversation Flow + +``` +User: "I need wireless headphones under $100" + +Agent: [Calls recommend_products MCP tool] + +MCP Server: [Returns 5 product results with names, prices, descriptions, URLs] + +Agent: [Analyzes products and responds to user with]: + "I found several great options for wireless headphones under $100: + + 1. Sony WH-CH710N - $89.99 ⭐ 9/10 + [Detailed reasoning about features, value, fit to requirements] + + 2. JBL Tune 760NC - $79.99 ⭐ 8/10 + [Reasoning] + + 3. Anker Soundcore Q30 - $69.99 ⭐ 8/10 + [Reasoning] + + My top pick is the Sony WH-CH710N because [explanation]..." +``` + +## Future Enhancements + +### Planned Features + +1. **Caching Layer**: Redis for common searches +2. **Advanced Filtering**: Price ranges, categories, ratings in query parsing +3. **Multiple Providers**: Add more search providers beyond SerpAPI +4. **Structured Query Parameters**: Optional structured input format +5. **Result Enrichment**: Add more metadata (reviews, ratings, shipping info) +6. **Price Tracking**: Historical price data +7. **Image URLs**: Include product image URLs when available + +### Architectural Improvements + +1. **Async/Await**: Non-blocking SerpAPI calls +2. **Parallel Searches**: Query multiple providers simultaneously +3. **Enhanced Parsing**: Better extraction of product details +4. **Rate Limiting**: Built-in rate limiting for API protection +5. **Result Caching**: Cache recent searches to reduce API calls + +## Technology Stack Summary + +| Layer | Technology | Purpose | +|-------|-----------|---------| +| **Protocol** | FastMCP | MCP server framework | +| **Search** | SerpAPI | Product search across retailers | +| **Integration** | SerpAPI Python Client | Direct SerpAPI integration | +| **Runtime** | Python 3.10+ | Application runtime | +| **Package Manager** | uv | Fast Python package management | +| **Containerization** | Docker | Deployment and isolation | + +## Conclusion + +The Shopping Agent represents a clean, lightweight MCP server implementation: +- ✅ Focused responsibility (data retrieval only) +- ✅ Fast response times (no LLM processing) +- ✅ Simple deployment and scaling +- ✅ Clear separation of concerns +- ✅ Agent-friendly architecture +- ✅ Production-ready error handling + +The server does one thing well: searches for products and returns structured data. +Your AI agent does what it does best: intelligent analysis and recommendations. + +Ready for deployment and real-world use! 🚀 diff --git a/mcp/shopping_tool/Dockerfile b/mcp/shopping_tool/Dockerfile new file mode 100644 index 0000000..e23c9e8 --- /dev/null +++ b/mcp/shopping_tool/Dockerfile @@ -0,0 +1,28 @@ +FROM python:3.11-slim + +WORKDIR /app + +# Install uv +RUN pip install uv + +# Copy project files +COPY pyproject.toml . +COPY shopping_agent.py . +COPY __init__.py . +COPY README.md . + +# Install dependencies +RUN uv pip install --system -e . + +# Environment variables (can be overridden at runtime) +ENV HOST=0.0.0.0 +ENV PORT=8000 +ENV MCP_TRANSPORT=http +ENV LOG_LEVEL=INFO + +# Expose the port +EXPOSE 8000 + +# Run the server +CMD ["python", "shopping_agent.py"] + diff --git a/mcp/shopping_tool/QUICKSTART.md b/mcp/shopping_tool/QUICKSTART.md new file mode 100644 index 0000000..f902919 --- /dev/null +++ b/mcp/shopping_tool/QUICKSTART.md @@ -0,0 +1,422 @@ +# Shopping Agent - Quick Start Guide + +This guide will help you get the Shopping Agent MCP server up and running quickly. + +## What You'll Need + +1. **SerpAPI Key** - Get it from [SerpAPI Dashboard](https://serpapi.com/manage-api-key) +2. **Python 3.10+** - Check with `python --version` +3. **uv package manager** - Install from [Astral UV](https://docs.astral.sh/uv/) + +## Installation Steps + +### Step 1: Set Up API Key + +```bash +# Export your SerpAPI key +export SERPAPI_API_KEY="your-serpapi-key-here" +``` + +**Tip**: Add this to your `~/.bashrc` or `~/.zshrc` to persist it: +```bash +echo 'export SERPAPI_API_KEY="your-key"' >> ~/.zshrc +source ~/.zshrc +``` + +### Step 2: Install Dependencies + +```bash +cd mcp/shopping_tool +uv pip install -e . +``` + +### Step 3: Start the Server + +```bash +python shopping_agent.py +``` + +You should see: +``` +INFO: Starting Shopping Agent MCP Server with SerpAPI +INFO: Note: This server provides search results. The calling agent provides reasoning. +INFO: Server running on http://0.0.0.0:8000 +``` + +### Step 4: Test the Server + +In a new terminal: + +```bash +# Test with the provided test script +python simple_test.py + +# Or test manually with curl +curl -X POST http://localhost:8000/mcp/tools/recommend_products \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{ + "query": "I want to buy a scarf for 40 dollars", + "max_results": 5 + }' +``` + +## MCP Inspector Demo (HTTP Transport) + +Use the MCP Inspector UI to explore the server interactively: + +1. Start the shopping agent with explicit port/transport: + ```bash + cd mcp/shopping_tool + export SERPAPI_API_KEY="your-key" + MCP_TRANSPORT=http PORT=8001 python shopping_agent.py + ``` +2. In a separate terminal (Node.js ≥18 required) launch the inspector: + ```bash + npx @modelcontextprotocol/inspector + ``` +3. When the browser opens, choose **Add server** and fill in: + - Name: `Shopping Agent` + - Transport: `HTTP` (use `Streamable HTTP` if that is the option offered) + - URL: `http://localhost:8001` +4. Connect and explore the `recommend_products` and `search_products` tools from the **Tools** tab. The response JSON renders in the inspector panel. + +To compare behavior with the movie MCP server, repeat the steps with `PORT=8002 MCP_TRANSPORT=http python ../movie_tool/movie_tool.py` and add it as a second server in the inspector. + +## Usage Examples + +### Example 1: Shopping for Scarves + +```bash +curl -X POST http://localhost:8000/mcp/tools/recommend_products \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{ + "query": "I want to buy a scarf for 40 dollars", + "max_results": 5 + }' +``` + +**Expected Response** (MCP server returns structured product data): +```json +{ + "query": "I want to buy a scarf for 40 dollars", + "products": [ + { + "name": "Winter Wool Scarf", + "price": "$38.99", + "description": "Soft merino wool scarf in multiple colors...", + "url": "https://example.com/product1", + "thumbnail": "https://example.com/image.jpg", + "source": "Amazon", + "rating": 4.5, + "reviews": 120 + }, + { + "name": "Cashmere Blend Scarf", + "price": "$35.99", + "description": "Luxury cashmere blend, various patterns...", + "url": "https://example.com/product2", + "thumbnail": "https://example.com/image2.jpg", + "source": "Etsy" + } + ], + "count": 2 +} +``` + +**Your AI agent should then analyze these products and add reasoning.** + +### Example 2: Finding Headphones + +```bash +curl -X POST http://localhost:8000/mcp/tools/recommend_products \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{ + "query": "wireless headphones under $100 with noise cancellation", + "max_results": 5 + }' +``` + +### Example 3: Using Python Client + +```python +import requests +import json + +response = requests.post( + "http://localhost:8000/mcp/tools/recommend_products", + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + }, + json={ + "query": "best laptop under $800 for programming", + "max_results": 5 + } +) + +products = response.json() +print(json.dumps(products, indent=2)) + +# Your AI agent would then analyze these products and provide recommendations +``` + +## Architecture Overview + +The Shopping Agent uses a simple, efficient architecture: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ User Query │ +│ "I want to buy a scarf for $40" │ +└─────────────────┬───────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ AI Agent (Your Client) │ +│ Calls recommend_products MCP tool │ +└─────────────────┬───────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Shopping Agent MCP Server │ +│ Search Products (SerpAPI) │ +│ Parse Results │ +│ Return Structured Data │ +└─────────────────┬───────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ AI Agent (Your Client) │ +│ Analyzes products and provides reasoning │ +│ • Evaluates match to requirements │ +│ • Considers budget constraints │ +│ • Ranks by suitability │ +│ • Explains reasoning │ +└─────────────────┬───────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Return to User │ +│ Recommendations with names, prices, links, and reasoning │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Technologies Used + +| Technology | Purpose | +|------------|---------| +| **FastMCP** | MCP server framework for tool exposure | +| **LangChain Community** | SerpAPI wrapper utilities | +| **SerpAPI** | Real-time product search across retailers | + +## Configuring Your AI Agent + +When using this MCP server, configure your AI agent with a system prompt like: + +``` +When users ask for product recommendations: + +1. Use the recommend_products tool to search for products +2. Analyze each product considering: + - How well it matches the user's requirements + - Whether it fits within their budget + - The value proposition (quality vs. price) + - Any specific features mentioned + +3. For each product, provide: + - A brief explanation of why it's a good match + - A recommendation score (1-10) + - Any caveats or considerations + +4. Rank products by how well they match the user's needs +5. Present the top 3-5 recommendations with your reasoning +``` + +## Example Agent Conversation + +**User**: "I want to buy a scarf for 40 dollars" + +**AI Agent**: *[Calls recommend_products MCP tool]* + +**MCP Server**: *[Returns structured product data]* + +**AI Agent Response to User**: +``` +I found 2 great scarves within your $40 budget: + +1. Winter Wool Scarf - $38.99 ⭐ Score: 9/10 + This is an excellent choice within your budget. The 100% merino wool + provides superior warmth and quality, making it great value at this + price point. Available in multiple colors. + +2. Cashmere Blend Scarf - $35.99 ⭐ Score: 8/10 + A more affordable luxury option. The cashmere blend provides softness + and warmth at a lower price. The various patterns give you style + flexibility. + +My top recommendation is the Winter Wool Scarf for its superior quality +and durability. +``` + +## Troubleshooting + +### Server Won't Start + +**Problem**: Server fails to start with API key errors + +**Solution**: +```bash +# Verify your key is set +echo $SERPAPI_API_KEY + +# If empty, export it again +export SERPAPI_API_KEY="your-key" +``` + +### Import Errors + +**Problem**: `ModuleNotFoundError` when starting + +**Solution**: +```bash +# Reinstall dependencies +uv pip install --force-reinstall -e . +``` + +### No Results Returned + +**Problem**: Server runs but returns no products + +**Solution**: +1. Check your SerpAPI quota at https://serpapi.com/dashboard +2. Verify the query is specific enough +3. Check server logs: `LOG_LEVEL=DEBUG python shopping_agent.py` + +### Connection Refused + +**Problem**: `Connection refused` when testing + +**Solution**: +```bash +# Check if server is running +ps aux | grep shopping_agent + +# If not, start the server +python shopping_agent.py +``` + +## Docker Deployment + +### Build and Run + +```bash +# Build the Docker image +docker build -t shopping-agent-mcp . + +# Run with API key +docker run -p 8000:8000 \ + -e SERPAPI_API_KEY="your-serpapi-key" \ + shopping-agent-mcp +``` + +### Docker Compose + +Create `docker-compose.yml`: + +```yaml +version: '3.8' +services: + shopping-agent: + build: . + ports: + - "8000:8000" + environment: + - SERPAPI_API_KEY=${SERPAPI_API_KEY} + - LOG_LEVEL=INFO +``` + +Run with: +```bash +docker-compose up +``` + +## API Reference + +### Tool: `recommend_products` + +**Description**: Search for products and return structured data for your AI agent to analyze + +**Request**: +```json +{ + "query": "string (required) - Natural language product request", + "max_results": "integer (optional) - Max results (default: 10, max: 20)" +} +``` + +**Response**: +```json +{ + "query": "string - Original query", + "products": [ + { + "name": "string - Product name", + "price": "string - Price", + "description": "string - Product description", + "url": "string - Purchase link" + } + ], + "count": "integer - Number of products", + "note": "string - Reminder that agent should provide reasoning" +} +``` + +### Tool: `search_products` + +**Description**: Raw product search (lower-level tool) + +**Request**: +```json +{ + "query": "string (required) - Search query", + "max_results": "integer (optional) - Max results (default: 10, max: 100)" +} +``` + +**Response**: +```json +{ + "query": "string - Search query", + "results": "string - Raw search results", + "note": "string - Usage note" +} +``` + +## Next Steps + +1. **Integrate with Your Agent**: Connect your AI agent (Claude, GPT-4, etc.) to use this MCP server +2. **Configure System Prompt**: Use the suggested prompt above to guide your agent's analysis +3. **Test**: Try various product queries and refine your agent's reasoning +4. **Monitor**: Add logging and monitoring for production use +5. **Scale**: Deploy with Docker and load balancing for high traffic + +## Support + +- Check logs with `LOG_LEVEL=DEBUG python shopping_agent.py` +- Review the [README.md](README.md) for detailed documentation +- Review the [ARCHITECTURE.md](ARCHITECTURE.md) for architecture details +- Verify API key has sufficient quota at https://serpapi.com/dashboard +- Test with the provided `simple_test.py` script + +## Summary + +✅ You've created a lightweight Shopping Agent MCP server +✅ It uses SerpAPI for real-time product search +✅ It returns structured data for your AI agent to analyze +✅ It follows MCP best practices with clear separation of concerns +✅ It's ready for production deployment with Docker + +Your AI agent does the smart analysis and recommendations! 🛍️ diff --git a/mcp/shopping_tool/README.md b/mcp/shopping_tool/README.md new file mode 100644 index 0000000..e6191df --- /dev/null +++ b/mcp/shopping_tool/README.md @@ -0,0 +1,352 @@ +# Shopping Agent MCP Tool + +A Model Context Protocol (MCP) server that provides product search capabilities using SerpAPI. The server returns structured product data, and the calling agent provides intelligent reasoning and recommendations. + +## Features + +- **Product Search**: Leverages SerpAPI (Google Shopping) to search across multiple retailers +- **Structured Data**: Returns rich product info including titles, prices, descriptions, thumbnails, ratings, and reviews +- **Agent-Driven Analysis**: The MCP server returns raw data; your AI agent analyzes and provides reasoning +- **Budget Awareness**: Product data includes prices for the agent to consider constraints +- **Configurable Results**: Limit search results (default 10, max 20) based on your needs + +## Tools + +### 1. `recommend_products` + +Searches for products based on a natural language query and returns structured product data. The calling agent should analyze this data and provide intelligent reasoning. + +**Parameters:** +- `query` (string, required): Natural language product request (e.g., "I want to buy a scarf for 40 dollars") +- `max_results` (integer, optional): Maximum number of results (default: 10, max: 20) + +**Returns:** +```json +{ + "query": "I want to buy a scarf for 40 dollars", + "products": [ + { + "name": "Cashmere Blend Scarf", + "price": "$35.99", + "description": "Soft and warm cashmere blend scarf in multiple colors...", + "url": "https://example.com/product", + "thumbnail": "https://example.com/image.jpg", + "source": "Amazon", + "rating": 4.5, + "reviews": 120 + } + ], + "count": 5 +} +``` + +**Features:** +- Returns rich structured product data including thumbnails and ratings +- The calling agent should analyze products and provide reasoning +- Products include names, prices, descriptions, and purchase URLs +- Only requires `SERPAPI_API_KEY` to function + +### 2. `search_products` + +Search for products across retailers (lower-level tool for raw search results). + +**Parameters:** +- `query` (string, required): Product search query +- `max_results` (integer, optional): Maximum results to return (default: 10, max: 100) + +**Returns:** +Raw search results from SerpAPI. + +## Setup + +### Prerequisites + +- Python 3.10 or higher +- [uv](https://docs.astral.sh/uv/) package manager +- SerpAPI key (required for product search) + +### Installation + +1. **Get API Key:** + - SerpAPI key: https://serpapi.com/manage-api-key + +2. **Install Dependencies:** + +```bash +cd mcp/shopping_tool +uv pip install -e . +``` + +### Configuration + +Set the required environment variable: + +```bash +export SERPAPI_API_KEY="your-serpapi-key" +``` + +Optional configuration: +```bash +export HOST="0.0.0.0" # Server host (default: 0.0.0.0) +export PORT="8000" # Server port (default: 8000) +export MCP_TRANSPORT="http" # Transport type (default: http, Inspector-ready) +export MCP_JSON_RESPONSE="1" # Force JSON responses (default: enabled) +export LOG_LEVEL="INFO" # Logging level (default: INFO) +``` + +## Running the Server + +### Development Mode + +```bash +cd mcp/shopping_tool +export SERPAPI_API_KEY="your-serpapi-key" +python shopping_agent.py +``` + +The server will start on `http://0.0.0.0:8000` by default and will return structured product data for your agent to analyze. + +### Command-line options + +You can override server behaviour with CLI flags: + +```bash +uv run shopping_agent.py --json-response --port 8020 +``` + +- `--json-response` / `--no-json-response`: toggle JSON responses without touching `MCP_JSON_RESPONSE` +- `--stateless-http` / `--stateful-http`: control FastMCP stateless HTTP mode +- `--host`, `--port`, `--transport`: override bind settings (fall back to environment variables when omitted) + +### MCP Inspector Demo (HTTP Transport) + +Follow these steps to debug the shopping agent with the official MCP Inspector UI: + +1. Start the server on its own port using HTTP transport: + ```bash + cd mcp/shopping_tool + export SERPAPI_API_KEY="your-key" + MCP_TRANSPORT=http PORT=8001 python shopping_agent.py + ``` +2. In a new terminal (requires Node.js ≥18), launch the inspector: + ```bash + npx @modelcontextprotocol/inspector + ``` +3. In the Inspector UI choose **Add server**, then supply: + - Name: `Shopping Agent (HTTP)` + - Transport: `HTTP` (or `Streamable HTTP` on older Inspector releases) + - URL: `http://localhost:8001` +4. Click **Connect**, open the **Tools** tab, and invoke `recommend_products` or `search_products`. Responses stream in the right-hand panel. + +Tip: run the `movie_tool` server on a different port (for example `PORT=8002 MCP_TRANSPORT=http python ../movie_tool/movie_tool.py`) to compare both MCP servers side by side inside the inspector. + +### Using Docker + +```bash +cd mcp/shopping_tool + +# Build the image +docker build -t shopping-agent-mcp . + +# Run the container +docker run -p 8000:8000 \ + -e SERPAPI_API_KEY="your-serpapi-key" \ + shopping-agent-mcp +``` + +## Architecture + +The shopping agent MCP server provides product search data. The calling agent (your AI) provides reasoning and recommendations: + +``` +User Query → [MCP Tool] Search Products → Return Structured Data → [Your Agent] Analyze & Recommend +``` + +### Workflow + +1. **MCP Server**: Receives query, searches SerpAPI, returns structured product data (no reasoning) +2. **Your Agent** (e.g., Claude, GPT-4): Analyzes the product data and provides intelligent reasoning for recommendations + +### Suggested Agent System Prompt + +When using this MCP server, configure your agent with a system prompt like this: + +``` +When users ask for product recommendations: +1. Use the recommend_products tool to search for products +2. Analyze each product considering: + - How well it matches the user's requirements + - Whether it fits within their budget + - The value proposition (quality vs. price) + - Any specific features mentioned in the query +3. For each product, provide: + - A brief explanation of why it's a good match + - A recommendation score (1-10) + - Any caveats or considerations +4. Rank products by how well they match the user's needs +5. Present the top 3-5 recommendations with your reasoning +``` + +### Technologies Used + +- **FastMCP**: MCP server framework +- **LangChain Community**: SerpAPI wrapper for product search +- **SerpAPI**: Real-time product search across retailers + +## Usage Examples + +### Example 1: Basic Product Search + +```python +# Query +"I want to buy a scarf for 40 dollars" + +# MCP Server Response (raw product data) +{ + "query": "I want to buy a scarf for 40 dollars", + "products": [ + { + "name": "Winter Wool Scarf", + "price": "$38.99", + "description": "100% merino wool...", + "url": "https://example.com/product", + "thumbnail": "https://...", + "source": "Retailer A" + }, + { + "name": "Cashmere Blend Scarf", + "price": "$35.99", + "description": "Soft cashmere blend...", + "url": "https://example.com/product2", + "thumbnail": "https://...", + "source": "Retailer B" + } + ], + "count": 2 +} + +# Your Agent should then analyze these products and provide reasoning: +# "Here are my top recommendations: +# +# 1. Winter Wool Scarf ($38.99) - Score: 9/10 +# This is an excellent choice within your $40 budget. The 100% merino wool +# provides superior warmth and quality, making it great value at this price point. +# +# 2. Cashmere Blend Scarf ($35.99) - Score: 8/10 +# A more affordable option that still offers luxury with its cashmere blend..." +``` + +### Example 2: Specific Requirements + +```python +# Query +"Find me wireless headphones under $100 with good noise cancellation" + +# MCP Server Response (raw product data) +{ + "query": "wireless headphones under $100 with good noise cancellation", + "products": [ + { + "name": "Sony WH-CH710N Wireless Headphones", + "price": "$89.99", + "description": "Active noise canceling...", + "url": "https://example.com/sony-headphones", + "rating": 4.4, + "reviews": 8500 + } + ], + "count": 1 +} + +# Your Agent analyzes and recommends: +# "I found the Sony WH-CH710N Wireless Headphones at $89.99 - this is an excellent +# match for your requirements: +# - ✅ Wireless Bluetooth connectivity +# - ✅ Active noise cancellation feature +# - ✅ Well under your $100 budget ($89.99) +# - ✅ Bonus: 35-hour battery life +# +# Recommendation Score: 9/10 +# This product checks all your boxes and comes from Sony, a trusted brand in audio..." +``` + + +### Using curl + +You can also test the MCP server tools using curl: + +```bash +# Test recommend_products tool (returns structured product data) +curl -X POST http://localhost:8000/mcp/tools/recommend_products \ + -H "Content-Type: application/json" \ + -H "Accept: application/json, text/event-stream" \ + -d '{ + "query": "I want to buy a scarf for 40 dollars", + "max_results": 5 + }' +``` + +## Troubleshooting + +### API Key Issues + +**SerpAPI Key Issues:** +If you see "SERPAPI_API_KEY not configured" errors: +1. Get your key from https://serpapi.com/manage-api-key +2. Export it: `export SERPAPI_API_KEY="your-key"` +3. Restart the server + +**General API Key Tips:** +1. Verify your API key is set correctly +2. Check that the environment variable is exported in the same shell session +3. Restart the server after setting environment variables + +### No Results Returned + +If searches return no results: +1. Try a more specific query with product name and budget +2. Check your SerpAPI quota at https://serpapi.com/dashboard +3. Review server logs for detailed error messages + +### Import Errors + +If you encounter import errors: +1. Ensure all dependencies are installed: `uv pip install -e .` +2. Check Python version is 3.10 or higher +3. Try reinstalling with `uv pip install --force-reinstall -e .` + +## Development + +### Project Structure + +``` +shopping_tool/ +├── shopping_agent.py # Main MCP server with SerpAPI integration +├── simple_test.py # Test script for product search +├── pyproject.toml # Dependencies and project metadata +├── README.md # This file +├── Dockerfile # Container configuration +└── __init__.py # Package initialization +``` + +### Contributing + +When contributing, ensure: +1. Code follows the existing style +2. All API keys are handled via environment variables +3. Error handling is comprehensive +4. Logging is informative but not excessive +5. Tests pass (if applicable) + +## License + +See the repository's LICENSE file for details. + +## Support + +For issues or questions: +1. Check the troubleshooting section above +2. Review server logs for detailed error messages +3. Ensure all API keys are valid and have sufficient quota +4. Open an issue in the repository with relevant logs + diff --git a/mcp/shopping_tool/__init__.py b/mcp/shopping_tool/__init__.py new file mode 100644 index 0000000..4c44d91 --- /dev/null +++ b/mcp/shopping_tool/__init__.py @@ -0,0 +1,6 @@ +"""Shopping Agent MCP Tool""" + +from .shopping_agent import recommend_products, search_products, run_server + +__all__ = ["recommend_products", "search_products", "run_server"] + diff --git a/mcp/shopping_tool/config.example b/mcp/shopping_tool/config.example new file mode 100644 index 0000000..cb38047 --- /dev/null +++ b/mcp/shopping_tool/config.example @@ -0,0 +1,21 @@ +# Shopping Agent MCP Server Configuration Example +# Copy this file to .env or export these variables in your shell + + +# Required: SerpAPI Key +# Get your key from: https://serpapi.com/manage-api-key +export SERPAPI_API_KEY="your-serpapi-key-here" + +# Optional: Server Configuration +# Host address (default: 0.0.0.0) +export HOST="0.0.0.0" + +# Server port (default: 8000) +export PORT="8000" + +# MCP transport type (default: http) +export MCP_TRANSPORT="http" + +# Logging level (default: INFO) +# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL +export LOG_LEVEL="INFO" diff --git a/mcp/shopping_tool/pyproject.toml b/mcp/shopping_tool/pyproject.toml new file mode 100644 index 0000000..ca58abd --- /dev/null +++ b/mcp/shopping_tool/pyproject.toml @@ -0,0 +1,15 @@ +[project] +name = "shopping_agent" +version = "0.1.0" +description = "Shopping Agent MCP Tool using SerpAPI for product search" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "fastmcp>=2.11.0", + "google-search-results>=2.4.2", + "requests>=2.32.3", +] + +[tool.setuptools] +py-modules = ["shopping_agent"] + diff --git a/mcp/shopping_tool/setup_env.sh b/mcp/shopping_tool/setup_env.sh new file mode 100755 index 0000000..1d83c35 --- /dev/null +++ b/mcp/shopping_tool/setup_env.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Helper script to set up your API keys +# +# Usage: +# 1. Run this script once: ./setup_env.sh +# 2. It will create a .env.local file for you to edit +# 3. Then run: source .env.local && python shopping_agent.py + +echo "🛍️ Shopping Agent Environment Setup" +echo "=====================================" +echo "" + +if [ -f ".env.local" ]; then + echo "ℹ️ .env.local already exists" + echo "" + read -p "Do you want to overwrite it? (y/N): " -n 1 -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Keeping existing .env.local" + exit 0 + fi +fi + +echo "Creating .env.local template..." +cat > .env.local << 'EOF' +# Shopping Agent MCP Server - Local Environment Configuration +# Load this file: source .env.local + +# Required: OpenAI API Key (https://platform.openai.com/api-keys) +export OPENAI_API_KEY="your-openai-api-key-here" + +# Required: SerpAPI Key (https://serpapi.com/manage-api-key) +export SERPAPI_API_KEY="your-serpapi-api-key-here" + +# Optional: Server Configuration +export HOST="0.0.0.0" +export PORT="8000" +export MCP_TRANSPORT="http" +export LOG_LEVEL="INFO" +EOF + +echo "✓ Created .env.local" +echo "" +echo "📝 Next steps:" +echo " 1. Edit .env.local and add your actual API keys" +echo " 2. Load the environment: source .env.local" +echo " 3. Run the server: python3 shopping_agent.py" +echo " 4. Test the server: python3 test_client.py (in another terminal)" + diff --git a/mcp/shopping_tool/shopping_agent.py b/mcp/shopping_tool/shopping_agent.py new file mode 100644 index 0000000..2c98baa --- /dev/null +++ b/mcp/shopping_tool/shopping_agent.py @@ -0,0 +1,312 @@ +"""Shopping Agent MCP Tool - Uses SerpAPI for product search""" + +import argparse +import os +import sys +import json +import logging +from typing import Any, Dict, Optional, Union +from fastmcp import FastMCP +from serpapi import GoogleSearch + +logger = logging.getLogger(__name__) + + +def _env_flag(name: str, default: str = "false") -> bool: + """Parse environment flag strings like 1/true/on into booleans.""" + value = os.getenv(name) + if value is None: + value = default + return value.strip().lower() in {"1", "true", "yes", "on"} + +# Environment variable for API key +SERPAPI_API_KEY = os.getenv("SERPAPI_API_KEY") + +# Initialize FastMCP +mcp = FastMCP("Shopping Agent") + +# Public agent card for A2A discovery +AGENT_CARD = { + "name": "shopping-agent", + "version": "1.0.0", + "description": "Shopping MCP tool using SerpAPI for product search", + "capabilities": { + "mcp": { + # Using cluster DNS; adjust if you front this with ingress + "endpoints": [ + { + "type": "http", + "url": os.getenv( + "AGENT_CARD_MCP_URL", + "http://shopping-agent:8000/mcp", + ), + } + ] + } + }, +} + + +@mcp.tool(annotations={"readOnlyHint": True, "destructiveHint": False, "idempotentHint": True}) +def recommend_products(query: str, max_results: int = 10) -> str: + """ + Recommend products based on natural language query (e.g., "good curtains under $40") + + This tool searches Google Shopping via SerpAPI and returns structured product data + including titles, prices, and descriptions. + + Args: + query: Natural language product request + max_results: Maximum number of product recommendations to return (default 10, max 20) + + Returns: + JSON string containing product search results with names, prices, descriptions, and links. + """ + # Validate query input + if not isinstance(query, str) or not query.strip(): + return json.dumps({"error": "Query must not be empty."}) + if len(query) > 256: + return json.dumps({"error": "Query is too long (max 256 characters)."}) + logger.info(f"Searching products for query: '{query}'") + + if not SERPAPI_API_KEY: + return json.dumps({"error": "SERPAPI_API_KEY not configured"}) + + # Limit max_results + max_results = min(max_results, 20) + + try: + # Configure SerpAPI Google Shopping search + params = { + "api_key": SERPAPI_API_KEY, + "engine": "google_shopping", + "q": query, + "google_domain": "google.com", + "gl": "us", + "hl": "en", + "num": max_results + } + + logger.debug(f"Searching with params: {json.dumps(params, default=str)}") + search = GoogleSearch(params) + results = search.get_dict() + + if "error" in results: + return json.dumps({"error": results["error"]}) + + shopping_results = results.get("shopping_results", []) + + # Format products + products = [] + for item in shopping_results: + product = { + "name": item.get("title"), + "price": item.get("price"), + "description": item.get("snippet") or item.get("description") or "No description available", + "url": item.get("link"), + "thumbnail": item.get("thumbnail"), + "source": item.get("source"), + "rating": item.get("rating"), + "reviews": item.get("reviews") + } + products.append(product) + + # Fallback to regular search if no shopping results found + if not products and "organic_results" in results: + logger.info("No shopping results found, falling back to organic results") + # This might happen if we switch engine to 'google' or if shopping has no results + # But with engine='google_shopping', we should get shopping_results + pass + + return json.dumps({ + "query": query, + "products": products[:max_results], + "count": len(products[:max_results]) + }, indent=2) + + except Exception as e: + logger.error(f"Error in recommend_products: {e}", exc_info=True) + return json.dumps({"error": str(e)}) + + +@mcp.tool(annotations={"readOnlyHint": True, "destructiveHint": False, "idempotentHint": True}) +def search_products(query: str, max_results: int = 10) -> str: + """ + Search for products using standard Google Search (internal tool) + + Args: + query: Product search query + max_results: Maximum number of results to return (default 10, max 100) + + Returns: + JSON string containing search results + """ + # Validate query input + if not isinstance(query, str) or not query.strip(): + return json.dumps({"error": "Query parameter must be a non-empty string."}) + if len(query) > 256: + return json.dumps({"error": "Query parameter is too long (max 256 characters)."}) + logger.info(f"Searching products for query: '{query}'") + + if not SERPAPI_API_KEY: + return json.dumps({"error": "SERPAPI_API_KEY not configured"}) + + # Limit max_results + max_results = min(max_results, 100) + + try: + # Use standard Google Search for broader context + params = { + "api_key": SERPAPI_API_KEY, + "engine": "google", + "q": query, + "google_domain": "google.com", + "gl": "us", + "hl": "en", + "num": max_results + } + + search = GoogleSearch(params) + results = search.get_dict() + + if "error" in results: + return json.dumps({"error": results["error"]}) + + return json.dumps( + { + "query": query, + "organic_results": results.get("organic_results", [])[:max_results], + "shopping_results": results.get("shopping_results", [])[:max_results], + }, + indent=2, + ) + + except Exception as e: + logger.error(f"Error in search_products: {e}", exc_info=True) + return json.dumps({"error": str(e)}) + + +def run_server( + transport: Optional[str] = None, + host: Optional[str] = None, + port: Optional[Union[int, str]] = None, + json_response: Optional[bool] = None, + stateless_http: Optional[bool] = None, +) -> None: + """Run the MCP server with optional overrides from CLI or environment.""" + if transport is None: + transport = os.getenv("MCP_TRANSPORT", "http") + if host is None: + host = os.getenv("HOST", "0.0.0.0") + if port is None: + port = int(os.getenv("PORT", "8000")) + else: + port = int(port) + if json_response is None: + json_response = _env_flag("MCP_JSON_RESPONSE", "true") + if stateless_http is None: + stateless_http = _env_flag("MCP_STATELESS_HTTP", "false") + + logger.info( + "Starting MCP server transport=%s host=%s port=%s json_response=%s stateless_http=%s", + transport, + host, + port, + json_response, + stateless_http, + ) + mcp.run( + transport=transport, + host=host, + port=port, + json_response=json_response, + stateless_http=stateless_http, + ) + + +# Attach agent card route if FastMCP exposes the FastAPI app +app = getattr(mcp, "app", None) +if app: + @app.get("/.well-known/agent.json") + def agent_card() -> Dict[str, Any]: + return AGENT_CARD + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Shopping Agent MCP Server") + parser.add_argument( + "--transport", + dest="transport", + default=None, + help="Transport to use for FastMCP (default: env MCP_TRANSPORT or http)", + ) + parser.add_argument( + "--host", + dest="host", + default=None, + help="Host interface to bind (default: env HOST or 0.0.0.0)", + ) + parser.add_argument( + "--port", + dest="port", + type=int, + default=None, + help="Port to bind (default: env PORT or 8000)", + ) + parser.add_argument( + "--json-response", + dest="json_response", + action="store_true", + help="Force JSON responses (overrides env MCP_JSON_RESPONSE)", + ) + parser.add_argument( + "--no-json-response", + dest="json_response", + action="store_false", + help="Disable JSON responses (overrides env MCP_JSON_RESPONSE)", + ) + parser.add_argument( + "--stateless-http", + dest="stateless_http", + action="store_true", + help="Enable stateless HTTP transport mode", + ) + parser.add_argument( + "--stateful-http", + dest="stateless_http", + action="store_false", + help="Disable stateless HTTP transport mode", + ) + parser.set_defaults(json_response=None, stateless_http=None) + return parser.parse_args() + + +def main() -> int: + # Configure logging only when run as a script, not on import + logging.basicConfig( + level=os.getenv("LOG_LEVEL", "INFO"), + stream=sys.stdout, + format="%(levelname)s: %(message)s", + ) + + args = _parse_args() + + if SERPAPI_API_KEY is None: + logger.error("Please configure the SERPAPI_API_KEY environment variable before running the server") + return 1 + + logger.info("Starting Shopping Agent MCP Server with SerpAPI") + logger.info("Note: This server provides search results. The calling agent provides reasoning.") + + run_server( + transport=args.transport, + host=args.host, + port=args.port, + json_response=args.json_response, + stateless_http=args.stateless_http, + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/sample-environments.yaml b/sample-environments.yaml index a49e297..fb69bea 100644 --- a/sample-environments.yaml +++ b/sample-environments.yaml @@ -38,6 +38,18 @@ data: "valueFrom": {"secretKeyRef": {"name": "slack-secret", "key": "bot-token"}} } ] + # mcp shopping uses http transport + mcp-shopping: | + [ + {"name": "MCP_URL", "value": "http://shopping-tool:8000/mcp"} + ] + mcp-shopping-config: | + [ + { + "name": "SERPAPI_API_KEY", + "valueFrom": {"secretKeyRef": {"name": "shopping-secret", "key": "serpapi-key"}} + } + ] slack-researcher-config: | [ {"name": "TASK_MODEL_ID", "value": "granite3.3:8b"},