Skip to main content
Glama

Python Apple MCP

by jxnl
apple_mcp.py5.71 kB
#!/usr/bin/env python3 """ Python Apple MCP (Model Context Protocol) Server This is a Python implementation of the server that handles interactions with macOS applications such as Contacts, Notes, Mail, Messages, Reminders, Calendar, and Maps using FastMCP. """ from pydantic import BaseModel, Field from typing import Optional, List, Dict, Any from datetime import datetime, timedelta from mcp.server.fastmcp import FastMCP from utils.contacts import ContactsModule from utils.notes import NotesModule from utils.message import MessageModule from utils.mail import MailModule from utils.reminders import RemindersModule from utils.calendar import CalendarModule from utils.maps import MapsModule # Initialize FastMCP server mcp = FastMCP( "Apple MCP", dependencies=[ "pydantic>=2.0.0", "httpx>=0.24.0", ] ) # Initialize utility modules contacts_module = ContactsModule() notes_module = NotesModule() message_module = MessageModule() mail_module = MailModule() reminders_module = RemindersModule() calendar_module = CalendarModule() maps_module = MapsModule() # Models for request/response types class Contact(BaseModel): name: str phones: List[str] class Note(BaseModel): title: str content: str folder: Optional[str] = "Claude" class Message(BaseModel): to: str content: str scheduled_time: Optional[str] = None class Email(BaseModel): to: str subject: str body: str cc: Optional[str] = None bcc: Optional[str] = None class Reminder(BaseModel): title: str notes: Optional[str] = None due_date: Optional[str] = None list_name: Optional[str] = None class CalendarEvent(BaseModel): title: str start_date: str end_date: str location: Optional[str] = None notes: Optional[str] = None is_all_day: bool = False calendar_name: Optional[str] = None class Location(BaseModel): name: str address: str # Contacts Tools @mcp.tool() async def find_contact(name: Optional[str] = None) -> List[Contact]: """Search for contacts by name. If no name is provided, returns all contacts.""" if name: phones = await contacts_module.find_number(name) return [Contact(name=name, phones=phones)] else: contacts_dict = await contacts_module.get_all_numbers() return [Contact(name=name, phones=phones) for name, phones in contacts_dict.items()] # Notes Tools @mcp.tool() async def create_note(note: Note) -> str: """Create a new note in Apple Notes""" return await notes_module.create_note(note.title, note.content, note.folder) @mcp.tool() async def search_notes(query: str) -> List[Note]: """Search for notes containing the given text""" notes = await notes_module.search_notes(query) return [Note(title=note['title'], content=note['content']) for note in notes] # Messages Tools @mcp.tool() async def send_message(message: Message) -> str: """Send an iMessage""" return await message_module.send_message(message.to, message.content, message.scheduled_time) @mcp.tool() async def read_messages(phone_number: str, limit: int = 10) -> List[Dict[str, Any]]: """Read recent messages from a specific contact""" return await message_module.read_messages(phone_number, limit) # Mail Tools @mcp.tool() async def send_email(email: Email) -> str: """Send an email using Apple Mail""" return await mail_module.send_email( to=email.to, subject=email.subject, body=email.body, cc=email.cc, bcc=email.bcc ) @mcp.tool() async def search_emails(query: str, limit: int = 10) -> List[Dict[str, Any]]: """Search emails containing the given text""" return await mail_module.search_emails(query, limit) # Reminders Tools @mcp.tool() async def create_reminder(reminder: Reminder) -> str: """Create a new reminder""" return await reminders_module.create_reminder( title=reminder.title, notes=reminder.notes, due_date=reminder.due_date, list_name=reminder.list_name ) @mcp.tool() async def search_reminders(query: str) -> List[Dict[str, Any]]: """Search for reminders containing the given text""" return await reminders_module.search_reminders(query) # Calendar Tools @mcp.tool() async def create_event(event: CalendarEvent) -> str: """Create a new calendar event""" return await calendar_module.create_event( title=event.title, start_date=event.start_date, end_date=event.end_date, location=event.location, notes=event.notes, is_all_day=event.is_all_day, calendar_name=event.calendar_name ) @mcp.tool() async def search_events(query: str, from_date: Optional[str] = None, to_date: Optional[str] = None) -> List[Dict[str, Any]]: """Search for calendar events""" 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") return await calendar_module.search_events(query, from_date, to_date) # Maps Tools @mcp.tool() async def search_locations(query: str, limit: int = 5) -> List[Location]: """Search for locations in Apple Maps""" locations = await maps_module.search_locations(query, limit) return [Location(name=loc['name'], address=loc['address']) for loc in locations] @mcp.tool() async def get_directions(from_address: str, to_address: str, transport_type: str = "driving") -> str: """Get directions between two locations""" return await maps_module.get_directions(from_address, to_address, transport_type) if __name__ == "__main__": mcp.run()

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