A TypeScript MCP server for iCloud Calendar with native multi-VALARM support.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add caldav-mcp -- npx -y No{
"mcpServers": {
"caldav-mcp": {
"command": "npx",
"args": ["-y", "No"],
"env": {
"CALDAV_USERNAME": "<caldav_username>",
"CALDAV_PASSWORD": "<caldav_password>",
"CALDAV_MCP_HOST": "<caldav_mcp_host>"
}
}
}
}CALDAV_USERNAMECALDAV_PASSWORDCALDAV_MCP_HOSTResumen de MCP Servers
# CalDAV MCP Server
[](https://www.typescriptlang.org/)
[](https://github.com/lukegskw/caldav-mcp/actions/workflows/container.yml)
[](https://www.npmjs.com/package/@lukegskw/caldav-mcp)
[](https://www.npmjs.com/package/@lukegskw/caldav-mcp)
[](https://github.com/lukegskw/caldav-mcp/pkgs/container/caldav-mcp)
[](https://registry.modelcontextprotocol.io/?q=io.github.lukegskw%2Fcaldav-mcp)
[](LICENSE)
**CalDAV MCP Server** is a Model Context Protocol server for managing iCloud Calendar
events, including native support for multiple `VALARM` reminders on one event.
iCloud Calendar is the only provider officially supported and manually validated in the
first release. The server works with any MCP client that supports `stdio` or Streamable
HTTP.
This independent project is not affiliated with, authorized, sponsored, or approved by
Apple Inc. Apple and iCloud are trademarks of their respective owner.
## Quick start
Install [Node.js 24+](https://nodejs.org/), create an
[Apple app-specific password](https://support.apple.com/en-us/102654), and add this
local `stdio` server to a JSON-configured MCP client such as Claude Desktop or Gemini:
```json
{
"mcpServers": {
"icloud-calendar": {
"command": "npx",
"args": ["--yes", "@lukegskw/caldav-mcp@latest"],
"env": {
"CALDAV_USERNAME": "user@example.com",
"CALDAV_PASSWORD": "xxxx-xxxx-xxxx-xxxx"
}
}
}
}
```
Restart the client and confirm that it lists six calendar tools. See
[client-specific setup](#mcp-client-setup) and [Docker deployment](#docker-compose)
below. Keep the configuration file private because it contains the app-specific
password.
## Navigation
- [About](#about)
- [Features](#features)
- [MCP tools](#mcp-tools)
- [Tech stack](#tech-stack)
- [Installation](#installation)
- [Configuration](#configuration)
- [MCP client setup](#mcp-client-setup)
- [Verification](#verification)
- [Limitations](#limitations)
- [Contributing](#contributing)
- [Releasing](#releasing)
## About
The server connects one configured account to iCloud through CalDAV. It discovers the
account's calendars and exposes normalized read and write operations through MCP.
Updates preserve the complete iCalendar resource, including unknown properties, Apple
extensions, `VTIMEZONE`, recurrence exceptions, and alarms omitted from a patch. Writes
use opaque resource identifiers and ETags instead of assuming that a CalDAV filename
matches an event UID.
Calendar resources are processed in memory. The server has no telemetry and no
application database, and raw iCalendar is returned only when explicitly requested.
## Features
- Discovers calendars available to the configured iCloud account.
- Lists events in semi-open time ranges and expands recurring occurrences.
- Creates timed, all-day, and recurring events.
- Supports zero, one, or multiple display alarms per event.
- Emits the Apple alarm extensions expected by iCloud Calendar.
- Reads events by opaque resource ID or by calendar ID and UID.
- Applies partial updates while preserving omitted and unknown iCalendar data.
- Uses ETags for optimistic concurrency on updates and deletions.
- Rejects isolated recurrence mutations instead of changing the complete series.
- Redacts credentials, raw calendar content, and CalDAV paths from logs and errors.
- Runs as a non-root container with a read-only root filesystem configuration.
- Supports `stdio` and Streamable HTTP MCP transports.
## MCP tools
### `list_calendars`
Lists the calendars discovered for the configured account. Each result includes an
opaque `calendar_id`, display name, description, timezone, and best-effort write status.
### `list_events`
Lists events in a semi-open interval and expands recurring occurrences. The maximum
range is 366 days, the default page size is 100, and the maximum page size is 500.
Results use a deterministic chronological order. Pagination cursors are opaque and
do not represent a snapshot when events are modified during traversal.
Example input:
```json
{
"calendar_id": "opaque-calendar-id",
"start": "2026-09-01T00:00:00Z",
"end": "2026-10-01T00:00:00Z",
"timezone": "Europe/Berlin",
"limit": 100
}
```
### `get_event`
Reads an event by `resource_id`, or by a `calendar_id` and UID pair. Raw iCalendar is
excluded by default and can be requested with `include_raw_ical: true` for controlled
diagnostics.
### `create_event`
Creates an event and reads back the representation stored by the server.
Timed event with two alarms:
```json
{
"calendar_id": "opaque-calendar-id",
"summary": "Buy Shinkansen tickets",
"start": {
"date_time": "2026-09-06T03:00:00+02:00",
"timezone": "Europe/Berlin"
},
"end": {
"date_time": "2026-09-06T03:30:00+02:00",
"timezone": "Europe/Berlin"
},
"description": "Smart-EX",
"location": null,
"alarms": [
{ "minutes_before": 1440, "action": "DISPLAY" },
{ "minutes_before": 0, "action": "DISPLAY" }
],
"rrule": null
}
```
All-day event with an exclusive end date:
```json
{
"calendar_id": "opaque-calendar-id",
"summary": "Trip",
"start": { "date": "2026-09-06" },
"end": { "date": "2026-09-08" },
"alarms": []
}
```
Recurring events accept an RFC 5545 rule without the `RRULE:` prefix:
```json
{
"calendar_id": "opaque-calendar-id",
"summary": "Weekly planning",
"start": {
"date_time": "2026-09-07T09:00:00+02:00",
"timezone": "Europe/Berlin"
},
"end": {
"date_time": "2026-09-07T09:30:00+02:00",
"timezone": "Europe/Berlin"
},
"rrule": "FREQ=WEEKLY;BYDAY=MO;COUNT=10"
}
```
### `update_event`
Patches an event or complete recurring series. Omitted fields are preserved, `null`
removes a nullable field, and `alarms: []` removes all alarms. An optional
`expected_etag` prevents overwriting a newer server version.
### `delete_event`
Deletes an event or complete recurring series, optionally requiring an observed ETag.
Deleting a single expanded occurrence is not supported in the current release.
## Tech stack
- [Node.js 24+](https://nodejs.org/)
- [TypeScript](https://www.typescriptlang.org/) with strict project rules
- [Model Context Protocol TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [tsdav](https://github.com/natelindev/tsdav)
- [ical.js](https://github.com/kewisch/ical.js)
- [Zod](https://zod.dev/)
- [Vitest](https://vitest.dev/)
- [pnpm](https://pnpm.io/)
- [Docker](https://www.docker.com/)
## Installation
### Prerequisites
- An iCloud account with Calendar enabled.
- Two-factor authentication enabled for the Apple Account.
- An [app-specific password](https://support.apple.com/en-us/102654).
- Docker and Docker Compose for container deployment, or Node.js 24+ for `npx`.
- pnpm is required only when building from source. Corepack and CI use the version
pinned in `package.json`.
### npm / npx
No global install or repository clone is required. MCP clients can launch the latest
published package directly:
```sh
CALDAV_USERNAME='user@example.com' \
CALDAV_PASSWORD='xxxx-xxxx-xxxx-xxxx' \
npx --yes @lukegskw/caldav-mcp@latest
```
The command waits for MCP messages on stdin and normally prints nothing to stdout. In
practice, add it to the client configuration as shown in [MCP client setup](#mcp-client-setup).
For reproducible environments, replace `latest` with an exact published version such as
`X.Y.Z`.
### Docker Compose
The recommended installation uses the published multi-architecture image:
```text
ghcr.io/lukegskw/caldav-mcp:latest
```
Download the Compose example:
```sh
curl -O https://raw.githubusercontent.com/lukegskw/caldav-mcp/main/compose.example.yaml
```
Provide the Apple Account email and app-specific password, then start the service:
```sh
export CALDAV_USERNAME='user@example.com'
export CALDAV_PASSWORD='xxxx-xxxx-xxxx-xxxx'
docker compose -f compose.example.yaml up -d
```
To publish a different host port, set:
```sh
export CALDAV_MCP_PUBLISHED_PORT=18100
docker compose -f compose.example.yaml up -d
```
The `latest` tag follows the newest stable release. Stable releases also publish an
exact tag such as `0.1.6` and a minor-series tag such as `0.1`. The Compose example
pins `latest` by digest so deployments are reproducible. To upgrade, download the
updated Compose example or replace the full image reference with the desired
published version and digest.
The Streamable HTTP endpoint will be available at:
```text
http://<host>:8100/mcp
```
The host port can change without changing port `8100` inside the container. No
persistent volume is required; calendar data remains in iCloud.
### Docker run
The same hardened container configuration can be started directly:
```sh
docker run -d \
--name caldav-mcp \
--restart unless-stopped \
--read-only \
--user 10001:10001 \
--cap-drop ALL \
--security-opt no-new-privileges:true \
--tmpfs /tmp:size=16m,mode=1777 \
-e CALDAV_PROVIDER=icloud \
-e CALDAV_USERNAME \
-e CALDAV_PASSWORD \
-e CALDAV_MCP_TRANSPORT=streamable-http \
-e CALDAV_MCP_HOST=0.0.0.0 \
-p 8100:8100 \
ghcr.io/lukegskw/caldav-mcp:latest
```
### Build the container from source
Building locally is optional. Prefer the published image unless you need to modify or
audit the container build.
```sh
git clone https://github.com/lukegskw/caldav-mcp.git
cd caldav-mcp
docker buildx build --load -t caldav-mcp:local .
```
### Local Node.js installatiLo que la gente pregunta sobre caldav-mcp
¿Qué es lukegskw/caldav-mcp?
+
lukegskw/caldav-mcp es mcp servers para el ecosistema de Claude AI. A TypeScript MCP server for iCloud Calendar with native multi-VALARM support. Tiene 3 estrellas en GitHub y su última actualización registrada es del 2026-09-12.
¿Cómo se instala caldav-mcp?
+
Puedes instalar caldav-mcp clonando el repositorio (https://github.com/lukegskw/caldav-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar lukegskw/caldav-mcp?
+
Nuestro agente de seguridad ha analizado lukegskw/caldav-mcp y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene lukegskw/caldav-mcp?
+
lukegskw/caldav-mcp es mantenido por lukegskw. La última actividad registrada en GitHub es del 2026-09-12, con 3 issues abiertos.
¿Hay alternativas a caldav-mcp?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega caldav-mcp en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/lukegskw-caldav-mcp)<a href="https://claudewave.com/repo/lukegskw-caldav-mcp"><img src="https://claudewave.com/api/badge/lukegskw-caldav-mcp" alt="Featured on ClaudeWave: lukegskw/caldav-mcp" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!
The fastest path to AI-powered full stack observability, even for lean teams.