PluginBench
MCP Server
Active

org.onekash/icloud-calendar-mcp MCP Server

org.onekash/icloud-calendar-mcp

Access and manage your iCloud Calendar from Claude and Cursor via CalDAV with security-first design.

What is the org.onekash/icloud-calendar-mcp MCP server?

The iCloud Calendar MCP Server is an MCP (Model Context Protocol) server that gives AI assistants like Claude access to iCloud Calendar via CalDAV. It provides tools to list calendars, retrieve events, create, update, and delete calendar entries with support for recurring events, proper timezone handling, and OWASP MCP Top 10 security compliance.

This server bridges iCloud Calendar and AI assistants, enabling natural-language calendar management. You can ask Claude to check your schedule, create meetings, reschedule events, and find conflicts—all backed by durable event handles, correct recurrence expansion, and security controls that protect your credentials and prevent data leakage.

How to install org.onekash/icloud-calendar-mcp

Copy-paste configuration for popular MCP clients.

transport: stdio
Config generated by PluginBench — verify against the source before use.
Environment / auth
  • ICLOUD_USERNAME
    required

    Your Apple ID email (e.g., user@icloud.com)

  • ICLOUD_PASSWORD
    required
    secret

    App-specific password for iCloud (not your main Apple ID password)

~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "icloud-calendar-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@icloud-calendar-mcp/server"
      ],
      "env": {
        "ICLOUD_USERNAME": "<YOUR_ICLOUD_USERNAME>",
        "ICLOUD_PASSWORD": "<YOUR_ICLOUD_PASSWORD>"
      }
    }
  }
}

Tools & capabilities

Tools this server exposes to the agent.

  • list_calendars — List all calendars from your iCloud account
  • get_events — Retrieve events within a date range from a calendar, with support for recurring series expansion
  • create_event — Create a new calendar event with optional recurrence, timezone, location, description, and reminders
  • update_event — Update an event (whole series or single occurrence) with scope control for recurring edits
  • delete_event — Delete an event (whole series or single occurrence) with scope control for recurring deletes

Use cases

  • Ask Claude 'What's on my calendar this week?' to check your schedule
  • Create meetings by saying 'Schedule a meeting with John tomorrow at 2pm'
  • Reschedule events: 'Move my 3pm meeting to 4pm'
  • Find scheduling conflicts: 'Show me overlapping time slots on Friday'
  • Manage recurring events with single-occurrence edits or series-wide changes

org.onekash/icloud-calendar-mcp MCP server FAQ

What is the iCloud Calendar MCP Server?

It's an MCP server that connects Claude and Cursor to your iCloud Calendar via CalDAV, letting you manage events through natural language. It handles recurring events correctly, maintains durable event references across sessions, and enforces OWASP MCP Top 10 security controls.

Is it free?

Yes. The server is open-source (Apache 2.0 license) and available on npm, PyPI, and GitHub. You only need an iCloud account and an app-specific password.

How do I install it in Claude Desktop?

Add the server to your Claude Desktop config file (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json; Linux: ~/.config/claude/claude_desktop_config.json; Windows: %APPDATA%\Claude\claude_desktop_config.json) with your iCloud credentials as environment variables. Use `npx @icloud-calendar-mcp/server`, `uvx icloud-calendar-mcp`, or run the JAR directly.

What authentication does it require?

You need your iCloud email address and an app-specific password (not your main Apple ID password). Generate an app-specific password at https://support.apple.com/en-us/HT204397 and set ICLOUD_USERNAME and ICLOUD_PASSWORD environment variables.

Does it work on macOS only?

No. It runs on any system with Java 21+ (macOS, Linux, Windows). It does not depend on macOS, AppleScript, or Calendar.app.

What happens if I edit a recurring event?

You control the scope: edit just one occurrence, this-and-future, or the whole series. Each occurrence has its own handle, and you must specify the scope when editing a recurring event to avoid accidental changes.

README (reference)

Source of truth, from the repository.

<p align="center"> <img src="images/logo.png" alt="iCloud Calendar MCP Server" width="200"/> </p> <h1 align="center">iCloud Calendar MCP Server</h1>

