Skip to main content
Glama
mvelak

Radicale CalDAV MCP Server

by mvelak
README.md
# Radicale CalDAV MCP Server

A Model Context Protocol (MCP) server built with [FastMCP](https://github.com/jlowin/fastmcp) / the official MCP Python SDK that bridges LLM agents (such as Nous Hermes, Claude, OpenAI) to a self-hosted [Radicale](https://radicale.org/) CalDAV calendar and task manager.

---

## Features

### 📅 Calendar Events (`VEVENT`)
- **`get_events`**: Query events within date/time ranges with optional keyword search across summary, description, and location.
- **`get_free_busy_slots`**: Calculate open, unbooked time slots during configurable business hours (e.g. 9:00 AM - 5:00 PM) in any IANA timezone.
- **`create_event`**: Schedule new events with automatic ISO validation, attendee invitations, and overlap/conflict detection.
- **`update_event`**: Modify existing events by UID without overwriting untouched fields.
- **`delete_event`**: Remove events by UID.

### 📝 Tasks & To-Dos (`VTODO`)
- **`list_todos`**: Fetch pending or completed tasks filtered by status (`NEEDS-ACTION`, `COMPLETED`, `IN-PROCESS`, `CANCELLED`, `ALL`).
- **`create_todo`**: Create tasks with due dates, priority levels (1-9), and descriptions.
- **`complete_todo`**: Mark tasks as completed with automatic completion timestamps.

### 🚀 Transports & Deployment
- **STDIO Transport**: Default transport for local execution (e.g. Claude Desktop, local agents).
- **SSE (Server-Sent Events) Transport**: Over HTTP for remote, always-on deployments (e.g. Coolify, Docker).

---

## Configuration

Configure the server via environment variables or a `.env` file:

| Variable | Default | Description |
|---|---|---|
| `RADICALE_BASE_URL` | `http://localhost:5232` | Base URL to Radicale (e.g. `https://radicale.dubblu.app`) |
| `RADICALE_USERNAME` | `mvela581` | CalDAV username |
| `RADICALE_PASSWORD` | `""` | CalDAV password |
| `RADICALE_CALENDAR_SLUG` | `seuspeptides` | Target calendar slug / collection name |
| `DEFAULT_TIMEZONE` | `America/New_York` | Default IANA timezone |
| `MCP_TRANSPORT` | `stdio` | Transport protocol: `stdio` or `sse` |
| `MCP_HOST` | `0.0.0.0` | Host interface for SSE mode |
| `MCP_PORT` | `8000` | Port number for SSE mode |

---

## Local Quickstart

### 1. Installation

```bash
# Clone and enter directory
cd radicale-mcp-server

# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install -r requirements.txt
```

### 2. Configure Environment

Copy `.env.example` to `.env` and set your credentials:

```bash
cp .env.example .env
```

### 3. Run Locally

#### STDIO Mode (Local Pipe)
```bash
python server.py --stdio
```

#### SSE Mode (HTTP Server)
```bash
python server.py --sse --host 0.0.0.0 --port 8000
```

### 4. Run Test Client

```bash
# Test via STDIO
python test_client.py --mode stdio

# Test via SSE (when server is running)
python test_client.py --mode sse --sse-url http://localhost:8000/sse
```

### 5. Run Automated Tests

```bash
pytest -v
```

---

## Coolify Deployment

Deploy the MCP server on [Coolify](https://coolify.io) with zero configuration:

1. Create a new service in Coolify: **Docker Compose** or **Dockerfile**.
2. Point it to this repository or paste the `docker-compose.yml`.
3. Set the following environment variables in Coolify UI:
   - `RADICALE_BASE_URL=https://radicale.dubblu.app`
   - `RADICALE_USERNAME=mvela581`
   - `RADICALE_PASSWORD=your_password`
   - `RADICALE_CALENDAR_SLUG=seuspeptides`
   - `DEFAULT_TIMEZONE=America/New_York`
   - `MCP_TRANSPORT=sse`
   - `MCP_PORT=8000`
4. Expose port `8000` via Coolify reverse proxy with your domain (e.g. `https://mcp-calendar.yourdomain.com`).
5. Your SSE endpoint will be accessible at:
   ```
   https://mcp-calendar.yourdomain.com/sse
   ```

---

## LLM Agent Integration (Nous Hermes / Claude Desktop)

### Claude Desktop Configuration

Add the following to your `claude_desktop_config.json`:

#### Local STDIO:
```json
{
  "mcpServers": {
    "radicale_calendar": {
      "command": "/path/to/radicale-mcp-server/.venv/bin/python",
      "args": ["/path/to/radicale-mcp-server/server.py", "--stdio"],
      "env": {
        "RADICALE_BASE_URL": "https://radicale.dubblu.app",
        "RADICALE_USERNAME": "mvela581",
        "RADICALE_PASSWORD": "your_password",
        "RADICALE_CALENDAR_SLUG": "seuspeptides",
        "DEFAULT_TIMEZONE": "America/New_York"
      }
    }
  }
}
```

#### Remote SSE (Coolify):
```json
{
  "mcpServers": {
    "radicale_calendar": {
      "url": "https://mcp-calendar.yourdomain.com/sse"
    }
  }
}
```

### Nous Hermes Agent Integration

Tool definitions are auto-generated from docstrings with type specifications. Sample prompt usage:

```json
{
  "name": "get_free_busy_slots",
  "arguments": {
    "start_date": "2026-08-26",
    "end_date": "2026-08-28",
    "slot_duration_minutes": 30,
    "working_hours_start": 9,
    "working_hours_end": 17,
    "timezone": "America/New_York"
  }
}
```

---

## License

MIT