Skip to main content
Glama

Radicale MCP

A thin MCP sidecar for an existing Radicale CalDAV/CardDAV server.

Radicale remains responsible for users, permissions, collections, storage, CalDAV and CardDAV. radicale-mcp only translates MCP tool calls into authenticated DAV requests. It has no database, no storage volume, no cache, and does not import Radicale internals.

What it exposes

  • Calendars and events: list, search, read, create, update, delete

  • Task lists and VTODO tasks: list, search, read, create, update, complete, delete

  • Address books and contacts: list, search, read, create, update, delete

  • Streamable HTTP MCP endpoint at /mcp

  • Public readiness endpoint at /health

  • Multiarch container image for linux/amd64 and linux/arm64

Image:

ghcr.io/forge-z/radicale-mcp:latest

Related MCP server: ical-mcp

Architecture

MCP client
    |
    | HTTPS + Bearer token
    v
radicale-mcp
    |
    | CalDAV / CardDAV
    v
Radicale
    |
    v
existing Radicale storage

The MCP container never mounts or reads Radicale's data or configuration directories.

Quick start

If Radicale is already running, add only the MCP sidecar to the same Docker network:

radicale-mcp:
  image: ghcr.io/forge-z/radicale-mcp:latest
  pull_policy: always
  restart: unless-stopped
  init: true

  environment:
    DAV_URL: http://radicale:5232/
    DAV_USERNAME: ${DAV_USERNAME}
    DAV_PASSWORD: ${DAV_PASSWORD}
    MCP_TOKEN: ${MCP_TOKEN}
    MCP_TIMEZONE: ${MCP_TIMEZONE:-UTC}
    PORT: "8080"

  expose:
    - "8080"

  read_only: true

  tmpfs:
    - /tmp:size=16m

  cap_drop:
    - ALL

  security_opt:
    - no-new-privileges:true

Example environment:

DAV_USERNAME=alice
DAV_PASSWORD=change-me
MCP_TOKEN=replace-with-a-long-random-token
MCP_TIMEZONE=Europe/London

Generate a token with:

openssl rand -hex 32

Expose radicale-mcp:8080 through your HTTPS reverse proxy and configure the MCP client with:

https://mcp.example.com/mcp
Authorization: Bearer <MCP_TOKEN>

Do not expose the MCP endpoint without HTTPS on an untrusted network.

Complete Compose example

compose.yaml shows Radicale and the sidecar together. It preserves Radicale as the only DAV/storage service and gives each container its own health check.

If you already have a production Radicale deployment, keep your existing Radicale volumes and configuration. Copy the MCP service rather than replacing or migrating the existing storage.

Configuration

Variable

Purpose

Default

DAV_URL

Radicale base URL reachable by the sidecar

http://radicale:5232/

DAV_USERNAME

Existing Radicale user

Required

DAV_PASSWORD

Password for that Radicale user

Required

MCP_TOKEN

Bearer token protecting /mcp

Required

MCP_TIMEZONE

IANA timezone used for naive date-times

Image default: America/Sao_Paulo; set explicitly for your deployment

PORT

Internal MCP HTTP port

8080 in the reference Compose

The sidecar uses the rights already granted to DAV_USERNAME. It does not create Radicale users or collections.

Health checks

GET /health is intentionally public and lightweight. It returns HTTP 200 only when the MCP process can successfully authenticate to the configured Radicale server with a DAV PROPFIND. If Radicale is unavailable or the configured DAV credentials fail, it returns HTTP 503.

That makes the MCP health endpoint a functional end-to-end readiness check for the adapter plus its Radicale dependency.

The reference Compose also gives Radicale its own local port health check and starts the MCP sidecar only after Radicale becomes healthy.

For Docker Compose platforms such as Coolify, health is still reported per component, while the overall Service/stack status is aggregated from required components. The MCP health check additionally verifies the real DAV dependency, so a healthy MCP means the complete MCP -> Radicale path is working.

Multiple users

The current design is intentionally simple:

One MCP instance = one Radicale identity.

Do not share one MCP token between people who should have different Radicale permissions.

For multiple users, run one sidecar per Radicale account:

Radicale
├── radicale-mcp-alice  -> DAV user alice
├── radicale-mcp-bob    -> DAV user bob
└── radicale-mcp-agent  -> DAV service account

Each sidecar has its own DAV_USERNAME, DAV_PASSWORD and MCP_TOKEN. Radicale remains the source of truth for access control and shared calendars/address books.

MCP tools

Resource

Tools

Events

list_calendars, list_events, search_events, get_event, create_event, update_event, delete_event

Tasks

list_task_lists, list_tasks, search_tasks, get_task, create_task, update_task, complete_task, delete_task

Contacts

list_addressbooks, list_contacts, search_contacts, get_contact, create_contact, update_contact, delete_contact

Collection and item IDs are DAV hrefs relative to DAV_URL, for example:

alice/work/
alice/work/4c1f.ics

Use IDs returned by the tools rather than constructing them manually.

Dates and concurrency

  • Date-times use ISO 8601.

  • Explicit offsets preserve the instant and are normalized safely for iCalendar.

  • Date-only events remain all-day DATE values.

  • Recurring resources are returned as series resources; occurrences are not expanded by the MCP layer.

  • Updates and deletes require the current strong ETag.

  • Stale ETags fail instead of silently overwriting a concurrent DAV change.

Example event creation:

{
  "calendar_id": "alice/work/",
  "summary": "Review",
  "start": "2026-10-01T09:00:00-03:00",
  "end": "2026-10-01T10:00:00-03:00"
}

Security model

  • /mcp requires Authorization: Bearer <MCP_TOKEN>.

  • DAV credentials stay inside the sidecar environment.

  • Credentials and tokens are not returned by MCP tools.

  • Clients cannot supply arbitrary DAV server URLs.

  • Redirects and path traversal are rejected.

  • The reference container runs as a non-root user with a read-only filesystem and dropped Linux capabilities.

For internet-facing deployments, terminate TLS at a trusted reverse proxy.

Development

python -m pip install .
python -m unittest discover -s tests -v
docker build -t radicale-mcp:dev .

The integration suite runs a real Radicale container separately from the MCP container and verifies that the MCP sidecar has no Radicale storage mounts.

GitHub Actions builds and tests natively on both AMD64 and ARM64 before publishing the multiarch image.

Contributing

See CONTRIBUTING.md.

License

MIT. See LICENSE.

Radicale is a separate project with its own license and is not bundled into the radicale-mcp image.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    MCP server for Apple Calendar and CalDAV providers. Enables listing, creating, updating, deleting events, and checking free/busy status with per-calendar write protection.
    6
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables managing calendars, events, contacts, and todos via a CalDAV server (Radicale) through MCP tools.
    -