Tests npm PyPI License MCP Registry Security

An MCP (Model Context Protocol) server that gives AI assistants access to iCloud Calendar via CalDAV, with security controls aligned with the OWASP MCP Top 10.

[!CAUTION] Never use your main Apple ID password. This server requires an app-specific password which can be revoked independently without affecting your Apple ID.

Why this server

  • Portable CalDAV. Runs anywhere a JVM runs. It does not depend on macOS, AppleScript, or Calendar.app.
  • Durable event handles. get_events and create_event return an opaque handle that references an event across sessions and process restarts, so editing or deleting one needs no re-listing.
  • Correct recurrence. A series expands into one result per occurrence in the range, and you can edit or delete a single occurrence, this-and-future, or the whole series.
  • Bounded responses. Date-span and event-count caps return a clear, structured error instead of a silently truncated response.
  • Security aligned with the OWASP MCP Top 10, backed by a dedicated test suite.
  • Published on the MCP Registry, npm, and PyPI.

Features

MCP Tools

ToolDescriptionRead-OnlyDestructive
list_calendarsList all calendars from iCloud accountYesNo
get_eventsGet events within a date range from a calendarYesNo
create_eventCreate a new calendar eventNoNo
update_eventUpdate an event (whole series or a single occurrence)NoNo
delete_eventDelete an event (whole series or a single occurrence)NoYes

MCP Resources

ResourceDescription
calendar://calendarsBrowse available calendars

MCP Prompts

User-initiated templates that guide Claude through a multi-step task:

PromptDescription
schedule_meetingDraft an event from a title, attendees, and duration, then create it
rescheduleMove an existing event by looking it up, then editing it
find_conflictsList a day's events and report overlapping time slots

Security Features

  • Credential Protection - Environment variables only, never in code or config
  • Input Validation - All parameters validated with SSRF protection
  • Rate Limiting - 60 reads/min, 20 writes/min per MCP specification
  • Secure Error Handling - No sensitive data leakage in error messages
  • OWASP MCP Top 10 Compliance - 282 security tests covering all major risks
  • ReDoS Protection - All regex patterns tested against catastrophic backtracking
  • Unicode Security - Protection against homoglyph and encoding attacks

Quick Start

Prerequisites

Installation

Choose your preferred installation method:

[!IMPORTANT] Every option runs the same Java build. Java 21 or newer must be on your PATH, including for npx and uvx. Those wrappers download and launch the JAR; they do not replace the JVM.

Option 1: npm (Recommended)

npx @icloud-calendar-mcp/server

Option 2: Python (uvx)

uvx icloud-calendar-mcp

Option 3: Direct JAR

# Download the latest release (version-agnostic name, always resolves)
curl -LO https://github.com/icloud-calendar-mcp/icloud-calendar-mcp/releases/latest/download/icloud-calendar-mcp-all.jar

# Run
java -jar icloud-calendar-mcp-all.jar

Option 4: Build from Source

git clone https://github.com/icloud-calendar-mcp/icloud-calendar-mcp.git
cd icloud-calendar-mcp
./gradlew fatJar
java -jar build/libs/icloud-calendar-mcp-*-all.jar

Configuration

Set your iCloud credentials as environment variables:

export ICLOUD_USERNAME="your-apple-id@icloud.com"
export ICLOUD_PASSWORD="your-app-specific-password"

Security Note: Use an app-specific password, not your main Apple ID password.


Claude Desktop Integration

Add to your Claude Desktop configuration:

PlatformConfig Path
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Linux~/.config/claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
<details open> <summary><strong>Using npm (Recommended)</strong></summary>
{
  "mcpServers": {
    "icloud-calendar": {
      "command": "npx",
      "args": ["@icloud-calendar-mcp/server"],
      "env": {
        "ICLOUD_USERNAME": "your-apple-id@icloud.com",
        "ICLOUD_PASSWORD": "your-app-specific-password"
      }
    }
  }
}
</details> <details> <summary><strong>Using uvx (Python)</strong></summary>
{
  "mcpServers": {
    "icloud-calendar": {
      "command": "uvx",
      "args": ["icloud-calendar-mcp"],
      "env": {
        "ICLOUD_USERNAME": "your-apple-id@icloud.com",
        "ICLOUD_PASSWORD": "your-app-specific-password"
      }
    }
  }
}
</details> <details> <summary><strong>Using JAR directly</strong></summary>
{
  "mcpServers": {
    "icloud-calendar": {
      "command": "java",
      "args": ["-jar", "/path/to/icloud-calendar-mcp-all.jar"],
      "env": {
        "ICLOUD_USERNAME": "your-apple-id@icloud.com",
        "ICLOUD_PASSWORD": "your-app-specific-password"
      }
    }
  }
}
</details>

