|
|
from mcp.server.fastmcp import FastMCP |
|
|
from datetime import datetime |
|
|
import random |
|
|
import urllib.parse |
|
|
|
|
|
|
|
|
mcp = FastMCP("HotelsAgent") |
|
|
|
|
|
|
|
|
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_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() |
|
|
|
|
|
|
|
|
for key in DESTINATION_HOTELS: |
|
|
if key in location_lower: |
|
|
hotels = DESTINATION_HOTELS[key] |
|
|
|
|
|
if stars < 5: |
|
|
return [h for h in hotels if h.get("stars", 5) <= stars + 1] |
|
|
return hotels |
|
|
|
|
|
|
|
|
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." |
|
|
|
|
|
|
|
|
location_clean = location.split(",")[0].strip() |
|
|
location_encoded = urllib.parse.quote(location) |
|
|
|
|
|
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("---") |
|
|
|
|
|
|
|
|
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): |
|
|
|
|
|
price_var = random.uniform(0.9, 1.15) |
|
|
price_per_night = int(hotel["base_price"] * price_var) |
|
|
total_price = price_per_night * nights |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
|
|
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_url = f"https://www.hotels.com/Hotel-Search?destination={location_encoded}&startDate={check_in}&endDate={check_out}&rooms=1&adults=2&sort=RECOMMENDED" |
|
|
|
|
|
|
|
|
google_url = f"https://www.google.com/travel/hotels/{location_encoded}?q={hotel_search}&dates={check_in}%20to%20{check_out}" |
|
|
|
|
|
|
|
|
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("") |
|
|
|
|
|
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() |
|
|
|