caldav-mcp
Allows managing iCloud calendars via CalDAV, including creating, reading, updating, and deleting events as well as handling attendees.
Provides read/write access to Nextcloud calendars via CalDAV, enabling event creation, retrieval, updating, deletion, search, and attendee management.
Provides read/write access to ownCloud calendars via CalDAV, enabling event creation, retrieval, updating, deletion, search, and attendee management.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@caldav-mcpWhat events do I have this week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
caldav-mcp
Give AI assistants full read/write access to any CalDAV calendar.
A self-hosted bridge between Model Context Protocol clients and your CalDAV infrastructure. Connect Claude, Codex, Cursor, VS Code, and other AI assistants to Nextcloud, Radicale, Baikal, and any RFC 4791 calendar server. Query events, create meetings, manage attendees, and move events between calendars — all through a single Docker container with no database and no external dependencies.
What it does
caldav-mcp gives your AI assistant direct access to your calendar. Instead of copy-pasting events or switching tabs, ask your assistant to do it:
"What's on my calendar tomorrow?" →
caldav_get_today_events"Find my next dentist appointment." →
caldav_search_events"Create a meeting next Tuesday at 14:00." →
caldav_create_event"Move this event to my personal calendar." →
caldav_move_event"When am I free next week?" →
caldav_get_freebusy"Add Alice and Bob to this event." →
caldav_add_attendee"Delete the duplicate appointment." →
caldav_delete_event
Related MCP server: mcp-labrat
Why caldav-mcp
Self-hosted AI assistants | Keep your AI calendar access on your own infrastructure. No third-party SaaS, no data leaves your network. |
Nextcloud / Radicale / Baikal integration | Works with any RFC 4791 CalDAV server. Radicale is integration-tested in CI, Nextcloud is used in development. Baikal, ownCloud, iCloud, and Fastmail are protocol-compatible. |
Centralized MCP infrastructure | One server instance for your entire homelab or team. Multiple AI clients connect to the same endpoint. |
Multiple CalDAV accounts | Credentials travel per-request in HTTP headers — a single server serves different CalDAV accounts without restarts or reconfiguration. |
Docker / homelab deployment | One Docker image, one |
Full read/write access | 14 focused tools covering calendar discovery, event queries, creation, updates, deletion, moves, and attendee management. |
Security built in | Optional API-key authentication with constant-time comparison, per-IP rate limiting with exponential backoff, input sanitization, and structured audit logging. |
How it works
flowchart LR
subgraph "MCP Client"
AI["AI / MCP Client\n(Claude, Cursor, VS Code, …)"]
end
subgraph "caldav-mcp"
EP["/mcp\nStreamable HTTP"]
AK["API Key Auth\n(optional)"]
RL["Per-IP Rate\nLimiting"]
end
subgraph "CalDAV Providers"
N["Nextcloud"]
R["Radicale"]
B["Baikal"]
end
AI -- "Streamable HTTP\n+ headers" --> EP
EP --> AK
EP --> RL
EP -- "CalDAV protocol" --> N
EP -- "CalDAV protocol" --> R
EP -- "CalDAV protocol" --> BStateless, per-request architecture
The server maintains no session state between requests. CalDAV credentials
travel per-request in HTTP headers (X-Caldav-Url, X-Caldav-Username,
X-Caldav-Password), which means:
Different requests can target different CalDAV accounts — a single server instance serves multiple users or calendars.
Environment variables provide a simpler single-account fallback — set
CALDAV_URL,CALDAV_USERNAME,CALDAV_PASSWORDand omit the headers.No database, no persistent account state — the only in-memory state is a thread-safe LRU cache of CalDAV client connections.
Two authentication layers sit between the client and the CalDAV server:
MCP endpoint auth — optional API key via
Authorization: BearerorX-Api-Keyheader. WhenCALDAV_MCP_API_KEYis unset, the endpoint is open. Protects the MCP endpoint itself.CalDAV credentials — HTTP headers (preferred) or environment variables (fallback). Authenticate against the actual CalDAV server.
Supported CalDAV servers
Provider / Server | Status |
Integration-tested (CI pipeline) | |
Known to work (used in development) | |
Protocol-compatible | |
Protocol-compatible | |
Protocol-compatible | |
Protocol-compatible | |
Other RFC 4791 CalDAV servers | Protocol-compatible |
Any server that implements the CalDAV standard (RFC 4791) should work. If it doesn't, open an issue.
MCP tools (14)
The server exposes 14 MCP tools across three categories.
Tool | Description |
List all available calendars for the configured account | |
Get events in a date range | |
Get events for today | |
Get events for the next 7 days | |
Get a specific event by UID, including attendees | |
Find events by text across summary, description, location, and categories | |
Get free/busy information for a time range |
Tool | Description |
Create a new event — supports recurring rules, priority, categories, and attendees | |
Partially update an existing event by UID | |
Delete an event by UID | |
Move an event between calendars |
Tool | Description |
Add an attendee to an event | |
Remove an attendee from an event | |
List attendees of an event |
Full API documentation: docs/api.md.
Quick start
1. Pull and run
Pull the latest image:
docker pull ghcr.io/gelse/caldav-mcp:latestThen run it directly (replace the environment variables with your values):
docker run -d \
-p 8600:8080 \
-e CALDAV_URL=https://cloud.example.com/remote.php/dav/calendars/user/ \
-e CALDAV_USERNAME=user \
-e CALDAV_PASSWORD=app-password \
-e CALDAV_MCP_API_KEY=your-secret-token \
-e TZ=Europe/Vienna \
ghcr.io/gelse/caldav-mcp:latestNote: The
CALDAV_URL,CALDAV_USERNAME, andCALDAV_PASSWORDenvironment variables are optional. If omitted, CalDAV credentials must be sent per-request via theX-Caldav-Url,X-Caldav-Username, andX-Caldav-PasswordHTTP headers — see MCP client configuration.
The server is now running at http://localhost:8600/mcp (Streamable HTTP).
2. Verify
curl -s http://localhost:8600/mcp \
-H "Authorization: Bearer your-secret-token" \
-H "X-Caldav-Url: https://cloud.example.com/remote.php/dav/calendars/user/" \
-H "X-Caldav-Username: user" \
-H "X-Caldav-Password: app-password" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}'MCP client configuration
Streamable HTTP only — the server does not support stdio transport. Any MCP client that supports Streamable HTTP can connect.
The standard configuration format with per-request CalDAV credentials:
{
"mcpServers": {
"caldav": {
"type": "http",
"url": "http://localhost:8600/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY",
"X-Caldav-Url": "https://cloud.example.com/remote.php/dav/calendars/user/",
"X-Caldav-Username": "user",
"X-Caldav-Password": "app-password"
}
}
}
}Client-specific configuration
Claude Desktop
Config file location:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
Uses the mcpServers key. Custom Connectors added via the UI require a paid plan.
Claude Code
Config file locations:
Global:
~/.claude/settings.jsonProject:
.mcp.json(in project root)
Uses the mcpServers key. You can also add via CLI:
claude mcp add --transport http caldav http://localhost:8600/mcpNote: The CLI does not support setting custom headers. Add the
headersblock manually in the JSON config after using the CLI command.
Cursor
Config file locations:
Project:
.cursor/mcp.jsonGlobal:
~/.cursor/mcp.json
Uses the mcpServers key.
VS Code
Config file location: .vscode/mcp.json
Uses the servers key, not mcpServers:
{
"servers": {
"caldav": {
"type": "http",
"url": "http://localhost:8600/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY",
"X-Caldav-Url": "https://cloud.example.com/remote.php/dav/calendars/user/",
"X-Caldav-Username": "user",
"X-Caldav-Password": "app-password"
}
}
}
}OpenCode
Config file location: project root (e.g. opencode.json).
Uses the mcpServers key with the standard format shown above.
OpenWebUI
Configure via Admin Panel → Settings → Connections. Add the MCP server URL and headers through the UI.
Multiple CalDAV accounts
Because credentials travel per-request in HTTP headers, a single server
instance can serve multiple CalDAV accounts. Configure each MCP client
connection with different X-Caldav-* headers.
Deployment
Install from a release
# Clone at a specific version
git clone --branch v0.1.0 https://github.com/gelse/caldav-mcp.git
cd caldav-mcp
cp .env.example .env
# Edit .env with your CalDAV credentials
docker compose up -dUsing the public Docker image
Docker image releases are published to the GitHub Container Registry. Pull the latest image:
docker pull ghcr.io/gelse/caldav-mcp:latestThen run it directly (replace the environment variables with your values):
docker run -d \
-p 8600:8080 \
-e CALDAV_URL=https://cloud.example.com/remote.php/dav/calendars/user/ \
-e CALDAV_USERNAME=user \
-e CALDAV_PASSWORD=app-password \
-e CALDAV_MCP_API_KEY=your-secret-token \
-e TZ=Europe/Vienna \
ghcr.io/gelse/caldav-mcp:latestNote: The CalDAV credentials (
CALDAV_URL,CALDAV_USERNAME,CALDAV_PASSWORD) are optional. You can omit them and instead provide credentials per-request via theX-Caldav-Url,X-Caldav-Username, andX-Caldav-PasswordHTTP headers in your MCP client configuration — see MCP client configuration.
Local / private deployment
The simplest setup — AI client and caldav-mcp on the same machine:
AI Client → http://localhost:8600/mcp → CalDAV Serverdocker compose up -dThe server listens on localhost:8600 and is not accessible from the
network unless you explicitly publish the port.
Remote / shared deployment
For multi-user or remote access, put the server behind a TLS-terminating reverse proxy:
AI Client → HTTPS → reverse proxy → caldav-mcp → CalDAV Serverserver {
listen 443 ssl;
server_name caldav-mcp.example.com;
ssl_certificate /etc/ssl/certs/caldav-mcp.pem;
ssl_certificate_key /etc/ssl/private/caldav-mcp-key.pem;
location /mcp {
proxy_pass http://127.0.0.1:8600/mcp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Built-in TLS
If you prefer not to use a reverse proxy, enable built-in TLS:
CALDAV_MCP_TLS_CERT=/path/to/cert.pem \
CALDAV_MCP_TLS_KEY=/path/to/key.pem \
docker compose up -d⚠️ Do not expose the MCP endpoint publicly without both authentication and TLS. Without
CALDAV_MCP_API_KEYset, the endpoint is open. Without TLS, all traffic — including API keys and CalDAV passwords — is transmitted in plaintext.
Authentication & security
Authentication
MCP endpoint auth (CALDAV_MCP_API_KEY):
Every request to
/mcpmust includeAuthorization: Bearer <token>orX-Api-Key: <token>.Token comparison uses constant-time comparison to prevent timing attacks.
When
CALDAV_MCP_API_KEYis unset, the endpoint is open. Do not expose it to the public internet without authentication.
CalDAV credentials are resolved per-request:
HTTP headers (preferred):
X-Caldav-Url,X-Caldav-Username,X-Caldav-PasswordEnvironment variables (fallback):
CALDAV_URL,CALDAV_USERNAME,CALDAV_PASSWORD
TLS
Option A: Enable built-in TLS by setting
CALDAV_MCP_TLS_CERTandCALDAV_MCP_TLS_KEY. The server listens on HTTPS directly.Option B: Run behind a TLS-terminating reverse proxy (Traefik, Caddy, nginx).
Without TLS, all traffic — including API keys and CalDAV passwords — is transmitted in plaintext.
Rate limiting
Failed authentication attempts are tracked per client IP using a sliding-window
rate limiter with exponential backoff. Defaults: 10 failures per 60-second
window. Configurable via CALDAV_MCP_RATE_LIMIT_MAX_FAILURES and
CALDAV_MCP_RATE_LIMIT_WINDOW_SECONDS.
Audit logging
All authentication attempts and tool operations are logged. Set
CALDAV_MCP_LOG_FORMAT=json for structured JSON output suitable for log
aggregation systems.
Deployment recommendations
Bind to
127.0.0.1or a private network unless you need remote access.Restrict access at the network/firewall layer to trusted hosts or a VPN.
Never commit CalDAV app passwords to version control.
Use a reverse proxy for TLS termination in production.
Configuration reference
All configuration is via environment variables, validated at startup with Pydantic.
Variable | Default | Description |
|
| Listen port (inside container) |
|
| Streamable HTTP endpoint path |
|
| Shared secret for MCP endpoint auth |
|
| IANA timezone (e.g. |
Variable | Default | Description |
|
| CalDAV server URL (fallback for |
|
| CalDAV username (fallback for |
|
| CalDAV password (fallback for |
|
| Verify TLS certs on CalDAV connections. Set |
Variable | Default | Description |
|
| Path to TLS certificate PEM file |
|
| Path to TLS private key PEM file |
|
| Optional CA bundle for custom certificate authorities |
Variable | Default | Description |
|
| Max failed auth attempts per IP within the sliding window |
|
| Sliding window duration in seconds |
Variable | Default | Description |
|
| Audit log format: |
Compatibility / limitations
Streamable HTTP only — the server uses MCP Streamable HTTP transport. There is no stdio transport. To use stdio, modify
server.pyto callmcp.run()instead ofmcp.run_http_async().Search is client-side —
caldav_search_eventsfetches all events and filters locally. This works well for small to medium calendars. Very large calendars may experience slower search.Move is non-atomic —
caldav_move_eventcopies the event to the target calendar with a new UID, then deletes the original. A failure after copy leaves a duplicate (the safer failure mode).Published Docker image — prebuilt images are available from GitHub Container Registry. Pull with
docker pull ghcr.io/gelse/caldav-mcp:latestor build locally withdocker build -t caldav-mcp ./docker compose up --build.No GitHub releases yet — the project is at version
0.1.0.
Setup
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -e ".[dev]"
cp .env.example .env # configure your CalDAV credentialsCommands
make test # Run unit tests
make test-integration # Run integration tests (requires docker-compose.test.yaml)
make test-performance # Run performance benchmarks
make lint # Lint with ruff (check + format)
make typecheck # Type check with mypy
make check # All checks: lint + typecheck + deps-check + test
make deps-check # Verify pyproject.toml and requirements.txt are in sync
make build # Build Docker imageFull contributing guide: docs/contributing.md.
caldav-mcp/
├── server.py # Thin entrypoint, launches FastMCP HTTP server
├── caldav_mcp/ # Core package
│ ├── tools/ # MCP tool handlers
│ │ ├── queries.py # Read-only tools (7)
│ │ ├── mutations.py # Write tools (4)
│ │ └── attendees.py # Attendee management (3)
│ ├── auth.py # Two-layer auth (API key + CalDAV creds)
│ ├── calendar.py # CalDAV calendar selection & serialization
│ ├── client_cache.py # Thread-safe LRU cache for DAVClient
│ ├── config.py # Env var parsing, header constants
│ ├── config_schema.py # Pydantic startup validation
│ ├── datetime_utils.py # Date/time parsing, timezone helpers
│ ├── errors.py # Typed exceptions, ToolResult dataclass
│ ├── event_builder.py # Pure iCalendar VEVENT construction
│ ├── sanitizers.py # Input sanitization, field length limits
│ ├── rate_limit.py # Sliding-window rate limiter
│ ├── audit.py # Structured JSON audit logging
│ ├── constants.py # Shared string constants
│ └── types.py # CalDAVClient Protocol definition
├── tests/ # Unit, integration, performance
├── docs/ # Architecture, API, contributing docs
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yaml # Production compose
├── docker-compose.test.yaml # Test compose with Radicale
├── requirements.txt # Runtime dependencies (pinned)
├── pyproject.toml # Dev config and dependencies
└── Makefile # Build/test shortcutsDependencies
Package | Version | Purpose |
3.4.7 | MCP server framework, Streamable HTTP transport | |
3.2.1 | CalDAV client library | |
7.2.2 | iCalendar RFC 5545 parsing/generation | |
>=2.28.0 | HTTP transport layer |
Troubleshooting
Symptom | Cause | Fix |
| CalDAV server unreachable | Verify |
| Self-signed or invalid TLS cert | Import the server's CA into the system trust store, or set |
| Missing or invalid API token | Set |
| No CalDAV headers or env vars | Provide |
| Typo or wrong calendar name | Run |
Events show wrong time | Server timezone not set | Set the |
Contributing
See docs/contributing.md for development setup, code
style, and architecture rules.
License
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Related MCP Connectors
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
GDPR-compliant calendar access for AI assistants. Google, Microsoft 365, Apple & more. EU-hosted.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
A MCP server that works with Google Calendar to manage event listing, reading, and updates.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceAn MCP server that exposes CalDAV calendar operations as tools for AI assistants. It enables users to connect to CalDAV servers to create and list calendar events within specific timeframes.73599MIT
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables interaction with CalDAV calendars to manage events and check availability through natural language or voice commands. It provides specific tools for listing, searching, and creating calendar entries using an OpenAI-compatible interface.-
- AlicenseNot gradedqualityFmaintenanceProvider-agnostic CalDAV calendar MCP server that connects any CalDAV calendar to AI assistants, enabling calendar operations like listing, creating, updating, and deleting events.AGPL 3.0
- AlicenseNot gradedqualityFmaintenanceA comprehensive MCP server that provides AI assistants with natural language access to Apple Calendar, enabling reading, searching, creating, and managing calendar events.3MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/gelse/caldav-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server