Usage Examples

Once configured, you can ask Claude:

  • "What's on my calendar this week?"
  • "Create a meeting with John tomorrow at 2pm"
  • "Show me all my calendars"
  • "Delete the dentist appointment on Friday"
  • "Move my 3pm meeting to 4pm"

Tool Parameters

list_calendars

No parameters required.

get_events

ParameterTypeRequiredDescription
calendar_idstringYesCalendar identifier (from list_calendars)
start_datestringYesStart date (YYYY-MM-DD)
end_datestringYesEnd date (YYYY-MM-DD)

Behavior to know about:

  • UTC day boundaries. start_date and end_date select whole UTC calendar days: start_date at 00:00 UTC through the end of end_date in UTC. Timed events return UTC startTime/endTime instants; all-day events return a plain YYYY-MM-DD. To resolve a user's day in another timezone, request one extra day on each side and keep the events whose start, converted to that zone, falls on the wanted day; all-day events are floating dates and need no conversion.
  • Limits. The range is capped at 366 days, and end_date must not precede start_date. The response is capped at 1000 events, and a single recurring series that expands to too many occurrences is rejected. If you hit a cap, query a week or a month at a time.
  • Recurring series. Each occurrence in the range is returned as its own result, carrying its own handle and a recurrenceId that identifies the instance.
  • Read-after-write. iCloud does not guarantee immediate visibility, so an event created moments ago can be missing from the next get_events for a short window. This is CDN indexing lag, not a deletion, so do not recreate it.

Each result includes uid, handle, summary, isAllDay, and startTime/endTime (timed) or startDate/endDate (all-day), plus any of description, location, rrule, recurrenceId, status, url, categories, priority, organizer, attendeeCount that are set.

create_event

ParameterTypeRequiredDescription
calendar_idstringYesTarget calendar
titlestringYesEvent title
start_timestringCond.ISO 8601 datetime for a timed event. A naive value (2026-01-15T09:00:00) is read as UTC unless timezone is set; a Z or offset value is an absolute instant that overrides timezone
end_timestringCond.ISO 8601 datetime for a timed event (same rules as start_time)
start_datestringCond.Start date YYYY-MM-DD for an all-day event
end_datestringCond.End date YYYY-MM-DD, inclusive, for an all-day event
is_all_daybooleanNoAll-day event flag
descriptionstringNoEvent description
locationstringNoEvent location
timezonestringNoIANA timezone for a timed event (e.g., America/New_York)
end_timezonestringNoIANA timezone for the end when it differs from the start (e.g., a flight). Falls back to timezone
rrulestringNoRecurrence rule (e.g., FREQ=WEEKLY;BYDAY=MO)
rdatesstring[]NoExtra occurrence dates (RFC 5545 RDATE)
exdatesstring[]NoExcluded occurrence dates (RFC 5545 EXDATE)
alarmsobject[]NoReminders on the event (see Alarms)

update_event

Only the fields you pass are changed.

ParameterTypeRequiredDescription
event_idstringYesReference to the event. Prefer the opaque handle from get_events/create_event; a bare UID also works for an event fetched earlier in the session (see Referencing an event)
titlestringNoNew title
start_timestringNoNew start time (ISO 8601, same rules as create)
end_timestringNoNew end time (ISO 8601)
start_datestringNoNew start date for an all-day event (YYYY-MM-DD)
end_datestringNoNew end date for an all-day event (YYYY-MM-DD)
is_all_daybooleanNoChange to all-day event
descriptionstringNoNew description
locationstringNoNew location
timezonestringNoIANA timezone (e.g., America/New_York)
end_timezonestringNoIANA timezone for the end when it differs from the start
rrulestringNoRecurrence rule
rdatesstring[]NoReplace RDATEs (omit to keep, empty array to clear)
exdatesstring[]NoReplace EXDATEs (omit to keep, empty array to clear)
alarmsobject[]NoReplace reminders (omit to keep, empty array to clear, a list to replace; see Alarms)
scopestringCond.Which occurrences a recurring edit affects (see Editing recurring events). Required when the handle points at one occurrence of a series

