apple-calendar-mcp
Reads and manages Apple Calendar on macOS through Apple's EventKit framework, the same database Calendar.app uses. Provides tools to list calendars and events, search events, expand recurring occurrences, find free time slots within working hours, and create, update (single occurrence, this and future, or whole series) or delete events with alarms, URLs and repeat rules.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@apple-calendar-mcpFind two free hours this week and book them for the CS350 project"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
apple-calendar-mcp
A Model Context Protocol server that lets Claude read and manage your Apple Calendar: list your schedule, find free time, and create, move or delete events, including recurring ones.
It talks to macOS through Apple's EventKit framework. That is the same database Calendar.app uses, so every account synced on your Mac (iCloud, Google, Exchange, your university's Outlook) shows up through one interface. Nothing leaves your machine except what Claude reads in the conversation.
You: Find me two free hours this week for the CS350 project, then block them.
Claude: ▸ get_time_context ▸ find_free_slots ▸ create_event
Booked "CS350 project" Thu 13:00–15:00 in Work. Wednesday 09:00–11:00 was also free.Features
Tool | What it does | Kind |
| Current local date, time and time zone, so "next Friday" resolves correctly | read |
| Calendars with account, colour and whether they're writable | read |
| Events in a range, with recurring events expanded into occurrences | read |
| Case-insensitive search across title, location and notes; all terms must match | read |
| Full details, including attendees and repeat rule | read |
| Gaps of at least N minutes within working hours, skipping weekends if you want | read |
| Timed or all-day events, with alarms, URL and repeat rules | write |
| Partial edits. Recurring events take | write |
| Delete one occurrence, this and later ones, or the whole series | destructive |
Other parts of the design:
Tool annotations. Each tool is marked read-only or destructive, so clients can ask you before they change anything.
--read-onlymode. Runs the server without the write tools at all.Prompt-injection hygiene. The server tells the model that event text is untrusted data. Anyone who sends you an invite controls that text.
Typed output. Every tool returns JSON with a published output schema, generated from pydantic models.
Related MCP server: Apple EventKit MCP Server
How it works
flowchart LR
C[Claude Desktop / Claude Code] -- "JSON-RPC over stdio" --> S
subgraph S [apple-calendar-mcp]
direction TB
T["server.py<br/>MCP tools + schemas"] --> V["service.py<br/>validation, defaults,<br/>search, free slots"]
V --> P{{"CalendarStore<br/>(Protocol)"}}
P --> EK["eventkit_store.py<br/>PyObjC → EventKit"]
P --> M["memory_store.py<br/>in-memory (tests, demo)"]
end
EK --> DB[(macOS Calendar database<br/>iCloud · Google · Exchange)]server.pydeclares the tools. The function signatures and pydanticFielddescriptions become the JSON Schema Claude sees. The file contains no logic.service.pyturns loose model input into precise requests. It parses ISO 8601, fills defaults (a 1-hour duration, all-day ranges, search windows), keeps the duration when only the start time moves, and builds search and free-slot finding on top of plain CRUD.CalendarStoreis a six-method protocol. The EventKit backend is the real one. The in-memory backend reproduces EventKit's recurrence semantics, so the entire service and MCP layer is tested on Linux CI.scheduling.pyfinds free slots with interval arithmetic: sort, merge the busy intervals, then sweep each day with two pointers. That is O(n log n + d) for n events over d days.
Design decisions worth knowing
Occurrence ids. EventKit gives every occurrence of a recurring event the same
eventIdentifier. Ids here are"<eventIdentifier>|<original start>", built from EventKit'soccurrenceDate. Each id therefore points at exactly one occurrence, even after that occurrence has been moved.span = all. EventKit only has this and future spans. All is implemented as future applied to the first occurrence. The target occurrence's time change is converted into the same shift for the whole series.Exclusive ends. For an all-day event on 3 Nov,
endis2026-11-04T00:00, the same convention as iCalendarDTEND. EventKit internally reports23:59:59on the last day, so the backend normalises in both directions. On input, an all-dayendis the inclusive last date, because that is how people say it ("5th to 7th").Concurrency. The MCP SDK runs sync tools on worker threads. All EventKit calls go through one lock, and each call runs inside an Objective-C autorelease pool.
Requirements
macOS 13 or later (macOS 14+ uses the newer full-access permission API)
Python 3.11+ and uv
Claude Desktop or Claude Code
Setup
git clone https://github.com/oguz-kagan-gocmez-edu/apple-calendar-mcp.git
cd apple-calendar-mcp
uv sync
uv run apple-calendar-mcp install-app # builds the helper app that holds calendar permission
uv run apple-calendar-mcp doctor # asks for permission, lists your calendarsdoctor triggers a macOS prompt for "Apple Calendar MCP". Choose Allow Full Access. You only do this once: Claude Desktop, Claude Code and Terminal all reuse that permission. install-app needs the Xcode Command Line Tools (xcode-select --install).
Claude Desktop
Open Settings → Developer → Edit Config and add the server (template: examples/claude_desktop_config.json):
{
"mcpServers": {
"apple-calendar": {
"command": "/opt/homebrew/bin/uv",
"args": ["--directory", "/Users/YOU/Projects/apple-calendar-mcp", "run", "apple-calendar-mcp"]
}
}
}Use absolute paths. Run which uv to find yours. Quit Claude Desktop completely (⌘Q) and reopen it.
Claude Code
claude mcp add apple-calendar -s user -- uv --directory /Users/YOU/Projects/apple-calendar-mcp run apple-calendar-mcpOptions
apple-calendar-mcp [--read-only] [--timezone Europe/Istanbul] [--log-level INFO]
apple-calendar-mcp --backend memory --demo # fake data, no Mac needed
apple-calendar-mcp doctor
apple-calendar-mcp install-app [--dest PATH]macOS permissions (read this if nothing works)
macOS protects calendars with TCC (Transparency, Consent and Control). It asks on behalf of the responsible app: normally the GUI app that started the process. Since macOS 14 that app must declare NSCalendarsFullAccessUsageDescription in its Info.plist, or the request is refused without any prompt. Terminal and Claude don't declare it, so running the server directly fails with "macOS refused calendar access without showing a prompt".
install-app fixes this. It builds ~/Applications/Apple Calendar MCP.app, a tiny ad-hoc-signed bundle with no Dock icon. The bundle declares calendar access and contains a ~70-line C launcher (launcher.c). When the bundle is installed, apple-calendar-mcp re-runs itself through the launcher. The launcher makes the bundle responsible for its own permissions, so macOS asks for "Apple Calendar MCP" whichever app started the server. Your Claude config doesn't change.
Choose Allow Full Access. "Add Events Only" is not enough to read your events.
To change your answer later: System Settings → Privacy & Security → Calendars → Apple Calendar MCP.
doctorshows whether the helper app is in use. SetAPPLE_CALENDAR_MCP_NO_APP=1to bypass it.Rebuilding the app (for example after an upgrade) may ask for permission once more.
Without a GUI session (SSH, launchd), the prompt can never appear. The server times out after 30 s with a clear error instead of hanging.
Try it without a Mac
The in-memory backend serves a realistic fake week, which is handy with the MCP Inspector:
npx @modelcontextprotocol/inspector uv run apple-calendar-mcp --backend memory --demoDevelopment
uv sync --group dev
uv run pytest --cov=apple_calendar_mcp # 116 tests
uv run ruff check . && uv run ruff format --check .
uv run mypy src # strictThe test suite has five layers:
Layer | File | What it covers |
Unit |
| ISO parsing, DST-safe recurrence expansion, interval merging and free slots |
Service |
| Create, update and delete validation, plus |
Protocol |
| Full lifecycle over a real MCP client session, schemas, annotations, error mapping |
Backend |
| The EventKit backend running on a fake PyObjC layer: permission flow, all-day conversion, recurrence-rule mapping |
CLI |
| Backend selection, |
CI runs on Ubuntu (Python 3.11–3.13) and macOS. The macOS job also imports the real PyObjC bindings and builds and signs the helper app.
Manual check on a Mac
CI cannot click "Allow" in a permission dialog. Before a release, run through this list:
uv run apple-calendar-mcp doctorshows all your accounts' calendars.In Claude: "What's on my calendar this week?" The results match Calendar.app.
Create a test event. It appears in Calendar.app within a few seconds and syncs to your phone.
Create a weekly test event. Move one occurrence (
this), then rename the rest (future), and check Calendar.app.Delete the series (
all).
Limitations and roadmap
No invitations. EventKit cannot add attendees. Attendees are read-only.
Recurrence subset. Repeat rules support daily, weekly (with weekdays), monthly and yearly frequency, with an interval and a count or until date. More complex rules created in Calendar.app (for example "last Friday of the month") are reported in simplified form.
Reminders are not supported yet. EventKit exposes them through the same store, so this would be a natural next step.
Remote connector. A CalDAV backend for iCloud would implement the same
CalendarStoreprotocol and could be served over streamable HTTP. That would let it work as a claude.ai custom connector on web and mobile.
License
MIT © Oğuz Kağan Göçmez
This server cannot be deployed
Maintenance
Related MCP Connectors
Calendar API for AI agents: events, availability, Google/Microsoft setup, scheduling, and iCal.
Connects ChatGPT to your Apple Calendar via a local Mac agent + Vercel relay
Manage Google, Outlook & Apple calendars and create private sync rules from chat.
Create and update subscription calendars from ChatGPT, Claude, or Codex.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides Claude with full access to Apple Calendar on macOS for event management, smart scheduling, and schedule analytics. It enables natural language event creation, conflict detection, and template-based scheduling through AppleScript integration.36 npm1MIT
- FlicenseNot gradedqualityFmaintenanceProvides Claude Desktop with access to Apple Calendar and Reminders on macOS for managing schedules and tasks through natural language. It supports comprehensive operations like creating, editing, and searching events and reminders, along with a custom hashtag-based tagging system.3-
- AlicenseNot gradedqualityCmaintenanceEnables Claude to interact with iCloud Calendar through CalDAV, allowing users to list, search, create, update, and delete calendar events using natural language.205 npmMIT
- AlicenseNot gradedqualityBmaintenanceProvides Claude with full access to Apple Calendar on macOS via EventKit, enabling reading, searching, creating, updating, and deleting events with support for recurring series, alarms, attendees, and free/busy availability.2MIT