dav-mcp
dav-mcp lets AI agents manage calendars, contacts, and tasks on CalDAV/CardDAV servers through 27 MCP tools.
List, create, update, delete, and query calendars/events, including free/busy search and batch event retrieval.
List, create, update, delete, and search address books/contacts, with batch contact retrieval.
List, create, update, delete, and query todos/tasks with status, due-date, priority, and completion fields.
Update fields via structured RFC properties or raw iCal/vCard data, including custom X-* properties.
Works across RFC-compliant providers such as Nextcloud, Baikal, Radicale, iCloud, and Google Calendar via OAuth.
Enables OAuth2-authenticated access to Google Calendar via CalDAV, allowing management of calendar events with support for creating, updating, and field-specific modifications using RFC-compliant properties.
Supports iCloud calendars and contacts via CalDAV/CardDAV protocols using app-specific password authentication, enabling full CRUD operations on events, contacts, and tasks stored in iCloud.
Provides full CalDAV and CardDAV support for managing calendars, contacts, and tasks stored in Nextcloud, including creating, updating, deleting, and querying calendar events, address book contacts, and VTODO tasks.
dav-mcp
Give your AI agents the power of organization — Transform them into orchestrating assistants managing calendars, contacts, and tasks.
Built on 27 production-ready tools spanning CalDAV, CardDAV, and VTODO protocols.
Quick Start
Claude Code plugin
In Claude Code, run:
/plugin install dav-mcp --marketplace PhilflowIO/dav-mcpClaude Code then asks for your server URL, username and password. The plugin also brings a skill that teaches Claude to use the tools well. Details are in the plugin README.
One-click install (Claude Desktop)
Download
dav-mcp-<version>.mcpbfrom the latest release. Releases from 4.1.2 on carry this file.Open it with Claude Desktop (macOS or Windows). Claude shows an install dialog.
Enter your server URL, username and password. The password is stored as a secret. Leave the authentication method at
Basicunless your server needsDigest.
The .mcpb file is an MCP Bundle: the server with its dependencies, so neither Node.js nor npx needs to be installed.
Claude Desktop / Cursor (Local)
Add to your MCP config file:
{
"mcpServers": {
"dav-mcp": {
"command": "npx",
"args": ["-y", "dav-mcp"],
"env": {
"CALDAV_SERVER_URL": "https://dav.example.com",
"CALDAV_USERNAME": "your_username",
"CALDAV_PASSWORD": "your_password"
}
}
}
}Config file locations:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
Restart Claude Desktop after adding the configuration.
n8n (Remote HTTP)
Start the HTTP server:
CALDAV_SERVER_URL=https://dav.example.com \
CALDAV_USERNAME=your_username \
CALDAV_PASSWORD=your_password \
BEARER_TOKEN=your-secret-token \
npx dav-mcp --httpThen in n8n:
Add AI Agent node
Add MCP Client Tool node and connect to AI Agent
Configure:
MCP Endpoint:
http://localhost:3000/mcpAuthentication: Bearer
Token: your-secret-token
Custom port:
npx dav-mcp --http --port=8080Docker
Pull the published image (distroless, runs as non-root, no shell):
docker run -d --name dav-mcp -p 3000:3000 --env-file .env \
ghcr.io/philflowio/dav-mcp:latestTags: latest, the exact release (5.0.0) and the minor line (5.0).
Set PORT to serve on a different port; the healthcheck follows it.
Or build from source:
git clone https://github.com/PhilflowIO/dav-mcp.git
cd dav-mcp
cp .env.example .env
# Edit .env with your credentials
docker-compose upRelated MCP server: caldav-mcp
The Orchestration
When partial tools force your AI to improvise, complete tools let it execute precise operations across all components.
Capability | dav-mcp | Most MCPs |
Calendar Management | Full CRUD (12 tools) | Create + list only (2-3 tools) |
Contact Management | Complete CardDAV (8 tools) | Often missing entirely |
Task Management | Full VTODO support (7 tools) | Rarely included |
Field-Based Updates | All RFC properties + custom fields | Rarely available |
Free/Busy | Works on every server (client-side) | Native REPORT, unsupported by most |
Server-Side Filtering | Efficient queries | Dumps all data |
Multi-Provider | Any CalDAV/CardDAV server | Limited provider support |
Total Tools | 27 tools | 2-6 tools |
Available Tools (27 Total)
CalDAV Tools (12 tools)
list_calendars - List all available calendars
list_events - List ALL events (use calendar_query for filtered searches)
create_event - Create a new calendar event
update_event - PREFERRED: Update any event field (SUMMARY, LOCATION, STATUS, custom X-* properties); move or convert an event with start_date/end_date/all_day
update_event_raw - Update event with raw iCal data (advanced)
delete_event - Delete an event permanently
calendar_query - PREFERRED: Search and filter events efficiently by text, date range, or location
make_calendar - Create a new calendar collection, optionally with a time zone (an IANA name such as
Europe/Berlin, sent as a VTIMEZONE)update_calendar - Update calendar properties (display name, description, color, time zone)
delete_calendar - Delete a calendar and all its events
calendar_multi_get - Batch fetch multiple specific events by URLs
freebusy_query - Find free and busy time in a range ("when am I free?"), calculated client-side
CardDAV Tools (8 tools)
list_addressbooks - List all available address books
list_contacts - List ALL contacts (use addressbook_query for filtered searches)
create_contact - Create a new contact (vCard)
update_contact - PREFERRED: Update any contact field (FN, EMAIL, TEL, ORG, ADR, custom X-* properties)
update_contact_raw - Update contact with raw vCard data (advanced)
delete_contact - Delete a contact permanently
addressbook_query - PREFERRED: Search and filter contacts efficiently by name, email, or organization
addressbook_multi_get - Batch fetch multiple specific contacts by URLs
VTODO Tools (7 tools)
list_todos - List ALL todos/tasks (use todo_query for filtered searches)
create_todo - Create a new todo/task with optional due date, priority, status
update_todo - PREFERRED: Update any todo field (SUMMARY, STATUS, PRIORITY, DUE, PERCENT-COMPLETE, custom X-* properties)
update_todo_raw - Update todo with raw VTODO iCal data (advanced)
delete_todo - Delete a todo/task permanently
todo_query - PREFERRED: Search and filter todos efficiently by status/due date
todo_multi_get - Batch fetch multiple specific todos by URLs
Time zones
An event or todo written without a time zone (a "floating" time such as
DTSTART:20261010T090000, or an all-day date) is read in its calendar's time
zone, as CalDAV specifies (RFC 4791 §9.9): the zone set with make_calendar /
update_calendar, which list_calendars shows. A calendar without one is read
in the zone dav-mcp runs in: the TZ environment variable (for example
TZ=Europe/Berlin in Docker or an HTTP deployment), else the system's. A time
without a zone given to the create and update tools is read the same way, and
an event stored without a zone stays without one when it is moved.
freebusy_query prints its slots in the calendar's zone and names it.
Real-World Applications
n8n Automation Workflows
Meeting Management: "Show me all Friday meetings" → calendar_query with date filter returns only relevant events
Contact Search: "Find everyone at Google" → addressbook_query with org filter finds matches efficiently
Task Reporting: "Show overdue high-priority tasks" → todo_query with filters returns specific results
Scheduled Cleanup: Daily cron job deletes completed tasks using targeted queries
Claude Desktop Integration
Quick Event Creation: "Create team meeting tomorrow 2 PM" → create_event executes immediately
Contact Lookup: "What's Sarah's email?" → addressbook_query with name filter finds contact
Calendar Overview: "What's on my calendar next week?" → calendar_query with date range shows events
Calendar Management: "Create a new calendar called Project Luna" → make_calendar creates collection
Works Across All Major Providers
Works with any CalDAV/CardDAV server that follows RFC 4791 and RFC 6352:
Nextcloud - Full support
Baikal - Full support
Radicale - Full support
iCloud - Works with app-specific password
Any RFC-compliant server - Standard protocol support
Authentication
AUTH_METHOD selects how dav-mcp logs in (case-insensitive):
| Credentials | Use for |
|
| Almost every server. If the server only offers Digest (for example Baikal set to Digest), dav-mcp switches to Digest by itself — no setting needed. |
|
| Servers that only accept Digest (RFC 7616). Unlike the automatic switch under |
|
| Google Calendar |
dav-mcp needs Node.js 22 or newer. A wrong configuration — an unknown
AUTH_METHOD value, or missing credentials for the chosen method — stops the
server at startup instead of falling back to Basic.
Google Calendar (OAuth2)
For Google Calendar, use OAuth2 authentication:
{
"mcpServers": {
"dav-mcp": {
"command": "npx",
"args": ["-y", "dav-mcp"],
"env": {
"AUTH_METHOD": "OAuth",
"GOOGLE_USER": "your@gmail.com",
"GOOGLE_CLIENT_ID": "your-client-id",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"GOOGLE_REFRESH_TOKEN": "your-refresh-token"
}
}
}
}Security
Input Validation: All inputs validated with Zod schemas before execution
Rate Limiting (HTTP mode): 100 requests per 15 minutes per client address, counted before the bearer token is checked. Clients on loopback or a private network (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) — another container on the same Docker network, for example — get 10,000. Limitation: dav-mcp sees the address of whatever connects to it. Behind a Docker port mapping or a reverse proxy that is the bridge gateway or the proxy, so all outside clients share that one address, its one counter and its raised limit. Rate-limit per client at the proxy if you expose the HTTP transport.
Bearer Auth: Token authentication for HTTP transport
No Credential Storage: Pass-through only, never logged or cached
Structured Logging: Audit trail with request IDs, no PII exposure
Tool-Call Log Off by Default:
LOG_TOOL_CALLS=truerecords every tool call with its arguments, for debugging — to~/.local/state/dav-mcp/tool-calls.jsonl(or$XDG_STATE_HOME,%LOCALAPPDATA%on Windows, orTOOL_CALL_LOG_FILE), readable by you only.TOOL_CALL_LOG_MODE=consolesends it to stderr instead.CORS Protection: Whitelist origins, block cross-site attacks
Privacy Policy
dav-mcp runs on your machine (or your own server) and talks only to the DAV server you configure. It has no telemetry and shares nothing with its maintainers or third parties. Tool results go to the AI assistant that called the tool. Credentials and calendar data are not stored by dav-mcp; the optional tool-call log is off by default. Full policy: PRIVACY.md. Contact: hello@philflow.io.
Documentation
MCP Specification - Model Context Protocol docs
tsdav Docs - CalDAV/CardDAV library reference
CalDAV RFC 4791 - CalDAV protocol specification
CardDAV RFC 6352 - CardDAV protocol specification
Contributing
Pull requests are welcome! Please read CONTRIBUTING.md for guidelines.
License
MIT License - see LICENSE for details
Acknowledgments
Built with:
tsdav - Excellent TypeScript CalDAV/CardDAV library
tsdav-utils - Field-agnostic utility layer for RFC-compliant field updates
MCP SDK - Model Context Protocol by Anthropic
ical.js - RFC-compliant iCalendar parser
Questions? Issues? Create a GitHub issue
Built for AI agents managing calendars, contacts, and tasks
Available Tools
27 toolsaddressbook_multi_getA
Batch fetch multiple specific contacts by their URLs. Use when you have exact contact URLs and want to retrieve their details
Inputs: contact_urls (required), addressbook_url (required).
addressbook_queryA
⭐ PREFERRED: Search and filter contacts efficiently (name, email, organization). Use for "find contacts with...", "search for email...", "contacts at company..." queries. Use instead of list_contacts when ANY filter is specified. Omit addressbook_url to search across ALL addressbooks automatically.
Inputs: limit, name_filter, email_filter, addressbook_url, +1 more.
calendar_multi_getA
Batch fetch multiple specific calendar events by their URLs. Use when you have exact event URLs and want to retrieve their details
Inputs: event_urls (required), calendar_url (required).
calendar_queryA
⭐ PREFERRED: Search and filter calendar events efficiently. Use instead of list_events to avoid loading thousands of entries. Omit calendar_url to search across ALL calendars automatically.
Inputs: limit, calendar_url, summary_filter, time_range_end, +2 more.
create_contactA
Create a new contact (vCard) with name, email, phone, organization, and other details
Inputs: full_name (required), addressbook_url (required), note, email, +4 more.
create_eventB
Create a new calendar event with title, date, time, optional description and location
Inputs: summary (required), end_date (required), start_date (required), calendar_url (required), +3 more.
create_todoA
Create a new todo/task in a calendar. Use this when user wants to add a task, todo item, or reminder with optional due date, priority, and status.
Inputs: summary (required), calendar_url (required), status, due_date, +3 more.
delete_calendarA
Delete a calendar and all its events. WARNING: on servers without a trash bin this cannot be undone; servers with one (e.g. Nextcloud) keep the calendar in the trash for a while. Use this when user explicitly asks to "delete calendar" or "remove calendar"
Inputs: calendar_url (required).
delete_contactA
Permanently delete a contact (vCard) from the address book. WARNING: This action cannot be undone — the contact is removed from the server immediately. Use only when the user explicitly requests deletion. Obtain the vCard URL and etag from list_contacts or addressbook_query first. The etag ensures no conflicting changes occurred since the contact was last retrieved.
Inputs: vcard_url (required), vcard_etag (required).
delete_eventA
Permanently delete a calendar event. WARNING: This action cannot be undone — the event is removed from the server immediately. Use only when the user explicitly requests deletion. Obtain the event URL and etag from list_events or calendar_query first. The etag ensures no conflicting changes occurred since the event was last retrieved.
Inputs: event_url (required), event_etag (required).
delete_todoA
Permanently delete a todo/task from the calendar. WARNING: This action cannot be undone — the todo is removed from the server immediately. Use only when the user explicitly requests deletion. Obtain the todo URL and etag from list_todos or todo_query first. The etag ensures no conflicting changes occurred since the todo was last retrieved.
Inputs: todo_url (required), todo_etag (required).
freebusy_queryA
Find free and busy time in a date range — use for "when am I free?", "am I available Tuesday afternoon?" or finding a slot for a new meeting. Searches all calendars unless one is given. Events marked TRANSPARENT (does not block time) and cancelled events are ignored; recurring events are expanded.
Inputs: time_range_end (required), time_range_start (required), calendar_url, include_event_details.
list_addressbooksA
List all available address books from the CardDAV server. Use this to get address book URLs needed for other contact operations
Inputs: no named parameters.
list_calendarsA
List all available calendars from the CalDAV server. Use this to get calendar URLs needed for other operations
Inputs: no named parameters.
list_contactsA
List ALL contacts from an address book without filtering. WARNING: Returns all contacts which can be thousands - use addressbook_query instead when searching for specific contacts by name, email, or organization to save tokens
Inputs: addressbook_url (required).
list_eventsA
List ALL events from a single calendar without filtering. WARNING: Returns all events which can be many thousands - use calendar_query instead for searching with filters (supports multi-calendar search).
Inputs: calendar_url (required), time_range_end, time_range_start.
list_todosA
List ALL todos/tasks from a calendar. WARNING: Returns all todos without filtering - use todo_query for searches with filters by status, summary, or due date.
Inputs: calendar_url (required).
make_calendarA
Create a new calendar collection on the CalDAV server with optional color, description, and component types. A timezone is accepted but not applied yet (the result says so). The URL is derived from display_name. If a calendar already exists at that URL, nothing is created and the error names the existing calendar — use it instead of creating another. If the URL is only held by something else (e.g. a deleted calendar in the trash bin), a numeric suffix is added (-2, -3, ...). Always use the URL returned in the response.
Inputs: display_name (required), color, timezone, components, +1 more.
todo_multi_getA
Batch fetch multiple specific todos by their URLs. More efficient than fetching one by one when you have exact todo URLs.
Inputs: todo_urls (required).
todo_queryA
⭐ PREFERRED: Search and filter todos efficiently. Use instead of list_todos to conserve tokens. Omit calendar_url to search across ALL calendars automatically.
Inputs: limit, calendar_url, status_filter, summary_filter, +2 more.
update_calendarB
Update an existing calendar's properties (display name, description, color, timezone). Use this when user asks to "rename calendar", "change calendar color", or "update calendar properties"
Inputs: calendar_url (required), color, timezone, description, +1 more.
update_contactB
PREFERRED: Update contact fields without vCard formatting. Supports: FN (full name), N (structured name), EMAIL, TEL (phone), ORG (organization), TITLE (job title), NOTE, URL, ADR (address), BDAY (birthday), and any RFC 6350 vCard property including custom X-* properties.
Inputs: vcard_url (required), vcard_etag (required), fields.
update_contact_rawA
ADVANCED: Update contact with raw vCard data. Requires manual vCard formatting - use update_contact instead for simple field updates (name, email, phone). Only use this if you have complete pre-formatted vCard data or need to update advanced vCard properties.
Inputs: vcard_url (required), vcard_etag (required), updated_vcard_data (required).
update_eventA
PREFERRED: Update event fields without iCal formatting. Use start_date/end_date/all_day to move an event or convert it between all-day and timed. Use fields for everything else: SUMMARY (title), DESCRIPTION (details), LOCATION (place), STATUS (TENTATIVE/CONFIRMED/CANCELLED), and any other RFC 5545 property including custom X-* properties (e.g., X-ZOOM-LINK, X-MEETING-ROOM).
Inputs: event_url (required), event_etag (required), fields, all_day, +2 more.
update_event_rawA
ADVANCED: Update event with raw iCal data. Requires manual iCal formatting - use update_event instead for simple field updates (summary, description). Only use this if you have complete pre-formatted iCal data or need to update advanced iCal properties.
Inputs: event_url (required), event_etag (required), updated_ical_data (required).
update_todoA
PREFERRED: Update todo fields without iCal formatting. Supports: SUMMARY (title), DESCRIPTION (details), STATUS (NEEDS-ACTION/IN-PROCESS/COMPLETED/CANCELLED), PRIORITY (0-9), DUE (due date), PERCENT-COMPLETE (0-100), and any RFC 5545 VTODO property including custom X-* properties.
Inputs: todo_url (required), todo_etag (required), fields.
update_todo_rawA
ADVANCED: Update todo with raw VTODO iCal data. Requires manual iCal formatting - use update_todo instead for simple field updates (summary, description, status). Only use this if you have complete pre-formatted VTODO data or need to update advanced iCal properties.
Inputs: todo_url (required), todo_etag (required), updated_ical_data (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 27 tools
Tools are cleanly partitioned by resource (calendar/event/contact/todo) and descriptions explicitly disambiguate list vs query vs multi_get and update vs update_raw, with PREFERRED/WARNING markers guiding selection. There is genuine overlap among the three read paths for each resource (e.g. list_events vs calendar_query vs calendar_multi_get), but descriptions make the boundaries clear.
Most tools follow a verb_noun pattern (list_events, create_contact, update_todo, delete_calendar) consistently. Deviations are systematic rather than chaotic: the noun-first *_query and *_multi_get families, the *_raw suffix variants, and make_calendar instead of create_calendar. Readable overall but not a single uniform convention.
27 tools is on the heavy side, but it reflects a broad CalDAV/CardDAV domain spanning calendars, events, todos, contacts, and addressbooks, each with its own CRUD lifecycle. The count is inflated somewhat by per-resource *_raw and list/query/multi_get variants, but each tool serves a defensible purpose.
Full lifecycle coverage (list/query/create/update/delete) exists for events, todos, and contacts, plus calendar management and freebusy queries. Minor gaps remain: addressbooks can only be listed (no create/update/delete), and there is no dedicated attendee/RSVP handling for events.
Maintenance
Related MCP Connectors
Calendars, tasks, contacts, bookings and agent inboxes for your assistant. EU-hosted, OAuth.
ADHD system of record for agents: tasks, goals, loops, calendar, focus stats.
The planner you can call: your tasks, calendar, notes, goals and habits, in your AI assistant.
AI planner: your calendars, to-dos, goals and booking links. Changes wait for your yes.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceTransform AI agents into orchestrating assistants managing calendars, contacts, and tasks via CalDAV, CardDAV, and VTODO protocols.298 npm1MIT
- AlicenseNot gradedqualityAmaintenanceConnects AI assistants to CalDAV servers so they can list calendars and browse, create, update, or delete events and to-do tasks within a chosen timeframe. Supports scheduling of recurring and all-day events, task filtering and pagination, and completion tracking through natural language.732 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to connect to CalDAV servers and manage calendars, events, and tasks through tools for listing, creating, updating, completing, and deleting items.732 npmMIT
- AlicenseNot gradedqualityAmaintenanceConnects AI assistants to CalDAV servers so they can list calendars, browse events within a timeframe, and create, update, delete, or complete events and tasks (VTODOs) through natural language. Supports recurring events, all-day entries, and todo filtering by status or due date with pagination.732 npmMIT