Skip to main content
Glama

Quickstart

pip install agents-calendar && agents-calendar sync --init

Merges MCP into host configs. Prints where credentials go. Does not write secrets into mcp.json. init is the same command.

TIP

🤖 Agent-Driven Setup: Give your coding agent this repo (clone or URL), then tell it to "install and set up agents-calendar."

Source checkouts can also be installed and managed with vand.


Related MCP server: icloud-calendar-mcp

What it does

List calendars, list events in a time range, add, update, delete. Recurrence rules stay on the CalDAV server (time-range report). Writes send If-None-Match: * on create and If-Match on update and delete, so a stale etag does not clobber.

The password is never printed, logged, or returned by a tool.


Credentials

Highest priority first:

  1. Process env: CALDAV_URL, CALDAV_USERNAME, CALDAV_PASSWORD, optional CALDAV_CALENDAR

  2. ~/.agents/calendar.json (mode 0600)

  3. ~/.agents/.env keys CALDAV_*

{
  "url": "https://example.com/dav/calendars/user/calendar/",
  "username": "user",
  "password": "app-password",
  "calendar": "Work",
  "timezone": "UTC"
}

calendar (or CALDAV_CALENDAR) is optional: the collection, by display name or URL, that add writes to. list searches every collection unless --calendar names one. Both commands and the MCP tools accept calendar per call.

timezone is an optional IANA name (America/New_York, Europe/Berlin, UTC, …). CALDAV_TIMEZONE overrides it. See Time zones.

CLI and MCP both read this file, so a desktop host does not need the password in its MCP config. A URL that is only a host or principal is resolved through calendar-home-set. add writes into a VEVENT collection, not a reminder collection.


Where it runs

Floor: any MCP client or a terminal. python -m agents_calendar serve is enough. No skills are installed.

Layer

What you get

Who

CLI + MCP

The five tools below, or the same verbs on the CLI

Any MCP host / any shell

Autowire

sync --init merges agents-calendar when the host config directory already exists, and ensures ~/.cursor/mcp.json

Cursor, Claude Desktop, Zed (context_servers), Antigravity / Gemini, Windsurf, Codex, Roo, Cline

MCP without autowire: point the host at python -m agents_calendar serve.


MCP tools

Primary surface. They mirror the CLI. Password never appears in the JSON.

Tool

What it does

calendar_calendars

Collections under the configured URL

calendar_list

VEVENTs between ISO start and end. Returns UTC and local times

calendar_get

Get a single VEVENT by href with UTC and local times

calendar_add

Create. If-None-Match so an existing UID is not overwritten

calendar_update

Replace. href and etag come from calendar_list or calendar_get

calendar_delete

Delete. Same href + etag pair

Six tools. Pass local wall time; the package applies the IANA zone. See Time zones.


Time zones

Offsets come from Python zoneinfo and the IANA time zone database (tzdata is installed with this package). Nothing here hard-codes a region.

The zone for a call is the first one that exists:

  1. The timezone argument / --timezone

  2. CALDAV_TIMEZONE, or timezone in calendar.json

  3. The calendar collection's CalDAV calendar-timezone, when that id is an IANA name

  4. The host zone (TZ, then the OS database)

  5. UTC

A naive value such as 2026-10-22T10:00:00 means 10:00 in that zone on that date. Daylight-saving transitions are per date. 2026-10-22T10:00:00Z or 2026-10-22T10:00:00+02:00 is an absolute instant and is stored as that instant. Do not convert a local wall time to UTC before sending it; a wrong offset stores a different instant.

If the wall time falls in a spring-forward gap, or occurs twice on a fall-back, the call fails and names the zone. Send an explicit offset for the instant you mean. Those ambiguous instants are stored as UTC, because DTSTART;TZID cannot represent both occurrences.

Timed events are written with DTSTART;TZID=… and a VTIMEZONE. The CalDAV server expands RRULE in that zone, so a weekly 10:00 stays 10:00 across the change. All-day events are DTSTART;VALUE=DATE / DTEND;VALUE=DATE. DTEND is exclusive: the same start and end date is one day, and a later end date is already exclusive.

Each event returns dtstart (UTC, or YYYY-MM-DD when all_day), dtstart_local (offset or date), the same pair for the end, timezone (IANA name), and all_day.

An update changes only the fields you pass. RRULE, alarms, attendees, and other properties stay. SEQUENCE increments.


CLI

Machine-readable catalog: python -m agents_calendar --help-json (do not scrape --help).

Command

Purpose

agents-calendar sync --init

Merge MCP. Alias: agents-calendar init

agents-calendar calendars

List collections

agents-calendar list --from <ISO> --to <ISO>

Events in that range with local & UTC times

agents-calendar get --href <href>

Get event details by href

agents-calendar add --summary "…" --dtstart <ISO> --dtend <ISO>

Create. Optional --location, --description, --timezone, --all-day

agents-calendar update --href <href> --etag <etag> …

Replace fields you pass

agents-calendar delete --href <href> --etag <etag>

Delete

agents-calendar serve

stdio MCP. Not the default

No subcommand prints help.


ABI

Contract in abi/:

  • WHY.md — server-side recurrence and etags

  • LAYOUT.md — credential file

  • MCP.md — five tools

  • CLI.md — the same verbs, plus init


Tests

python -m unittest discover tests

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to connect to CalDAV servers to list calendars and events, create, update, and delete calendar events, and manage tasks (VTODOs) including listing, creating, updating, completing, and deleting them.
    614 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to connect to CalDAV servers and manage calendars through natural language, including listing calendars and browsing, creating, updating, and deleting events and tasks (VTODOs). Supports recurring events, all-day events, due-date filtering, status changes, and pagination of long task lists.
    614 npm
    MIT