Apple Reminders MCP Server
An MCP (Model Context Protocol) server that provides programmatic access to Apple Reminders via SSE (Server-Sent Events) transport. Built for integration with Poke.com and other MCP clients.
Features
- ✅ Full access to Apple Reminders via EventKit
- ✅ SSE transport for real-time communication
- ✅ API key authentication
- ✅ Rate limiting and security headers
- ✅ Swift-based native macOS integration
- ✅ Comprehensive reminder management (create, read, update, delete, complete)
- ✅ Reminder list management
- ✅ Advanced filtering (by list, date, completion status, search)
Requirements
- macOS 12.0 or later
- Node.js 18.0 or later
- Swift 5.9 or later (comes with Xcode Command Line Tools)
- npm or yarn
Installation
Clone the repository
git clone https://github.com/meimakes/apple-mcp-server.git cd apple-mcp-serverInstall dependencies
npm installGenerate API key
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"Configure environment
Copy
.env.exampleto.envand add your generated API key:cp .env.example .envEdit
.env:PORT=3000 API_KEY=your_generated_key_here LOG_LEVEL=infoBuild the project
npm run buildThis will:
- Compile TypeScript to JavaScript
- Build the Swift binary for EventKit integration
Usage
Starting the Server
npm start
The server will start on the configured port (default: 3000) and display:
SSE server listening on port 3000
Health check: http://localhost:3000/
SSE endpoint: http://localhost:3000/sse
Setting up ngrok (for remote access)
To make the server accessible from Poke.com or other external services:
# Install ngrok if you haven't already
brew install ngrok
# Start ngrok tunnel
ngrok http 3000
Copy the HTTPS URL (e.g., https://abc123.ngrok.io) for use in Poke.com configuration.
Configuring Poke.com
- Go to Poke.com connector settings
- Add a new MCP connector:
- Name: Apple Reminders
- Endpoint URL:
https://your-ngrok-url.ngrok.io/sse - API Key: Your generated API key from
.env
Permissions
On first run, the Swift binary will request access to Reminders. You'll see a system prompt:
- Click "OK" to grant access
- Alternatively, go to System Settings > Privacy & Security > Reminders
- Ensure the terminal app or the Swift binary has access
Available Tools
1. list_reminder_lists
Get all reminder lists.
Example:
{}
Returns:
[
{
"id": "...",
"name": "Personal",
"color": "#FF0000",
"count": 5
}
]
2. create_reminder_list
Create a new reminder list.
Parameters:
name(required): Name of the listcolor(optional): Hex color code (e.g., "#FF0000")
Example:
{
"name": "Shopping",
"color": "#00FF00"
}
3. list_reminders
List reminders with optional filtering.
Parameters:
listId(optional): Filter by list IDlistName(optional): Filter by list nameshowCompleted(optional): Include completed reminders (default: false)dueWithin(optional): Filter by due date - "today", "tomorrow", "this-week", "overdue", "no-date"search(optional): Search in title and notes
Example:
{
"listName": "Personal",
"showCompleted": false,
"dueWithin": "today"
}
4. create_reminder
Create a new reminder.
Parameters:
title(required): Title of the reminderlistId(optional): ID of the listlistName(optional): Name of the listnotes(optional): Additional notesdueDate(optional): ISO 8601 date stringdueDateIncludesTime(optional): Whether the due date includes timepriority(optional): 0=none, 1=high, 5=medium, 9=lowurl(optional): Associated URL
Example:
{
"title": "Buy groceries",
"listName": "Shopping",
"notes": "Milk, eggs, bread",
"dueDate": "2025-11-20T10:00:00Z",
"dueDateIncludesTime": true,
"priority": 1
}
5. update_reminder
Update an existing reminder.
Parameters:
id(required): ID of the remindertitle(optional): New titlenotes(optional): New notes (null to clear)dueDate(optional): New due date (null to clear)dueDateIncludesTime(optional): Whether due date includes timepriority(optional): New priorityurl(optional): New URL (null to clear)moveToListId(optional): Move to different list
Example:
{
"id": "...",
"title": "Buy groceries and supplies",
"priority": 5
}
6. complete_reminder
Mark a reminder as complete or incomplete.
Parameters:
id(required): ID of the remindercompleted(required): true or false
Example:
{
"id": "...",
"completed": true
}
7. delete_reminder
Delete a reminder permanently.
Parameters:
id(required): ID of the reminder
Example:
{
"id": "..."
}
API Endpoints
GET /
Health check endpoint (no authentication required).
Returns server status and active session count.
GET /sse
SSE endpoint for MCP client connections (requires authentication).
Include API key in x-api-key header.
POST /messages
Message handling endpoint (requires authentication).
Include API key in x-api-key header.
Authentication
All protected endpoints require an API key in the x-api-key header:
curl -H "x-api-key: your_api_key_here" http://localhost:3000/sse
Error Codes
401 Unauthorized- Missing API key403 Forbidden- Invalid API key429 Too Many Requests- Rate limit exceeded (100 requests per 15 minutes)
Security
- ✅ API key authentication on all protected endpoints
- ✅ Rate limiting (100 requests per 15 min per IP)
- ✅ Security headers via Helmet
- ✅ HTTPS via ngrok for remote access
- ✅ Input validation via Zod schemas
- ✅ Session timeout after 30 minutes of inactivity
Development
Project Structure
apple-reminders-mcp/
├── src/
│ ├── index.ts # Entry point
│ ├── config.ts # Configuration
│ ├── types.ts # TypeScript types
│ ├── server/
│ │ ├── sse.ts # SSE server
│ │ └── session.ts # Session management
│ ├── middleware/
│ │ └── auth.ts # Authentication
│ ├── mcp/
│ │ ├── server.ts # MCP server
│ │ ├── tools.ts # Tool definitions
│ │ └── handlers.ts # Tool handlers
│ ├── utils/
│ │ ├── logger.ts # Logging
│ │ └── swift-bridge.ts # Swift communication
│ └── swift/
│ ├── Models.swift # Data models
│ ├── RemindersManager.swift # EventKit integration
│ ├── main.swift # Swift entry point
│ └── build.sh # Build script
├── .env.example
├── package.json
├── tsconfig.json
└── README.md
Scripts
npm run build:ts- Compile TypeScriptnpm run build:swift- Build Swift binarynpm run build- Build both TypeScript and Swiftnpm start- Start the servernpm run dev- Build and startnpm run clean- Clean build artifacts
Rebuilding Swift Binary
If you make changes to Swift files:
npm run build:swift
Logging
Set log level in .env:
LOG_LEVEL=debug # debug, info, warn, error
Troubleshooting
Permission Denied Error
If you see a permission error:
- Go to System Settings > Privacy & Security > Reminders
- Add your terminal app or the Swift binary
- Restart the server
Swift Binary Not Found
npm run build:swift
Port Already in Use
Change the port in .env:
PORT=3001
ngrok Connection Issues
Make sure ngrok is installed and running:
ngrok http 3000
TypeScript Compilation Errors
Clean and rebuild:
npm run clean
npm run build
License
MIT
Contributing
Contributions are welcome! Please open an issue or submit a pull request.