delete_event

ParameterTypeRequiredDescription
event_idstringYesReference to the event. Prefer the opaque handle; a bare UID also works for an event fetched earlier in the session
scopestringCond.Which occurrences a recurring delete removes (see Editing recurring events). Required when the handle points at one occurrence of a series

Referencing an event

get_events and create_event return two identifiers for each event: a uid and an opaque handle. Pass the handle to update_event and delete_event. It is self-contained and works from a fresh process, so the normal flow is get_events (or create_event) to obtain the handle, then update_event/delete_event with it. No extra lookup step is needed across sessions.

A bare uid is also accepted, but only for an event fetched earlier in the same session, where it resolves through a short-lived in-memory cache. There is no stateless server-side lookup by UID: iCloud rejects a CalDAV calendar-query UID prop-filter (HTTP 412), and an unfiltered query would return the whole calendar. Prefer the handle.

A handle carries the event's ETag. If the event changed elsewhere since the handle was issued, the edit reports a conflict rather than overwriting the newer version; re-run get_events for a fresh handle and retry. On success, update_event returns a refreshed handle carrying the new ETag, so use that one for the next edit in a chain.

Editing recurring events

get_events returns one result per occurrence of a recurring series, each with its own handle. When you edit or delete an occurrence handle, set scope:

  • this_occurrence: change or cancel only that instance.
  • this_and_future: that instance and every later one.
  • all_events: the whole series.

scope is required when the handle points at one occurrence of a series. The operation is rejected without it, so a single-occurrence edit never changes the whole series by accident. Omit scope for standalone events. rrule, rdates, and exdates cannot be combined with this_occurrence or this_and_future.

Alarms

create_event and update_event take an alarms array. Each entry is an object:

FieldRequiredDescription
triggerYesRelative duration (-PT15M, -P1D) or an absolute UTC instant (20260115T093000Z)
actionNoDISPLAY (default), AUDIO, or EMAIL
descriptionNoAlarm text (defaults to "Reminder" for DISPLAY)
summaryNoSubject line, EMAIL only
repeat_countNoNumber of times to repeat
repeat_durationNoGap between repeats (RFC 5545 duration)

On update_event, omit alarms to keep the existing ones, pass an empty array to clear them, or pass a list to replace them.


Troubleshooting

A new event does not appear right away. iCloud does not guarantee immediate visibility, so a just-created event can be missing from the next get_events for a short window (CDN indexing lag). The create_event success response is authoritative. Do not recreate the event.

get_events returns a size or count error. The range is too wide. Query a week or a month at a time; the response is capped at 1000 events.

Authentication fails. Use an app-specific password, not your Apple ID password, and set ICLOUD_USERNAME to your full iCloud email address.

Not sure which calendar_id to use. Call list_calendars and use the id of the calendar you want.

A recurring edit was rejected or changed every instance. Set scope (see Editing recurring events): an occurrence handle needs this_occurrence, this_and_future, or all_events.

Times look shifted by your timezone. get_events uses UTC day boundaries (see get_events). Pass timezone when creating timed events, and use the extra-day approach to resolve a local day.


Security

This server is designed with security as a primary concern, following the OWASP MCP Top 10 guidelines.

Privacy

The server talks only to your machine (over STDIO) and to iCloud (caldav.icloud.com). It has no telemetry and sends your calendar data nowhere else. Credentials come from environment variables and are never logged.

Security Controls

