From 35a3fa92aa40b58cda43d9d9011b4aefbd4d92a0 Mon Sep 17 00:00:00 2001 From: Sarthak Bhardwaj Date: Fri, 11 Apr 2025 10:21:03 +0530 Subject: [PATCH] Add Airbnb --- community_usecase/Airbnb-MCP/Airbnb_MCP.py | 127 ++++++++++++++++++ community_usecase/Airbnb-MCP/README.md | 103 ++++++++++++++ .../Airbnb-MCP/mcp_servers_config.json | 12 ++ 3 files changed, 242 insertions(+) create mode 100644 community_usecase/Airbnb-MCP/Airbnb_MCP.py create mode 100644 community_usecase/Airbnb-MCP/README.md create mode 100644 community_usecase/Airbnb-MCP/mcp_servers_config.json diff --git a/community_usecase/Airbnb-MCP/Airbnb_MCP.py b/community_usecase/Airbnb-MCP/Airbnb_MCP.py new file mode 100644 index 0000000..8a30873 --- /dev/null +++ b/community_usecase/Airbnb-MCP/Airbnb_MCP.py @@ -0,0 +1,127 @@ +import asyncio +import sys +from pathlib import Path +from typing import List, Dict + +from dotenv import load_dotenv +from camel.models import ModelFactory +from camel.toolkits import FunctionTool, MCPToolkit +from camel.types import ModelPlatformType, ModelType +from camel.logger import set_log_level + +from owl.utils.enhanced_role_playing import OwlRolePlaying, arun_society + +import pathlib + +set_log_level(level="DEBUG") + +# Load environment variables from .env file if available +load_dotenv() + + +async def construct_society( + question: str, + tools: List[FunctionTool], +) -> OwlRolePlaying: + """Build a multi-agent OwlRolePlaying instance with enhanced content curation capabilities.""" + models = { + "user": ModelFactory.create( + model_platform=ModelPlatformType.OPENAI, + model_type=ModelType.GPT_4O, + model_config_dict={ + "temperature": 0.7, + # "max_tokens": 4000 # Add token limit to prevent overflow + }, + ), + "assistant": ModelFactory.create( + model_platform=ModelPlatformType.OPENAI, + model_type=ModelType.GPT_4O, + model_config_dict={ + "temperature": 0.7, + #"max_tokens": 4000 + }, + ), + } + + user_agent_kwargs = {"model": models["user"]} + assistant_agent_kwargs = { + "model": models["assistant"], + "tools": tools, + } + + task_kwargs = { + "task_prompt": question, + "with_task_specify": False, + } + + return OwlRolePlaying( + **task_kwargs, + user_role_name="content_curator", + user_agent_kwargs=user_agent_kwargs, + assistant_role_name="research_assistant", + assistant_agent_kwargs=assistant_agent_kwargs, + ) + +async def main(): + config_path = Path(__file__).parent / "mcp_servers_config.json" + mcp_toolkit = MCPToolkit(config_path=str(config_path)) + + try: + await mcp_toolkit.connect() + + default_task = ( + "Find me the best Airbnb in Gurugram with a check-in date of 2025-06-01 " + "and a check-out date of 2025-06-07 for 2 adults. Return the top 5 listings with their names, " + "prices, and locations." + ) + + task = sys.argv[1] if len(sys.argv) > 1 else default_task + + # Connect to all MCP toolkits + tools = [*mcp_toolkit.get_tools()] + society = await construct_society(task, tools) + + try: + # Add error handling for the society execution + result = await arun_society(society) + + # Handle the result properly + if isinstance(result, tuple) and len(result) == 3: + answer, chat_history, token_count = result + else: + answer = str(result) + chat_history = [] + token_count = 0 + + except Exception as e: + print(f"Error during society execution: {str(e)}") + raise + + finally: + # Cleanup + await asyncio.sleep(1) + tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] + for task in tasks: + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + + try: + await mcp_toolkit.disconnect() + except Exception as e: + print(f"Cleanup error (can be ignored): {e}") + +if __name__ == "__main__": + try: + asyncio.run(main()) + except KeyboardInterrupt: + print("\nShutting down gracefully...") + finally: + if sys.platform == 'win32': + try: + import asyncio.windows_events + asyncio.windows_events._overlapped = None + except (ImportError, AttributeError): + pass \ No newline at end of file diff --git a/community_usecase/Airbnb-MCP/README.md b/community_usecase/Airbnb-MCP/README.md new file mode 100644 index 0000000..714b3d8 --- /dev/null +++ b/community_usecase/Airbnb-MCP/README.md @@ -0,0 +1,103 @@ + +# 🏑 CAMEL-AI + MCP: Airbnb Use Case + +This example demonstrates how to use the [CAMEL-AI OWL framework](https://github.com/camel-ai/owl) and **MCP (Model Context Protocol)** to search for Airbnb listings using a custom MCP server (`@openbnb/mcp-server-airbnb`). Agents in the OWL framework coordinate to perform tool-augmented travel research in a structured, automated way. + +--- + +## ✨ Use Case + +> _β€œFind me the best Airbnb in Gurugram with a check-in date of 2025-06-01 and a check-out date of 2025-06-07 for 2 adults. Return the top 5 listings with their names, prices, and locations.”_ + +Agents leverage an MCP server to execute real-time Airbnb queries and return formatted results. + +--- + +## πŸ“¦ Setup + +### 1. Clone and install dependencies + +```bash +git clone https://github.com/camel-ai/owl +cd owl +pip install -r requirements.txt +``` + +--- + +### 2. Configure MCP Server + +In your `mcp_servers_config.json`, add the following: + +```json +{ + "mcpServers": { + "airbnb": { + "command": "npx", + "args": [ + "-y", + "@openbnb/mcp-server-airbnb", + "--ignore-robots-txt" + ] + } + } +} +``` + +> πŸ› οΈ You will need **Node.js and NPM** installed. Run `npx` will automatically fetch the Airbnb MCP server. + +--- + +### 3. Run the Example Script + +```bash +python community_usecase/Airbnb_MCP +``` + +You can also customize the prompt inside the script itself. Edit the `default_task` section of `Airbnb_MCP.py` like this: + +```python +# Replace this line: +default_task = ( + "here you need to add the task" +) + +# Example: +default_task = ( + "Find me the best Airbnb in Gurugram with a check-in date of 2025-06-01 " + "and a check-out date of 2025-06-07 for 2 adults. Return the top 5 listings with their names, " + "prices, and locations." +) +``` + +This allows agents to work from your hardcoded task without passing anything via command line. + +--- + +## 🧠 How It Works + +- **MCPToolkit** reads the config and connects to the `@openbnb/mcp-server-airbnb`. +- **OWL RolePlaying Agents** simulate a conversation between a `content_curator` and a `research_assistant`. +- The **assistant agent** calls the MCP Airbnb server to fetch listings. +- The results are processed, formatted, and printed. + +--- + +--- + +## 🚧 Notes + +- This script uses **GPT-4o** via OpenAI for both user and assistant roles. +- Supports async execution and graceful cleanup of agents and MCP sessions. +- Add retries and fallback logic for production use. + +--- + +## πŸ“Œ References + +- [MCP Overview (Anthropic)](https://docs.anthropic.com/en/docs/agents-and-tools/mcp) +- [CAMEL-AI GitHub](https://github.com/camel-ai/camel) +- [OWL Framework](https://github.com/camel-ai/owl) +- [MCP Airbnb Plugin](https://www.npmjs.com/package/@openbnb/mcp-server-airbnb) +~~~ + diff --git a/community_usecase/Airbnb-MCP/mcp_servers_config.json b/community_usecase/Airbnb-MCP/mcp_servers_config.json new file mode 100644 index 0000000..7fb2e63 --- /dev/null +++ b/community_usecase/Airbnb-MCP/mcp_servers_config.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "airbnb": { + "command": "npx", + "args": [ + "-y", + "@openbnb/mcp-server-airbnb", + "--ignore-robots-txt" + ] + } + } +}