che-ical-mcp
Provides native EventKit integration for managing Apple Calendar events and Reminders, including support for task tagging, conflict detection, and batch operations.
Enables direct interaction with macOS system calendars and reminder lists to manage schedules, track tasks, and perform multi-keyword searches.
che-ical-mcp
macOS Calendar & Reminders MCP server - Native EventKit integration for complete calendar and task management.
Why che-ical-mcp?
Feature | Other Calendar MCPs | che-ical-mcp |
Calendar Events | Yes | Yes |
Reminders/Tasks | No | Yes |
Reminder #Tags | No | Yes (MCP-level) |
Multi-keyword Search | No | Yes |
Duplicate Detection | No | Yes |
Conflict Detection | No | Yes |
Batch Operations | No | Yes |
Local Timezone | No | Yes |
Source Disambiguation | No | Yes |
Create Calendar | Some | Yes |
Delete Calendar | Some | Yes |
Event Reminders | Some | Yes |
Location & URL | Some | Yes |
Language | Python | Swift (Native) |
Quick Start
For Claude Desktop
Option A: MCPB One-Click Install (Recommended)
Download the latest .mcpb file from Releases and double-click to install.
Option B: Manual Configuration
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"che-ical-mcp": {
"command": "/usr/local/bin/che-ical-mcp"
}
}
}For Claude Code (CLI)
Option A: Install as Plugin (Recommended)
The plugin includes slash commands (/today, /week, /quick-event, /remind), skills, and a PreToolUse hook that automatically verifies day-of-week when creating or updating events — preventing date/weekday mismatch errors.
claude plugin add --marketplace psychquant-claude-plugins che-ical-mcpNote: The plugin wraps the MCP binary with auto-download. If the binary is not found at
~/bin/CheICalMCP, it will be downloaded from GitHub Releases on first use.
Option B: Install as standalone MCP
If you only need the MCP server without plugin features:
# Create ~/bin if needed
mkdir -p ~/bin
# Download the latest release
curl -L https://github.com/kiki830621/che-ical-mcp/releases/latest/download/CheICalMCP -o ~/bin/CheICalMCP
chmod +x ~/bin/CheICalMCP
# Add to Claude Code
# --scope user : available across all projects (stored in ~/.claude.json)
# --transport stdio: local binary execution via stdin/stdout
# -- : separator between claude options and the command
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCP💡 Tip: Always install the binary to a local directory like
~/bin/. Avoid placing it in cloud-synced folders (Dropbox, iCloud, OneDrive) as file sync operations can cause MCP connection timeouts.
Build from Source (Optional)
git clone https://github.com/kiki830621/che-ical-mcp.git
cd che-ical-mcp
make release && make install⚠️ Swift 6 / Xcode 18 users: Do not use
swift builddirectly — upstream MCP SDK has a concurrency error (swift-sdk#214). The Makefile auto-detects this and falls back to Swift 5 language mode.
On first use, macOS will prompt for Calendar and Reminders access - click "Allow".
CLI Mode (No MCP Server)
All 28 tools can be invoked directly from the command line without running the MCP server:
# Flag-based: --key value pairs
CheICalMCP --cli list_events --start_date 2026-03-29 --end_date 2026-03-30
# JSON via stdin
echo '{"tool":"list_calendars","arguments":{}}' | CheICalMCP --cli
# Use with Claude Code via shell
claude -p "Run: ~/bin/CheICalMCP --cli list_events_quick --range today"Useful for launchd jobs, shell scripts, CI pipelines, and agents that prefer subprocess over MCP protocol. TCC permissions still required — run CheICalMCP --setup first if needed.
All 28 Tools
Tool | Description |
| List all calendars and reminder lists (includes source_type) |
| Create a new calendar |
| Delete a calendar |
| Rename a calendar or change its color (v0.9.0) |
Tool | Description |
| List events with filter/sort/limit (v1.0.0) |
| Create an event (with reminders, location, URL, per-event timezone) |
| Update an event (including timezone, recurrence, span for recurring) |
| Delete an event (with occurrence support for recurring) |
Tool | Description |
| List reminders with filter/sort/limit, tags extraction (v1.0.0) |
| Create a reminder with due date, tags (v1.3.0) |
| Update a reminder (including tags, |
| Mark as completed/incomplete |
| Delete a reminder |
| Search reminders by keyword(s) or tag (v1.3.0) |
| List all unique tags with usage counts (v1.3.0) |
Tool | Description |
| Search events by keyword(s) with AND/OR matching |
| Quick shortcuts: |
| Create multiple events at once (with per-event timezone) |
| Check for overlapping events in a time range |
| Copy an event to another calendar (with optional move) |
| Move multiple events to another calendar |
| Delete events by IDs or date range, with dry-run preview (v1.0.0) |
| Find duplicate events across calendars (v0.5.0) |
| Create multiple reminders at once (v0.9.0) |
| Delete multiple reminders at once (v0.9.0) |
Tool | Description |
| Undo the most recent calendar/reminder operation |
| Redo the last undone operation |
| List undoable operations with timestamps |
Installation
Requirements
macOS 13.0+
Xcode Command Line Tools (only if building from source)
For Claude Desktop
Method 1: MCPB One-Click Install (Recommended)
Download
che-ical-mcp.mcpbfrom ReleasesDouble-click the
.mcpbfile to installRestart Claude Desktop
Method 2: Manual Configuration
Download the binary:
curl -L https://github.com/kiki830621/che-ical-mcp/releases/latest/download/CheICalMCP -o /usr/local/bin/che-ical-mcp chmod +x /usr/local/bin/che-ical-mcpEdit
~/Library/Application Support/Claude/claude_desktop_config.json:{ "mcpServers": { "che-ical-mcp": { "command": "/usr/local/bin/che-ical-mcp" } } }Restart Claude Desktop
For Claude Code (CLI)
# Create ~/bin if needed
mkdir -p ~/bin
# Download the binary
curl -L https://github.com/kiki830621/che-ical-mcp/releases/latest/download/CheICalMCP -o ~/bin/CheICalMCP
chmod +x ~/bin/CheICalMCP
# Register with Claude Code (user scope = available in all projects)
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCPBuild from Source (Optional)
git clone https://github.com/kiki830621/che-ical-mcp.git
cd che-ical-mcp
make release && make install
# Register with Claude Code
claude mcp add --scope user --transport stdio che-ical-mcp -- ~/bin/CheICalMCP⚠️ Swift 6 / Xcode 18 使用者: 不要直接使用
swift build— 上游 MCP SDK 有 concurrency 錯誤(swift-sdk#214)。Makefile 會自動偵測並回退到 Swift 5 語言模式。
Grant Permissions
On first use, macOS will prompt for Calendar and Reminders access. Click Allow for both.
⚠️ macOS Sequoia (15.x) Note: The permission dialog is attributed to the parent application that launched the MCP server, not the binary itself. This means:
Environment
Permission Attributed To
Claude Desktop
Claude Desktop.app ✅ (works automatically)
Claude Code in Terminal.app
Terminal.app ✅ (works automatically)
Claude Code in VS Code
VS Code ❌ (may not show dialog)
Claude Code in iTerm2
iTerm2 ✅ (works automatically)
If the permission dialog doesn't appear (common with VS Code), you need to add
NSCalendarsFullAccessUsageDescriptionto VS Code's Info.plist:# Add calendar usage description to VS Code /usr/libexec/PlistBuddy -c "Add :NSCalendarsFullAccessUsageDescription string 'VS Code needs calendar access for MCP extensions.'" \ "/Applications/Visual Studio Code.app/Contents/Info.plist" /usr/libexec/PlistBuddy -c "Add :NSRemindersFullAccessUsageDescription string 'VS Code needs reminders access for MCP extensions.'" \ "/Applications/Visual Studio Code.app/Contents/Info.plist" # Re-sign VS Code (required after Info.plist modification) codesign -s - -f --deep "/Applications/Visual Studio Code.app" # Restart VS Code, then the permission dialog will appearNote: This modification will be overwritten when VS Code updates. You'll need to re-apply it after each VS Code update.
v1.0.0 Features
Flexible Date Parsing
All date parameters now accept 4 formats:
Format | Example | Interpretation |
Full ISO8601 |
| Exact date and time (offset preserved) |
Without timezone |
| Uses event |
Date only |
| Midnight in event |
Time only |
| Today at that time |
Per-Event Timezone (v1.5.0)
Set the display timezone for individual events — essential for multi-timezone travel itineraries.
"Create a flight departure at 09:14 Berlin time"
→ create_event(title: "Flight LH123", start_time: "2026-04-08T09:14:00", timezone: "Europe/Berlin", ...)
"Update the hotel check-in to Dubai time"
→ update_event(event_id: "...", timezone: "Asia/Dubai")
"Remove the custom timezone from an event"
→ update_event(event_id: "...", clear_timezone: true)timezoneparameter accepts IANA identifiers (e.g.,Europe/Berlin,America/New_York,Asia/Taipei)When
timezoneis provided, naive datetimes (without offset) are interpreted in that timezoneEvent output includes the event's own timezone in
timezonefield and formatsstart_date_local/end_date_localaccordinglyAvailable on
create_event,update_event, andcreate_events_batchUndo/redo preserves per-event timezone
Attendees & Organizer (Read-Only)
Event responses include participant information when available. These fields are read-only due to EventKit limitations — they cannot be set or modified through the MCP.
Available in: list_events, search_events, list_events_quick, check_conflicts
attendees (array, optional) — Present when the event has participants. Each attendee object contains:
Field | Type | Description |
| string or null | Display name, null if not in Address Book |
| string | Email address extracted from participant URL |
| string | One of: |
| string | One of: |
| string | One of: |
| boolean | Whether this participant is the current user |
organizer (object, optional) — Present when the event has an organizer. Contains:
Field | Type | Description |
| string or null | Display name |
| string | Email address |
| boolean | Whether the organizer is the current user |
Note: Both fields are omitted when the event has no participants or organizer (e.g., local calendar events created without invitees).
Fuzzy Calendar Matching
Calendar names are now matched case-insensitively. If not found, the error message lists all available calendars.
Enhanced list/delete Tools
list_events:filter(all/past/future/all_day),sort(asc/desc),limitlist_reminders:filter(all/incomplete/completed/overdue),sort(due_date/creation_date/priority/title),limitdelete_events_batch: date range mode (before_date/after_date) +dry_runpreview
Breaking Change:
list_eventsandlist_remindersnow return{events/reminders: [...], metadata: {...}}instead of a plain array.
Usage Examples
Calendar Management
"List all my calendars"
"What's on my schedule next week?"
"Create a meeting tomorrow at 2 PM titled 'Team Sync'"
"Add a dentist appointment on Friday at 10 AM with location '123 Main St'"
"Delete the meeting called 'Cancelled Meeting'"Reminder Management
"List my incomplete reminders"
"Show all reminders in my Shopping list"
"Add a reminder: Buy milk"
"Create a reminder to call mom tomorrow at 5 PM"
"Mark 'Buy milk' as completed"
"Delete the reminder about groceries"Reminder Management (v1.5.0)
"Remove the due date from 'Buy groceries'"
→ update_reminder(reminder_id: "...", clear_due_date: true)Advanced Features (v0.3.0+)
"Search for events containing 'meeting'"
"Search for events with both 'project' AND 'review'"
"What do I have today?"
"Show me this week's schedule"
"Are there any conflicts if I schedule a meeting from 2-3 PM?"
"Create 3 weekly team meetings for the next 3 weeks"
"Copy the dentist appointment to my Work calendar"
"Move all events from 'Old Calendar' to 'New Calendar'"
"Delete all the cancelled events"
"Find duplicate events between 'IDOL' and 'Idol' calendars"DX Improvements (v1.0.0)
"Show my next 5 upcoming events"
→ list_events(start_date: "2026-02-06", end_date: "2026-12-31", filter: "future", sort: "asc", limit: 5)
"Show my overdue reminders"
→ list_reminders(filter: "overdue")
"Preview which events would be deleted from 'Old Calendar' before 2025"
→ delete_events_batch(calendar_name: "Old Calendar", before_date: "2025-01-01", dry_run: true)
"Create an event at 2 PM" (no need for full ISO8601!)
→ create_event(start_time: "14:00", end_time: "15:00", ...)Supported Calendar Sources
Works with any calendar synced to macOS Calendar app:
iCloud Calendar
Google Calendar
Microsoft Outlook/Exchange
CalDAV calendars
Local calendars
Same-Name Calendar Disambiguation (v0.6.0+)
If you have calendars with the same name from different sources (e.g., "Work" in both iCloud and Google), use the calendar_source parameter:
"Create an event in my iCloud Work calendar"
→ create_event(calendar_name: "Work", calendar_source: "iCloud", ...)
"Show events from my Google Work calendar"
→ list_events(calendar_name: "Work", calendar_source: "Google", ...)If ambiguity is detected, the error message will list all available sources.
Troubleshooting
Problem | Solution |
Server disconnected | Rebuild with |
Permission denied | Grant Calendar/Reminders access in System Settings > Privacy & Security |
Permission dialog never appears | See Grant Permissions for macOS Sequoia workaround |
Permission denied over SSH | See SSH Access below |
Permission denied under launchd | See launchd / Automation below |
Calendar not found | Ensure the calendar is visible in macOS Calendar app |
Reminders not syncing | Check iCloud sync in System Settings |
SSH Access
macOS TCC (Transparency, Consent, and Control) grants privacy permissions per-application. SSH sessions run under sshd, which is a different security context — so permissions granted to Terminal or Claude Code locally do not carry over to SSH.
Workaround A — Run locally first (recommended):
Run
CheICalMCPonce on the target Mac locally (not over SSH)Grant Calendar and Reminders access when the TCC dialog appears
SSH sessions should then inherit the grant for the
CheICalMCPbinary
Workaround B — Grant Full Disk Access to sshd:
Open System Settings → Privacy & Security → Full Disk Access
Click +, press ⌘⇧G, type
/usr/sbin/sshd, and add itRestart the SSH session
⚠️ Workaround B grants
sshdbroad file access — only use this on machines you fully control.
launchd / Automation
When running CheICalMCP from launchd, cron, or other non-interactive automation, macOS TCC cannot show permission dialogs. Use --setup to pre-grant permissions:
# Step 1: Run once from Terminal (triggers TCC permission dialog)
CheICalMCP --setup
# Step 2: Grant Calendar & Reminders access in the dialog that appears
# Step 3: The binary now has permission — launchd jobs can use itDetection: CheICalMCP automatically detects non-interactive sessions (missing
TERMenv var or direct launchd child) and provides targeted error messages with--setupinstructions. This works even for indirect launch chains (launchd → Claude Code → CheICalMCP).Note: If
--setupgrants permission but the MCP still fails under launchd, TCC may have associated the permission with the parent process. In that case, manually add CheICalMCP in System Settings → Privacy & Security → Calendar/Reminders.
Technical Details
Current Version: v1.7.0
Framework: MCP Swift SDK v0.12.0
Calendar API: EventKit (native macOS framework)
Transport: stdio
Platform: macOS 13.0+ (Ventura and later)
Tools: 28 tools for calendars, events, reminders, tags, undo/redo, and advanced operations
Version History
Version | Changes |
v1.7.0 | Attendee & organizer info (#17): read-only |
v1.6.0 | (#13): pre-authorize TCC permissions for launchd/automation. Non-interactive session detection (TERM + ppid). Combined SSH+launchd error messages. (#14): invoke all 28 tools directly from command line without MCP server. Flag-based ( |
v1.5.0 | Per-event timezone (#12): |
v1.4.0 | LLM reliability: Fix default search range (±2yr instead of distantPast/Future), |
v1.3.1 | Docs fix: Clarified that tags are MCP-level (not native Reminders.app tags); Apple provides no public API for native tags |
v1.3.0 | Reminder tags (MCP-level): |
v1.2.0 | Idempotent writes: |
v1.1.0 | Recurrence + Location: recurring events/reminders (daily/weekly/monthly/yearly), structured locations with coordinates, location-based reminder triggers (geofence enter/leave), rich recurrence output |
v1.0.0 | DX improvements: flexible date parsing (4 formats), fuzzy calendar matching, |
v0.9.0 | 4 new tools (20→24): |
v0.8.2 | i18n week support: |
v0.8.1 | Fix: |
v0.8.0 | BREAKING: |
v0.7.0 | Tool annotations for Anthropic Connectors Directory, auto-refresh mechanism, improved batch tool descriptions |
v0.6.0 | Source disambiguation: |
v0.5.0 | Batch delete, duplicate detection, multi-keyword search, improved permission errors, PRIVACY.md |
v0.4.0 | Copy/move events: |
v0.3.0 | Advanced features: search, quick range, batch create, conflict check, timezone display |
v0.2.0 | Swift rewrite with full Reminders support |
v0.1.x | Python version (deprecated) |
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE for details.
Author
Created by Che Cheng (@kiki830621)
If you find this useful, please consider giving it a star!
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/PsychQuant/che-ical-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server