ControlImplementation
Credential StorageEnvironment variables only, never logged or exposed
Input ValidationAll inputs validated (calendar IDs, dates, times, text fields)
SSRF ProtectionBlocks internal IPs, localhost, and dangerous URI schemes
Rate LimitingSliding window: 60 reads/min, 20 writes/min
Error HandlingPasswords, tokens, paths, emails sanitized from errors
Injection PreventionICS content properly escaped, command injection tested
ETag NormalizationRFC 7232 compliant, strips quotes/W/ prefix/XML entities
Content-Length GuardEarly rejection of oversized responses before buffering
Circuit BreakerPrevents cascading failures with automatic recovery
Audit LoggingCUD operations logged via MCP logging protocol (MCP08)
ReDoS ProtectionAll regex patterns tested for catastrophic backtracking
Unicode SecurityHomoglyph, normalization, and encoding bypass protection

OWASP MCP Top 10 Coverage

RiskMitigationTests
MCP01: Token MismanagementCredentials masked in logs/errors, secure storage14
MCP02: Privilege EscalationFixed tool set, no dynamic registration5
MCP03: Tool Argument InjectionInput validation, parameterized operations8
MCP04: Sensitive Data ExposureError sanitization, credential masking10
MCP05: Command InjectionInput treated as data, not executed3
MCP06: Prompt InjectionMalicious text stored as data, not interpreted3
MCP08: Insecure LoggingRate limiting, sensitive data sanitization31
MCP09: Resource ExhaustionRate limiting, input size limits, DoS protection25
MCP10: Context Over-sharingIsolated state, no cross-request data leakage3

See SECURITY.md for full security documentation and vulnerability disclosure process.


Testing

Tests live in two places: the MCP server module and the vendored icaldav-core iCalendar library. Both run with:

./gradlew test

Test Coverage (MCP server)

CategoryTestsDescription
Security282Adversarial inputs, OWASP MCP Top 10, ReDoS, Unicode
CalDAV Protocol181XML parsing, HTTP client, models, ETag normalization
ICS Format150RFC 5545 parsing, building, patching
Error Handling56Secure error responses, credential sanitization
Integration45End-to-end tools, MCP spec compliance, annotations
Input Validation44All parameter validation rules
Service Layer26Calendar operations, caching
Rate Limiting18Concurrent access, window reset
Cancellation12Operation cancellation, cleanup
Logging9MCP logging compliance
Progress9Progress reporting
E2E11Live CalDAV + end-to-end integration

Security Test Categories

CategoryTestsCoverage
Adversarial Inputs53SQL/NoSQL injection, XSS, path traversal
ICS Patcher Security43CRLF injection, property injection, encoding attacks
Unicode Security38Homoglyphs, normalization, RTL override
Logger Security31Log injection, credential sanitization
OWASP MCP Risks29MCP01-10 specific attack vectors
Progress Security27Token enumeration, injection
ReDoS Protection25Catastrophic backtracking, resource exhaustion
Cancellation Security22Replay attacks, race conditions
Credential Security14Token masking, secure storage

Running Specific Tests

# All tests
./gradlew test

# Security tests only
./gradlew test --tests "*SecurityTest*"
./gradlew test --tests "AdversarialTest"

# OWASP MCP specific tests
./gradlew test --tests "OwaspMcpSecurityTest"

# Unicode security tests
./gradlew test --tests "UnicodeSecurityTest"

# ReDoS protection tests
./gradlew test --tests "ReDoSSecurityTest"

# CalDAV tests
./gradlew test --tests "*CalDav*"

# ICS tests
./gradlew test --tests "*Ics*"

Architecture

+------------------------------------------------------------------+
|                    MCP Server (STDIO Transport)                    |
|                                                                    |
|  +----------------+  +----------------+  +----------------------+  |
|  | Rate Limiter   |  |   Input        |  |  Secure Error        |  |
|  | 60r/20w/min    |  |  Validator     |  |  Handler             |  |
|  +----------------+  +----------------+  +----------------------+  |
|                                                                    |
|  +----------------+  +----------------+  +----------------------+  |
|  | MCP Logger     |  | Cancellation   |  |  Progress            |  |
|  | (RFC 5424)     |  | Manager        |  |  Reporter            |  |
|  +----------------+  +----------------+  +----------------------+  |
|                                                                    |
|  Tools: list_calendars | get_events | create_event |               |
|         update_event | delete_event                                |
|                                                                    |
|  Resources: calendar://calendars                                   |
+------------------------------------------------------------------+
                              |
                              v
