Apple Reminders MCP Server
by madebydia
README.md
# 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
1. **Clone the repository**
```bash
git clone https://github.com/madebydia/apple-mcp-server.git
cd apple-mcp-server
```
2. **Install dependencies**
```bash
npm install
```
3. **Generate API key**
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
```
4. **Configure environment**
Copy `.env.example` to `.env` and add your generated API key:
```bash
cp .env.example .env
```
Edit `.env`:
```
PORT=3000
API_KEY=your_generated_key_here
LOG_LEVEL=info
```
5. **Build the project**
```bash
npm run build
```
This will:
- Compile TypeScript to JavaScript
- Build the Swift binary for EventKit integration
## Usage
### Starting the Server
```bash
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:
```bash
# 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
1. Go to Poke.com connector settings
2. 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:
1. Click "OK" to grant access
2. Alternatively, go to **System Settings > Privacy & Security > Reminders**
3. Ensure the terminal app or the Swift binary has access
## Available Tools
### 1. `list_reminder_lists`
Get all reminder lists.
**Example:**
```json
{}
```
**Returns:**
```json
[
{
"id": "...",
"name": "Personal",
"color": "#FF0000",
"count": 5
}
]
```
### 2. `create_reminder_list`
Create a new reminder list.
**Parameters:**
- `name` (required): Name of the list
- `color` (optional): Hex color code (e.g., "#FF0000")
**Example:**
```json
{
"name": "Shopping",
"color": "#00FF00"
}
```
### 3. `list_reminders`
List reminders with optional filtering.
**Parameters:**
- `listId` (optional): Filter by list ID
- `listName` (optional): Filter by list name
- `showCompleted` (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:**
```json
{
"listName": "Personal",
"showCompleted": false,
"dueWithin": "today"
}
```
### 4. `create_reminder`
Create a new reminder.
**Parameters:**
- `title` (required): Title of the reminder
- `listId` (optional): ID of the list
- `listName` (optional): Name of the list
- `notes` (optional): Additional notes
- `dueDate` (optional): ISO 8601 date string
- `dueDateIncludesTime` (optional): Whether the due date includes time
- `priority` (optional): 0=none, 1=high, 5=medium, 9=low
- `url` (optional): Associated URL
**Example:**
```json
{
"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 reminder
- `title` (optional): New title
- `notes` (optional): New notes (null to clear)
- `dueDate` (optional): New due date (null to clear)
- `dueDateIncludesTime` (optional): Whether due date includes time
- `priority` (optional): New priority
- `url` (optional): New URL (null to clear)
- `moveToListId` (optional): Move to different list
**Example:**
```json
{
"id": "...",
"title": "Buy groceries and supplies",
"priority": 5
}
```
### 6. `complete_reminder`
Mark a reminder as complete or incomplete.
**Parameters:**
- `id` (required): ID of the reminder
- `completed` (required): true or false
**Example:**
```json
{
"id": "...",
"completed": true
}
```
### 7. `delete_reminder`
Delete a reminder permanently.
**Parameters:**
- `id` (required): ID of the reminder
**Example:**
```json
{
"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:
```bash
curl -H "x-api-key: your_api_key_here" http://localhost:3000/sse
```
### Error Codes
- `401 Unauthorized` - Missing API key
- `403 Forbidden` - Invalid API key
- `429 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 TypeScript
- `npm run build:swift` - Build Swift binary
- `npm run build` - Build both TypeScript and Swift
- `npm start` - Start the server
- `npm run dev` - Build and start
- `npm run clean` - Clean build artifacts
### Rebuilding Swift Binary
If you make changes to Swift files:
```bash
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:
1. Go to **System Settings > Privacy & Security > Reminders**
2. Add your terminal app or the Swift binary
3. Restart the server
### Swift Binary Not Found
```bash
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:
```bash
ngrok http 3000
```
### TypeScript Compilation Errors
Clean and rebuild:
```bash
npm run clean
npm run build
```
## License
MIT
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues