Skip to main content
Glama

Python Apple MCP

by jxnl
maps.py14.8 kB
""" Maps utility module for interacting with Apple Maps. This module provides functions to perform various operations with Apple Maps like searching for locations, saving locations, getting directions, etc. """ import logging import json import uuid from typing import Dict, List, Any, Optional, Tuple, Union from .applescript import ( run_applescript_async, AppleScriptError, format_applescript_value, parse_applescript_record, parse_applescript_list ) logger = logging.getLogger(__name__) class MapsModule: """Module for interacting with Apple Maps""" async def check_maps_access(self) -> bool: """ Check if Maps app is accessible Returns: True if Maps app is accessible, False otherwise """ try: script = ''' try tell application "Maps" 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 Maps app: {e}") return False async def search_locations(self, query: str) -> Dict[str, Any]: """Search for locations in Apple Maps""" script = f''' tell application "Maps" try activate search "{query}" delay 1 set locations to {{}} set searchResults to selected location if searchResults is not missing value then set locName to name of searchResults set locAddress to formatted address of searchResults if locAddress is missing value then set locAddress to "Unknown" end if set locationInfo to {{name:locName, address:locAddress}} set end of locations to locationInfo end if return locations on error errMsg return "ERROR:" & errMsg end try end tell ''' try: result = await run_applescript_async(script) if result.startswith("ERROR:"): logger.error(f"Error in AppleScript: {result}") return { "success": False, "message": result.replace("ERROR:", ""), "locations": [] } locations = parse_applescript_list(result) return { "success": True, "locations": [parse_applescript_record(loc) for loc in locations] } except AppleScriptError as e: logger.error(f"Error searching locations: {e}") return { "success": False, "message": str(e), "locations": [] } async def save_location(self, name: str, address: str) -> Dict[str, Any]: """ Save a location to favorites Args: name: Name of the location address: Address to save Returns: A dictionary containing the result of the operation """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info(f"Saving location: {name} at {address}") script = f''' tell application "Maps" activate -- First search for the location search "{address}" -- Wait for search to complete delay 1 -- Try to get the current location set foundLocation to selected location if foundLocation is not missing value then -- Add to favorites add to favorites foundLocation with properties {{name:"{name}"}} -- Return success with location details set locationAddress to formatted address of foundLocation if locationAddress is missing value then set locationAddress to "{address}" end if return "SUCCESS:Added \\"" & "{name}" & "\\" to favorites" else return "ERROR:Could not find location for \\"" & "{address}" & "\\"" end if end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", "") } except Exception as e: logger.error(f"Error saving location: {e}") return { "success": False, "message": f"Error saving location: {str(e)}" } async def get_directions( self, from_address: str, to_address: str, transport_type: str = 'driving' ) -> Dict[str, Any]: """ Get directions between two locations Args: from_address: Starting address to_address: Destination address transport_type: Type of transport to use (default: 'driving') Returns: A dictionary containing the result of the operation """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info(f"Getting directions from {from_address} to {to_address} by {transport_type}") script = f''' tell application "Maps" activate -- Ask for directions get directions from "{from_address}" to "{to_address}" by "{transport_type}" return "SUCCESS:Displaying directions from \\"" & "{from_address}" & "\\" to \\"" & "{to_address}" & "\\" by {transport_type}" end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", ""), "route": { "from": from_address, "to": to_address, "transport_type": transport_type } if success else None } except Exception as e: logger.error(f"Error getting directions: {e}") return { "success": False, "message": f"Error getting directions: {str(e)}" } async def drop_pin(self, name: str, address: str) -> Dict[str, Any]: """ Create a pin at a specified location Args: name: Name of the pin address: Location address Returns: A dictionary containing the result of the operation """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info(f"Creating pin at {address} with name {name}") script = f''' tell application "Maps" activate -- Search for the location search "{address}" -- Wait for search to complete delay 1 -- Try to get the current location set foundLocation to selected location if foundLocation is not missing value then -- Drop pin (note: this is a user interface action) return "SUCCESS:Location found. Right-click and select 'Drop Pin' to create a pin named \\"" & "{name}" & "\\"" else return "ERROR:Could not find location for \\"" & "{address}" & "\\"" end if end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", "") } except Exception as e: logger.error(f"Error dropping pin: {e}") return { "success": False, "message": f"Error dropping pin: {str(e)}" } async def list_guides(self) -> Dict[str, Any]: """ List all guides in Apple Maps Returns: A dictionary containing guides information """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info("Listing guides from Maps") script = ''' tell application "Maps" activate -- Open guides view open location "maps://?show=guides" return "SUCCESS:Opened guides view in Maps" end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", ""), "guides": [] # Note: Currently no direct AppleScript access to guides } except Exception as e: logger.error(f"Error listing guides: {e}") return { "success": False, "message": f"Error listing guides: {str(e)}" } async def add_to_guide(self, location_address: str, guide_name: str) -> Dict[str, Any]: """ Add a location to a specific guide Args: location_address: The address of the location to add guide_name: The name of the guide to add to Returns: A dictionary containing the result of the operation """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info(f"Adding location {location_address} to guide {guide_name}") script = f''' tell application "Maps" activate -- Search for the location search "{location_address}" -- Wait for search to complete delay 1 return "SUCCESS:Location found. Click the location pin, then '...' button, and select 'Add to Guide' to add to \\"" & "{guide_name}" & "\\"" end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", "") } except Exception as e: logger.error(f"Error adding to guide: {e}") return { "success": False, "message": f"Error adding to guide: {str(e)}" } async def create_guide(self, guide_name: str) -> Dict[str, Any]: """ Create a new guide with the given name Args: guide_name: The name for the new guide Returns: A dictionary containing the result of the operation """ try: if not await self.check_maps_access(): return { "success": False, "message": "Cannot access Maps app. Please grant access in System Settings > Privacy & Security > Automation." } logger.info(f"Creating new guide: {guide_name}") script = f''' tell application "Maps" activate -- Open guides view open location "maps://?show=guides" return "SUCCESS:Opened guides view. Click '+' button and select 'New Guide' to create \\"" & "{guide_name}" & "\\"" end tell ''' result = await run_applescript_async(script) success = result.startswith("SUCCESS:") return { "success": success, "message": result.replace("SUCCESS:", "").replace("ERROR:", "") } except Exception as e: logger.error(f"Error creating guide: {e}") return { "success": False, "message": f"Error creating guide: {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