# caldav-mcp
🗓️ A CalDAV Model Context Protocol (MCP) server to expose calendar operations as tools for AI assistants. [![Release](https://github.com/dominik1001/caldav-mcp/actions/workflows/release.yml/badge.svg)](https://github.com/dominik1001/caldav-mcp/actions/workflows/release.yml) [![npm version](https://badge.fury.io/js/caldav-mcp.svg)](https://www.npmjs.com/package/caldav-mcp) [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io) [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
## ✨ Features - Connect to CalDAV servers - List calendars - List calendar events within a specific timeframe - Create calendar events - Update calendar events - Delete calendar events by UID ## Setup ``` { "mcpServers": { ..., "calendar": { "command": "npx", "args": [ "caldav-mcp" ], "env": { "CALDAV_BASE_URL": "", "CALDAV_USERNAME": "", "CALDAV_PASSWORD": "" } } } } ``` ## Development ### Quick Start Run the MCP server in development mode with auto-reload: ```bash npm run dev ``` This will run the TypeScript code directly with watch mode and automatically load environment variables from `.env`. ### Manual Build Alternatively, you can compile TypeScript to JavaScript and run it: 1. Compile: ```bash npx tsc ``` 2. Run: ```bash node dist/index.js ``` ## Available Tools ### list-calendars List all calendars returning both name and URL Parameters: none Returns: - List of all available calendars ### list-events List all events between start and end date in the calendar specified by its URL Parameters: - `start`: string — Start date (ISO 8601) - `end`: string — End date (ISO 8601) - `calendarUrl`: string Returns: - A list of events that fall within the given timeframe, each containing `uid`, `summary`, `start`, `end`, and optionally `description` and `location` ### create-event Creates an event in the calendar specified by its URL. For all-day events, set `wholeDay` to true. For a single-day all-day event, use `start` and `end` datetimes on the same calendar date; they do not need to be identical timestamps. Parameters: - `summary`: string - `start`: string — Start datetime (ISO 8601) - `end`: string — End datetime (ISO 8601) - `wholeDay`: boolean (optional) — Create as a whole-day event - `calendarUrl`: string - `description`: string (optional) - `location`: string (optional) - `recurrenceRule`: object (optional) - `freq`: enum (`DAILY` | `WEEKLY` | `MONTHLY` | `YEARLY`) (optional) - `interval`: number (optional) - `count`: number (optional) - `until`: string (optional) - `byday`: array of string (optional) - `bymonthday`: array of number (optional) - `bymonth`: array of number (optional) Returns: - The unique ID of the created event ### update-event Updates an existing event in the calendar specified by its URL. Only provided fields are changed. For a one-day full-day event, set `wholeDay` to true and set `start` and `end` to the same calendar day. Parameters: - `uid`: string — Unique identifier of the event to update (obtained from list-events) - `calendarUrl`: string - `summary`: string (optional) - `start`: string (optional) - `end`: string (optional) - `wholeDay`: boolean (optional) — Update whether this is a whole-day event - `description`: string (optional) - `location`: string (optional) - `recurrenceRule`: object (optional) - `freq`: enum (`DAILY` | `WEEKLY` | `MONTHLY` | `YEARLY`) (optional) - `interval`: number (optional) - `count`: number (optional) - `until`: string (optional) - `byday`: array of string (optional) - `bymonthday`: array of number (optional) - `bymonth`: array of number (optional) Returns: - The unique ID of the updated event ### delete-event Deletes an event in the calendar specified by its URL Parameters: - `uid`: string — Unique identifier of the event to delete (obtained from list-events) - `calendarUrl`: string Returns: - Confirmation message when the event is successfully deleted ### list-todos List tasks (VTODOs) in the calendar specified by its URL. By default returns only open tasks (NEEDS-ACTION and IN-PROCESS), sorted by manual order then due date. Use `status` to include completed (`COMPLETED`) or all (`ALL`) tasks, and `limit`/`offset` to page through long lists. Parameters: - `calendarUrl`: string - `status`: enum (`OPEN` | `ALL` | `NEEDS-ACTION` | `COMPLETED` | `IN-PROCESS` | `CANCELLED`) (optional) — Filter by status. `OPEN` (default) = NEEDS-ACTION + IN-PROCESS; `ALL` = everything; or an exact status (NEEDS-ACTION, COMPLETED, IN-PROCESS, CANCELLED). - `due_before`: string (optional) — Only tasks with a due date at or before this (ISO 8601). Undated tasks are excluded when a due window is set. - `due_after`: string (optional) — Only tasks with a due date at or after this (ISO 8601). Undated tasks are excluded when a due window is set. - `limit`: number (optional) — Max tasks to return (default 50, max 500) - `offset`: number (optional) — Tasks to skip (default 0) Returns: - An object `{ todos, total, limit, offset }` where `total` is the count before pagination. Each todo has `uid`, `summary`, `status`, and optionally `due`, `start`, `completed`, `description`, `location`. ### create-todo Creates a task (VTODO) in the calendar specified by its URL. Only `summary` is required; a task may have no dates. Use `due` for a deadline and `start` for when work should begin. Parameters: - `summary`: string - `calendarUrl`: string - `due`: string (optional) — Due datetime (ISO 8601) - `start`: string (optional) — Start datetime (ISO 8601) - `description`: string (optional) - `location`: string (optional) - `status`: enum (`NEEDS-ACTION` | `COMPLETED` | `IN-PROCESS` | `CANCELLED`) (optional) — Defaults to NEEDS-ACTION when omitted Returns: - The unique ID of the created todo ### update-todo Updates an existing task (VTODO) in the calendar specified by its URL. Only provided fields are changed. To mark a task done, prefer the `complete-todo` tool. Parameters: - `uid`: string — Unique identifier of the todo to update (from list-todos) - `calendarUrl`: string - `summary`: string (optional) - `due`: string (optional) - `start`: string (optional) - `description`: string (optional) - `location`: string (optional) - `status`: enum (`NEEDS-ACTION` | `COMPLETED` | `IN-PROCESS` | `CANCELLED`) (optional) Returns: - The unique ID of the updated todo ### complete-todo Marks a task (VTODO) as done. Sets its status to COMPLETED and records the completion time. Parameters: - `uid`: string — Unique identifier of the todo to complete (from list-todos) - `calendarUrl`: string Returns: - The unique ID of the completed todo ### delete-todo Deletes a task (VTODO) in the calendar specified by its URL Parameters: - `uid`: string — Unique identifier of the todo to delete (from list-todos) - `calendarUrl`: string Returns: - Confirmation message when the todo is successfully deleted ## License MIT