Skip to main content
Glama

maps

Search locations, save favorites, and get directions using Apple Maps. Manage guides, pin locations, and set map centers with precise coordinates for efficient navigation and location management.

Instructions

Search locations, manage guides, save favorites, and get directions using Apple Maps

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addressNoAddress of the location (required for save, pin, addToGuide)
fromAddressNoStarting address for directions (required for directions)
guideNameNoName of the guide (required for createGuide and addToGuide)
latitudeNoLatitude for the center point (required for setCenter)
limitNoMaximum number of results to return (optional for search)
longitudeNoLongitude for the center point (required for setCenter)
nameNoName of the location (required for save and pin)
operationYesOperation to perform with Maps
queryNoSearch query for locations (required for search)
toAddressNoDestination address for directions (required for directions)
transportTypeNoType of transport to use (optional for directions)

Implementation Reference

  • Main execution handler for the 'maps' tool. Handles operations like search, save, directions, etc., by executing specific AppleScript files via runAppleScriptSafely.
    export async function handleMaps( args: MapsArgs, loadModule: LoadModuleFunction ): Promise<ToolResult> { try { const mapsModule = await loadModule("maps"); switch (args.operation) { case "search": { const resultStr = await runAppleScriptSafely( "maps_search.scpt", [args.query] ); const parsedResult: SearchResponse = JSON.parse(resultStr); let detailedText = parsedResult.message || "Search completed"; if (parsedResult.locations && parsedResult.locations.length > 0) { detailedText += "\n\n"; parsedResult.locations.forEach((location: any, index: number) => { detailedText += `Location ${index + 1}:\n`; detailedText += `• Name: ${location.name}\n`; detailedText += `• Address: ${location.address}\n`; if (location.latitude !== null && location.longitude !== null) { detailedText += `• Coordinates: ${location.latitude.toFixed( 6 )}, ${location.longitude.toFixed(6)}\n`; } if (location.category) { detailedText += `• Category: ${location.category}\n`; } if (index < parsedResult.locations.length - 1) { detailedText += "\n"; } }); } return { content: [ { type: "text", text: detailedText, }, ], success: parsedResult.success, locations: parsedResult.locations, query: args.query, limit: args.limit, isError: !parsedResult.success, }; } case "save": { const resultStr = await runAppleScriptSafely( "maps_save.scpt", [args.name, args.address] ); const parsedResult: any = JSON.parse(resultStr); if (parsedResult.guides && Array.isArray(parsedResult.guides) && parsedResult.guides.length > 0) { return { content: [{ type: "text", text: parsedResult.message || "Save operation completed" }], success: parsedResult.success, location: parsedResult.location, name: args.name, address: args.address, isError: !parsedResult.success, }; } return { content: [], success: parsedResult.success, location: parsedResult.location, name: args.name, address: args.address, isError: !parsedResult.success, }; } case "pin": { const resultStr = await runAppleScriptSafely( "maps_pin.scpt", [args.name, args.address] ); const parsedResult: any = JSON.parse(resultStr); if (parsedResult.guides && Array.isArray(parsedResult.guides) && parsedResult.guides.length > 0) { return { content: [{ type: "text", text: parsedResult.message || "Pin operation completed" }], success: parsedResult.success, location: parsedResult.location, name: args.name, address: args.address, isError: !parsedResult.success, }; } else { return { content: [], success: parsedResult.success, location: parsedResult.location, name: args.name, address: args.address, isError: !parsedResult.success, }; } } case "directions": { const resultStr = await runAppleScriptSafely( "maps_directions.scpt", [args.fromAddress, args.toAddress, args.transportType || "driving"] ); const parsedResult: DirectionsResponse = JSON.parse(resultStr); let detailedText = parsedResult.message || "Directions request completed"; if (parsedResult.success && parsedResult.route) { detailedText += "\n\n"; detailedText += `• From: ${parsedResult.route.startAddress}\n`; detailedText += `• To: ${parsedResult.route.endAddress}\n`; detailedText += `• Distance: ${parsedResult.route.distance}\n`; detailedText += `• Duration: ${parsedResult.route.duration}\n`; detailedText += `• Transport Type: ${ args.transportType || "driving" }\n`; } return { content: [{ type: "text", text: detailedText }], success: parsedResult.success, route: parsedResult.route, fromAddress: args.fromAddress, toAddress: args.toAddress, transportType: args.transportType || "driving", isError: !parsedResult.success, }; } case "listGuides": { const resultStr = await runAppleScriptSafely( "maps_list_guides.scpt" ); const parsedResult: ListGuidesResponse = JSON.parse(resultStr); let detailedText = parsedResult.message || "Guide listing completed"; if (parsedResult.success && parsedResult.guides && Array.isArray(parsedResult.guides) && parsedResult.guides.length > 0) { detailedText += "\n\n"; detailedText += "Available guides:\n"; parsedResult.guides.forEach((guide: any, index: number) => { detailedText += `${index + 1}. ${guide.name} (${ guide.itemCount } items)\n`; }); } return { content: [{ type: "text", text: detailedText }], success: parsedResult.success, guides: parsedResult.guides, isError: !parsedResult.success, }; } case "addToGuide": { const resultStr = await runAppleScriptSafely( "maps_add_to_guide.scpt", [args.address, args.guideName] ); const parsedResult: GuideManipulationResponse = JSON.parse(resultStr); return { content: [{ type: "text", text: parsedResult.message || "Add to guide operation completed" }], success: parsedResult.success, guideName: parsedResult.guideName || args.guideName, locationName: parsedResult.locationName, address: args.address, isError: !parsedResult.success, }; } case "createGuide": { const resultStr = await runAppleScriptSafely( "maps_create_guide.scpt", [args.guideName] ); const parsedResult: GuideManipulationResponse = JSON.parse(resultStr); return { content: [{ type: "text", text: parsedResult.message || "Create guide operation completed" }], success: parsedResult.success, guideName: parsedResult.guideName || args.guideName, isError: !parsedResult.success, }; } case "getCenter": { // Use the correct script filename const resultStr = await runAppleScriptSafely( "/Users/zach/Dev/MCP/apple/src/scripts/getMapCenterCoordinates.applescript" ); const parsedResult: CenterResponse = JSON.parse(resultStr); let detailedText = parsedResult.message || "Get center operation completed"; if ( parsedResult.success && parsedResult.latitude !== undefined && parsedResult.longitude !== undefined ) { detailedText += "\n\n"; detailedText += `• Latitude: ${parsedResult.latitude.toFixed(6)}\n`; detailedText += `• Longitude: ${parsedResult.longitude.toFixed(6)}\n`; detailedText += `• Google Maps Link: https://www.google.com/maps?q=${parsedResult.latitude},${parsedResult.longitude}`; } return { content: [ { type: "text", text: detailedText, }, ], success: parsedResult.success, latitude: parsedResult.latitude, longitude: parsedResult.longitude, isError: !parsedResult.success, }; } case "setCenter": { // Convert numbers to strings and make sure they're properly formatted const latitudeStr = String(args.latitude); const longitudeStr = String(args.longitude); const resultStr = await runAppleScriptSafely( "/Users/zach/Dev/MCP/apple/src/scripts/setMapCenterCoordinates.applescript", [latitudeStr, longitudeStr] ); const parsedResult: CenterResponse = JSON.parse(resultStr); let detailedText = parsedResult.message || "Set center operation completed"; if (parsedResult.success) { detailedText += "\n\n"; detailedText += `• Latitude: ${args.latitude.toFixed(6)}\n`; detailedText += `• Longitude: ${args.longitude.toFixed(6)}\n`; detailedText += `• Google Maps Link: https://www.google.com/maps?q=${args.latitude},${args.longitude}`; } return { content: [ { type: "text", text: detailedText, }, ], success: parsedResult.success, latitude: args.latitude, longitude: args.longitude, isError: !parsedResult.success, }; } default: throw new Error(`Unknown maps operation: ${(args as any).operation}`); } } catch (error) { // Provide more detailed error information const errorMessage = error instanceof Error ? error.message : String(error); // Check if the error is related to script path let additionalInfo = ""; if (errorMessage.includes("No such file or directory") || errorMessage.includes("cannot find") || errorMessage.includes("unknown token")) { additionalInfo = "\n\nPossible issues:\n" + "- The AppleScript files may not be in the expected locations\n" + "- The AppleScript files may not have correct permissions\n" + "- The script execution syntax may need adjustment for your environment"; } return { content: [ { type: "text", text: `Error in maps tool: ${errorMessage}${additionalInfo}`, }, ], isError: true, }; } }
  • Zod schema (MapsArgsSchema) for input validation of maps tool arguments, defining discriminated union based on 'operation'.
    export const MapsArgsSchema = z.discriminatedUnion("operation", [ z.object({ operation: z.literal("search"), query: z.string().min(1), limit: z.number().optional(), }), z.object({ operation: z.literal("save"), name: z.string().min(1), address: z.string().min(1), }), z.object({ operation: z.literal("pin"), name: z.string().min(1), address: z.string().min(1), }), z.object({ operation: z.literal("directions"), fromAddress: z.string().min(1), toAddress: z.string().min(1), transportType: z.enum(["driving", "walking", "transit"]).optional(), }), z.object({ operation: z.literal("listGuides") }), z.object({ operation: z.literal("addToGuide"), address: z.string().min(1), guideName: z.string().min(1), }), z.object({ operation: z.literal("createGuide"), guideName: z.string().min(1), }), z.object({ operation: z.literal("getCenter") }), z.object({ operation: z.literal("setCenter"), latitude: z.number(), longitude: z.number(), }), ]);
  • tools.ts:259-315 (registration)
    MCP protocol Tool registration for 'maps': defines name, description, and JSON inputSchema advertised to clients.
    const MAPS_TOOL: Tool = { name: "maps", description: "Search locations, manage guides, save favorites, and get directions using Apple Maps", inputSchema: { type: "object", properties: { operation: { type: "string", description: "Operation to perform with Maps", enum: ["search", "save", "directions", "pin", "listGuides", "addToGuide", "createGuide", "getCenter", "setCenter"] // Add setCenter }, query: { type: "string", description: "Search query for locations (required for search)" }, limit: { type: "number", description: "Maximum number of results to return (optional for search)" }, name: { type: "string", description: "Name of the location (required for save and pin)" }, address: { type: "string", description: "Address of the location (required for save, pin, addToGuide)" }, fromAddress: { type: "string", description: "Starting address for directions (required for directions)" }, toAddress: { type: "string", description: "Destination address for directions (required for directions)" }, transportType: { type: "string", description: "Type of transport to use (optional for directions)", enum: ["driving", "walking", "transit"] }, guideName: { type: "string", description: "Name of the guide (required for createGuide and addToGuide)" }, // Add parameters for setCenter latitude: { type: "number", description: "Latitude for the center point (required for setCenter)" }, longitude: { type: "number", description: "Longitude for the center point (required for setCenter)" } }, required: ["operation"] } };
  • index.ts:144-147 (registration)
    Dispatch logic in main server CallToolRequest handler: parses args with MapsArgsSchema and calls handleMaps.
    case "maps": { const validatedArgs = MapsArgsSchema.parse(args); return await handleMaps(validatedArgs, loadModule); }
  • Helper module 'maps' with JXA functions for Maps operations (loaded by loadModule but not used in current handler implementation).
    const maps = { searchLocations, saveLocation, getDirections, dropPin, listGuides, addToGuide, createGuide, getMapCenterCoordinates, // Keep the (non-functional) getter for now setMapCenterCoordinates // Add the new setter function }; export default maps;

Other Tools

Related Tools

Latest Blog Posts

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

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