update : calendar mcp linked
This commit is contained in:
parent
e4cea90a18
commit
d8f27f6d4b
5 changed files with 196 additions and 7 deletions
|
|
@ -41,8 +41,6 @@ pip install -r requirements.txt
|
||||||
GOOGLE_MAPS_API_KEY=your_google_maps_api_key
|
GOOGLE_MAPS_API_KEY=your_google_maps_api_key
|
||||||
ACCUWEATHER_API_KEY=your_accuweather_api_key
|
ACCUWEATHER_API_KEY=your_accuweather_api_key
|
||||||
OPENAI_API_KEY=your_openai_api_key
|
OPENAI_API_KEY=your_openai_api_key
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧠 Built With
|
## 🧠 Built With
|
||||||
|
|
@ -56,4 +54,30 @@ OPENAI_API_KEY=your_openai_api_key
|
||||||
|
|
||||||
-- Airbnb MCP
|
-- Airbnb MCP
|
||||||
|
|
||||||
-- Accuweather
|
-- Accuweather
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Calendar MCP Server (`calendar_mcp.py`)
|
||||||
|
|
||||||
|
This script is a dedicated MCP (Modular Cognitive Process) server that integrates with **Google Calendar** to create events via API calls. It works seamlessly with the rest of the multi-agent system built with Agno and FastMCP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🛠 Features
|
||||||
|
|
||||||
|
- Creates Google Calendar events using the `create_event` tool
|
||||||
|
- Accepts event title, description, date/time, location, attendees, and reminders
|
||||||
|
- Uses a refresh token for persistent access (no re-authentication needed)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌱 Setup
|
||||||
|
|
||||||
|
Add the following to your `.env` file in the root directory:
|
||||||
|
|
||||||
|
```env
|
||||||
|
GOOGLE_CLIENT_ID=your_google_client_id
|
||||||
|
GOOGLE_CLIENT_SECRET=your_google_client_secret
|
||||||
|
GOOGLE_REFRESH_TOKEN=your_refresh_token
|
||||||
|
```
|
||||||
|
|
@ -10,17 +10,20 @@ from dotenv import load_dotenv
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
async def run_agent(message: str) -> None:
|
async def run_agent(message: str) -> None:
|
||||||
"""Run the Airbnb, Google Maps, Weather agent with the given message."""
|
"""Run the Airbnb, Google Maps, Weather and Calendar agent with the given message."""
|
||||||
|
|
||||||
google_maps_key = os.getenv("GOOGLE_MAPS_API_KEY")
|
google_maps_key = os.getenv("GOOGLE_MAPS_API_KEY")
|
||||||
accuweather_key = os.getenv("ACCUWEATHER_API_KEY")
|
accuweather_key = os.getenv("ACCUWEATHER_API_KEY")
|
||||||
openai_key = os.getenv("OPENAI_API_KEY")
|
openai_key = os.getenv("OPENAI_API_KEY")
|
||||||
|
google_maps_key = os.getenv("GOOGLE_CLIENT_ID")
|
||||||
if not google_maps_key:
|
if not google_maps_key:
|
||||||
raise ValueError("🚨 Missing GOOGLE_MAPS_API_KEY in environment variables.")
|
raise ValueError("🚨 Missing GOOGLE_MAPS_API_KEY in environment variables.")
|
||||||
elif not accuweather_key:
|
elif not accuweather_key:
|
||||||
raise ValueError("🚨 Missing ACCUWEATHER_API_KEY in environment variables.")
|
raise ValueError("🚨 Missing ACCUWEATHER_API_KEY in environment variables.")
|
||||||
elif not openai_key:
|
elif not openai_key:
|
||||||
raise ValueError("🚨 Missing OPENAI_API_KEY in environment variables.")
|
raise ValueError("🚨 Missing OPENAI_API_KEY in environment variables.")
|
||||||
|
elif not google_maps_key:
|
||||||
|
raise ValueError("🚨 Missing GOOGLE_CLIENT_ID in environment variables.")
|
||||||
env = {
|
env = {
|
||||||
**os.environ,
|
**os.environ,
|
||||||
"GOOGLE_MAPS_API_KEY": os.getenv("GOOGLE_MAPS_API_KEY"),
|
"GOOGLE_MAPS_API_KEY": os.getenv("GOOGLE_MAPS_API_KEY"),
|
||||||
|
|
@ -33,7 +36,7 @@ async def run_agent(message: str) -> None:
|
||||||
"npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt", # ✅ Airbnb mcp added
|
"npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt", # ✅ Airbnb mcp added
|
||||||
"npx -y @modelcontextprotocol/server-google-maps", # ✅ Google Maps 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
|
"uvx --from git+https://github.com/adhikasp/mcp-weather.git mcp-weather", # ✅ Weather mcp added
|
||||||
# "https://www.gumloop.com/mcp/gcalendar",
|
"/Users/priyanshmaheshwari/Desktop/EchovibeLabs/awesome-llm-apps/mcp_ai_agents/ai_travel_planner_mcp_agent_team/calendar_mcp.py" # ✅ Calendar mcp added
|
||||||
|
|
||||||
],
|
],
|
||||||
env=env,
|
env=env,
|
||||||
|
|
@ -58,8 +61,14 @@ async def run_agent(message: str) -> None:
|
||||||
goal="Connects to Booking.com and Airbnb APIs to search and filter accommodations based on user preferences (price range, amenities, location)"
|
goal="Connects to Booking.com and Airbnb APIs to search and filter accommodations based on user preferences (price range, amenities, location)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
calendar_agent = Agent(
|
||||||
|
tools=[mcp_tools],
|
||||||
|
name="Calendar Agent",
|
||||||
|
goal="Creates calendar events for travel plans, including reminders and location details."
|
||||||
|
)
|
||||||
|
|
||||||
team = Team(
|
team = Team(
|
||||||
members=[maps_agent, weather_agent, booking_agent],
|
members=[maps_agent, weather_agent, booking_agent, calendar_agent],
|
||||||
name="Travel Planning Team",
|
name="Travel Planning Team",
|
||||||
markdown=True,
|
markdown=True,
|
||||||
show_tool_calls=True
|
show_tool_calls=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,21 @@
|
||||||
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv() # Loads from .env
|
||||||
|
|
||||||
|
SCOPES = ['https://www.googleapis.com/auth/calendar']
|
||||||
|
|
||||||
|
flow = InstalledAppFlow.from_client_config({
|
||||||
|
"installed": {
|
||||||
|
"client_id": os.getenv("GOOGLE_CLIENT_ID"),
|
||||||
|
"client_secret": os.getenv("GOOGLE_CLIENT_SECRET"),
|
||||||
|
"redirect_uris": ["urn:ietf:wg:oauth:2.0:oob"],
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token"
|
||||||
|
}
|
||||||
|
}, SCOPES)
|
||||||
|
|
||||||
|
creds = flow.run_local_server(port=0)
|
||||||
|
print("\n=== REFRESH TOKEN ===\n")
|
||||||
|
print(creds.refresh_token)
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
agno==1.2.13
|
agno==1.2.13
|
||||||
mcp==1.6.0
|
mcp==1.6.0
|
||||||
streamlit==1.44.1
|
streamlit==1.44.1
|
||||||
|
google-api-python-client
|
||||||
|
google-auth
|
||||||
|
google-auth-oauthlib
|
||||||
Loading…
Reference in a new issue