A Model Context Protocol (MCP) server that provides seamless integration between Claude and macOS Apple Reminders app. Built with TypeScript and AppleScript for reliable, native Reminders access.
- Complete Reminders Management: Create, read, update, and delete reminders
- List Management: Access and organize reminders across multiple lists
- Advanced Filtering: Search by text, filter by completion status, or target specific lists
- Rich Metadata: Due dates, priorities, notes, creation/modification timestamps
- Native Integration: Direct AppleScript integration with zero external dependencies
- Type-Safe: Built with TypeScript for reliability and maintainability
- macOS: This server uses AppleScript and requires macOS with the Reminders app
- Node.js: Version 16 or higher
- Claude Desktop or Claude Code CLI: For MCP integration
- Clone this repository:
git clone https://github.com/dbmcco/apple-reminders-mcp.git
cd apple-reminders-mcp- Install dependencies:
npm install- Build the server:
npm run buildAdd this to your Claude Desktop configuration file (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"reminders": {
"command": "node",
"args": ["/absolute/path/to/apple-reminders-mcp/dist/index.js"]
}
}
}Run this command:
claude mcp add -s user reminders node /absolute/path/to/apple-reminders-mcp/dist/index.jsImportant: Replace /absolute/path/to/apple-reminders-mcp with the actual path where you cloned this repository.
Get all available reminder lists.
Returns: Array of lists with name and id properties.
Example:
// Response:
[
{"name": "Reminders", "id": "x-apple-reminder://..."},
{"name": "Work", "id": "x-apple-reminder://..."},
{"name": "Personal", "id": "x-apple-reminder://..."}
]Retrieve reminders with optional filtering.
Parameters:
listName(string, optional): Filter by specific list namecompleted(boolean, optional): Filter by completion statussearchTerm(string, optional): Search in names and bodies
Returns: Array of reminder objects with full metadata.
Examples:
// Get all incomplete reminders
get_reminders(undefined, false)
// Get all reminders from "Work" list
get_reminders("Work")
// Get completed reminders from "Personal" list
get_reminders("Personal", true)
// Search for reminders containing "meeting"
get_reminders(undefined, undefined, "meeting")Create a new reminder in a specified list.
Parameters:
name(string, required): Reminder titlelistName(string, required): Target list namebody(string, optional): Notes/descriptiondueDate(string, optional): Due date in format "MM/DD/YYYY HH:MM AM/PM"priority(number, optional): 0=none, 1=high, 5=medium, 9=low
Returns: ID of the created reminder.
Examples:
// Simple reminder
create_reminder("Buy groceries", "Personal")
// Reminder with due date and priority
create_reminder(
"Submit report",
"Work",
"Include Q4 metrics",
"12/31/2025 5:00 PM",
1
)
// Reminder with notes
create_reminder(
"Call dentist",
"Personal",
"Schedule annual checkup"
)Update an existing reminder.
Parameters:
reminderId(string, required): ID of the reminder to updatename(string, optional): New titlebody(string, optional): New notescompleted(boolean, optional): Completion statusdueDate(string, optional): New due datepriority(number, optional): New priority
Examples:
// Mark reminder as complete
update_reminder("x-apple-reminder://...", {completed: true})
// Update due date
update_reminder("x-apple-reminder://...", {
dueDate: "01/15/2026 2:00 PM"
})
// Update multiple fields
update_reminder("x-apple-reminder://...", {
name: "Updated title",
body: "New notes",
priority: 1
})Delete a reminder permanently.
Parameters:
reminderId(string, required): ID of the reminder to delete
Example:
delete_reminder("x-apple-reminder://...")Search for reminders by text in names or bodies.
Parameters:
searchTerm(string, required): Text to search for
Returns: Array of matching reminder objects.
Example:
// Find all reminders mentioning "Claude"
search_reminders("Claude")You: Show me all incomplete tasks from my "Today" list
Claude: [uses get_reminders("Today", false)]
You: Mark the first one as complete
Claude: [uses update_reminder with completed: true]
You: Remind me to call John tomorrow at 2pm
Claude: [uses create_reminder with due date]
You: Show me all reminders related to the "Website" project
Claude: [uses search_reminders("Website")]
You: Move them all to the "Work" list
Claude: [uses update_reminder for each result]
You: What did I complete this week in my "Personal" list?
Claude: [uses get_reminders("Personal", true)]
{
id: string; // Unique reminder ID
name: string; // Reminder title
body?: string; // Optional notes/description
completed: boolean; // Completion status
list: string; // Parent list name
dueDate?: string; // Optional due date
priority: number; // 0=none, 1=high, 5=medium, 9=low
creationDate: string; // When reminder was created
modificationDate: string; // When last modified
}{
name: string; // List display name
id: string; // Unique list ID
}npm run buildnpm run devnpm run startThis MCP server uses a clean architecture:
- MCP Server Layer (
index.ts): Handles MCP protocol communication - AppleScript Executor (
applescript-executor.ts): Manages all Reminders app interactions - Type Safety: Zod validation and TypeScript for reliability
The AppleScript integration uses osascript for direct system integration, avoiding external dependencies and app translocation issues.
If you get permission errors, ensure:
- Terminal (or your app) has Automation permissions for Reminders
- Go to System Preferences > Security & Privacy > Privacy > Automation
- Enable access for the app running this server
Due dates must use the format: "MM/DD/YYYY HH:MM AM/PM"
Examples:
"12/25/2025 9:00 AM""01/01/2026 11:30 PM"
Reminder IDs are system-generated Apple URLs (e.g., x-apple-reminder://...). They're not portable across systems but are stable within a single macOS installation.
Built with Claude (Anthropic) using the Model Context Protocol SDK.
MIT License - see LICENSE file for details
Contributions are welcome! Please feel free to submit issues or pull requests.
For issues, questions, or feature requests, please open an issue on GitHub.