# Mcp Icloud Calendar

> A Go-based MCP server for Apple iCloud Calendar via CalDAV — manage calendars and events through AI assistants with cross-platform support.

- **Type:** MCP server
- **Install:** `agentstack add mcp-roygabriel-mcp-icloud-calendar`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [roygabriel](https://agentstack.voostack.com/s/roygabriel)
- **Installs:** 0
- **Category:** [Productivity](https://agentstack.voostack.com/c/productivity)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [roygabriel](https://github.com/roygabriel)
- **Source:** https://github.com/roygabriel/mcp-icloud-calendar

## Install

```sh
agentstack add mcp-roygabriel-mcp-icloud-calendar
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# iCloud Calendar MCP Server

A [Model Context Protocol](https://modelcontextprotocol.io) server that gives AI assistants full access to Apple iCloud Calendar through CalDAV. List calendars, search events, create, update, and delete events -- all from Claude or any MCP-compatible client.

Built with Go and the [mcp-go SDK](https://mcp-go.dev). Ships as a single static binary for Linux, macOS, and Windows.

---

## Table of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage with Claude Desktop](#usage-with-claude-desktop)
- [Available Tools](#available-tools)
- [Development](#development)
- [Architecture](#architecture)
- [Security](#security)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)

---

## Features

**Calendar Operations**
- List all iCloud calendars with paths, names, descriptions, and colors
- Search events with date range filters and pagination
- Create events with title, time, description, location, and attendees
- Update individual fields on existing events (partial update with pointer fields)
- Delete events permanently

**Recurring Events & Attendees**
- Expand recurring events (RRULE) into individual occurrences within a date range
- Manage attendees with roles (CHAIR, REQ-PARTICIPANT, OPT-PARTICIPANT) and statuses

**Multi-Account Support**
- Manage multiple iCloud accounts from a single server instance
- Configure via `ACCOUNTS_FILE` JSON or single-account environment variables
- Per-account rate limiting and retry logic

**Operational**
- Structured JSON logging with UUID request correlation
- Configurable timeout middleware on every tool call (default 25s)
- Automatic retry with exponential backoff for transient failures
- Rate limiting per account to avoid iCloud throttling
- Health endpoint (`/healthz`, `/readyz`) and Prometheus metrics (`/metrics`)
- Audit logging for mutating operations (no PII)
- Input validation for all tool parameters
- MCP tool annotations (read-only, destructive, idempotent) for client-side safety
- Graceful shutdown on SIGTERM/SIGINT
- mTLS and custom CA support for enterprise deployments
- `file://` credential loading for Docker/Kubernetes secrets
- CI pipeline with tests, linting, and vulnerability scanning

---

## Quick Start

```bash
# Install
go install github.com/rgabriel/mcp-icloud-calendar@latest

# Set credentials (app-specific password, not your main iCloud password)
export ICLOUD_EMAIL="you@icloud.com"
export ICLOUD_PASSWORD="xxxx-xxxx-xxxx-xxxx"

# Run
mcp-icloud-calendar
```

Or download a prebuilt binary from the [Releases](https://github.com/rgabriel/mcp-icloud-calendar/releases) page.

---

## Prerequisites

- **Go 1.21+** -- [install](https://go.dev/doc/install) (only needed when building from source)
- **iCloud account** with two-factor authentication enabled
- **App-specific password** -- required for CalDAV access

### Generating an App-Specific Password

1. Go to [appleid.apple.com](https://appleid.apple.com) and sign in
2. Navigate to **Sign-In and Security** > **App-Specific Passwords**
3. Click **Generate an app-specific password**
4. Enter a label (e.g. "MCP Calendar Server") and click **Create**
5. Copy the generated password (`xxxx-xxxx-xxxx-xxxx`) and store it securely

Notes:
- Your Apple ID must have two-factor authentication enabled
- You can create up to 25 active app-specific passwords
- Changing your main Apple ID password revokes all app-specific passwords
- Never use your main iCloud password for CalDAV access

---

## Installation

### From Source

```bash
git clone https://github.com/rgabriel/mcp-icloud-calendar.git
cd mcp-icloud-calendar
make build
```

### Using `go install`

```bash
go install github.com/rgabriel/mcp-icloud-calendar@latest
```

### Docker

```bash
docker build -t mcp-icloud-calendar .

docker run \
  -e ICLOUD_EMAIL="you@icloud.com" \
  -e ICLOUD_PASSWORD="xxxx-xxxx-xxxx-xxxx" \
  mcp-icloud-calendar
```

The Docker image uses a multi-stage build with a [distroless](https://github.com/GoogleContainerTools/distroless) base image and runs as a non-root user.

### Prebuilt Binaries

Download the binary for your platform from the [Releases](https://github.com/rgabriel/mcp-icloud-calendar/releases) page. Binaries are available for:

| Platform | Architecture | Binary |
|----------|-------------|--------|
| Linux | x86_64 | `mcp-icloud-calendar-linux-amd64` |
| Linux | ARM64 | `mcp-icloud-calendar-linux-arm64` |
| macOS | Intel | `mcp-icloud-calendar-macos-amd64` |
| macOS | Apple Silicon | `mcp-icloud-calendar-macos-arm64` |
| Windows | x86_64 | `mcp-icloud-calendar-windows-amd64.exe` |

SHA256 checksums are provided alongside each binary.

---

## Configuration

### Single Account

The server requires two environment variables at minimum:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `ICLOUD_EMAIL` | Yes | | Your iCloud email address (Apple ID) |
| `ICLOUD_PASSWORD` | Yes | | App-specific password from appleid.apple.com |
| `ICLOUD_CALENDAR_ID` | No | | Default calendar path (e.g., `/1234567/calendars/home/`) |
| `LOG_LEVEL` | No | `INFO` | Logging verbosity: `DEBUG`, `INFO`, `WARN`, `ERROR` |
| `TOOL_TIMEOUT` | No | `25s` | Timeout per tool call (Go duration, e.g., `30s`, `1m`) |
| `MAX_RETRIES` | No | `3` | Retry attempts for transient CalDAV failures |
| `RETRY_BASE_DELAY` | No | `1s` | Base delay for exponential backoff |
| `RATE_LIMIT_RPS` | No | `10` | CalDAV requests per second per account |
| `RATE_LIMIT_BURST` | No | `20` | Burst allowance for rate limiter |
| `MAX_CONNS_PER_HOST` | No | `10` | Max HTTP connections to iCloud per account |
| `HEALTH_PORT` | No | | Port for health/metrics HTTP server (e.g., `8080`) |
| `TLS_CERT_FILE` | No | | Client TLS certificate for mTLS |
| `TLS_KEY_FILE` | No | | Client TLS key for mTLS |
| `TLS_CA_FILE` | No | | Custom CA certificate |

You can set these as environment variables or place them in a `.env` file:

```bash
cp .env.example .env
# Edit .env with your credentials
```

Credentials support `file://` prefixes for Docker/Kubernetes secrets (e.g., `ICLOUD_PASSWORD=file:///run/secrets/password`).

### Multi-Account

To manage multiple iCloud accounts, set the `ACCOUNTS_FILE` environment variable pointing to a JSON file:

```json
{
  "accounts": [
    {
      "name": "personal",
      "email": "personal@icloud.com",
      "password": "xxxx-xxxx-xxxx-xxxx",
      "calendarId": "/1234567/calendars/home/"
    },
    {
      "name": "work",
      "email": "work@icloud.com",
      "password": "yyyy-yyyy-yyyy-yyyy"
    }
  ]
}
```

Each tool accepts an optional `account` parameter. Omit it to use the default account.

---

## Usage with Claude Desktop

Add the server to your Claude Desktop configuration file.

**macOS** -- `~/Library/Application Support/Claude/claude_desktop_config.json`

**Linux** -- `~/.config/claude/claude_desktop_config.json`

**Windows** -- `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "icloud-calendar": {
      "command": "/path/to/mcp-icloud-calendar",
      "env": {
        "ICLOUD_EMAIL": "you@icloud.com",
        "ICLOUD_PASSWORD": "xxxx-xxxx-xxxx-xxxx"
      }
    }
  }
}
```

Restart Claude Desktop after saving.

---

## Available Tools

The server exposes 5 MCP tools. Each tool includes schema constraints and annotations indicating whether it is read-only, destructive, or idempotent.

### list_calendars

List all available iCloud calendars. Returns each calendar's path, display name, description, and color. Call this first to discover valid `calendarId` values.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `account` | string | | Account name for multi-account setups |

### search_events

Search for calendar events within a date range. Returns paginated results with event details including recurrence info and attendees.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `account` | string | | Account name for multi-account setups |
| `calendarId` | string | *(server default)* | Calendar path from `list_calendars` |
| `startTime` | string | | Start of date range (RFC 3339, e.g., `2025-03-01T00:00:00Z`) |
| `endTime` | string | | End of date range (RFC 3339) |
| `limit` | number | `50` | Max events to return (1-500) |
| `offset` | number | `0` | Events to skip for pagination |
| `expandRecurrence` | boolean | `false` | Expand recurring events into individual occurrences (requires both `startTime` and `endTime`) |

### create_event

Create a new calendar event. Returns the created event's unique ID.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `account` | string | | Account name for multi-account setups |
| `title` | string | *(required)* | Event title or summary |
| `startTime` | string | *(required)* | Start time (RFC 3339) |
| `endTime` | string | *(required)* | End time (RFC 3339) |
| `description` | string | | Event description or notes |
| `location` | string | | Event location |
| `calendarId` | string | *(server default)* | Calendar path to create the event in |
| `attendees` | string | | JSON array of attendee objects (see below) |

**Attendee format:**

```json
[
  {"email": "alice@example.com", "name": "Alice", "role": "REQ-PARTICIPANT"},
  {"email": "bob@example.com", "name": "Bob", "role": "OPT-PARTICIPANT", "status": "TENTATIVE"}
]
```

Supported roles: `CHAIR`, `REQ-PARTICIPANT`, `OPT-PARTICIPANT`. Supported statuses: `NEEDS-ACTION`, `ACCEPTED`, `DECLINED`, `TENTATIVE`.

### update_event

Update specific fields of an existing event. Only include the fields you want to change -- omitted fields remain unchanged.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `account` | string | | Account name for multi-account setups |
| `eventId` | string | *(required)* | Event ID (UID) from `search_events` |
| `calendarId` | string | *(server default)* | Calendar path containing the event |
| `title` | string | | Updated title |
| `description` | string | | Updated description |
| `location` | string | | Updated location |
| `startTime` | string | | Updated start time (RFC 3339) |
| `endTime` | string | | Updated end time (RFC 3339) |

### delete_event

Permanently delete a calendar event. This action cannot be undone.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `account` | string | | Account name for multi-account setups |
| `eventId` | string | *(required)* | Event ID (UID) from `search_events` |
| `calendarId` | string | *(required)* | Calendar path containing the event |

---

## Development

### Building

```bash
make build          # Build binary with version embedding
make test           # Run tests with race detector
make lint           # Run golangci-lint
make clean          # Remove build artifacts
make docker         # Build Docker image
make run            # Build and run
```

### Running Locally

```bash
export ICLOUD_EMAIL="you@icloud.com"
export ICLOUD_PASSWORD="xxxx-xxxx-xxxx-xxxx"
make run
```

### Testing

The project includes 88 table-driven tests across 14 test files, covering all tool handlers, CalDAV client logic, input validation, retry/rate-limiting wrappers, recurrence expansion, attendee parsing, and error paths. Tests use mock implementations of the `CalendarService` interface -- no live CalDAV connection required.

```bash
make test
```

### Testing with MCP Inspector

Use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to interactively test the server:

```bash
npx @modelcontextprotocol/inspector mcp-icloud-calendar
```

### CI Pipeline

Every push to `main` or `dev` and every pull request runs:

- `go vet` and `go test -race` -- correctness and data race detection
- `golangci-lint` -- static analysis (errcheck, govet, staticcheck, gosec, gocritic, and more)
- `govulncheck` -- known vulnerability scanning

Tagged releases (`v*.*.*`) trigger automated cross-platform builds with SHA256 checksums.

---

## Architecture

```
mcp-icloud-calendar/
  main.go                Server setup, multi-account init, tool registration, middleware chain
  config/
    config.go            Environment variable loading, validation, file:// credential support
    accounts.go          Multi-account JSON configuration
  caldav/
    interface.go         CalendarService interface
    client.go            CalDAV client (caldav.icloud.com, TLS/mTLS)
    retry.go             Retry wrapper with exponential backoff
    ratelimit.go         Rate-limiting wrapper (token bucket)
    recurrence.go        RRULE expansion for recurring events
    attendees.go         Attendee parsing and serialization
    validation.go        Input validation for CalDAV parameters
  tools/
    accounts.go          AccountClients multi-account resolver
    list_calendars.go    list_calendars handler
    search_events.go     search_events handler
    create_event.go      create_event handler
    update_event.go      update_event handler
    delete_event.go      delete_event handler
  health/server.go       Health check and readiness endpoints
  metrics/               Prometheus metrics and tool call middleware
  middleware/             Request ID middleware (UUID correlation)
  logging/               Structured JSON logging (slog)
```

**Client chain:** Each account gets its own pipeline: `realClient -> RateLimitedClient -> RetryClient`

**Middleware chain:** Each tool call passes through `RequestID -> Timeout -> Metrics -> handler`. The request ID middleware assigns a UUID for log correlation. The timeout middleware enforces a configurable deadline. The metrics middleware records tool call duration and outcome.

**Audit logging:** Mutating operations (`create_event`, `update_event`, `delete_event`) are logged via a post-call hook with tool name, account, calendar ID, and status -- no PII (titles, descriptions, locations) is included.

### Dependencies

| Package | Purpose |
|---------|---------|
| [mcp-go](https://github.com/mark3labs/mcp-go) | MCP SDK -- tool registration, stdio transport |
| [go-webdav](https://github.com/emersion/go-webdav) | CalDAV protocol client |
| [go-ical](https://github.com/emersion/go-ical) | iCalendar (RFC 5545) parsing |
| [rrule-go](https://github.com/teambition/rrule-go) | Recurrence rule expansion |
| [godotenv](https://github.com/joho/godotenv) | `.env` file loading |
| [uuid](https://github.com/google/uuid) | Event UID and request ID generation |
| [prometheus/client_golang](https://github.com/prometheus/client_golang) | Prometheus metrics |
| [x/time/rate](https://pkg.go.dev/golang.org/x/time/rate) | Token bucket rate limiter |

---

## Security

- **App-specific passwords only** -- never accepts or stores your main iCloud password
- **TLS everywhere** -- all CalDAV communication uses HTTPS with TLS verification
- **mTLS support** -- optional client certificate authentication for enterprise environments
- **Input validation** -- all tool parameters are validated for type, range, and format
- **Size and format limits** -- title length, time range, and parameter constraints enforced via MCP schema
- **Credential file loading** -- `file://` prefix for secure secret injection (Docker, Kubernetes)
- **Distroless Docker image** -- minimal attack surface, runs as non-root
- **No third-party data sharing** -- the server runs locally and communicates only with iCloud servers
- **Revocable access** -- app-specific passwords can be revoked at any time from appleid.apple.com
- **Audit trail** -- mutating operations are logged without PII for compliance

Never commit your `.env` file to version control. The `.gitignore` already excludes it.

---

## Troubleshooting

### Authentication Failed

- Verify you are using an app-specif

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [roygabriel](https://github.com/roygabriel)
- **Source:** [roygabriel/mcp-icloud-calendar](https://github.com/roygabriel/mcp-icloud-calendar)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-roygabriel-mcp-icloud-calendar
- Seller: https://agentstack.voostack.com/s/roygabriel
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
