Skip to main content
Glama
BQ31X

Tavily Web Search MCP Server

by BQ31X
get_appointment_weather_fixed.py6.75 kB
import os import requests from datetime import datetime from zoneinfo import ZoneInfo from dotenv import load_dotenv def get_upcoming_appointments(api_key): """Fetches upcoming appointments from the Cal.com API.""" print("Retrieving upcoming appointments...") url = f"https://api.cal.com/v1/bookings?apiKey={api_key}&status=upcoming" try: response = requests.get(url) response.raise_for_status() bookings = response.json().get("bookings", []) # Ensure we only process appointments that are not cancelled and sort them. accepted_bookings = sorted( [b for b in bookings if b.get("status") == "ACCEPTED"], key=lambda b: b['startTime'] ) return accepted_bookings except requests.exceptions.RequestException as e: print(f"Error fetching appointments: {e}") return [] def get_weather_for_location(location): """Gets current weather for a location using a free weather API.""" try: # Using wttr.in - a free weather service that returns JSON url = f"https://wttr.in/{location}?format=j1" response = requests.get(url, timeout=10) response.raise_for_status() data = response.json() if 'current_condition' in data and data['current_condition']: current = data['current_condition'][0] return { 'temperature_f': current.get('temp_F', 'Unknown'), 'temperature_c': current.get('temp_C', 'Unknown'), 'condition': current.get('weatherDesc', [{}])[0].get('value', 'Unknown'), 'humidity': current.get('humidity', 'Unknown'), 'wind_mph': current.get('windspeedMiles', 'Unknown'), 'wind_dir': current.get('winddir16Point', 'Unknown') } except Exception as e: print(f"Error fetching weather: {e}") return None def extract_location_from_booking(booking): """ Enhanced location extraction with multiple fallback strategies. Based on Cal.com webhook documentation analysis via MCP Context7. """ # Strategy 1: Check top-level location field (most reliable) location = booking.get('location') if location and isinstance(location, str) and location.strip(): if not location.startswith('integrations:') and 'http' not in location: print(f"✅ Found location in top-level field: {location}") return location.strip() # Strategy 2: Check responses.location structure (legacy format) responses = booking.get('responses', {}) if isinstance(responses, dict): location_response = responses.get('location', {}) if isinstance(location_response, dict): # Handle nested value structure location_value = location_response.get('value') if isinstance(location_value, dict): location = location_value.get('value') elif isinstance(location_value, str): location = location_value if location and isinstance(location, str) and location.strip(): if not location.startswith('integrations:') and 'http' not in location: print(f"✅ Found location in responses field: {location}") return location.strip() # Strategy 3: Extract from event title or description title = booking.get('title', '') if 'at ' in title.lower(): potential_location = title.lower().split('at ')[-1].strip() if len(potential_location) > 2 and len(potential_location) < 50: print(f"✅ Extracted location from title: {potential_location}") return potential_location return None def display_summary(appointment, weather, location): """Displays a summary of the appointment and weather forecast.""" # Convert UTC time string from API to a local datetime object for display utc_start_time = datetime.fromisoformat(appointment['startTime'].replace('Z', '+00:00')) local_tz = ZoneInfo(appointment.get("user", {}).get("timeZone") or "America/New_York") local_start_time = utc_start_time.astimezone(local_tz) print("\n" + "="*60) print("🗓️ APPOINTMENT & WEATHER SUMMARY") print("="*60) print(f"📋 Meeting: {appointment['title']}") print(f"🕐 When: {local_start_time.strftime('%A, %B %d, %Y, at %I:%M %p %Z')}") print(f"📍 Where: {location}") if weather: print(f"\n🌤️ WEATHER FORECAST FOR {location.upper()}:") print(f" 🌡️ Temperature: {weather['temperature_f']}°F ({weather['temperature_c']}°C)") print(f" ☁️ Conditions: {weather['condition']}") print(f" 💨 Wind: {weather['wind_mph']} mph {weather['wind_dir']}") print(f" 💧 Humidity: {weather['humidity']}%") else: print(f"\n❌ Could not retrieve weather forecast for {location}") print("="*60) def main(): """Main function to run the script.""" load_dotenv() cal_api_key = os.getenv("CALCOM_API_KEY") if not cal_api_key: print("Error: CALCOM_API_KEY not found. Please check your .env file.") return appointments = get_upcoming_appointments(cal_api_key) if not appointments: print("No upcoming appointments found.") return print(f"\n📅 Found {len(appointments)} upcoming appointment(s):") print("-" * 50) for i, appt in enumerate(appointments): # Convert UTC time for display in the menu utc_start = datetime.fromisoformat(appt['startTime'].replace('Z', '+00:00')) local_tz = ZoneInfo(appt.get("user", {}).get("timeZone") or "America/New_York") local_start = utc_start.astimezone(local_tz) print(f" {i+1}: {appt['title']} on {local_start.strftime('%a, %b %d at %I:%M %p %Z')}") try: choice = int(input(f"\nSelect appointment (1-{len(appointments)}): ")) - 1 if not 0 <= choice < len(appointments): raise ValueError except ValueError: print("❌ Invalid selection.") return selected_appointment = appointments[choice] # Use enhanced location extraction location = extract_location_from_booking(selected_appointment) if not location: print("\n❌ No physical location found for this appointment.") print("💡 Weather lookup requires a city name or address in the appointment location.") return print(f"\n🔍 Looking up weather for: {location}") weather = get_weather_for_location(location) display_summary(selected_appointment, weather, location) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BQ31X/MCP-Session-Code'

If you have feedback or need assistance with the MCP directory API, please join our Discord server