+------------------------------------------------------------------+
|                      CalendarService                               |
|  Orchestrates CalDAV operations, caches calendar metadata          |
+------------------------------------------------------------------+
                              |
                              v
+------------------------------------------------------------------+
|                      CalDAV Client Layer                           |
|                                                                    |
|  +-------------------+  +-------------------+  +----------------+  |
|  | OkHttpCalDav      |  |  IcsParser        |  |  IcsBuilder    |  |
|  | Client            |  |  (icaldav-core)   |  |  (icaldav-core)|  |
|  +-------------------+  +-------------------+  +----------------+  |
|                                                                    |
|  +-------------------+  +-------------------+  +----------------+  |
|  | ICloudXml         |  |  IcsPatcher       |  |  EtagUtils     |  |
|  | Parser            |  |  (event edits)    |  |  (RFC 7232)    |  |
|  +-------------------+  +-------------------+  +----------------+  |
|                                                                    |
|  +-------------------+                                             |
|  | Credential        |                                             |
|  | Manager           |                                             |
|  +-------------------+                                             |
+------------------------------------------------------------------+
                              |
                              v
+------------------------------------------------------------------+
|                    iCloud CalDAV API                               |
|                    caldav.icloud.com                               |
+------------------------------------------------------------------+

Development

Build

# Build
./gradlew build

# Build fat JAR
./gradlew fatJar

# Run tests
./gradlew test

# Clean build
./gradlew clean build

Project Structure

src/main/kotlin/org/onekash/mcp/calendar/
├── Main.kt                 # MCP server entry point
├── caldav/                 # CalDAV protocol implementation
│   ├── CalDavClient.kt     # Client interface
│   ├── CalDavModels.kt     # Domain models
│   ├── OkHttpCalDavClient.kt
│   ├── ICloudXmlParser.kt
│   └── EtagUtils.kt        # RFC 7232 ETag normalization
├── ics/                    # ICS format handling (via icaldav-core)
│   ├── IcsParser.kt        # Parse iCalendar data
│   ├── IcsBuilder.kt       # Generate iCalendar data
│   └── IcsPatcher.kt       # Patch existing events (CRLF-safe)
├── service/                # Business logic
│   └── CalendarService.kt  # CalDAV orchestration + event cache
├── security/               # Security controls
│   └── CredentialManager.kt
├── validation/             # Input validation
│   └── InputValidator.kt
├── error/                  # Error handling
│   └── SecureErrorHandler.kt
├── ratelimit/              # Rate limiting
│   └── RateLimiter.kt
├── logging/                # MCP logging
│   └── McpLogger.kt
├── progress/               # Progress reporting
│   └── ProgressReporter.kt
└── cancellation/           # Operation cancellation
    └── CancellationManager.kt

Testing with MCP Inspector

ICLOUD_USERNAME="test@icloud.com" \
ICLOUD_PASSWORD="test-app-password" \
npx @mcp-use/inspector java -jar build/libs/icloud-calendar-mcp-*-all.jar

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Security Issues

For security vulnerabilities, please see SECURITY.md for our responsible disclosure process. Do not open public issues for security vulnerabilities.


License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.


Acknowledgments

Related MCP servers

Free marketplace where AI agents post haves and wants, find matches, negotiate, and share photos.

Search 250M+ research papers, citations and author profiles. Free OpenAlex account; OAuth sign-in.

Argentina's official public data (INDEC, BCRA, 38 portals): search, read tables, cited answers.

View repository →

Hard spend caps, OS sandboxing, and signed receipts for autonomous coding agents.

8
Rust
Apache-2.0
View repository →
MIMizuki logo

Mizuki

Active

Fixed-price maintenance for public GitHub issues, paid in USDC on Solana.

8
Rust
Apache-2.0
View repository →
LILinear Project logo

Linear Project

Maintained

Scope-gated Linear project administration with optional GitHub and Obsidian evidence adapters

0
TypeScript
MIT
View repository →