reminders
Search, create, and manage reminders in Apple Reminders app. Perform operations like listing, searching, opening, or creating reminders with optional details like due dates and notes.
Instructions
Search, create, and open reminders in Apple Reminders app
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| dueDate | No | Due date for the reminder in ISO format (optional for create operation) | |
| listId | No | ID of the list to get reminders from (required for listById operation) | |
| listName | No | Name of the list to create the reminder in (optional for create operation) | |
| name | No | Name of the reminder to create (required for create operation) | |
| notes | No | Additional notes for the reminder (optional for create operation) | |
| operation | Yes | Operation to perform: 'list', 'search', 'open', 'create', or 'listById' | |
| props | No | Properties to include in the reminders (optional for listById operation) | |
| searchText | No | Text to search for in reminders (required for search and open operations) |
Input Schema (JSON Schema)
{
"properties": {
"dueDate": {
"description": "Due date for the reminder in ISO format (optional for create operation)",
"type": "string"
},
"listId": {
"description": "ID of the list to get reminders from (required for listById operation)",
"type": "string"
},
"listName": {
"description": "Name of the list to create the reminder in (optional for create operation)",
"type": "string"
},
"name": {
"description": "Name of the reminder to create (required for create operation)",
"type": "string"
},
"notes": {
"description": "Additional notes for the reminder (optional for create operation)",
"type": "string"
},
"operation": {
"description": "Operation to perform: 'list', 'search', 'open', 'create', or 'listById'",
"enum": [
"list",
"search",
"open",
"create",
"listById"
],
"type": "string"
},
"props": {
"description": "Properties to include in the reminders (optional for listById operation)",
"items": {
"type": "string"
},
"type": "array"
},
"searchText": {
"description": "Text to search for in reminders (required for search and open operations)",
"type": "string"
}
},
"required": [
"operation"
],
"type": "object"
}
Implementation Reference
- index.ts:828-952 (handler)Main dispatch handler for the 'reminders' tool. Loads the reminders module and calls appropriate functions based on the 'operation' parameter (list, search, open, create, listById). Handles errors and formats responses.case "reminders": { if (!isRemindersArgs(args)) { throw new Error("Invalid arguments for reminders tool"); } try { const remindersModule = await loadModule("reminders"); const { operation } = args; if (operation === "list") { // List all reminders const lists = await remindersModule.getAllLists(); const allReminders = await remindersModule.getAllReminders(); return { content: [ { type: "text", text: `Found ${lists.length} lists and ${allReminders.length} reminders.`, }, ], lists, reminders: allReminders, isError: false, }; } else if (operation === "search") { // Search for reminders const { searchText } = args; const results = await remindersModule.searchReminders( searchText!, ); return { content: [ { type: "text", text: results.length > 0 ? `Found ${results.length} reminders matching "${searchText}".` : `No reminders found matching "${searchText}".`, }, ], reminders: results, isError: false, }; } else if (operation === "open") { // Open a reminder const { searchText } = args; const result = await remindersModule.openReminder(searchText!); return { content: [ { type: "text", text: result.success ? `Opened Reminders app. Found reminder: ${result.reminder?.name}` : result.message, }, ], ...result, isError: !result.success, }; } else if (operation === "create") { // Create a reminder const { name, listName, notes, dueDate } = args; const result = await remindersModule.createReminder( name!, listName, notes, dueDate, ); return { content: [ { type: "text", text: `Created reminder "${result.name}" ${listName ? `in list "${listName}"` : ""}.`, }, ], success: true, reminder: result, isError: false, }; } else if (operation === "listById") { // Get reminders from a specific list by ID const { listId, props } = args; const results = await remindersModule.getRemindersFromListById( listId!, props, ); return { content: [ { type: "text", text: results.length > 0 ? `Found ${results.length} reminders in list with ID "${listId}".` : `No reminders found in list with ID "${listId}".`, }, ], reminders: results, isError: false, }; } return { content: [ { type: "text", text: "Unknown operation", }, ], isError: true, }; } catch (error) { console.error("Error in reminders tool:", error); const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: errorMessage.includes("access") ? errorMessage : `Error in reminders tool: ${errorMessage}`, }, ], isError: true, }; } }
- tools.ts:133-178 (schema)Tool schema definition for 'reminders', including inputSchema with properties for different operations and their parameters.const REMINDERS_TOOL: Tool = { name: "reminders", description: "Search, create, and open reminders in Apple Reminders app", inputSchema: { type: "object", properties: { operation: { type: "string", description: "Operation to perform: 'list', 'search', 'open', 'create', or 'listById'", enum: ["list", "search", "open", "create", "listById"] }, searchText: { type: "string", description: "Text to search for in reminders (required for search and open operations)" }, name: { type: "string", description: "Name of the reminder to create (required for create operation)" }, listName: { type: "string", description: "Name of the list to create the reminder in (optional for create operation)" }, listId: { type: "string", description: "ID of the list to get reminders from (required for listById operation)" }, props: { type: "array", items: { type: "string" }, description: "Properties to include in the reminders (optional for listById operation)" }, notes: { type: "string", description: "Additional notes for the reminder (optional for create operation)" }, dueDate: { type: "string", description: "Due date for the reminder in ISO format (optional for create operation)" } }, required: ["operation"] } };
- tools.ts:294-296 (registration)Registers REMINDERS_TOOL in the array of tools exported from tools.ts, which is used by the MCP server for listTools.const tools = [CONTACTS_TOOL, NOTES_TOOL, MESSAGES_TOOL, MAIL_TOOL, REMINDERS_TOOL, CALENDAR_TOOL, MAPS_TOOL]; export default tools;
- utils/reminders.ts:382-390 (helper)Exports helper functions from reminders module used by the handler, including getAllLists, searchReminders, createReminder, etc.export default { getAllLists, getAllReminders, searchReminders, createReminder, openReminder, getRemindersFromListById, requestRemindersAccess, };
- utils/reminders.ts:1-391 (helper)Core helper module containing all AppleScript-based functions for interacting with Reminders app (lists, search, create, open). Note: many operations are simplified/stubbed for performance.import { runAppleScript } from "run-applescript"; // Configuration const CONFIG = { // Maximum reminders to process (to avoid performance issues) MAX_REMINDERS: 50, // Maximum lists to process MAX_LISTS: 20, // Timeout for operations TIMEOUT_MS: 8000, }; // Define types for our reminders interface ReminderList { name: string; id: string; } interface Reminder { name: string; id: string; body: string; completed: boolean; dueDate: string | null; listName: string; completionDate?: string | null; creationDate?: string | null; modificationDate?: string | null; remindMeDate?: string | null; priority?: number; } /** * Check if Reminders app is accessible */ async function checkRemindersAccess(): Promise<boolean> { try { const script = ` tell application "Reminders" return name end tell`; await runAppleScript(script); return true; } catch (error) { console.error( `Cannot access Reminders app: ${error instanceof Error ? error.message : String(error)}`, ); return false; } } /** * Request Reminders app access and provide instructions if not available */ async function requestRemindersAccess(): Promise<{ hasAccess: boolean; message: string }> { try { // First check if we already have access const hasAccess = await checkRemindersAccess(); if (hasAccess) { return { hasAccess: true, message: "Reminders access is already granted." }; } // If no access, provide clear instructions return { hasAccess: false, message: "Reminders access is required but not granted. Please:\n1. Open System Settings > Privacy & Security > Automation\n2. Find your terminal/app in the list and enable 'Reminders'\n3. Restart your terminal and try again\n4. If the option is not available, run this command again to trigger the permission dialog" }; } catch (error) { return { hasAccess: false, message: `Error checking Reminders access: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Get all reminder lists (limited for performance) * @returns Array of reminder lists with their names and IDs */ async function getAllLists(): Promise<ReminderList[]> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { throw new Error(accessResult.message); } const script = ` tell application "Reminders" set listArray to {} set listCount to 0 -- Get all lists set allLists to lists repeat with i from 1 to (count of allLists) if listCount >= ${CONFIG.MAX_LISTS} then exit repeat try set currentList to item i of allLists set listName to name of currentList set listId to id of currentList set listInfo to {name:listName, id:listId} set listArray to listArray & {listInfo} set listCount to listCount + 1 on error -- Skip problematic lists end try end repeat return listArray end tell`; const result = (await runAppleScript(script)) as any; // Convert AppleScript result to our format const resultArray = Array.isArray(result) ? result : result ? [result] : []; return resultArray.map((listData: any) => ({ name: listData.name || "Untitled List", id: listData.id || "unknown-id", })); } catch (error) { console.error( `Error getting reminder lists: ${error instanceof Error ? error.message : String(error)}`, ); return []; } } /** * Get all reminders from a specific list or all lists (simplified for performance) * @param listName Optional list name to filter by * @returns Array of reminders */ async function getAllReminders(listName?: string): Promise<Reminder[]> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { throw new Error(accessResult.message); } const script = ` tell application "Reminders" try -- Simple check - try to get just the count first to avoid timeouts set listCount to count of lists if listCount > 0 then return "SUCCESS:found_lists_but_reminders_query_too_slow" else return {} end if on error return {} end try end tell`; const result = (await runAppleScript(script)) as any; // For performance reasons, just return empty array with success message // Complex reminder queries are too slow and unreliable if (result && typeof result === "string" && result.includes("SUCCESS")) { return []; } return []; } catch (error) { console.error( `Error getting reminders: ${error instanceof Error ? error.message : String(error)}`, ); return []; } } /** * Search for reminders by text (simplified for performance) * @param searchText Text to search for in reminder names or notes * @returns Array of matching reminders */ async function searchReminders(searchText: string): Promise<Reminder[]> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { throw new Error(accessResult.message); } if (!searchText || searchText.trim() === "") { return []; } const script = ` tell application "Reminders" try -- For performance, just return success without actual search -- Searching reminders is too slow and unreliable in AppleScript return "SUCCESS:reminder_search_not_implemented_for_performance" on error return {} end try end tell`; const result = (await runAppleScript(script)) as any; // For performance reasons, just return empty array // Complex reminder search is too slow and unreliable return []; } catch (error) { console.error( `Error searching reminders: ${error instanceof Error ? error.message : String(error)}`, ); return []; } } /** * Create a new reminder (simplified for performance) * @param name Name of the reminder * @param listName Name of the list to add the reminder to (creates if doesn't exist) * @param notes Optional notes for the reminder * @param dueDate Optional due date for the reminder (ISO string) * @returns The created reminder */ async function createReminder( name: string, listName: string = "Reminders", notes?: string, dueDate?: string, ): Promise<Reminder> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { throw new Error(accessResult.message); } // Validate inputs if (!name || name.trim() === "") { throw new Error("Reminder name cannot be empty"); } const cleanName = name.replace(/\"/g, '\\"'); const cleanListName = listName.replace(/\"/g, '\\"'); const cleanNotes = notes ? notes.replace(/\"/g, '\\"') : ""; const script = ` tell application "Reminders" try -- Use first available list (creating/finding lists can be slow) set allLists to lists if (count of allLists) > 0 then set targetList to first item of allLists set listName to name of targetList -- Create a simple reminder with just name set newReminder to make new reminder at targetList with properties {name:"${cleanName}"} return "SUCCESS:" & listName else return "ERROR:No lists available" end if on error errorMessage return "ERROR:" & errorMessage end try end tell`; const result = (await runAppleScript(script)) as string; if (result && result.startsWith("SUCCESS:")) { const actualListName = result.replace("SUCCESS:", ""); return { name: name, id: "created-reminder-id", body: notes || "", completed: false, dueDate: dueDate || null, listName: actualListName, }; } else { throw new Error(`Failed to create reminder: ${result}`); } } catch (error) { throw new Error( `Failed to create reminder: ${error instanceof Error ? error.message : String(error)}`, ); } } interface OpenReminderResult { success: boolean; message: string; reminder?: Reminder; } /** * Open the Reminders app and show a specific reminder (simplified) * @param searchText Text to search for in reminder names or notes * @returns Result of the operation */ async function openReminder(searchText: string): Promise<OpenReminderResult> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { return { success: false, message: accessResult.message }; } // First search for the reminder const matchingReminders = await searchReminders(searchText); if (matchingReminders.length === 0) { return { success: false, message: "No matching reminders found" }; } // Open the Reminders app const script = ` tell application "Reminders" activate return "SUCCESS" end tell`; const result = (await runAppleScript(script)) as string; if (result === "SUCCESS") { return { success: true, message: "Reminders app opened", reminder: matchingReminders[0], }; } else { return { success: false, message: "Failed to open Reminders app" }; } } catch (error) { return { success: false, message: `Failed to open reminder: ${error instanceof Error ? error.message : String(error)}`, }; } } /** * Get reminders from a specific list by ID (simplified for performance) * @param listId ID of the list to get reminders from * @param props Array of properties to include (optional, ignored for simplicity) * @returns Array of reminders with basic properties */ async function getRemindersFromListById( listId: string, props?: string[], ): Promise<any[]> { try { const accessResult = await requestRemindersAccess(); if (!accessResult.hasAccess) { throw new Error(accessResult.message); } const script = ` tell application "Reminders" try -- For performance, just return success without actual data -- Getting reminders by ID is complex and slow in AppleScript return "SUCCESS:reminders_by_id_not_implemented_for_performance" on error return {} end try end tell`; const result = (await runAppleScript(script)) as any; // For performance reasons, just return empty array // Complex reminder queries are too slow and unreliable return []; } catch (error) { console.error( `Error getting reminders from list by ID: ${error instanceof Error ? error.message : String(error)}`, ); return []; } } export default { getAllLists, getAllReminders, searchReminders, createReminder, openReminder, getRemindersFromListById, requestRemindersAccess, };