Skip to main content
Glama

Python Apple MCP

by jxnl
calendar.py7.13 kB
"""Calendar module for interacting with Apple Calendar.""" import logging from typing import Dict, List, Any, Optional from datetime import datetime, timedelta from .applescript import ( run_applescript_async, AppleScriptError, format_applescript_value, parse_applescript_record, parse_applescript_list ) logger = logging.getLogger(__name__) class CalendarModule: """Module for interacting with Apple Calendar""" async def check_calendar_access(self) -> bool: """Check if Calendar app is accessible""" try: script = ''' try tell application "Calendar" get name return true end tell on error return false end try ''' result = await run_applescript_async(script) return result.lower() == 'true' except Exception as e: logger.error(f"Cannot access Calendar app: {e}") return False async def search_events(self, search_text: str, limit: Optional[int] = None, from_date: Optional[str] = None, to_date: Optional[str] = None) -> List[Dict[str, Any]]: """Search for calendar events matching text""" if not from_date: from_date = datetime.now().strftime("%Y-%m-%d") if not to_date: to_date = (datetime.now().replace(hour=23, minute=59, second=59) + timedelta(days=7)).strftime("%Y-%m-%d") script = f''' tell application "Calendar" set matchingEvents to {{}} set searchStart to date "{from_date}" set searchEnd to date "{to_date}" set foundEvents to every event whose summary contains "{search_text}" and start date is greater than or equal to searchStart and start date is less than or equal to searchEnd repeat with e in foundEvents set end of matchingEvents to {{ title:summary of e, start_date:start date of e, end_date:end date of e, location:location of e, notes:description of e, calendar:name of calendar of e }} end repeat return matchingEvents as text end tell ''' try: result = await run_applescript_async(script) events = parse_applescript_list(result) if limit: events = events[:limit] return [parse_applescript_record(event) for event in events] except AppleScriptError as e: logger.error(f"Error searching events: {e}") return [] async def open_event(self, event_id: str) -> Dict[str, Any]: """Open a specific calendar event""" script = f''' tell application "Calendar" try set theEvent to first event whose uid is "{event_id}" show theEvent return "Opened event: " & summary of theEvent on error return "ERROR: Event not found" end try end tell ''' try: result = await run_applescript_async(script) success = not result.startswith("ERROR:") return { "success": success, "message": result.replace("ERROR: ", "") if not success else result } except AppleScriptError as e: return { "success": False, "message": str(e) } async def get_events(self, limit: Optional[int] = None, from_date: Optional[str] = None, to_date: Optional[str] = None) -> List[Dict[str, Any]]: """Get calendar events in a date range""" if not from_date: from_date = datetime.now().strftime("%Y-%m-%d") if not to_date: to_date = (datetime.now().replace(hour=23, minute=59, second=59) + timedelta(days=7)).strftime("%Y-%m-%d") script = f''' tell application "Calendar" set allEvents to {{}} set searchStart to date "{from_date}" set searchEnd to date "{to_date}" set foundEvents to every event whose start date is greater than or equal to searchStart and start date is less than or equal to searchEnd repeat with e in foundEvents set end of allEvents to {{ title:summary of e, start_date:start date of e, end_date:end date of e, location:location of e, notes:description of e, calendar:name of calendar of e }} end repeat return allEvents as text end tell ''' try: result = await run_applescript_async(script) events = parse_applescript_list(result) if limit: events = events[:limit] return [parse_applescript_record(event) for event in events] except AppleScriptError as e: logger.error(f"Error getting events: {e}") return [] async def create_event(self, title: str, start_date: datetime, end_date: datetime, location: str = None, notes: str = None, calendar_name: str = None) -> Dict[str, Any]: """Create a new calendar event""" # Using a simpler approach for Calendar that is more likely to work formatted_start = start_date.strftime("%Y-%m-%d %H:%M:%S") formatted_end = end_date.strftime("%Y-%m-%d %H:%M:%S") # Create a simpler script that just adds an event to the default calendar script = f''' tell application "Calendar" try tell application "Calendar" tell (first calendar whose name is "Calendar") make new event at end with properties {{summary:"{title}", start date:(date "{formatted_start}"), end date:(date "{formatted_end}")}} return "SUCCESS:Event created successfully" end tell end tell on error errMsg return "ERROR:" & errMsg end try end tell ''' try: result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", "") } except AppleScriptError as e: logger.error(f"Error creating event: {e}") return { "success": False, "message": str(e) }

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/jxnl/python-apple-mcp'

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