Upload hotels_server.py with huggingface_hub
Browse files- hotels_server.py +254 -0
hotels_server.py
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mcp.server.fastmcp import FastMCP
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
import random
|
| 4 |
+
import urllib.parse
|
| 5 |
+
|
| 6 |
+
# Initialize FastMCP server for Hotels
|
| 7 |
+
mcp = FastMCP("HotelsAgent")
|
| 8 |
+
|
| 9 |
+
# Destination-specific real hotels
|
| 10 |
+
DESTINATION_HOTELS = {
|
| 11 |
+
"dubai": [
|
| 12 |
+
{"name": "Burj Al Arab Jumeirah", "stars": 5, "base_price": 1500, "rating": 4.8},
|
| 13 |
+
{"name": "Atlantis The Palm", "stars": 5, "base_price": 450, "rating": 4.6},
|
| 14 |
+
{"name": "Armani Hotel Dubai", "stars": 5, "base_price": 600, "rating": 4.7},
|
| 15 |
+
{"name": "Jumeirah Beach Hotel", "stars": 5, "base_price": 400, "rating": 4.5},
|
| 16 |
+
{"name": "One&Only The Palm", "stars": 5, "base_price": 800, "rating": 4.8},
|
| 17 |
+
{"name": "Address Downtown Dubai", "stars": 5, "base_price": 350, "rating": 4.6},
|
| 18 |
+
],
|
| 19 |
+
"paris": [
|
| 20 |
+
{"name": "The Ritz Paris", "stars": 5, "base_price": 1200, "rating": 4.9},
|
| 21 |
+
{"name": "Four Seasons Hotel George V Paris", "stars": 5, "base_price": 1100, "rating": 4.8},
|
| 22 |
+
{"name": "Le Meurice Paris", "stars": 5, "base_price": 900, "rating": 4.7},
|
| 23 |
+
{"name": "Shangri-La Hotel Paris", "stars": 5, "base_price": 800, "rating": 4.7},
|
| 24 |
+
{"name": "Hotel Plaza Athenee Paris", "stars": 5, "base_price": 950, "rating": 4.8},
|
| 25 |
+
],
|
| 26 |
+
"tokyo": [
|
| 27 |
+
{"name": "The Peninsula Tokyo", "stars": 5, "base_price": 700, "rating": 4.8},
|
| 28 |
+
{"name": "Aman Tokyo", "stars": 5, "base_price": 1000, "rating": 4.9},
|
| 29 |
+
{"name": "Park Hyatt Tokyo", "stars": 5, "base_price": 600, "rating": 4.7},
|
| 30 |
+
{"name": "The Ritz-Carlton Tokyo", "stars": 5, "base_price": 650, "rating": 4.7},
|
| 31 |
+
{"name": "Mandarin Oriental Tokyo", "stars": 5, "base_price": 700, "rating": 4.8},
|
| 32 |
+
],
|
| 33 |
+
"london": [
|
| 34 |
+
{"name": "The Savoy London", "stars": 5, "base_price": 700, "rating": 4.7},
|
| 35 |
+
{"name": "Claridge's London", "stars": 5, "base_price": 800, "rating": 4.8},
|
| 36 |
+
{"name": "The Ritz London", "stars": 5, "base_price": 750, "rating": 4.7},
|
| 37 |
+
{"name": "Four Seasons Hotel London at Park Lane", "stars": 5, "base_price": 650, "rating": 4.6},
|
| 38 |
+
],
|
| 39 |
+
"rome": [
|
| 40 |
+
{"name": "Hotel Hassler Roma", "stars": 5, "base_price": 600, "rating": 4.7},
|
| 41 |
+
{"name": "Hotel de Russie Rome", "stars": 5, "base_price": 550, "rating": 4.6},
|
| 42 |
+
{"name": "St. Regis Rome", "stars": 5, "base_price": 500, "rating": 4.5},
|
| 43 |
+
{"name": "Rome Cavalieri Waldorf Astoria", "stars": 5, "base_price": 450, "rating": 4.6},
|
| 44 |
+
],
|
| 45 |
+
"bali": [
|
| 46 |
+
{"name": "Four Seasons Resort Bali at Sayan", "stars": 5, "base_price": 800, "rating": 4.9},
|
| 47 |
+
{"name": "The Mulia Bali", "stars": 5, "base_price": 500, "rating": 4.7},
|
| 48 |
+
{"name": "Ayana Resort and Spa Bali", "stars": 5, "base_price": 400, "rating": 4.6},
|
| 49 |
+
{"name": "St. Regis Bali Resort", "stars": 5, "base_price": 600, "rating": 4.8},
|
| 50 |
+
{"name": "The Legian Bali", "stars": 5, "base_price": 350, "rating": 4.5},
|
| 51 |
+
],
|
| 52 |
+
"new york": [
|
| 53 |
+
{"name": "The Plaza Hotel New York", "stars": 5, "base_price": 800, "rating": 4.6},
|
| 54 |
+
{"name": "The St. Regis New York", "stars": 5, "base_price": 900, "rating": 4.7},
|
| 55 |
+
{"name": "Mandarin Oriental New York", "stars": 5, "base_price": 750, "rating": 4.7},
|
| 56 |
+
{"name": "Four Seasons Hotel New York Downtown", "stars": 5, "base_price": 850, "rating": 4.6},
|
| 57 |
+
],
|
| 58 |
+
"maldives": [
|
| 59 |
+
{"name": "Soneva Fushi Maldives", "stars": 5, "base_price": 1800, "rating": 4.9},
|
| 60 |
+
{"name": "One&Only Reethi Rah Maldives", "stars": 5, "base_price": 1500, "rating": 4.8},
|
| 61 |
+
{"name": "Anantara Kihavah Maldives Villas", "stars": 5, "base_price": 1200, "rating": 4.8},
|
| 62 |
+
{"name": "Waldorf Astoria Maldives Ithaafushi", "stars": 5, "base_price": 2000, "rating": 4.9},
|
| 63 |
+
],
|
| 64 |
+
"santorini": [
|
| 65 |
+
{"name": "Grace Hotel Santorini", "stars": 5, "base_price": 800, "rating": 4.8},
|
| 66 |
+
{"name": "Canaves Oia Santorini", "stars": 5, "base_price": 700, "rating": 4.7},
|
| 67 |
+
{"name": "Andronis Luxury Suites", "stars": 5, "base_price": 900, "rating": 4.9},
|
| 68 |
+
{"name": "Mystique Santorini", "stars": 5, "base_price": 650, "rating": 4.6},
|
| 69 |
+
],
|
| 70 |
+
"barcelona": [
|
| 71 |
+
{"name": "Hotel Arts Barcelona", "stars": 5, "base_price": 450, "rating": 4.6},
|
| 72 |
+
{"name": "W Barcelona", "stars": 5, "base_price": 400, "rating": 4.5},
|
| 73 |
+
{"name": "Mandarin Oriental Barcelona", "stars": 5, "base_price": 550, "rating": 4.7},
|
| 74 |
+
{"name": "Majestic Hotel & Spa Barcelona", "stars": 5, "base_price": 350, "rating": 4.5},
|
| 75 |
+
],
|
| 76 |
+
"amsterdam": [
|
| 77 |
+
{"name": "Waldorf Astoria Amsterdam", "stars": 5, "base_price": 600, "rating": 4.7},
|
| 78 |
+
{"name": "Conservatorium Hotel Amsterdam", "stars": 5, "base_price": 500, "rating": 4.6},
|
| 79 |
+
{"name": "The Dylan Amsterdam", "stars": 5, "base_price": 450, "rating": 4.6},
|
| 80 |
+
{"name": "InterContinental Amstel Amsterdam", "stars": 5, "base_price": 550, "rating": 4.7},
|
| 81 |
+
],
|
| 82 |
+
"sydney": [
|
| 83 |
+
{"name": "Park Hyatt Sydney", "stars": 5, "base_price": 650, "rating": 4.8},
|
| 84 |
+
{"name": "Four Seasons Hotel Sydney", "stars": 5, "base_price": 550, "rating": 4.6},
|
| 85 |
+
{"name": "Shangri-La Hotel Sydney", "stars": 5, "base_price": 450, "rating": 4.5},
|
| 86 |
+
{"name": "The Langham Sydney", "stars": 5, "base_price": 400, "rating": 4.5},
|
| 87 |
+
],
|
| 88 |
+
"singapore": [
|
| 89 |
+
{"name": "Marina Bay Sands Singapore", "stars": 5, "base_price": 500, "rating": 4.6},
|
| 90 |
+
{"name": "Raffles Hotel Singapore", "stars": 5, "base_price": 800, "rating": 4.8},
|
| 91 |
+
{"name": "The Fullerton Hotel Singapore", "stars": 5, "base_price": 400, "rating": 4.6},
|
| 92 |
+
{"name": "Capella Singapore", "stars": 5, "base_price": 700, "rating": 4.8},
|
| 93 |
+
],
|
| 94 |
+
"bangkok": [
|
| 95 |
+
{"name": "Mandarin Oriental Bangkok", "stars": 5, "base_price": 400, "rating": 4.8},
|
| 96 |
+
{"name": "The Peninsula Bangkok", "stars": 5, "base_price": 350, "rating": 4.7},
|
| 97 |
+
{"name": "Shangri-La Hotel Bangkok", "stars": 5, "base_price": 250, "rating": 4.5},
|
| 98 |
+
{"name": "Four Seasons Hotel Bangkok", "stars": 5, "base_price": 450, "rating": 4.7},
|
| 99 |
+
],
|
| 100 |
+
"bucharest": [
|
| 101 |
+
{"name": "JW Marriott Bucharest Grand Hotel", "stars": 5, "base_price": 180, "rating": 4.6},
|
| 102 |
+
{"name": "InterContinental Bucharest", "stars": 5, "base_price": 150, "rating": 4.5},
|
| 103 |
+
{"name": "Radisson Blu Hotel Bucharest", "stars": 5, "base_price": 120, "rating": 4.4},
|
| 104 |
+
{"name": "Sheraton Bucharest Hotel", "stars": 5, "base_price": 140, "rating": 4.5},
|
| 105 |
+
{"name": "Hilton Garden Inn Bucharest", "stars": 4, "base_price": 90, "rating": 4.4},
|
| 106 |
+
],
|
| 107 |
+
"cairo": [
|
| 108 |
+
{"name": "Four Seasons Hotel Cairo at The First Residence", "stars": 5, "base_price": 350, "rating": 4.7},
|
| 109 |
+
{"name": "Marriott Mena House Cairo", "stars": 5, "base_price": 300, "rating": 4.6},
|
| 110 |
+
{"name": "The Nile Ritz-Carlton Cairo", "stars": 5, "base_price": 280, "rating": 4.5},
|
| 111 |
+
{"name": "Kempinski Nile Hotel Cairo", "stars": 5, "base_price": 250, "rating": 4.5},
|
| 112 |
+
],
|
| 113 |
+
"marrakech": [
|
| 114 |
+
{"name": "Royal Mansour Marrakech", "stars": 5, "base_price": 1200, "rating": 4.9},
|
| 115 |
+
{"name": "La Mamounia Marrakech", "stars": 5, "base_price": 700, "rating": 4.8},
|
| 116 |
+
{"name": "Four Seasons Resort Marrakech", "stars": 5, "base_price": 600, "rating": 4.7},
|
| 117 |
+
{"name": "Mandarin Oriental Marrakech", "stars": 5, "base_price": 550, "rating": 4.7},
|
| 118 |
+
],
|
| 119 |
+
"istanbul": [
|
| 120 |
+
{"name": "Four Seasons Hotel Istanbul at Sultanahmet", "stars": 5, "base_price": 450, "rating": 4.8},
|
| 121 |
+
{"name": "Ciragan Palace Kempinski Istanbul", "stars": 5, "base_price": 500, "rating": 4.7},
|
| 122 |
+
{"name": "The St. Regis Istanbul", "stars": 5, "base_price": 400, "rating": 4.6},
|
| 123 |
+
{"name": "Raffles Istanbul", "stars": 5, "base_price": 380, "rating": 4.6},
|
| 124 |
+
],
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
# Generic luxury hotel chains for unknown destinations
|
| 128 |
+
GENERIC_HOTELS = [
|
| 129 |
+
{"chain": "JW Marriott", "stars": 5, "base_price": 300, "rating": 4.6},
|
| 130 |
+
{"chain": "Hilton", "stars": 5, "base_price": 250, "rating": 4.5},
|
| 131 |
+
{"chain": "InterContinental", "stars": 5, "base_price": 280, "rating": 4.5},
|
| 132 |
+
{"chain": "Hyatt Regency", "stars": 5, "base_price": 260, "rating": 4.5},
|
| 133 |
+
{"chain": "Sheraton", "stars": 5, "base_price": 220, "rating": 4.4},
|
| 134 |
+
{"chain": "Radisson Blu", "stars": 4, "base_price": 180, "rating": 4.4},
|
| 135 |
+
]
|
| 136 |
+
|
| 137 |
+
def get_hotels_for_destination(location: str, stars: int):
|
| 138 |
+
"""Get hotels for a specific destination."""
|
| 139 |
+
location_lower = location.lower().split(",")[0].strip()
|
| 140 |
+
|
| 141 |
+
# Check for known destinations
|
| 142 |
+
for key in DESTINATION_HOTELS:
|
| 143 |
+
if key in location_lower:
|
| 144 |
+
hotels = DESTINATION_HOTELS[key]
|
| 145 |
+
# Filter by stars if needed
|
| 146 |
+
if stars < 5:
|
| 147 |
+
return [h for h in hotels if h.get("stars", 5) <= stars + 1]
|
| 148 |
+
return hotels
|
| 149 |
+
|
| 150 |
+
# For unknown destinations, generate hotels with the destination name
|
| 151 |
+
location_clean = location.split(",")[0].strip()
|
| 152 |
+
return [
|
| 153 |
+
{"name": f"{h['chain']} {location_clean}", "stars": h["stars"], "base_price": h["base_price"], "rating": h["rating"]}
|
| 154 |
+
for h in GENERIC_HOTELS
|
| 155 |
+
]
|
| 156 |
+
|
| 157 |
+
@mcp.tool()
|
| 158 |
+
def search_hotels(location: str, check_in: str, check_out: str, stars: int = 4) -> str:
|
| 159 |
+
"""Search for hotels in a specific location. Returns a list of hotel options with booking links."""
|
| 160 |
+
|
| 161 |
+
try:
|
| 162 |
+
d1 = datetime.strptime(check_in, "%Y-%m-%d")
|
| 163 |
+
d2 = datetime.strptime(check_out, "%Y-%m-%d")
|
| 164 |
+
nights = (d2 - d1).days
|
| 165 |
+
check_in_fmt = d1.strftime("%B %d")
|
| 166 |
+
check_out_fmt = d2.strftime("%B %d, %Y")
|
| 167 |
+
if nights < 1:
|
| 168 |
+
return "Error: Check-out must be after check-in."
|
| 169 |
+
except ValueError:
|
| 170 |
+
return "Error: Dates must be in YYYY-MM-DD format."
|
| 171 |
+
|
| 172 |
+
# Clean location for URLs
|
| 173 |
+
location_clean = location.split(",")[0].strip()
|
| 174 |
+
location_encoded = urllib.parse.quote(location) # Full location for search
|
| 175 |
+
|
| 176 |
+
results = []
|
| 177 |
+
results.append(f"🏨 **Hotels in {location}**")
|
| 178 |
+
results.append(f"📅 {check_in_fmt} - {check_out_fmt} ({nights} night{'s' if nights > 1 else ''})")
|
| 179 |
+
results.append("")
|
| 180 |
+
results.append("---")
|
| 181 |
+
|
| 182 |
+
# Get destination-specific hotels
|
| 183 |
+
available_hotels = get_hotels_for_destination(location, stars)
|
| 184 |
+
selected_hotels = random.sample(available_hotels, min(4, len(available_hotels)))
|
| 185 |
+
|
| 186 |
+
for i, hotel in enumerate(selected_hotels, 1):
|
| 187 |
+
# Calculate price with some variation
|
| 188 |
+
price_var = random.uniform(0.9, 1.15)
|
| 189 |
+
price_per_night = int(hotel["base_price"] * price_var)
|
| 190 |
+
total_price = price_per_night * nights
|
| 191 |
+
|
| 192 |
+
# Get rating with small variation
|
| 193 |
+
rating = round(min(5.0, hotel["rating"] + random.uniform(-0.1, 0.1)), 1)
|
| 194 |
+
reviews = random.randint(1000, 8000)
|
| 195 |
+
|
| 196 |
+
star_emoji = "⭐" * hotel.get("stars", 5)
|
| 197 |
+
|
| 198 |
+
# Build WORKING booking URLs
|
| 199 |
+
# Booking.com - search for hotel name + location
|
| 200 |
+
hotel_search = urllib.parse.quote(f"{hotel['name']}")
|
| 201 |
+
booking_url = f"https://www.booking.com/searchresults.html?ss={hotel_search}&checkin={check_in}&checkout={check_out}&group_adults=2&no_rooms=1"
|
| 202 |
+
|
| 203 |
+
# Hotels.com - search by destination (more reliable than hotel name)
|
| 204 |
+
hotels_url = f"https://www.hotels.com/Hotel-Search?destination={location_encoded}&startDate={check_in}&endDate={check_out}&rooms=1&adults=2&sort=RECOMMENDED"
|
| 205 |
+
|
| 206 |
+
# Google Hotels - most reliable for finding specific hotels
|
| 207 |
+
google_url = f"https://www.google.com/travel/hotels/{location_encoded}?q={hotel_search}&dates={check_in}%20to%20{check_out}"
|
| 208 |
+
|
| 209 |
+
# Amenities
|
| 210 |
+
if hotel.get("stars", 5) >= 5:
|
| 211 |
+
amenities = ["🏊 Pool", "🧖 Spa", "🍽️ Restaurant", "🏋️ Gym", "🛎️ Concierge"]
|
| 212 |
+
else:
|
| 213 |
+
amenities = ["📶 WiFi", "☕ Breakfast", "🏋️ Gym", "🅿️ Parking"]
|
| 214 |
+
|
| 215 |
+
results.append("")
|
| 216 |
+
results.append(f"### 🏨 Option {i}: {hotel['name']}")
|
| 217 |
+
results.append(f"{star_emoji} • {rating}/5 ({reviews:,} reviews)")
|
| 218 |
+
results.append(f"💰 **${price_per_night}/night** → **${total_price:,} total** for {nights} nights")
|
| 219 |
+
results.append(f"✨ {' • '.join(amenities)}")
|
| 220 |
+
results.append(f"🔗 [Booking.com]({booking_url}) | [Google Hotels]({google_url})")
|
| 221 |
+
results.append("")
|
| 222 |
+
|
| 223 |
+
results.append("---")
|
| 224 |
+
results.append("")
|
| 225 |
+
# General search link for more options
|
| 226 |
+
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)")
|
| 227 |
+
|
| 228 |
+
return "\n".join(results)
|
| 229 |
+
|
| 230 |
+
@mcp.tool()
|
| 231 |
+
def get_hotel_details(hotel_name: str) -> str:
|
| 232 |
+
"""Get detailed information about a specific hotel."""
|
| 233 |
+
rating = round(random.uniform(4.3, 4.9), 1)
|
| 234 |
+
reviews = random.randint(1000, 5000)
|
| 235 |
+
|
| 236 |
+
return f"""🏨 **{hotel_name}**
|
| 237 |
+
|
| 238 |
+
📍 **Location:** Prime city center location
|
| 239 |
+
⭐ **Rating:** {rating}/5.0 ({reviews:,} guest reviews)
|
| 240 |
+
|
| 241 |
+
**Premium Amenities:**
|
| 242 |
+
• 🏊 Infinity rooftop pool with city views
|
| 243 |
+
• 🧖 Full-service spa & wellness center
|
| 244 |
+
• 🍽️ Award-winning restaurants & bars
|
| 245 |
+
• 🏋️ State-of-the-art fitness center
|
| 246 |
+
• 📶 Complimentary high-speed WiFi
|
| 247 |
+
• 🛎️ 24-hour concierge service
|
| 248 |
+
• 🚗 Valet parking available
|
| 249 |
+
• 🛏️ Premium bedding & pillow menu
|
| 250 |
+
|
| 251 |
+
**Check-in:** 3:00 PM | **Check-out:** 12:00 PM"""
|
| 252 |
+
|
| 253 |
+
if __name__ == "__main__":
|
| 254 |
+
mcp.run()
|