
iCloud Calendar (CalDAV)
io.github.Glob0x17Published by GitHub account Glob0x17v0.2.1Updated Oct 24, 2026
iCloud Calendar over CalDAV: list, create, update, move and delete events. Optional read-only mode.
Overview
Local MCP server that connects an assistant to iCloud Calendar over CalDAV to list calendars and read, create, update, move and delete events.
- What you can do
- List calendars and read events in a date range, optionally for one calendar, sorted by start time, plus a connection check with recent event counts and a calendars resource listing calendars by name. Create events with title, times, all-day flag, location, notes, URL, alarms and recurrence. Update any of those fields or move an event to another calendar atomically. Delete an event by identifier.
- When to use it
- Useful when you want an assistant to read or manage your iCloud calendars from a desktop MCP client on Linux, macOS or Windows, without going through the macOS Calendar app. Start in read-only mode to try it before enabling writes.
- Requirements
- Runs locally over stdio, started by the client, typically with uvx from PyPI. Needs Python 3.12 or later and uv, an Apple ID with iCloud Calendar enabled, and an app-specific password from appleid.apple.com. Set ICLOUD_USERNAME and ICLOUD_PASSWORD; optional CALDAV_SERVER_URL, MCP_ICAL_READ_ONLY and MCP_ICAL_LOG_LEVEL. Desktop clients only.
Installation
In SourceWeft
- Open iCloud Calendar (CalDAV) in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
iCloud Calendar MCP Server
[PyPI] [Python 3.12+] [License: MIT]
A Model Context Protocol server that gives MCP clients access to iCloud Calendar over CalDAV: list calendars, read, create, update, move and delete events. It works on Linux, macOS and Windows, since it talks to iCloud directly instead of going through the macOS Calendar app.
This is a maintained fork of zwrong/iCalendar, itself derived from the macOS
mcp-ical server. See Changes in this fork.
Tools
The calendars://list resource also lists the calendars. With MCP_ICAL_READ_ONLY=true, the three write tools are
not registered at all.
Requirements
- Python 3.12 or later and uv
- An Apple ID with iCloud Calendar enabled
- An app-specific password for that Apple ID
App-specific password
- Sign in to appleid.apple.com, open Sign-In and Security, then App-Specific Passwords.
- Generate a password, for example named
mcp-icloud-caldav.
The username is your Apple ID address, which is not necessarily an @icloud.com address.
An app-specific password gives access to iCloud CalDAV, CardDAV and IMAP: keep it out of version control and revoke
it if it leaks.
Installation
The package is published on PyPI as mcp-icloud-caldav. With uv, MCP clients can
start it directly, without a separate install step:
uvx downloads the package into a cached, isolated environment on first use. To install it permanently instead:
uv tool install mcp-icloud-caldav (or pipx install mcp-icloud-caldav).
From source:
Configuration
Credentials are read in this order:
-
Environment variables (recommended)
-
MCP_ICAL_CONFIG: path to a JSON file shaped likeconfig.json.example -
config_private.json, thenconfig.json, at the repository root (kept for compatibility)
Other settings:
The server speaks MCP over stdio and is started by the client. To check it by hand:
It waits on stdin and prints nothing on stdout.
Client setup
Use the absolute path of uvx (which uvx) if the client cannot find it: clients often start servers without your
shell PATH, which shows up as spawn uvx ENOENT. Usual locations:
The command and its argument are separate fields: the command is uvx (or its path) and mcp-icloud-caldav is an
argument. A config where the command is the single string "uvx mcp-icloud-caldav" fails with ENOENT, because
the client looks for a program with that exact name, space included.
Keeping the password out of the client config
Most clients store env values in clear text in their config file. A small wrapper that reads an env file avoids
that:
Then point the client at ~/.local/bin/mcp-icloud-caldav-run. Starting read-only and switching to false once reading works
is a sensible first step.
Claude Desktop
In claude_desktop_config.json (Settings, Developer, Edit Config). On macOS it is
~/Library/Application Support/Claude/claude_desktop_config.json:
or, with the wrapper, "command": "/home/you/.local/bin/mcp-icloud-caldav-run" and no env. Quit Claude Desktop
completely and start it again after editing. On macOS, server logs are in
~/Library/Logs/Claude/mcp-server-icloud-calendar.log.
Claude Code
or, with the wrapper, claude mcp add --scope user icloud-calendar -- ~/.local/bin/mcp-icloud-caldav-run.
Do not quote what follows --: -- uvx mcp-icloud-caldav registers uvx as the command and mcp-icloud-caldav as
its argument, while -- "uvx mcp-icloud-caldav" registers one program name and fails with ENOENT. To fix an
existing entry, remove it with claude mcp remove icloud-calendar --scope user and add it again.
/mcp in a session shows the server state and its tools; claude mcp get icloud-calendar shows the registered
command and arguments.
Other clients
Any MCP client that can start a stdio server works: run uvx mcp-icloud-caldav with the environment variables above.
The server is also listed in the MCP Registry as
io.github.Glob0x17/mcp-icloud-caldav.
Behavior worth knowing
- Times. Event times are written in UTC. A time with an offset (
2030-01-07T09:30:00+01:00) is converted, and a time without one is taken as the machine's local time. Times are shown back in the machine's timezone. All-day events are written as dates, with the end date exclusive as the iCalendar standard requires. - Moving between calendars. iCloud refuses the same event UID in two calendars, so a move cannot be
"copy then delete".
update_eventwithcalendar_nameuses a WebDAVMOVE, which is atomic on the server: if it fails, the event stays where it was. A move without other changes keeps the original iCalendar data untouched. - Finding events. Listings fill an in-memory index (UID to URL) that lives as long as the server process.
Lookups then go straight to the event, falling back to the
<calendar>/<UID>.icsURL iCloud uses for most events, and only then to a scan of all calendars. iCloud does not support CalDAV UID searches. - Volume. iCloud returns any number of events per request. The practical limit is the client: many cap a tool result at around 25,000 tokens, roughly 300 events in this server's output, so split long ranges.
- Scope. Only calendars hosted on iCloud are visible. Exchange, Google or other accounts added to the Calendar app on a device are not reachable through iCloud CalDAV, and neither are read-only subscribed (ICS) calendars.
Privacy and security
- The only network destination is the configured CalDAV server; there is no telemetry.
- The password never appears in logs, at any level, nor in the configuration object's
repr. - Logs go to stderr only, since stdout carries the MCP protocol. Event contents (titles, notes) are logged only at
DEBUGor below; atINFO, only identifiers. Some clients save server stderr to disk, so keepDEBUGfor troubleshooting. - Dependencies are locked in
uv.lockand resolved from the official PyPI index only.
Troubleshooting
debug_calendar_connection and MCP_ICAL_LOG_LEVEL=DEBUG help narrow things down.
Development
Integration tests run against a real account, read-only, and are skipped unless credentials are set:
Project layout:
Changes in this fork
0.2.1: documentation only (uvx locations, ENOENT causes, client paths on macOS).
0.2.0, compared with zwrong/iCalendar 0.1.0:
- Dependencies. Lockfile regenerated from the official PyPI index (it resolved packages through a third-party
mirror over plain HTTP). Upgrade to
mcp2.x (FastMCPbecameMCPServer) andcaldav3.x; the original code no longer starts against current releases. - Configuration. Environment variables,
MCP_ICAL_CONFIG, read-only mode, configurable log level, no event contents in logs aboveDEBUG. - Fixes.
- Creating an event with a timezone offset failed (
Unable to guess TZID); all-day events and recurrence end dates were written incorrectly. - Alarms were never read back.
- Updating an event without a location, notes or URL failed; changing its time produced invalid iCalendar data.
- Moving an event deleted it before saving the copy, so a failed save lost it.
- New events got a UID containing spaces and the machine's hostname.
- Creating an event with a timezone offset failed (
- Behavior. Events sorted by start time, compact output without empty fields, in-memory event index.
- Tests. Unit tests for configuration, read-only mode, logging, iCalendar output, moves and lookups.
- Packaging. Published on PyPI as
mcp-icloud-caldavand listed in the MCP Registry. The Python package and the command are renamed frommcp_ical/mcp-ical, which clashed with the original macOS project. The unusedmcp[cli]extra was dropped.
Credits and license
MIT, see LICENSE.
- The original macOS
mcp-icalserver (Omar D.), whose copyright notice is kept inLICENSE - zwrong/iCalendar, the iCloud CalDAV port this fork builds on
- python-caldav and the Model Context Protocol Python SDK
Source: README.md at commit 828041e
Tools
0Version history
1- v0.2.1LatestOct 11, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts