from mcp.server.fastmcp import FastMCP from datetime import datetime import random import urllib.parse # Initialize FastMCP server for Hotels mcp = FastMCP("HotelsAgent") # Destination-specific real hotels DESTINATION_HOTELS = { "dubai": [ {"name": "Burj Al Arab Jumeirah", "stars": 5, "base_price": 1500, "rating": 4.8}, {"name": "Atlantis The Palm", "stars": 5, "base_price": 450, "rating": 4.6}, {"name": "Armani Hotel Dubai", "stars": 5, "base_price": 600, "rating": 4.7}, {"name": "Jumeirah Beach Hotel", "stars": 5, "base_price": 400, "rating": 4.5}, {"name": "One&Only The Palm", "stars": 5, "base_price": 800, "rating": 4.8}, {"name": "Address Downtown Dubai", "stars": 5, "base_price": 350, "rating": 4.6}, ], "paris": [ {"name": "The Ritz Paris", "stars": 5, "base_price": 1200, "rating": 4.9}, {"name": "Four Seasons Hotel George V Paris", "stars": 5, "base_price": 1100, "rating": 4.8}, {"name": "Le Meurice Paris", "stars": 5, "base_price": 900, "rating": 4.7}, {"name": "Shangri-La Hotel Paris", "stars": 5, "base_price": 800, "rating": 4.7}, {"name": "Hotel Plaza Athenee Paris", "stars": 5, "base_price": 950, "rating": 4.8}, ], "tokyo": [ {"name": "The Peninsula Tokyo", "stars": 5, "base_price": 700, "rating": 4.8}, {"name": "Aman Tokyo", "stars": 5, "base_price": 1000, "rating": 4.9}, {"name": "Park Hyatt Tokyo", "stars": 5, "base_price": 600, "rating": 4.7}, {"name": "The Ritz-Carlton Tokyo", "stars": 5, "base_price": 650, "rating": 4.7}, {"name": "Mandarin Oriental Tokyo", "stars": 5, "base_price": 700, "rating": 4.8}, ], "london": [ {"name": "The Savoy London", "stars": 5, "base_price": 700, "rating": 4.7}, {"name": "Claridge's London", "stars": 5, "base_price": 800, "rating": 4.8}, {"name": "The Ritz London", "stars": 5, "base_price": 750, "rating": 4.7}, {"name": "Four Seasons Hotel London at Park Lane", "stars": 5, "base_price": 650, "rating": 4.6}, ], "rome": [ {"name": "Hotel Hassler Roma", "stars": 5, "base_price": 600, "rating": 4.7}, {"name": "Hotel de Russie Rome", "stars": 5, "base_price": 550, "rating": 4.6}, {"name": "St. Regis Rome", "stars": 5, "base_price": 500, "rating": 4.5}, {"name": "Rome Cavalieri Waldorf Astoria", "stars": 5, "base_price": 450, "rating": 4.6}, ], "bali": [ {"name": "Four Seasons Resort Bali at Sayan", "stars": 5, "base_price": 800, "rating": 4.9}, {"name": "The Mulia Bali", "stars": 5, "base_price": 500, "rating": 4.7}, {"name": "Ayana Resort and Spa Bali", "stars": 5, "base_price": 400, "rating": 4.6}, {"name": "St. Regis Bali Resort", "stars": 5, "base_price": 600, "rating": 4.8}, {"name": "The Legian Bali", "stars": 5, "base_price": 350, "rating": 4.5}, ], "new york": [ {"name": "The Plaza Hotel New York", "stars": 5, "base_price": 800, "rating": 4.6}, {"name": "The St. Regis New York", "stars": 5, "base_price": 900, "rating": 4.7}, {"name": "Mandarin Oriental New York", "stars": 5, "base_price": 750, "rating": 4.7}, {"name": "Four Seasons Hotel New York Downtown", "stars": 5, "base_price": 850, "rating": 4.6}, ], "maldives": [ {"name": "Soneva Fushi Maldives", "stars": 5, "base_price": 1800, "rating": 4.9}, {"name": "One&Only Reethi Rah Maldives", "stars": 5, "base_price": 1500, "rating": 4.8}, {"name": "Anantara Kihavah Maldives Villas", "stars": 5, "base_price": 1200, "rating": 4.8}, {"name": "Waldorf Astoria Maldives Ithaafushi", "stars": 5, "base_price": 2000, "rating": 4.9}, ], "santorini": [ {"name": "Grace Hotel Santorini", "stars": 5, "base_price": 800, "rating": 4.8}, {"name": "Canaves Oia Santorini", "stars": 5, "base_price": 700, "rating": 4.7}, {"name": "Andronis Luxury Suites", "stars": 5, "base_price": 900, "rating": 4.9}, {"name": "Mystique Santorini", "stars": 5, "base_price": 650, "rating": 4.6}, ], "barcelona": [ {"name": "Hotel Arts Barcelona", "stars": 5, "base_price": 450, "rating": 4.6}, {"name": "W Barcelona", "stars": 5, "base_price": 400, "rating": 4.5}, {"name": "Mandarin Oriental Barcelona", "stars": 5, "base_price": 550, "rating": 4.7}, {"name": "Majestic Hotel & Spa Barcelona", "stars": 5, "base_price": 350, "rating": 4.5}, ], "amsterdam": [ {"name": "Waldorf Astoria Amsterdam", "stars": 5, "base_price": 600, "rating": 4.7}, {"name": "Conservatorium Hotel Amsterdam", "stars": 5, "base_price": 500, "rating": 4.6}, {"name": "The Dylan Amsterdam", "stars": 5, "base_price": 450, "rating": 4.6}, {"name": "InterContinental Amstel Amsterdam", "stars": 5, "base_price": 550, "rating": 4.7}, ], "sydney": [ {"name": "Park Hyatt Sydney", "stars": 5, "base_price": 650, "rating": 4.8}, {"name": "Four Seasons Hotel Sydney", "stars": 5, "base_price": 550, "rating": 4.6}, {"name": "Shangri-La Hotel Sydney", "stars": 5, "base_price": 450, "rating": 4.5}, {"name": "The Langham Sydney", "stars": 5, "base_price": 400, "rating": 4.5}, ], "singapore": [ {"name": "Marina Bay Sands Singapore", "stars": 5, "base_price": 500, "rating": 4.6}, {"name": "Raffles Hotel Singapore", "stars": 5, "base_price": 800, "rating": 4.8}, {"name": "The Fullerton Hotel Singapore", "stars": 5, "base_price": 400, "rating": 4.6}, {"name": "Capella Singapore", "stars": 5, "base_price": 700, "rating": 4.8}, ], "bangkok": [ {"name": "Mandarin Oriental Bangkok", "stars": 5, "base_price": 400, "rating": 4.8}, {"name": "The Peninsula Bangkok", "stars": 5, "base_price": 350, "rating": 4.7}, {"name": "Shangri-La Hotel Bangkok", "stars": 5, "base_price": 250, "rating": 4.5}, {"name": "Four Seasons Hotel Bangkok", "stars": 5, "base_price": 450, "rating": 4.7}, ], "bucharest": [ {"name": "JW Marriott Bucharest Grand Hotel", "stars": 5, "base_price": 180, "rating": 4.6}, {"name": "InterContinental Bucharest", "stars": 5, "base_price": 150, "rating": 4.5}, {"name": "Radisson Blu Hotel Bucharest", "stars": 5, "base_price": 120, "rating": 4.4}, {"name": "Sheraton Bucharest Hotel", "stars": 5, "base_price": 140, "rating": 4.5}, {"name": "Hilton Garden Inn Bucharest", "stars": 4, "base_price": 90, "rating": 4.4}, ], "cairo": [ {"name": "Four Seasons Hotel Cairo at The First Residence", "stars": 5, "base_price": 350, "rating": 4.7}, {"name": "Marriott Mena House Cairo", "stars": 5, "base_price": 300, "rating": 4.6}, {"name": "The Nile Ritz-Carlton Cairo", "stars": 5, "base_price": 280, "rating": 4.5}, {"name": "Kempinski Nile Hotel Cairo", "stars": 5, "base_price": 250, "rating": 4.5}, ], "marrakech": [ {"name": "Royal Mansour Marrakech", "stars": 5, "base_price": 1200, "rating": 4.9}, {"name": "La Mamounia Marrakech", "stars": 5, "base_price": 700, "rating": 4.8}, {"name": "Four Seasons Resort Marrakech", "stars": 5, "base_price": 600, "rating": 4.7}, {"name": "Mandarin Oriental Marrakech", "stars": 5, "base_price": 550, "rating": 4.7}, ], "istanbul": [ {"name": "Four Seasons Hotel Istanbul at Sultanahmet", "stars": 5, "base_price": 450, "rating": 4.8}, {"name": "Ciragan Palace Kempinski Istanbul", "stars": 5, "base_price": 500, "rating": 4.7}, {"name": "The St. Regis Istanbul", "stars": 5, "base_price": 400, "rating": 4.6}, {"name": "Raffles Istanbul", "stars": 5, "base_price": 380, "rating": 4.6}, ], } # Generic luxury hotel chains for unknown destinations GENERIC_HOTELS = [ {"chain": "JW Marriott", "stars": 5, "base_price": 300, "rating": 4.6}, {"chain": "Hilton", "stars": 5, "base_price": 250, "rating": 4.5}, {"chain": "InterContinental", "stars": 5, "base_price": 280, "rating": 4.5}, {"chain": "Hyatt Regency", "stars": 5, "base_price": 260, "rating": 4.5}, {"chain": "Sheraton", "stars": 5, "base_price": 220, "rating": 4.4}, {"chain": "Radisson Blu", "stars": 4, "base_price": 180, "rating": 4.4}, ] def get_hotels_for_destination(location: str, stars: int): """Get hotels for a specific destination.""" location_lower = location.lower().split(",")[0].strip() # Check for known destinations for key in DESTINATION_HOTELS: if key in location_lower: hotels = DESTINATION_HOTELS[key] # Filter by stars if needed if stars < 5: return [h for h in hotels if h.get("stars", 5) <= stars + 1] return hotels # For unknown destinations, generate hotels with the destination name location_clean = location.split(",")[0].strip() return [ {"name": f"{h['chain']} {location_clean}", "stars": h["stars"], "base_price": h["base_price"], "rating": h["rating"]} for h in GENERIC_HOTELS ] @mcp.tool() def search_hotels(location: str, check_in: str, check_out: str, stars: int = 4) -> str: """Search for hotels in a specific location. Returns a list of hotel options with booking links.""" try: d1 = datetime.strptime(check_in, "%Y-%m-%d") d2 = datetime.strptime(check_out, "%Y-%m-%d") nights = (d2 - d1).days check_in_fmt = d1.strftime("%B %d") check_out_fmt = d2.strftime("%B %d, %Y") if nights < 1: return "Error: Check-out must be after check-in." except ValueError: return "Error: Dates must be in YYYY-MM-DD format." # Clean location for URLs location_clean = location.split(",")[0].strip() location_encoded = urllib.parse.quote(location) # Full location for search results = [] results.append(f"🏨 **Hotels in {location}**") results.append(f"📅 {check_in_fmt} - {check_out_fmt} ({nights} night{'s' if nights > 1 else ''})") results.append("") results.append("---") # Get destination-specific hotels available_hotels = get_hotels_for_destination(location, stars) selected_hotels = random.sample(available_hotels, min(4, len(available_hotels))) for i, hotel in enumerate(selected_hotels, 1): # Calculate price with some variation price_var = random.uniform(0.9, 1.15) price_per_night = int(hotel["base_price"] * price_var) total_price = price_per_night * nights # Get rating with small variation rating = round(min(5.0, hotel["rating"] + random.uniform(-0.1, 0.1)), 1) reviews = random.randint(1000, 8000) star_emoji = "⭐" * hotel.get("stars", 5) # Build WORKING booking URLs # Booking.com - search for hotel name + location hotel_search = urllib.parse.quote(f"{hotel['name']}") booking_url = f"https://www.booking.com/searchresults.html?ss={hotel_search}&checkin={check_in}&checkout={check_out}&group_adults=2&no_rooms=1" # Hotels.com - search by destination (more reliable than hotel name) hotels_url = f"https://www.hotels.com/Hotel-Search?destination={location_encoded}&startDate={check_in}&endDate={check_out}&rooms=1&adults=2&sort=RECOMMENDED" # Google Hotels - most reliable for finding specific hotels google_url = f"https://www.google.com/travel/hotels/{location_encoded}?q={hotel_search}&dates={check_in}%20to%20{check_out}" # Amenities if hotel.get("stars", 5) >= 5: amenities = ["🏊 Pool", "🧖 Spa", "🍽️ Restaurant", "🏋️ Gym", "🛎️ Concierge"] else: amenities = ["📶 WiFi", "☕ Breakfast", "🏋️ Gym", "🅿️ Parking"] results.append("") results.append(f"### 🏨 Option {i}: {hotel['name']}") results.append(f"{star_emoji} • {rating}/5 ({reviews:,} reviews)") results.append(f"💰 **${price_per_night}/night** → **${total_price:,} total** for {nights} nights") results.append(f"✨ {' • '.join(amenities)}") results.append(f"🔗 [Booking.com]({booking_url}) | [Google Hotels]({google_url})") results.append("") results.append("---") results.append("") # General search link for more options results.append(f"🔍 **See all hotels:** [Search {location_clean} on Booking.com](https://www.booking.com/searchresults.html?ss={location_encoded}&checkin={check_in}&checkout={check_out}&group_adults=2)") return "\n".join(results) @mcp.tool() def get_hotel_details(hotel_name: str) -> str: """Get detailed information about a specific hotel.""" rating = round(random.uniform(4.3, 4.9), 1) reviews = random.randint(1000, 5000) return f"""🏨 **{hotel_name}** 📍 **Location:** Prime city center location ⭐ **Rating:** {rating}/5.0 ({reviews:,} guest reviews) **Premium Amenities:** • 🏊 Infinity rooftop pool with city views • 🧖 Full-service spa & wellness center • 🍽️ Award-winning restaurants & bars • 🏋️ State-of-the-art fitness center • 📶 Complimentary high-speed WiFi • 🛎️ 24-hour concierge service • 🚗 Valet parking available • 🛏️ Premium bedding & pillow menu **Check-in:** 3:00 PM | **Check-out:** 12:00 PM""" if __name__ == "__main__": mcp.run()