English | 简体中文 A Model Context Protocol (MCP) server that provides native integration with Apple Reminders and Calendar on macOS. This server allows you to interact with Apple Reminders and Calendar Events through a standardized interface with comprehensive management capabilities. - List Management: View all reminders and reminder lists with advanced filtering options - Reminder Operations: Full
Add this skill
npx mdskills install FradSer/mcp-server-apple-remindersComprehensive macOS Reminders/Calendar integration with advanced features and clean architecture
English | 简体中文
A Model Context Protocol (MCP) server that provides native integration with Apple Reminders and Calendar on macOS. This server allows you to interact with Apple Reminders and Calendar Events through a standardized interface with comprehensive management capabilities.
Apple now separates Reminders and Calendar permissions into write-only and full-access scopes. The Swift bridge declares the following privacy keys so Claude can both read and write data when you approve access:
NSRemindersUsageDescriptionNSRemindersFullAccessUsageDescriptionNSRemindersWriteOnlyAccessUsageDescriptionNSCalendarsUsageDescriptionNSCalendarsFullAccessUsageDescriptionNSCalendarsWriteOnlyAccessUsageDescriptionWhen the CLI detects a notDetermined authorization status it calls requestFullAccessToReminders / requestFullAccessToEvents, which in turn triggers macOS to show the correct prompt. If the OS ever loses track of permissions, rerun ./check-permissions.sh to re-open the dialogs.
If a Claude tool call still encounters a permission failure, the Node.js layer automatically runs a minimal AppleScript (osascript -e 'tell application "Reminders" …') to surface the dialog and then retries the Swift CLI once.
If you see Failed to read calendar events, verify Calendar is set to Full Calendar Access:
System Settings > Privacy & Security > CalendarsYou can also re-run ./check-permissions.sh (it now validates both Reminders and Calendars access).
Verification command
pnpm test -- src/swift/Info.plist.test.ts
The test suite ensures all required usage-description strings are present before shipping the binary.
You can run the server directly using npx:
npx mcp-server-apple-events
Open Cursor
Open Cursor settings
Click on "MCP" in the sidebar
Click "Add new global MCP server"
Configure the server with the following settings:
{
"mcpServers": {
"apple-reminders": {
"command": "npx",
"args": ["-y", "mcp-server-apple-events"]
}
}
}
stdioapple-remindersmcp-server-apple-eventsYou need to configure Claude Desktop to recognize the Apple Events MCP server. There are two ways to access the configuration:
claude_desktop_config.jsonFor macOS:
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
For Windows:
code %APPDATA%\Claude\claude_desktop_config.json
Add the following configuration to your claude_desktop_config.json:
Option A: Using npx (recommended)
{
"mcpServers": {
"apple-reminders": {
"command": "npx",
"args": ["-y", "mcp-server-apple-events"]
}
}
}
Option B: Using local build
If you have built the project locally, use node with the path to run.cjs:
{
"mcpServers": {
"apple-reminders": {
"command": "node",
"args": ["/absolute/path/to/mcp-server-apple-events/bin/run.cjs"]
}
}
}
For more information on connecting local MCP servers, see the official MCP documentation.
For the changes to take effect:
Once configured, you can ask Claude to interact with your Apple Reminders. Here are some example prompts:
Create a reminder to "Buy groceries" for tomorrow at 5 PM.
Add a reminder to "Call mom" with a note "Ask about weekend plans".
Create a reminder in my "Work" list to "Submit report" due next Friday.
Create a reminder with URL "Check this website: https://google.com".
Create a high priority reminder to "Finish quarterly report" due Friday.
Add an urgent high-priority reminder to "Call client back" for today.
Create a medium priority reminder to "Review documents".
Create a daily reminder to "Take medication" at 9 AM.
Add a weekly reminder every Monday to "Team standup meeting".
Create a monthly reminder on the 1st to "Pay rent".
Set up a yearly reminder on March 15 to "File taxes".
Remind me to "Buy milk" when I arrive at the grocery store.
Create a reminder to "Check mailbox" when I get home.
Add a reminder to "Submit timesheet" when I leave the office.
Create a reminder "Review PR" with tags work and urgent.
Add a reminder "Buy birthday gift" tagged personal and shopping.
Create a reminder with tags: project-alpha, backend, review.
Create a reminder "Grocery shopping" with subtasks: milk, eggs, bread, butter.
Add a reminder "Pack for trip" with checklist items: passport, charger, clothes, toiletries.
Create "Sprint planning" with subtasks: review backlog, estimate stories, assign tasks.
Show subtasks for my "Grocery shopping" reminder.
Mark the "milk" subtask as complete.
Add a new subtask "cheese" to my grocery list reminder.
Reorder the subtasks in my packing list.
Show me all high priority reminders.
Show reminders tagged with "work".
Show recurring reminders only.
Find location-based reminders.
Show reminders with incomplete subtasks.
Update the reminder "Buy groceries" with a new title "Buy organic groceries".
Update "Call mom" reminder to be due today at 6 PM.
Update the reminder "Submit report" and mark it as completed.
Change the notes on "Buy groceries" to "Don't forget milk and eggs".
Set priority to high on my "Finish report" reminder.
Add the tag "urgent" to my "Review PR" reminder.
Show me all my reminders.
List all reminders in my "Shopping" list.
Show my completed reminders.
Show all my reminder lists.
Show reminders from my "Work" list.
The server will:
The server ships with a consolidated prompt registry exposed via the MCP ListPrompts and GetPrompt endpoints. Each template shares a mission, context inputs, numbered process, constraints, output format, and quality bar so downstream assistants receive predictable scaffolding instead of brittle free-form examples.
today_focus (what you most want to accomplish today) input produces a same-day execution blueprint that keeps priority work balanced with recovery time. Supports intelligent task clustering, focus block scheduling, automatic reminder list organization, and auto-creates calendar time blocks when many due-today reminders need fixed slots. Quick Win clusters become 15-minute "Focus Sprint — [Outcome]" holds that finish at each reminder's due timestamp, while Standard tasks map to 30-, 45-, or 60-minute events anchored to the same due-time window.task_idea (a short description of what you want to do) generates an optimally scheduled reminder structure.review_focus (e.g., overdue or a list name) to audit and optimize existing reminders.user_ideas (your thoughts and ideas for what you want to accomplish this week) guides a Monday-through-Sunday reset with time blocks tied to existing lists.pnpm test -- src/server/prompts.test.ts to assert metadata, schema compatibility, and narrative assembly each time you amend prompt copy.This server now exposes service-scoped MCP tools that mirror Apple Reminders and Calendar domains. Use the identifier that matches the resource you want to manipulate:
Tool Name: reminders_tasks
Manages individual reminder tasks with full CRUD support, including priority, alarms, recurrence rules, start/due/completion dates, location triggers, tags, and subtasks.
Actions: read, create, update, delete
Main Handler Functions:
handleReadReminders() - Read reminders with filtering optionshandleCreateReminder() - Create new remindershandleUpdateReminder() - Update existing remindershandleDeleteReminder() - Delete remindersRead Action (action: "read"):
id (optional): Unique identifier of a specific reminder to readfilterList (optional): Name of the reminder list to showshowCompleted (optional): Include completed reminders (default: false)search (optional): Search term to filter reminders by title or contentdueWithin (optional): Filter by due date range ("today", "tomorrow", "this-week", "overdue", "no-date")filterPriority (optional): Filter by priority level ("high", "medium", "low", "none")filterRecurring (optional): Filter to only show recurring reminders when truefilterLocationBased (optional): Filter to only show location-based reminders when truefilterTags (optional): Filter by tags (reminders must have ALL specified tags)Create Action (action: "create"):
title (required): Title of the reminderstartDate (optional): Start date in format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:mm:ss'dueDate (optional): Due date in format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:mm:ss'targetList (optional): Name of the reminders list to add tonote (optional): Note text to attach to the reminderurl (optional): URL to associate with the reminderlocation (optional): Location text (EKCalendarItem.location) (not a geofence trigger)priority (optional): Priority level (0=none, 1=high, 2=medium, 3=low)alarms (optional): Array of alarm objects (see Alarm Object below)recurrenceRules (optional): Array of recurrence rules (see Recurrence Rules below)recurrence (optional): Legacy single recurrence rule object (shorthand for one-item recurrenceRules)locationTrigger (optional): Location trigger object (see Location Triggers section below)tags (optional): Array of tags to add to the remindersubtasks (optional): Array of subtask titles to create with the reminderUpdate Action (action: "update"):
id (required): Unique identifier of the reminder to updatetitle (optional): New title for the reminderstartDate (optional): New start datedueDate (optional): New due date in format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:mm:ss'note (optional): New note texturl (optional): New URL to attach to the reminderlocation (optional): New location text (set to empty string to clear)completed (optional): Mark reminder as completed/uncompletedcompletionDate (optional): Set an explicit completion date/timetargetList (optional): Name of the list containing the reminderpriority (optional): New priority level (0=none, 1=high, 2=medium, 3=low)alarms (optional): Replace alarms with this arrayclearAlarms (optional): Set to true to remove all alarmsrecurrenceRules (optional): Replace recurrence rules with this arrayrecurrence (optional): Legacy single recurrence rule (shorthand for one-item recurrenceRules)clearRecurrence (optional): Set to true to remove recurrencelocationTrigger (optional): New location triggerclearLocationTrigger (optional): Set to true to remove location triggertags (optional): Replace all tags with this arrayaddTags (optional): Tags to add (merges with existing)removeTags (optional): Tags to removeDelete Action (action: "delete"):
id (required): Unique identifier of the reminder to delete{
"relativeOffset": -900, // Seconds (relative to due/start); negative = before
"absoluteDate": "2025-11-04T09:00:00+08:00", // Absolute trigger time (optional)
"locationTrigger": { // Geofence trigger (optional)
"title": "Office",
"latitude": 37.7749,
"longitude": -122.4194,
"radius": 100,
"proximity": "enter"
}
}
Each alarm must specify exactly one of relativeOffset, absoluteDate, or locationTrigger.
recurrenceRules){
"frequency": "daily" | "weekly" | "monthly" | "yearly",
"interval": 1, // Every N periods (default: 1)
"endDate": "YYYY-MM-DD", // Optional end date
"occurrenceCount": 10, // Optional max occurrences
"daysOfWeek": [1, 3, 5], // 1=Sunday, 7=Saturday (for weekly)
"daysOfMonth": [1, 15], // 1-31 (for monthly)
"monthsOfYear": [3, 6] // 1-12 (for yearly)
}
{
"title": "Home", // Location name
"latitude": 37.7749, // Latitude coordinate
"longitude": -122.4194, // Longitude coordinate
"radius": 100, // Geofence radius in meters (default: 100)
"proximity": "enter" // "enter" or "leave"
}
{
"action": "create",
"title": "Buy groceries",
"dueDate": "2024-03-25 18:00:00",
"targetList": "Shopping",
"note": "Don't forget milk and eggs",
"priority": 1,
"tags": ["shopping", "errands"],
"subtasks": ["Milk", "Eggs", "Bread"]
}
{
"action": "create",
"title": "Team standup",
"dueDate": "2024-03-25 09:00:00",
"recurrence": {
"frequency": "weekly",
"interval": 1,
"daysOfWeek": [2, 3, 4, 5, 6]
}
}
{
"action": "create",
"title": "Buy milk",
"locationTrigger": {
"title": "Grocery Store",
"latitude": 37.7749,
"longitude": -122.4194,
"radius": 200,
"proximity": "enter"
}
}
{
"action": "read",
"filterList": "Work",
"showCompleted": false,
"dueWithin": "today",
"filterPriority": "high",
"filterTags": ["urgent"]
}
{
"action": "delete",
"id": "reminder-123"
}
Tool Name: reminders_subtasks
Manages subtasks/checklists within reminders. Subtasks are stored in the notes field using a human-readable format visible in the native Reminders app.
Actions: read, create, update, delete, toggle, reorder
Main Handler Functions:
handleReadSubtasks() - List all subtasks for a reminderhandleCreateSubtask() - Add a new subtaskhandleUpdateSubtask() - Modify a subtaskhandleDeleteSubtask() - Remove a subtaskhandleToggleSubtask() - Flip completion statushandleReorderSubtasks() - Change subtask orderRead Action (action: "read"):
reminderId (required): Parent reminder IDCreate Action (action: "create"):
reminderId (required): Parent reminder IDtitle (required): Subtask titleUpdate Action (action: "update"):
reminderId (required): Parent reminder IDsubtaskId (required): Subtask ID to updatetitle (optional): New titlecompleted (optional): New completion statusDelete Action (action: "delete"):
reminderId (required): Parent reminder IDsubtaskId (required): Subtask ID to deleteToggle Action (action: "toggle"):
reminderId (required): Parent reminder IDsubtaskId (required): Subtask ID to toggleReorder Action (action: "reorder"):
reminderId (required): Parent reminder IDorder (required): Array of all subtask IDs in desired order{
"action": "read",
"reminderId": "reminder-123"
}
{
"action": "create",
"reminderId": "reminder-123",
"title": "Pick up dry cleaning"
}
{
"action": "toggle",
"reminderId": "reminder-123",
"subtaskId": "a1b2c3d4"
}
Subtasks are stored in the notes field with this human-readable format:
User notes here...
---SUBTASKS---
[ ] {a1b2c3d4} First task
[x] {e5f6g7h8} Completed task
[ ] {i9j0k1l2} Another task
---END SUBTASKS---
This format ensures subtasks are visible in the native Reminders app while enabling programmatic access.
Tool Name: reminders_lists
Manages reminder lists - view existing lists or create new ones for organizing reminders.
Actions: read, create, update, delete
Main Handler Functions:
handleReadReminderLists() - Read all reminder listshandleCreateReminderList() - Create new reminder listshandleUpdateReminderList() - Update existing reminder listshandleDeleteReminderList() - Delete reminder listsRead Action (action: "read"):
Create Action (action: "create"):
name (required): Name for new reminder listUpdate Action (action: "update"):
name (required): Current name of the list to updatenewName (required): New name for the reminder listDelete Action (action: "delete"):
name (required): Name of the list to delete{
"action": "create",
"name": "Project Alpha"
}
Tool Name: calendar_events
Handles EventKit calendar events (time blocks) with CRUD capabilities.
Actions: read, create, update, delete
Main Handler Functions:
handleReadCalendarEvents() - Read events with optional filtershandleCreateCalendarEvent() - Create calendar eventshandleUpdateCalendarEvent() - Update existing eventshandleDeleteCalendarEvent() - Delete calendar eventsRead Action (action: "read"):
id (optional): Unique identifier of an event to readfilterCalendar (optional): Calendar name filtersearch (optional): Keyword match against title, notes, or locationavailability (optional): Filter by availability ("busy", "free", "tentative", "unavailable", "not-supported")startDate (optional): Filter events starting on/after this dateendDate (optional): Filter events ending on/before this dateCreate Action (action: "create"):
title (required): Event titlestartDate (required): Start date/timeendDate (required): End date/timetargetCalendar (optional): Calendar name to create innote, location, structuredLocation, url, isAllDay (optional): Additional metadataavailability (optional): Availability ("busy", "free", "tentative", "unavailable")alarms (optional): Array of alarm objects (see Alarm Object above)recurrenceRules (optional): Array of recurrence rules (see Recurrence Rule Object above)Update Action (action: "update"):
id (required): Event identifierclearAlarms (optional): Set to true to remove all alarmsclearRecurrence (optional): Set to true to remove all recurrence rulesspan (optional): Scope for recurring event changes: "this-event" or "future-events"Delete Action (action: "delete"):
id (required): Event identifier to removespan (optional): Scope for recurring event deletes: "this-event" or "future-events"Tool Name: calendar_calendars
Returns the available calendars from EventKit. This is useful before creating or updating events to confirm calendar identifiers.
Actions: read
Main Handler Function:
handleReadCalendars() - List all calendars with IDs and titlesExample Usage
{
"action": "read"
}
Example Response
{
"content": [
{
"type": "text",
"text": "### Calendars (Total: 3)\n- Work (ID: cal-1)\n- Personal (ID: cal-2)\n- Shared (ID: cal-3)"
}
],
"isError": false
}
Success Response:
{
"content": [
{
"type": "text",
"text": "Successfully created reminder: Buy groceries"
}
],
"isError": false
}
Reminder with Enhanced Features:
When reading reminders, the output includes visual indicators for enhanced features:
Example output:
- [ ] Buy groceries 🏷️📋
- List: Shopping
- ID: reminder-123
- Priority: high
- Tags: #shopping #errands
- Subtasks (1/3):
- [x] Milk
- [ ] Eggs
- [ ] Bread
- Due: 2024-03-25 18:00:00
Note about URL fields: The url field is fully supported by EventKit API. When you create or update a reminder with a URL parameter, the URL is stored in two places for maximum compatibility:
url property (visible in Reminders app detail view via the "i" icon)Dual Storage Approach:
Reminder note content here...
URLs:
- https://example.com
- https://another-url.com
This ensures URLs are accessible both in the Reminders app UI and through the API/notes for parsing.
URL Extraction: You can extract URLs from reminder notes using regex:
// Extract URLs from notes using regex
const urlsRegex = reminder.notes?.match(/https?:\/\/[^\s]+/g) || [];
Benefits of Structured Format:
List Response:
{
"reminders": [
{
"title": "Buy groceries",
"list": "Shopping",
"isCompleted": false,
"dueDate": "2024-03-25 18:00:00",
"priority": 1,
"tags": ["shopping", "errands"],
"subtasks": [
{ "id": "a1b2c3d4", "title": "Milk", "isCompleted": true },
{ "id": "e5f6g7h8", "title": "Eggs", "isCompleted": false }
],
"subtaskProgress": { "completed": 1, "total": 2, "percentage": 50 },
"notes": "Don't forget the organic options",
"url": null
}
],
"total": 1,
"filter": {
"list": "Shopping",
"showCompleted": false
}
}
The server provides intelligent reminder organization capabilities through four built-in strategies:
Automatically categorizes reminders based on priority keywords:
Organizes reminders based on their due dates:
Intelligently categorizes reminders by content analysis:
Simple binary organization:
Organize all reminders by priority:
Organize my reminders by priority
Categorize work-related reminders:
Organize reminders from Work list by category
Sort overdue items:
Organize overdue reminders by due date
Tags provide cross-list categorization for reminders. They are stored in the notes field using the [#tag] format, which keeps them human-readable in the native Reminders app.
Tags are stored at the end of notes:
User notes here...
[#work] [#urgent] [#project-alpha]
Create with tags:
{
"action": "create",
"title": "Review code",
"tags": ["work", "code-review", "urgent"]
}
Filter by tags:
{
"action": "read",
"filterTags": ["work", "urgent"]
}
Update tags (add/remove):
{
"action": "update",
"id": "reminder-123",
"addTags": ["completed"],
"removeTags": ["urgent"]
}
MIT
Contributions welcome! Please read the contributing guidelines first.
pnpm install
pnpm build
pnpm test
pnpm exec biome check
The CLI entry point includes a project-root fallback, so you can start the server from nested paths (for example dist/ or editor task runners) without losing access to the bundled Swift binary. The bootstrapper walks up to ten directories to find package.json; if you customise the folder layout, keep the manifest reachable within that depth to retain the guarantee.
pnpm build - Build the Swift helper binary (required before starting the server)pnpm build:swift - Build the Swift helper binary onlypnpm dev - TypeScript development mode with file watching via tsx (runtime TS execution)pnpm start - Start the MCP server over stdio (auto-fallback to runtime TS if no build)pnpm test - Run the comprehensive Jest test suitepnpm check - Run Biome formatting and TypeScript type checkingRuntime Dependencies:
@modelcontextprotocol/sdk ^1.25.1 - MCP protocol implementationexit-on-epipe ^1.0.1 - Graceful process termination handlingtsx ^4.21.0 - TypeScript execution and REPLzod ^4.3.5 - Runtime type validationDevelopment Dependencies:
typescript ^5.9.3 - TypeScript compiler@types/node ^25.0.3 - Node.js type definitions@types/jest ^30.0.0 - Jest type definitionsjest ^30.2.0 - Testing frameworkbabel-jest ^30.2.0 - Babel Jest transformerbabel-plugin-transform-import-meta ^2.3.3 - Babel import meta transformts-jest ^29.4.6 - Jest TypeScript support@biomejs/biome ^2.3.11 - Code formatting and lintingBuild Tools:
Install via CLI
npx mdskills install FradSer/mcp-server-apple-remindersMCP Server Apple Reminders is a free, open-source AI agent skill. English | 简体中文 A Model Context Protocol (MCP) server that provides native integration with Apple Reminders and Calendar on macOS. This server allows you to interact with Apple Reminders and Calendar Events through a standardized interface with comprehensive management capabilities. - List Management: View all reminders and reminder lists with advanced filtering options - Reminder Operations: Full
Install MCP Server Apple Reminders with a single command:
npx mdskills install FradSer/mcp-server-apple-remindersThis downloads the skill files into your project and your AI agent picks them up automatically.
MCP Server Apple Reminders works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Gemini Cli, Amp, Roo Code, Goose. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.