caldav-blade-mcp
A precision CalDAV MCP server that gives AI agents structured access to calendar data. Built for the Model Context Protocol with token efficiency as a first-class design goal.
Why another calendar MCP?
Most calendar integrations dump entire iCalendar blobs into the context window. A single week view can burn 3,000+ tokens before the model even starts reasoning. caldav-blade-mcp takes a different approach:
- Compact output — pipe-delimited, one line per event, null fields omitted. A day's events in ~200 tokens.
- Batch operations —
cal_events_batchfetches N calendars in one tool call. One call instead of eleven for a family digest. - Purpose-built views —
cal_today,cal_week,cal_freebusygive you exactly what you need with zero configuration. - Write-gated — read by default, writes require explicit opt-in.
cal_deletehas an additionalconfirm=truesafety gate.
Quick start
# Install
uv pip install -e .
# Configure (single provider)
export CALDAV_URL="https://caldav.fastmail.com/dav/calendars/user/you@fastmail.com"
export CALDAV_USERNAME="you@fastmail.com"
export CALDAV_PASSWORD="app-specific-password"
# Run
caldav-blade-mcp
13 tools, 3 categories
Read (9 tools)
| Tool | Purpose | Token cost |
|---|---|---|
cal_info |
Health check — providers, connection, write gate | ~50 |
cal_calendars |
List all calendars (name, UID, provider) | ~20/cal |
cal_events |
Events from one calendar in date range | ~30/event |
cal_events_batch |
Events from N calendars in one call | ~30/event |
cal_event |
Full detail by UID (attendees, recurrence) | ~100 |
cal_search |
Search by text, attendee, location | ~30/event |
cal_today |
Today's events across all calendars | ~30/event |
cal_week |
This week's events across all calendars | ~30/event |
cal_freebusy |
Busy periods only — cheapest availability check | ~15/period |
Write (4 tools, gated)
| Tool | Purpose |
|---|---|
cal_create |
Create event with all fields (description, location, recurrence, attendees, alarm) |
cal_update |
Partial update — only changed fields, auto-increments SEQUENCE |
cal_delete |
Delete by UID — requires confirm=true |
cal_move |
Move event between calendars |
Output format
── Work ──
08:30-09:30 | Standup | uid=abc123
14:00-15:00 | Design review @ Level 3 | loc=Level 3 | uid=def456
── Personal ──
All day | School holidays | uid=ghi789
18:30-19:30 | Swim squad | uid=jkl012
Multi-provider support
Run against multiple CalDAV servers simultaneously — useful when calendars span Fastmail, iCloud, Google, or self-hosted (Radicale, Baïkal, Nextcloud).
export CALDAV_PROVIDERS="fastmail,icloud"
export CALDAV_FASTMAIL_URL="https://caldav.fastmail.com/dav/calendars/user/..."
export CALDAV_FASTMAIL_USERNAME="you@fastmail.com"
export CALDAV_FASTMAIL_PASSWORD="fm-app-password"
export CALDAV_ICLOUD_URL="https://caldav.icloud.com/"
export CALDAV_ICLOUD_USERNAME="you@icloud.com"
export CALDAV_ICLOUD_PASSWORD="app-specific-password"
Single-provider mode (the CALDAV_URL / CALDAV_USERNAME / CALDAV_PASSWORD env vars) remains fully supported for simple setups.
Security model
| Layer | Mechanism |
|---|---|
| Write gate | CALDAV_WRITE_ENABLED=true required for any mutation |
| Delete safety | cal_delete additionally requires confirm=true |
| Credential scrubbing | Passwords and server URLs stripped from all error output |
| Bearer auth | Optional CALDAV_MCP_API_TOKEN for HTTP transport |
| No caching | Credentials read from env at startup, never persisted |
Claude Code integration
Add to your MCP config (e.g. claude.nix or settings.json):
{
"mcpServers": {
"calendar-piers": {
"type": "stdio",
"command": "uv",
"args": ["--directory", "~/src/caldav-blade-mcp", "run", "caldav-blade-mcp"],
"env": {
"CALDAV_URL": "...",
"CALDAV_USERNAME": "...",
"CALDAV_PASSWORD": "...",
"CALDAV_WRITE_ENABLED": "false"
}
}
}
}
A bundled SKILL.md teaches Claude the optimal tool-calling patterns — batch over individual, freebusy over full event scans, convenience views for common queries.
Development
make install-dev # Install with dev + test dependencies
make test # Unit tests (mocked caldav, no server needed)
make check # Lint + format + type-check
make run # Start MCP server (stdio)
Architecture
src/caldav_blade_mcp/
├── server.py — FastMCP 2.0 server, 13 @mcp.tool decorators
├── client.py — CalDAVClient with multi-provider, typed exceptions
├── formatters.py — Token-efficient output (pipe-delimited, null omission)
├── models.py — Provider config, write-gate, constants
└── auth.py — Bearer token middleware for HTTP transport
Built with FastMCP 2.0, caldav, and python-dateutil.
License
MIT
Metadata
Release files for caldav-blade-mcp 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| caldav_blade_mcp-0.4.0.tar.gz | 142.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| caldav_blade_mcp-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 165.2 kB
Release files / caldav_blade_mcp-0.4.0.tar.gz
| Download URL | caldav_blade_mcp-0.4.0.tar.gz |
|---|---|
| Size | 142.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4055b35730f79b0be7710881fd01962bd32e22c8fd7ab14f3bc90c0a8f225212
|
|
BLAKE2b-256 checksum How to use checksums |
c925c22b2852f0efe05bc80d94cede9f12dc4a0a438018209019d8b434f757a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2026.
Transparency logRelease files / caldav_blade_mcp-0.4.0-py3-none-any.whl
| Download URL | caldav_blade_mcp-0.4.0-py3-none-any.whl |
|---|---|
| Size | 22.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2694e3c7dc7ff54964b63f0e979e4e65c43b43640d15485af313980604d0eecc
|
|
BLAKE2b-256 checksum How to use checksums |
d93d7f2d6324960445c808dc3ee6d81948ff76d6a35dbfd40521fd81588be8d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 6, 2026.
Transparency log