{
  "markdown": "<p align=\"center\">\n  <img src=\"images/logo.png\" alt=\"iCloud Calendar MCP Server\" width=\"200\"/>\n</p>\n\n<h1 align=\"center\">iCloud Calendar MCP Server</h1>\n\n[![Tests](https://github.com/icloud-calendar-mcp/icloud-calendar-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/icloud-calendar-mcp/icloud-calendar-mcp/actions/workflows/test.yml)\n[![npm](https://img.shields.io/npm/v/@icloud-calendar-mcp/server.svg)](https://www.npmjs.com/package/@icloud-calendar-mcp/server)\n[![PyPI](https://img.shields.io/pypi/v/icloud-calendar-mcp.svg)](https://pypi.org/project/icloud-calendar-mcp/)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n[![MCP Registry](https://img.shields.io/badge/MCP-Registry-green.svg)](https://registry.modelcontextprotocol.io/?search=org.onekash)\n[![Security](https://img.shields.io/badge/Security-OWASP%20MCP%20Top%2010-blue.svg)](#security)\n\nAn 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](https://owasp.org/www-project-mcp-top-10/).\n\n> [!CAUTION]\n> **Never use your main Apple ID password.** This server requires an [app-specific password](https://support.apple.com/en-us/HT204397) which can be revoked independently without affecting your Apple ID.\n\n## Why this server\n\n- **Portable CalDAV.** Runs anywhere a JVM runs. It does not depend on macOS, AppleScript, or Calendar.app.\n- **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.\n- **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.\n- **Bounded responses.** Date-span and event-count caps return a clear, structured error instead of a silently truncated response.\n- **Security aligned with the OWASP MCP Top 10**, backed by a dedicated test suite.\n- **Published on the MCP Registry, npm, and PyPI.**\n\n## Features\n\n### MCP Tools\n\n| Tool | Description | Read-Only | Destructive |\n|------|-------------|:---------:|:-----------:|\n| `list_calendars` | List all calendars from iCloud account | Yes | No |\n| `get_events` | Get events within a date range from a calendar | Yes | No |\n| `create_event` | Create a new calendar event | No | No |\n| `update_event` | Update an event (whole series or a single occurrence) | No | No |\n| `delete_event` | Delete an event (whole series or a single occurrence) | No | Yes |\n\n### MCP Resources\n\n| Resource | Description |\n|----------|-------------|\n| `calendar://calendars` | Browse available calendars |\n\n### MCP Prompts\n\nUser-initiated templates that guide Claude through a multi-step task:\n\n| Prompt | Description |\n|--------|-------------|\n| `schedule_meeting` | Draft an event from a title, attendees, and duration, then create it |\n| `reschedule` | Move an existing event by looking it up, then editing it |\n| `find_conflicts` | List a day's events and report overlapping time slots |\n\n### Security Features\n\n- **Credential Protection** - Environment variables only, never in code or config\n- **Input Validation** - All parameters validated with SSRF protection\n- **Rate Limiting** - 60 reads/min, 20 writes/min per MCP specification\n- **Secure Error Handling** - No sensitive data leakage in error messages\n- **OWASP MCP Top 10 Compliance** - 282 security tests covering all major risks\n- **ReDoS Protection** - All regex patterns tested against catastrophic backtracking\n- **Unicode Security** - Protection against homoglyph and encoding attacks\n\n---\n\n## Quick Start\n\n### Prerequisites\n\n- **Java 21+** (for all installation methods)\n- iCloud account with [app-specific password](https://support.apple.com/en-us/HT204397)\n\n### Installation\n\nChoose your preferred installation method:\n\n> [!IMPORTANT]\n> 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.\n\n#### Option 1: npm (Recommended)\n\n```bash\nnpx @icloud-calendar-mcp/server\n```\n\n#### Option 2: Python (uvx)\n\n```bash\nuvx icloud-calendar-mcp\n```\n\n#### Option 3: Direct JAR\n\n```bash\n# Download the latest release (version-agnostic name, always resolves)\ncurl -LO https://github.com/icloud-calendar-mcp/icloud-calendar-mcp/releases/latest/download/icloud-calendar-mcp-all.jar\n\n# Run\njava -jar icloud-calendar-mcp-all.jar\n```\n\n#### Option 4: Build from Source\n\n```bash\ngit clone https://github.com/icloud-calendar-mcp/icloud-calendar-mcp.git\ncd icloud-calendar-mcp\n./gradlew fatJar\njava -jar build/libs/icloud-calendar-mcp-*-all.jar\n```\n\n### Configuration\n\nSet your iCloud credentials as environment variables:\n\n```bash\nexport ICLOUD_USERNAME=\"your-apple-id@icloud.com\"\nexport ICLOUD_PASSWORD=\"your-app-specific-password\"\n```\n\n> **Security Note**: Use an [app-specific password](https://support.apple.com/en-us/HT204397), not your main Apple ID password.\n\n---\n\n## Claude Desktop Integration\n\nAdd to your Claude Desktop configuration:\n\n| Platform | Config Path |\n|----------|-------------|\n| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |\n| Linux | `~/.config/claude/claude_desktop_config.json` |\n| Windows | `%APPDATA%\\Claude\\claude_desktop_config.json` |\n\n<details open>\n<summary><strong>Using npm (Recommended)</strong></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"icloud-calendar\": {\n      \"command\": \"npx\",\n      \"args\": [\"@icloud-calendar-mcp/server\"],\n      \"env\": {\n        \"ICLOUD_USERNAME\": \"your-apple-id@icloud.com\",\n        \"ICLOUD_PASSWORD\": \"your-app-specific-password\"\n      }\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Using uvx (Python)</strong></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"icloud-calendar\": {\n      \"command\": \"uvx\",\n      \"args\": [\"icloud-calendar-mcp\"],\n      \"env\": {\n        \"ICLOUD_USERNAME\": \"your-apple-id@icloud.com\",\n        \"ICLOUD_PASSWORD\": \"your-app-specific-password\"\n      }\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><strong>Using JAR directly</strong></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"icloud-calendar\": {\n      \"command\": \"java\",\n      \"args\": [\"-jar\", \"/path/to/icloud-calendar-mcp-all.jar\"],\n      \"env\": {\n        \"ICLOUD_USERNAME\": \"your-apple-id@icloud.com\",\n        \"ICLOUD_PASSWORD\": \"your-app-specific-password\"\n      }\n    }\n  }\n}\n```\n</details>\n\n---\n\n## Usage Examples\n\nOnce configured, you can ask Claude:\n\n- *\"What's on my calendar this week?\"*\n- *\"Create a meeting with John tomorrow at 2pm\"*\n- *\"Show me all my calendars\"*\n- *\"Delete the dentist appointment on Friday\"*\n- *\"Move my 3pm meeting to 4pm\"*\n\n### Tool Parameters\n\n#### list_calendars\nNo parameters required.\n\n#### get_events\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `calendar_id` | string | Yes | Calendar identifier (from `list_calendars`) |\n| `start_date` | string | Yes | Start date (`YYYY-MM-DD`) |\n| `end_date` | string | Yes | End date (`YYYY-MM-DD`) |\n\nBehavior to know about:\n\n- **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.\n- **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.\n- **Recurring series.** Each occurrence in the range is returned as its own result, carrying its own `handle` and a `recurrenceId` that identifies the instance.\n- **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.\n\nEach 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.\n\n#### create_event\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `calendar_id` | string | Yes | Target calendar |\n| `title` | string | Yes | Event title |\n| `start_time` | string | Cond. | 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` |\n| `end_time` | string | Cond. | ISO 8601 datetime for a timed event (same rules as `start_time`) |\n| `start_date` | string | Cond. | Start date `YYYY-MM-DD` for an all-day event |\n| `end_date` | string | Cond. | End date `YYYY-MM-DD`, inclusive, for an all-day event |\n| `is_all_day` | boolean | No | All-day event flag |\n| `description` | string | No | Event description |\n| `location` | string | No | Event location |\n| `timezone` | string | No | IANA timezone for a timed event (e.g., `America/New_York`) |\n| `end_timezone` | string | No | IANA timezone for the end when it differs from the start (e.g., a flight). Falls back to `timezone` |\n| `rrule` | string | No | Recurrence rule (e.g., `FREQ=WEEKLY;BYDAY=MO`) |\n| `rdates` | string[] | No | Extra occurrence dates (RFC 5545 RDATE) |\n| `exdates` | string[] | No | Excluded occurrence dates (RFC 5545 EXDATE) |\n| `alarms` | object[] | No | Reminders on the event (see [Alarms](#alarms)) |\n\n#### update_event\nOnly the fields you pass are changed.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `event_id` | string | Yes | Reference 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](#referencing-an-event)) |\n| `title` | string | No | New title |\n| `start_time` | string | No | New start time (ISO 8601, same rules as create) |\n| `end_time` | string | No | New end time (ISO 8601) |\n| `start_date` | string | No | New start date for an all-day event (`YYYY-MM-DD`) |\n| `end_date` | string | No | New end date for an all-day event (`YYYY-MM-DD`) |\n| `is_all_day` | boolean | No | Change to all-day event |\n| `description` | string | No | New description |\n| `location` | string | No | New location |\n| `timezone` | string | No | IANA timezone (e.g., `America/New_York`) |\n| `end_timezone` | string | No | IANA timezone for the end when it differs from the start |\n| `rrule` | string | No | Recurrence rule |\n| `rdates` | string[] | No | Replace RDATEs (omit to keep, empty array to clear) |\n| `exdates` | string[] | No | Replace EXDATEs (omit to keep, empty array to clear) |\n| `alarms` | object[] | No | Replace reminders (omit to keep, empty array to clear, a list to replace; see [Alarms](#alarms)) |\n| `scope` | string | Cond. | Which occurrences a recurring edit affects (see [Editing recurring events](#editing-recurring-events)). Required when the handle points at one occurrence of a series |\n\n#### delete_event\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `event_id` | string | Yes | Reference to the event. Prefer the opaque `handle`; a bare UID also works for an event fetched earlier in the session |\n| `scope` | string | Cond. | Which occurrences a recurring delete removes (see [Editing recurring events](#editing-recurring-events)). Required when the handle points at one occurrence of a series |\n\n### Referencing an event\n\n`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.\n\nA 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.\n\nA 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.\n\n### Editing recurring events\n\n`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`:\n\n- `this_occurrence`: change or cancel only that instance.\n- `this_and_future`: that instance and every later one.\n- `all_events`: the whole series.\n\n`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`.\n\n### Alarms\n\n`create_event` and `update_event` take an `alarms` array. Each entry is an object:\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `trigger` | Yes | Relative duration (`-PT15M`, `-P1D`) or an absolute UTC instant (`20260115T093000Z`) |\n| `action` | No | `DISPLAY` (default), `AUDIO`, or `EMAIL` |\n| `description` | No | Alarm text (defaults to \"Reminder\" for `DISPLAY`) |\n| `summary` | No | Subject line, `EMAIL` only |\n| `repeat_count` | No | Number of times to repeat |\n| `repeat_duration` | No | Gap between repeats (RFC 5545 duration) |\n\nOn `update_event`, omit `alarms` to keep the existing ones, pass an empty array to clear them, or pass a list to replace them.\n\n---\n\n## Troubleshooting\n\n**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.\n\n**`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.\n\n**Authentication fails.** Use an [app-specific password](https://support.apple.com/en-us/HT204397), not your Apple ID password, and set `ICLOUD_USERNAME` to your full iCloud email address.\n\n**Not sure which `calendar_id` to use.** Call `list_calendars` and use the `id` of the calendar you want.\n\n**A recurring edit was rejected or changed every instance.** Set `scope` (see [Editing recurring events](#editing-recurring-events)): an occurrence handle needs `this_occurrence`, `this_and_future`, or `all_events`.\n\n**Times look shifted by your timezone.** `get_events` uses UTC day boundaries (see [get_events](#get_events)). Pass `timezone` when creating timed events, and use the extra-day approach to resolve a local day.\n\n---\n\n## Security\n\nThis server is designed with security as a primary concern, following the [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) guidelines.\n\n### Privacy\n\nThe 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.\n\n### Security Controls\n\n| Control | Implementation |\n|---------|----------------|\n| **Credential Storage** | Environment variables only, never logged or exposed |\n| **Input Validation** | All inputs validated (calendar IDs, dates, times, text fields) |\n| **SSRF Protection** | Blocks internal IPs, localhost, and dangerous URI schemes |\n| **Rate Limiting** | Sliding window: 60 reads/min, 20 writes/min |\n| **Error Handling** | Passwords, tokens, paths, emails sanitized from errors |\n| **Injection Prevention** | ICS content properly escaped, command injection tested |\n| **ETag Normalization** | RFC 7232 compliant, strips quotes/W/ prefix/XML entities |\n| **Content-Length Guard** | Early rejection of oversized responses before buffering |\n| **Circuit Breaker** | Prevents cascading failures with automatic recovery |\n| **Audit Logging** | CUD operations logged via MCP logging protocol (MCP08) |\n| **ReDoS Protection** | All regex patterns tested for catastrophic backtracking |\n| **Unicode Security** | Homoglyph, normalization, and encoding bypass protection |\n\n### OWASP MCP Top 10 Coverage\n\n| Risk | Mitigation | Tests |\n|------|------------|-------|\n| **MCP01: Token Mismanagement** | Credentials masked in logs/errors, secure storage | 14 |\n| **MCP02: Privilege Escalation** | Fixed tool set, no dynamic registration | 5 |\n| **MCP03: Tool Argument Injection** | Input validation, parameterized operations | 8 |\n| **MCP04: Sensitive Data Exposure** | Error sanitization, credential masking | 10 |\n| **MCP05: Command Injection** | Input treated as data, not executed | 3 |\n| **MCP06: Prompt Injection** | Malicious text stored as data, not interpreted | 3 |\n| **MCP08: Insecure Logging** | Rate limiting, sensitive data sanitization | 31 |\n| **MCP09: Resource Exhaustion** | Rate limiting, input size limits, DoS protection | 25 |\n| **MCP10: Context Over-sharing** | Isolated state, no cross-request data leakage | 3 |\n\nSee [SECURITY.md](SECURITY.md) for full security documentation and vulnerability disclosure process.\n\n---\n\n## Testing\n\nTests live in two places: the MCP server module and the vendored `icaldav-core`\niCalendar library. Both run with:\n\n```bash\n./gradlew test\n```\n\n### Test Coverage (MCP server)\n\n| Category | Tests | Description |\n|----------|-------|-------------|\n| **Security** | 282 | Adversarial inputs, OWASP MCP Top 10, ReDoS, Unicode |\n| **CalDAV Protocol** | 181 | XML parsing, HTTP client, models, ETag normalization |\n| **ICS Format** | 150 | RFC 5545 parsing, building, patching |\n| **Error Handling** | 56 | Secure error responses, credential sanitization |\n| **Integration** | 45 | End-to-end tools, MCP spec compliance, annotations |\n| **Input Validation** | 44 | All parameter validation rules |\n| **Service Layer** | 26 | Calendar operations, caching |\n| **Rate Limiting** | 18 | Concurrent access, window reset |\n| **Cancellation** | 12 | Operation cancellation, cleanup |\n| **Logging** | 9 | MCP logging compliance |\n| **Progress** | 9 | Progress reporting |\n| **E2E** | 11 | Live CalDAV + end-to-end integration |\n\n### Security Test Categories\n\n| Category | Tests | Coverage |\n|----------|-------|----------|\n| **Adversarial Inputs** | 53 | SQL/NoSQL injection, XSS, path traversal |\n| **ICS Patcher Security** | 43 | CRLF injection, property injection, encoding attacks |\n| **Unicode Security** | 38 | Homoglyphs, normalization, RTL override |\n| **Logger Security** | 31 | Log injection, credential sanitization |\n| **OWASP MCP Risks** | 29 | MCP01-10 specific attack vectors |\n| **Progress Security** | 27 | Token enumeration, injection |\n| **ReDoS Protection** | 25 | Catastrophic backtracking, resource exhaustion |\n| **Cancellation Security** | 22 | Replay attacks, race conditions |\n| **Credential Security** | 14 | Token masking, secure storage |\n\n### Running Specific Tests\n\n```bash\n# All tests\n./gradlew test\n\n# Security tests only\n./gradlew test --tests \"*SecurityTest*\"\n./gradlew test --tests \"AdversarialTest\"\n\n# OWASP MCP specific tests\n./gradlew test --tests \"OwaspMcpSecurityTest\"\n\n# Unicode security tests\n./gradlew test --tests \"UnicodeSecurityTest\"\n\n# ReDoS protection tests\n./gradlew test --tests \"ReDoSSecurityTest\"\n\n# CalDAV tests\n./gradlew test --tests \"*CalDav*\"\n\n# ICS tests\n./gradlew test --tests \"*Ics*\"\n```\n\n---\n\n## Architecture\n\n```\n+------------------------------------------------------------------+\n|                    MCP Server (STDIO Transport)                    |\n|                                                                    |\n|  +----------------+  +----------------+  +----------------------+  |\n|  | Rate Limiter   |  |   Input        |  |  Secure Error        |  |\n|  | 60r/20w/min    |  |  Validator     |  |  Handler             |  |\n|  +----------------+  +----------------+  +----------------------+  |\n|                                                                    |\n|  +----------------+  +----------------+  +----------------------+  |\n|  | MCP Logger     |  | Cancellation   |  |  Progress            |  |\n|  | (RFC 5424)     |  | Manager        |  |  Reporter            |  |\n|  +----------------+  +----------------+  +----------------------+  |\n|                                                                    |\n|  Tools: list_calendars | get_events | create_event |               |\n|         update_event | delete_event                                |\n|                                                                    |\n|  Resources: calendar://calendars                                   |\n+------------------------------------------------------------------+\n                              |\n                              v\n+------------------------------------------------------------------+\n|                      CalendarService                               |\n|  Orchestrates CalDAV operations, caches calendar metadata          |\n+------------------------------------------------------------------+\n                              |\n                              v\n+------------------------------------------------------------------+\n|                      CalDAV Client Layer                           |\n|                                                                    |\n|  +-------------------+  +-------------------+  +----------------+  |\n|  | OkHttpCalDav      |  |  IcsParser        |  |  IcsBuilder    |  |\n|  | Client            |  |  (icaldav-core)   |  |  (icaldav-core)|  |\n|  +-------------------+  +-------------------+  +----------------+  |\n|                                                                    |\n|  +-------------------+  +-------------------+  +----------------+  |\n|  | ICloudXml         |  |  IcsPatcher       |  |  EtagUtils     |  |\n|  | Parser            |  |  (event edits)    |  |  (RFC 7232)    |  |\n|  +-------------------+  +-------------------+  +----------------+  |\n|                                                                    |\n|  +-------------------+                                             |\n|  | Credential        |                                             |\n|  | Manager           |                                             |\n|  +-------------------+                                             |\n+------------------------------------------------------------------+\n                              |\n                              v\n+------------------------------------------------------------------+\n|                    iCloud CalDAV API                               |\n|                    caldav.icloud.com                               |\n+------------------------------------------------------------------+\n```\n\n---\n\n## Development\n\n### Build\n\n```bash\n# Build\n./gradlew build\n\n# Build fat JAR\n./gradlew fatJar\n\n# Run tests\n./gradlew test\n\n# Clean build\n./gradlew clean build\n```\n\n### Project Structure\n\n```\nsrc/main/kotlin/org/onekash/mcp/calendar/\n├── Main.kt                 # MCP server entry point\n├── caldav/                 # CalDAV protocol implementation\n│   ├── CalDavClient.kt     # Client interface\n│   ├── CalDavModels.kt     # Domain models\n│   ├── OkHttpCalDavClient.kt\n│   ├── ICloudXmlParser.kt\n│   └── EtagUtils.kt        # RFC 7232 ETag normalization\n├── ics/                    # ICS format handling (via icaldav-core)\n│   ├── IcsParser.kt        # Parse iCalendar data\n│   ├── IcsBuilder.kt       # Generate iCalendar data\n│   └── IcsPatcher.kt       # Patch existing events (CRLF-safe)\n├── service/                # Business logic\n│   └── CalendarService.kt  # CalDAV orchestration + event cache\n├── security/               # Security controls\n│   └── CredentialManager.kt\n├── validation/             # Input validation\n│   └── InputValidator.kt\n├── error/                  # Error handling\n│   └── SecureErrorHandler.kt\n├── ratelimit/              # Rate limiting\n│   └── RateLimiter.kt\n├── logging/                # MCP logging\n│   └── McpLogger.kt\n├── progress/               # Progress reporting\n│   └── ProgressReporter.kt\n└── cancellation/           # Operation cancellation\n    └── CancellationManager.kt\n```\n\n### Testing with MCP Inspector\n\n```bash\nICLOUD_USERNAME=\"test@icloud.com\" \\\nICLOUD_PASSWORD=\"test-app-password\" \\\nnpx @mcp-use/inspector java -jar build/libs/icloud-calendar-mcp-*-all.jar\n```\n\n---\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n### Security Issues\n\nFor security vulnerabilities, please see [SECURITY.md](SECURITY.md) for our responsible disclosure process. **Do not open public issues for security vulnerabilities.**\n\n---\n\n## License\n\nThis project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## Acknowledgments\n\n- [Model Context Protocol](https://modelcontextprotocol.io) by Anthropic\n- [MCP Kotlin SDK](https://github.com/modelcontextprotocol/kotlin-sdk) by Anthropic & JetBrains\n- [ical4j](https://www.ical4j.org/) for low-level ICS parsing (via the bundled icaldav-core library)\n- [OkHttp](https://square.github.io/okhttp/) for HTTP client\n- [OWASP MCP Top 10](https://owasp.org/www-project-mcp-top-10/) for security guidance\n",
  "bytes": 26073,
  "sha": "d425dfead1ce19758b17eff8e45025857f5a766132f25a3082d8c3bd4819cdf8",
  "repo_slug": "icloud-calendar-mcp/icloud-calendar-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_org_onekash_icloud_calendar_mcp_fabdbf69/readme"
}