mirror of
https://github.com/Shubhamsaboo/awesome-llm-apps.git
synced 2026-04-30 07:08:44 -05:00
Merge pull request #181 from priyanshm07/ai-travel-planner-mcp-team
Added new demo: AI Travel Planning agent
This commit is contained in:
118
mcp_ai_agents/ai_travel_planner_mcp_agent_team/README.md
Normal file
118
mcp_ai_agents/ai_travel_planner_mcp_agent_team/README.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
## 🌍 AI Travel Planner Agent
|
||||||
|
|
||||||
|
This is a Streamlit-based application that helps users plan their travel itineraries using AI. The app integrates with various mcp servers to provide a comprehensive travel planning experience, including weather forecasts, maps, and calendar integration.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
## MCP Servers Integration
|
||||||
|
|
||||||
|
This project utilizes several MCP (Model Context Protocol) servers to provide a comprehensive travel planning experience:
|
||||||
|
|
||||||
|
### 1. Weather MCP Server
|
||||||
|
- **Functionality**: Provides real-time weather data and forecasts
|
||||||
|
|
||||||
|
### 2. Maps MCP Server
|
||||||
|
- **Functionality**: Handles location-based services and navigation
|
||||||
|
- **Features**:
|
||||||
|
- Search for places and points of interest
|
||||||
|
- Get detailed place information
|
||||||
|
- Retrieve driving/walking directions
|
||||||
|
|
||||||
|
### 3. Calendar MCP Server
|
||||||
|
- **Functionality**: Manages calendar events and scheduling
|
||||||
|
- **Features**:
|
||||||
|
- Create and manage calendar events
|
||||||
|
- Handle time zone conversions
|
||||||
|
- Schedule reminders and notifications
|
||||||
|
- **Integration**: Implemented in `calendar_mcp.py`
|
||||||
|
|
||||||
|
### 4. Booking MCP Server
|
||||||
|
- **Functionality**: Airbnb MCP server used
|
||||||
|
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
1. **API Keys and Credentials**:
|
||||||
|
- **Google Maps API Key**: Set up a Google Maps API Key from Google Cloud Console
|
||||||
|
- **Google Calendar API**: Enable and configure the Calendar API Key
|
||||||
|
- **Google OAuth Credentials**: Client ID and Client Secret and Refresh Token for authentication
|
||||||
|
- **AccuWeather API KEY**: Get AccuWeather API key https://developer.accuweather.com/
|
||||||
|
- **OpenAI API Key**: Sign up at OpenAI to obtain your API key.
|
||||||
|
|
||||||
|
2. **Python 3.8+**: Ensure you have Python 3.8 or higher installed.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. Clone this repository:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/ai_travel_planner_mcp_agent_team
|
||||||
|
cd ai_travel_planner_mcp_agent_team
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install the required Python packages:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Set up environment variables:
|
||||||
|
Create a `.env` file in the project root with the following variables:
|
||||||
|
```
|
||||||
|
GOOGLE_CLIENT_ID=
|
||||||
|
GOOGLE_CLIENT_SECRET=
|
||||||
|
GOOGLE_REFRESH_TOKEN=
|
||||||
|
GOOGLE_MAPS_API_KEY=
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
ACCUWEATHER_API_KEY=
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the App
|
||||||
|
|
||||||
|
1. Generate OAuth token for Google Calendar
|
||||||
|
|
||||||
|
2. Start the Streamlit app:
|
||||||
|
```bash
|
||||||
|
streamlit run app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
3. In the app interface:
|
||||||
|
- Use the sidebar to configure your preferences
|
||||||
|
- Enter your travel details
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
- `app.py`: Main Streamlit application
|
||||||
|
- `calendar_mcp.py`: Calendar mcp integration functionality
|
||||||
|
- `requirements.txt`: Project dependencies
|
||||||
|
- `.env`: Environment variables
|
||||||
|
|
||||||
|
## Calendar MCP Integration
|
||||||
|
|
||||||
|
The `calendar_mcp.py` module provides seamless integration with Google Calendar through the MCP (Model Context Protocol) framework. This integration allows the travel planner to:
|
||||||
|
|
||||||
|
- **Create Events**: Automatically create calendar events for travel activities, flights, and accommodations
|
||||||
|
- **Schedule Management**: Handle time zone conversions and scheduling conflicts
|
||||||
|
- **Event Details**: Include comprehensive event information such as:
|
||||||
|
- Location details with Google Maps links
|
||||||
|
- Weather forecasts for the event time
|
||||||
|
- Travel duration and transportation details
|
||||||
|
- Notes and reminders
|
||||||
|
|
||||||
|
### Calendar Setup
|
||||||
|
|
||||||
|
1. **OAuth Authentication**:
|
||||||
|
- The application uses OAuth 2.0 for secure authentication with Google Calendar
|
||||||
|
- First-time setup requires generating refresh token
|
||||||
|
- Refresh tokens are stored securely in the `.env` file
|
||||||
|
|
||||||
|
2. **Event Creation**:
|
||||||
|
```python
|
||||||
|
# Example of creating a calendar event
|
||||||
|
event = {
|
||||||
|
'summary': 'Flight to Paris',
|
||||||
|
'location': 'Charles de Gaulle Airport',
|
||||||
|
'description': 'Flight details and weather forecast',
|
||||||
|
'start': {'dateTime': '2024-04-20T10:00:00', 'timeZone': 'Europe/Paris'},
|
||||||
|
'end': {'dateTime': '2024-04-20T12:00:00', 'timeZone': 'Europe/Paris'}
|
||||||
|
}
|
||||||
|
```
|
||||||
356
mcp_ai_agents/ai_travel_planner_mcp_agent_team/app.py
Normal file
356
mcp_ai_agents/ai_travel_planner_mcp_agent_team/app.py
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
|
||||||
|
from agno.agent import Agent
|
||||||
|
from agno.team.team import Team
|
||||||
|
from agno.tools.mcp import MultiMCPTools
|
||||||
|
from agno.models.openai import OpenAIChat
|
||||||
|
import streamlit as st
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
# Remove dotenv import and loading since we'll use sidebar
|
||||||
|
# from dotenv import load_dotenv
|
||||||
|
# load_dotenv()
|
||||||
|
|
||||||
|
async def run_agent(message: str):
|
||||||
|
"""Run the Airbnb, Google Maps, Weather and Calendar agent with the given message."""
|
||||||
|
|
||||||
|
# Get API keys from session state
|
||||||
|
google_maps_key = st.session_state.get('google_maps_key')
|
||||||
|
accuweather_key = st.session_state.get('accuweather_key')
|
||||||
|
openai_key = st.session_state.get('openai_key')
|
||||||
|
google_client_id = st.session_state.get('google_client_id')
|
||||||
|
google_client_secret = st.session_state.get('google_client_secret')
|
||||||
|
google_refresh_token = st.session_state.get('google_refresh_token')
|
||||||
|
|
||||||
|
if not google_maps_key:
|
||||||
|
raise ValueError("🚨 Missing Google Maps API Key. Please enter it in the sidebar.")
|
||||||
|
elif not accuweather_key:
|
||||||
|
raise ValueError("🚨 Missing AccuWeather API Key. Please enter it in the sidebar.")
|
||||||
|
elif not openai_key:
|
||||||
|
raise ValueError("🚨 Missing OpenAI API Key. Please enter it in the sidebar.")
|
||||||
|
elif not google_client_id:
|
||||||
|
raise ValueError("🚨 Missing Google Client ID. Please enter it in the sidebar.")
|
||||||
|
elif not google_client_secret:
|
||||||
|
raise ValueError("🚨 Missing Google Client Secret. Please enter it in the sidebar.")
|
||||||
|
elif not google_refresh_token:
|
||||||
|
raise ValueError("🚨 Missing Google Refresh Token. Please enter it in the sidebar.")
|
||||||
|
|
||||||
|
# 👉 Set OPENAI_API_KEY globally
|
||||||
|
os.environ["OPENAI_API_KEY"] = openai_key
|
||||||
|
|
||||||
|
env = {
|
||||||
|
**os.environ,
|
||||||
|
"GOOGLE_MAPS_API_KEY": google_maps_key,
|
||||||
|
"ACCUWEATHER_API_KEY": accuweather_key,
|
||||||
|
"OPENAI_API_KEY": openai_key,
|
||||||
|
"GOOGLE_CLIENT_ID": google_client_id,
|
||||||
|
"GOOGLE_CLIENT_SECRET": google_client_secret,
|
||||||
|
"GOOGLE_REFRESH_TOKEN": google_refresh_token
|
||||||
|
}
|
||||||
|
|
||||||
|
async with MultiMCPTools(
|
||||||
|
[
|
||||||
|
"npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt", # ✅ Airbnb mcp added
|
||||||
|
"npx -y @modelcontextprotocol/server-google-maps", # ✅ Google Maps mcp added
|
||||||
|
"uvx --from git+https://github.com/adhikasp/mcp-weather.git mcp-weather", # ✅ Weather mcp added
|
||||||
|
"./calendar_mcp.py"
|
||||||
|
],
|
||||||
|
env=env,
|
||||||
|
) as mcp_tools:
|
||||||
|
|
||||||
|
#Define specialized agents with enhanced instructions
|
||||||
|
maps_agent = Agent(
|
||||||
|
tools=[mcp_tools],
|
||||||
|
model=OpenAIChat(id="gpt-4o-mini", api_key=openai_key),
|
||||||
|
name="Maps Agent",
|
||||||
|
goal="""As a Maps Agent, your responsibilities include:
|
||||||
|
1. Finding optimal routes between locations
|
||||||
|
2. Identifying points of interest near destinations
|
||||||
|
3. Calculating travel times and distances
|
||||||
|
4. Suggesting transportation options
|
||||||
|
5. Finding nearby amenities and services
|
||||||
|
6. Providing location-based recommendations
|
||||||
|
|
||||||
|
Always consider:
|
||||||
|
- Traffic conditions and peak hours
|
||||||
|
- Alternative routes and transportation modes
|
||||||
|
- Accessibility and convenience
|
||||||
|
- Safety and well-lit areas
|
||||||
|
- Proximity to other planned activities"""
|
||||||
|
)
|
||||||
|
|
||||||
|
weather_agent = Agent(
|
||||||
|
tools=[mcp_tools],
|
||||||
|
name="Weather Agent",
|
||||||
|
model=OpenAIChat(id="gpt-4o-mini", api_key=openai_key),
|
||||||
|
goal="""As a Weather Agent, your responsibilities include:
|
||||||
|
1. Providing detailed weather forecasts for destinations
|
||||||
|
2. Alerting about severe weather conditions
|
||||||
|
3. Suggesting weather-appropriate activities
|
||||||
|
4. Recommending the best travel times based on the weather conditions.
|
||||||
|
5. Providing seasonal travel recommendations
|
||||||
|
|
||||||
|
Always consider:
|
||||||
|
- Temperature ranges and comfort levels
|
||||||
|
- Precipitation probability
|
||||||
|
- Wind conditions
|
||||||
|
- UV index and sun protection
|
||||||
|
- Seasonal variations
|
||||||
|
- Weather alerts and warnings"""
|
||||||
|
)
|
||||||
|
|
||||||
|
booking_agent = Agent(
|
||||||
|
tools=[mcp_tools],
|
||||||
|
name="Booking Agent",
|
||||||
|
model=OpenAIChat(id="gpt-4o-mini", api_key=openai_key),
|
||||||
|
goal="""As a Booking Agent, your responsibilities include:
|
||||||
|
1. Finding accommodations within budget on airbnb
|
||||||
|
2. Comparing prices across platforms
|
||||||
|
3. Checking availability for specific dates
|
||||||
|
4. Verifying amenities and policies
|
||||||
|
5. Finding last-minute deals when applicable
|
||||||
|
|
||||||
|
Always consider:
|
||||||
|
- Location convenience
|
||||||
|
- Price competitiveness
|
||||||
|
- Cancellation policies
|
||||||
|
- Guest reviews and ratings
|
||||||
|
- Amenities matching preferences
|
||||||
|
- Special requirements or accessibility needs"""
|
||||||
|
)
|
||||||
|
|
||||||
|
calendar_agent = Agent(
|
||||||
|
tools=[mcp_tools],
|
||||||
|
name="Calendar Agent",
|
||||||
|
model=OpenAIChat(id="gpt-4o-mini", api_key=openai_key),
|
||||||
|
goal="""As a Calendar Agent, your responsibilities include:
|
||||||
|
1. Creating detailed travel itineraries
|
||||||
|
2. Setting reminders for bookings and check-ins
|
||||||
|
3. Scheduling activities and reservations
|
||||||
|
4. Adding reminders for booking deadlines, check-ins, and other important events.
|
||||||
|
5. Coordinating with other team members' schedules
|
||||||
|
|
||||||
|
Always consider:
|
||||||
|
- Time zone differences
|
||||||
|
- Travel duration between activities
|
||||||
|
- Buffer time for unexpected delays
|
||||||
|
- Important deadlines and check-in times
|
||||||
|
- Synchronization with other team members"""
|
||||||
|
)
|
||||||
|
|
||||||
|
team = Team(
|
||||||
|
members=[maps_agent, weather_agent, booking_agent, calendar_agent],
|
||||||
|
name="Travel Planning Team",
|
||||||
|
markdown=True,
|
||||||
|
show_tool_calls=True,
|
||||||
|
instructions="""As a Travel Planning Team, coordinate to create comprehensive travel plans:
|
||||||
|
1. Share information between agents to ensure consistency
|
||||||
|
2. Consider dependencies between different aspects of the trip
|
||||||
|
3. Prioritize user preferences and constraints
|
||||||
|
4. Provide backup options when primary choices are unavailable
|
||||||
|
5. Maintain a balance between planned activities and free time
|
||||||
|
6. Consider local events and seasonal factors
|
||||||
|
7. Ensure all recommendations align with the user's budget
|
||||||
|
8. Provide a detailed breakdown of the trip, including bookings, routes, weather, and planned activities.
|
||||||
|
9. Add the journey start date in the user calendar"""
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await team.arun(message)
|
||||||
|
output = result.messages[-1].content
|
||||||
|
return output
|
||||||
|
|
||||||
|
# -------------------- Streamlit App --------------------
|
||||||
|
|
||||||
|
# Configure the page
|
||||||
|
st.set_page_config(
|
||||||
|
page_title="AI Travel Planner",
|
||||||
|
page_icon="✈️",
|
||||||
|
layout="wide"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sidebar for API keys
|
||||||
|
with st.sidebar:
|
||||||
|
st.header("🔑 API Keys Configuration")
|
||||||
|
st.markdown("Please enter your API keys to use the travel planner.")
|
||||||
|
|
||||||
|
# Initialize session state for API keys if not exists
|
||||||
|
if 'google_maps_key' not in st.session_state:
|
||||||
|
st.session_state.google_maps_key = ""
|
||||||
|
if 'accuweather_key' not in st.session_state:
|
||||||
|
st.session_state.accuweather_key = ""
|
||||||
|
if 'openai_key' not in st.session_state:
|
||||||
|
st.session_state.openai_key = ""
|
||||||
|
if 'google_client_id' not in st.session_state:
|
||||||
|
st.session_state.google_client_id = ""
|
||||||
|
if 'google_client_secret' not in st.session_state:
|
||||||
|
st.session_state.google_client_secret = ""
|
||||||
|
if 'google_refresh_token' not in st.session_state:
|
||||||
|
st.session_state.google_refresh_token = ""
|
||||||
|
|
||||||
|
# API key input fields
|
||||||
|
st.session_state.google_maps_key = st.text_input(
|
||||||
|
"Google Maps API Key",
|
||||||
|
value=st.session_state.google_maps_key,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
st.session_state.accuweather_key = st.text_input(
|
||||||
|
"AccuWeather API Key",
|
||||||
|
value=st.session_state.accuweather_key,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
st.session_state.openai_key = st.text_input(
|
||||||
|
"OpenAI API Key",
|
||||||
|
value=st.session_state.openai_key,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
st.session_state.google_client_id = st.text_input(
|
||||||
|
"Google Client ID",
|
||||||
|
value=st.session_state.google_client_id,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
st.session_state.google_client_secret = st.text_input(
|
||||||
|
"Google Client Secret",
|
||||||
|
value=st.session_state.google_client_secret,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
st.session_state.google_refresh_token = st.text_input(
|
||||||
|
"Google Refresh Token",
|
||||||
|
value=st.session_state.google_refresh_token,
|
||||||
|
type="password"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if all API keys are filled
|
||||||
|
all_keys_filled = all([
|
||||||
|
st.session_state.google_maps_key,
|
||||||
|
st.session_state.accuweather_key,
|
||||||
|
st.session_state.openai_key,
|
||||||
|
st.session_state.google_client_id,
|
||||||
|
st.session_state.google_client_secret,
|
||||||
|
st.session_state.google_refresh_token
|
||||||
|
])
|
||||||
|
|
||||||
|
if not all_keys_filled:
|
||||||
|
st.warning("⚠️ Please fill in all API keys to use the travel planner.")
|
||||||
|
else:
|
||||||
|
st.success("✅ All API keys are configured!")
|
||||||
|
|
||||||
|
# Title and description
|
||||||
|
st.title("✈️ AI Travel Planner")
|
||||||
|
st.markdown("""
|
||||||
|
This AI-powered travel planner helps you create personalized travel itineraries using:
|
||||||
|
- 🗺️ Maps and navigation
|
||||||
|
- 🌤️ Weather forecasts
|
||||||
|
- 🏨 Accommodation booking
|
||||||
|
- 📅 Calendar management
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Create two columns for input
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
# Source and Destination
|
||||||
|
source = st.text_input("Source", placeholder="Enter your departure city")
|
||||||
|
destination = st.text_input("Destination", placeholder= "Enter your destination city")
|
||||||
|
|
||||||
|
# Travel Dates
|
||||||
|
travel_dates = st.date_input(
|
||||||
|
"Travel Dates",
|
||||||
|
[date.today(), date.today()],
|
||||||
|
min_value=date.today(),
|
||||||
|
help="Select your travel dates"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
# Budget
|
||||||
|
budget = st.number_input(
|
||||||
|
"Budget (in USD)",
|
||||||
|
min_value=0,
|
||||||
|
max_value=10000,
|
||||||
|
step=100,
|
||||||
|
help="Enter your total budget for the trip"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Travel Preferences
|
||||||
|
travel_preferences = st.multiselect(
|
||||||
|
"Travel Preferences",
|
||||||
|
["Adventure", "Relaxation", "Sightseeing", "Cultural Experiences",
|
||||||
|
"Beach", "Mountain", "Luxury", "Budget-Friendly", "Food & Dining",
|
||||||
|
"Shopping", "Nightlife", "Family-Friendly"],
|
||||||
|
help="Select your travel preferences"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Additional preferences
|
||||||
|
st.subheader("Additional Preferences")
|
||||||
|
col3, col4 = st.columns(2)
|
||||||
|
|
||||||
|
with col3:
|
||||||
|
accommodation_type = st.selectbox(
|
||||||
|
"Preferred Accommodation",
|
||||||
|
["Any", "Hotel", "Hostel", "Apartment", "Resort"],
|
||||||
|
help="Select your preferred type of accommodation"
|
||||||
|
)
|
||||||
|
|
||||||
|
transportation_mode = st.multiselect(
|
||||||
|
"Preferred Transportation",
|
||||||
|
["Train", "Bus", "Flight", "Rental Car"],
|
||||||
|
help="Select your preferred modes of transportation"
|
||||||
|
)
|
||||||
|
|
||||||
|
with col4:
|
||||||
|
dietary_restrictions = st.multiselect(
|
||||||
|
"Dietary Restrictions",
|
||||||
|
["None", "Vegetarian", "Vegan", "Gluten-Free", "Halal", "Kosher"],
|
||||||
|
help="Select any dietary restrictions"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Submit Button
|
||||||
|
if st.button("Plan My Trip", type="primary", disabled=not all_keys_filled):
|
||||||
|
if not source or not destination:
|
||||||
|
st.error("Please enter both source and destination cities.")
|
||||||
|
elif not travel_preferences:
|
||||||
|
st.warning("Consider selecting some travel preferences for better recommendations.")
|
||||||
|
else:
|
||||||
|
# Create a loading spinner
|
||||||
|
with st.spinner("🤖 AI Agents are planning your perfect trip..."):
|
||||||
|
try:
|
||||||
|
# Construct the message for the agents
|
||||||
|
message = f"""
|
||||||
|
Plan a trip with the following details:
|
||||||
|
- From: {source}
|
||||||
|
- To: {destination}
|
||||||
|
- Dates: {travel_dates[0]} to {travel_dates[1]}
|
||||||
|
- Budget in USD: ${budget}
|
||||||
|
- Preferences: {', '.join(travel_preferences)}
|
||||||
|
- Accommodation: {accommodation_type}
|
||||||
|
- Transportation: {', '.join(transportation_mode)}
|
||||||
|
- Dietary Restrictions: {', '.join(dietary_restrictions)}
|
||||||
|
|
||||||
|
Please provide a comprehensive travel plan including:
|
||||||
|
1. Recommended accommodations
|
||||||
|
2. Daily itinerary with activities
|
||||||
|
3. Transportation options
|
||||||
|
4. The Expected Day Weather
|
||||||
|
5. Estimated cost of the Trip
|
||||||
|
6. Add the Departure Date to the calendar
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Run the agents
|
||||||
|
response = asyncio.run(run_agent(message))
|
||||||
|
|
||||||
|
# Display the response
|
||||||
|
st.success("✅ Your travel plan is ready!")
|
||||||
|
st.markdown(response)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"An error occurred while planning your trip: {str(e)}")
|
||||||
|
st.info("Please try again or contact support if the issue persists.")
|
||||||
|
|
||||||
|
# Add a footer
|
||||||
|
st.markdown("---")
|
||||||
|
st.markdown("""
|
||||||
|
<div style='text-align: center'>
|
||||||
|
<p>Powered by AI Travel Planning Agents</p>
|
||||||
|
<p>Your personal travel assistant for creating memorable experiences</p>
|
||||||
|
</div>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
132
mcp_ai_agents/ai_travel_planner_mcp_agent_team/calendar_mcp.py
Executable file
132
mcp_ai_agents/ai_travel_planner_mcp_agent_team/calendar_mcp.py
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from google.oauth2.credentials import Credentials
|
||||||
|
from googleapiclient.discovery import build
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='DEBUG: %(asctime)s - %(message)s',
|
||||||
|
stream=sys.stderr
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
mcp = FastMCP("Google Calendar MCP", dependencies=["python-dotenv", "google-api-python-client", "google-auth", "google-auth-oauthlib"])
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
|
||||||
|
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
|
||||||
|
GOOGLE_REFRESH_TOKEN = os.getenv("GOOGLE_REFRESH_TOKEN")
|
||||||
|
|
||||||
|
if not GOOGLE_CLIENT_ID or not GOOGLE_CLIENT_SECRET or not GOOGLE_REFRESH_TOKEN:
|
||||||
|
logger.error("Error: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_REFRESH_TOKEN environment variables are required")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def create_event(
|
||||||
|
summary: str,
|
||||||
|
start_time: str,
|
||||||
|
end_time: str,
|
||||||
|
description: str = None,
|
||||||
|
location: str = None,
|
||||||
|
attendees: list = None,
|
||||||
|
reminders: dict = None
|
||||||
|
) -> str:
|
||||||
|
"""Create a calendar event with specified details
|
||||||
|
|
||||||
|
Args:
|
||||||
|
summary: Event title
|
||||||
|
start_time: Start time (ISO format)
|
||||||
|
end_time: End time (ISO format)
|
||||||
|
description: Event description
|
||||||
|
location: Event location
|
||||||
|
attendees: List of attendee emails
|
||||||
|
reminders: Reminder settings for the event
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String with event creation confirmation and link
|
||||||
|
"""
|
||||||
|
logger.debug(f'Creating calendar event with args: {locals()}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.debug('Creating OAuth2 client')
|
||||||
|
# Google OAuth2
|
||||||
|
creds = Credentials(
|
||||||
|
None,
|
||||||
|
refresh_token=GOOGLE_REFRESH_TOKEN,
|
||||||
|
token_uri="https://oauth2.googleapis.com/token",
|
||||||
|
client_id=GOOGLE_CLIENT_ID,
|
||||||
|
client_secret=GOOGLE_CLIENT_SECRET
|
||||||
|
)
|
||||||
|
logger.debug('OAuth2 client created')
|
||||||
|
|
||||||
|
logger.debug('Creating calendar service')
|
||||||
|
calendar_service = build('calendar', 'v3', credentials=creds)
|
||||||
|
logger.debug('Calendar service created')
|
||||||
|
|
||||||
|
event = {
|
||||||
|
'summary': summary,
|
||||||
|
'start': {
|
||||||
|
'dateTime': start_time,
|
||||||
|
'timeZone': 'Asia/Seoul'
|
||||||
|
},
|
||||||
|
'end': {
|
||||||
|
'dateTime': end_time,
|
||||||
|
'timeZone': 'Asia/Seoul'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if description:
|
||||||
|
event['description'] = description
|
||||||
|
|
||||||
|
if location:
|
||||||
|
event['location'] = location
|
||||||
|
logger.debug(f'Location added: {location}')
|
||||||
|
|
||||||
|
if attendees:
|
||||||
|
event['attendees'] = [{'email': email} for email in attendees]
|
||||||
|
logger.debug(f'Attendees added: {event["attendees"]}')
|
||||||
|
|
||||||
|
if reminders:
|
||||||
|
event['reminders'] = reminders
|
||||||
|
logger.debug(f'Custom reminders set: {json.dumps(reminders)}')
|
||||||
|
else:
|
||||||
|
event['reminders'] = {
|
||||||
|
'useDefault': False,
|
||||||
|
'overrides': [
|
||||||
|
{'method': 'popup', 'minutes': 10}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
logger.debug(f'Default reminders set: {json.dumps(event["reminders"])}')
|
||||||
|
|
||||||
|
logger.debug('Attempting to insert event')
|
||||||
|
response = calendar_service.events().insert(calendarId='primary', body=event).execute()
|
||||||
|
logger.debug(f'Event insert response: {json.dumps(response)}')
|
||||||
|
|
||||||
|
return f"Event created: {response.get('htmlLink', 'No link available')}"
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
logger.debug(f'ERROR OCCURRED:')
|
||||||
|
logger.debug(f'Error type: {type(error).__name__}')
|
||||||
|
logger.debug(f'Error message: {str(error)}')
|
||||||
|
import traceback
|
||||||
|
logger.debug(f'Error traceback: {traceback.format_exc()}')
|
||||||
|
raise Exception(f"Failed to create event: {str(error)}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run the MCP calendar server."""
|
||||||
|
try:
|
||||||
|
mcp.run()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Server stopped by user")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fatal error running server: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
agno==1.2.13
|
||||||
|
mcp==1.6.0
|
||||||
|
streamlit==1.44.1
|
||||||
|
google-api-python-client==2.118.0
|
||||||
|
google-auth==2.28.1
|
||||||
|
google-auth-oauthlib==1.2.0
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
requests==2.31.0
|
||||||
|
openai==1.12.0
|
||||||
Reference in New Issue
Block a user