Skip to main content
Glama
cora-p
by cora-p
README.md
# proton-calendar-mcp

An MCP server for reading — and eventually modifying — a Proton Calendar.

## Architecture

Proton Calendar has no public API and no CalDAV support, and event data is
end-to-end encrypted. This server is built in phases:

- **Phase 1 (working): reads** via the calendar's secret ICS share link
  (Proton Calendar → Settings → Calendars → Share via link, "full view").
  The feed is fetched on demand and cached for 60 seconds. Recurring events
  are expanded into concrete occurrences (RRULE, EXDATE, and overridden
  instances are honored).
- **Phase 2 (planned): writes.** See DEVELOPMENT.md once started.

## Tools

| Tool | Purpose |
| --- | --- |
| `list_events` | Events in a date range (default: next 7 days) |
| `search_events` | Text search over title/description/location |
| `get_event` | Full details for one event by UID |

## Setup

```sh
npm install
npm run build
```

Configure in your MCP client (e.g. `claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "proton-calendar": {
      "command": "node",
      "args": ["/path/to/proton-mcp/dist/index.js"],
      "env": {
        "PROTON_ICS_URL": "https://calendar.proton.me/api/calendar/v1/url/..."
      }
    }
  }
}
```

The ICS URL is a secret — anyone holding it can read the calendar. Keep it
out of version control.

## Development

```sh
npm run dev    # tsc --watch
```

Smoke test without an MCP client by piping JSON-RPC over stdin:

```sh
printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_events","arguments":{}}}' \
  | PROTON_ICS_URL="..." node dist/index.js
```