Skip to main content
Glama

One thin, local MCP server for all your calendars. Nextcloud · iCloud · Google · any CalDAV, merged into a single view your agent can read and manage.

npm CI MCP Registry Node Platforms License: MIT

Quick start · Accounts · Connect · Tools · Guardrails · Providers · Contributing

 you   › Find me an hour on Thursday afternoon and put the dentist there.

 agent › find_free_time  start=Thu 12:00  end=Thu 18:00  duration_minutes=60
         ↳ 13:00–15:30 · 16:15–18:00
       › create_event    calendar="icloud/personal"  title="Dentist"  start=Thu 13:00
         ↳ ✓ created  Thu 13:00–14:00  · icloud/personal

         Done. Thursday 13:00 is booked; you're free again from 14:00.

✨ Why

🗂️ One merged view Every calendar on every account in one sorted list, with recurring events expanded. No more "which account was that in?"

🧳 Portable One TOML file with no secrets in it. Secrets are references to your OS secret store, env vars or a password manager, so the same config works on every machine.

🪶 Thin and local Your agent client starts it over stdio when needed. Nothing runs in the background, there's no port open, and no cloud sits in between.

🛡️ Safe by default Deleting events and anything that emails other people stay off until you allow them. Edits never overwrite changes made elsewhere.

Related MCP server: caldav-mcp

🧭 How it works

flowchart LR
    A["🤖 Agent<br><sub>Claude Code · Claude Desktop · Cursor</sub>"] -- "MCP · stdio" --> P["<b>pim-mcp</b><br><sub>on your machine</sub>"]
    S[("🔐 OS secret store<br><sub>Keychain · Secret Service · DPAPI</sub>")] -. "app passwords / tokens" .-> P
    P -- CalDAV --> N["☁️ Nextcloud"]
    P -- CalDAV --> I["🍎 iCloud"]
    P -- "CalDAV + OAuth" --> G["📅 Google"]
    P -- CalDAV --> O["🌐 any CalDAV"]

🚀 Quick start

Requires Node.js 22+.

npm install -g pim-mcp                         # 1 · install (or prefix commands with `npx -y`)
pim-mcp init                                   # 2 · write ~/.config/pim-mcp/config.toml
pim-mcp secret set pim-mcp/icloud              # 3 · store an app password (prompted, not echoed)
pim-mcp check                                  # 4 · verify every account
claude mcp add pim -s user -- npx -y pim-mcp   # 5 · connect your agent

pim-mcp check lists what it found:

✓ nextcloud (nextcloud) — 3 calendar(s)
    nextcloud/personal               Personal
    nextcloud/work                   Work
✓ icloud (icloud) — 2 calendar(s)
    icloud/family                    Family
    icloud/travel                    Travel

The config lives at ~/.config/pim-mcp/config.toml on every OS (C:\Users\<you>\.config\pim-mcp\config.toml on Windows). Set PIM_MCP_CONFIG to use another path.

🔐 Secrets

Passwords and tokens never go in the config. It holds a reference instead:

Reference

Resolves to

keychain:service/account

your OS secret store. Easiest: pim-mcp secret set service/account

env:NAME

an environment variable

cmd:<command>

a command's output, e.g. cmd:op read op://Private/iCloud/password, cmd:pass show icloud, cmd:bw get password icloud

Stored as generic passwords in your login Keychain. You can also manage them in Keychain Access, or with security add-generic-password -s pim-mcp -a icloud -w.

Needs secret-tool:

sudo apt install libsecret-tools     # Debian / Ubuntu
sudo dnf install libsecret           # Fedora
sudo pacman -S libsecret             # Arch

On a headless machine there's usually no keyring running. Use env: refs (set them in your MCP client's env block) or pass:

password = "cmd:pass show pim-mcp/icloud"

Secrets are encrypted with DPAPI, the per-user encryption Credential Manager also uses. They're stored under %APPDATA%\pim-mcp\secrets\, and only your Windows user on this machine can decrypt them. Nothing to install. cmd: refs run in cmd.exe.

👤 Accounts

  1. Nextcloud → Settings → Security → Devices & sessions → Create new app password

  2. pim-mcp secret set pim-mcp/nextcloud

[[accounts]]
id = "nextcloud"
provider = "nextcloud"
url = "https://your.next.cloud/remote.php/dav"
username = "your-login"
password = "keychain:pim-mcp/nextcloud"
  1. account.apple.com → Sign-In and Security → App-Specific Passwords

  2. pim-mcp secret set pim-mcp/icloud

[[accounts]]
id = "icloud"
provider = "icloud"
username = "you@icloud.com"   # the email you sign into your Apple Account with
password = "keychain:pim-mcp/icloud"

Google only allows OAuth for CalDAV:

  1. Google Cloud Console: create a project and enable the CalDAV API.

  2. OAuth consent screen: choose External and add yourself as a test user. Then set the publishing status to In production, because tokens issued in "Testing" mode expire after 7 days. An "unverified app" warning at sign-in is expected for a personal app.

  3. Credentials → Create OAuth client ID → Desktop app. Put the client ID in the config and store the secret: pim-mcp secret set pim-mcp/google-client-secret

  4. pim-mcp auth google --account google opens your browser and stores the refresh token in your OS secret store.

[[accounts]]
id = "google"
provider = "google"
username = "you@gmail.com"
client_id = "xxxx.apps.googleusercontent.com"
client_secret = "keychain:pim-mcp/google-client-secret"
refresh_token = "keychain:pim-mcp/google"
[[accounts]]
id = "fastmail"
provider = "caldav"
url = "https://caldav.fastmail.com/"
username = "you@fastmail.com"
password = "keychain:pim-mcp/fastmail"

Known URLs are in Providers.

🔌 Connect your agent

Claude Code (any OS)

claude mcp add pim -s user -- npx -y pim-mcp

Claude Desktop, Cursor and other GUI clients. Add this to the client's MCP config:

{
  "mcpServers": {
    "pim": { "command": "npx", "args": ["-y", "pim-mcp"] }
  }
}

GUI apps don't always see your shell's PATH. If the server fails to start, replace npx with the full path from which npx, e.g. /opt/homebrew/bin/npx.

{
  "mcpServers": {
    "pim": { "command": "cmd", "args": ["/c", "npx", "-y", "pim-mcp"] }
  }
}

npx is a batch script on Windows, so it runs through cmd /c.

Claude Desktop isn't available for Linux; use Claude Code or another MCP client with the same command / args as macOS. env: refs go in the client's env block:

"pim": {
  "command": "npx",
  "args": ["-y", "pim-mcp"],
  "env": { "ICLOUD_PASSWORD": "…" }
}

🧰 Tools

Tool

What it does

📚

list_calendars

All calendars and their ids (icloud/work). Anywhere a tool takes a calendar, a plain name works too.

🗓️

list_events

Events from all calendars in a range, merged and sorted. Defaults to today through the next 7 days.

🔎

search_events

Text search over title, location and description.

📄

get_event

Full details: description, attendees, organizer, recurrence rule, reminders.

🕐

find_free_time

Free windows of at least N minutes, optionally within working hours.

➕

create_event

Timed or all-day, with recurrence, up to 3 reminders, and busy/free status.

✏️

update_event

Changes only the fields you pass. Recurring events take scope: instance or series.

🗑️

delete_event

Off unless allow_delete = true. Takes the event's title, so approval prompts show its name, and refuses a title that doesn't match the event.

What agents see:

  • Times without an offset are in your configured timezone.

  • Output is ISO 8601 with offsets.

  • All-day events use YYYY-MM-DD, and their end date is inclusive.

🛡️ Guardrails

timezone = "Europe/Amsterdam"            # default: the system timezone

[guardrails]
allow_delete  = false                    # delete_event is refused
allow_invites = false                    # no adding attendees, no editing/deleting events that have them

[[accounts]]
# …
read_only           = true               # no writes to this account at all
read_only_calendars = ["Family"]         # protect specific calendars
hide_calendars      = ["Birthdays"]      # don't show these at all
  • Refusals explain themselves. When a guardrail blocks something, the agent is told which setting would allow it, so it asks you instead of retrying.

  • No lost edits. Every write checks the event's ETag. If the event changed elsewhere since it was read, the write fails instead of overwriting.

🌍 Providers

Provider

Status

Setup

Nextcloud / ownCloud

✅&nbsp;tested

nextcloud · https://<host>/remote.php/dav

iCloud

✅&nbsp;tested

icloud · app-specific password

Google Calendar

🧪&nbsp;beta

google · OAuth. Not yet tried with a real account; reports welcome

Fastmail

🟡&nbsp;untested

caldav · https://caldav.fastmail.com/

Yahoo

🟡&nbsp;untested

caldav · https://caldav.calendar.yahoo.com

mailbox.org

🟡&nbsp;untested

caldav · https://dav.mailbox.org/

Posteo

🟡&nbsp;untested

caldav · https://posteo.de:8443/

Radicale · Baïkal · SOGo · Synology

🟡&nbsp;untested

caldav · your server's DAV URL

Outlook · Microsoft 365 · Exchange

🚧&nbsp;wanted

no CalDAV; needs a Microsoft Graph backend

Proton Calendar

❌&nbsp;n/a

no CalDAV or public API

🟡 untested means standard CalDAV that should just work but hasn't been confirmed with pim-mcp yet. Tried one? A PR updating this table is very welcome.

🗺️ Roadmap

  • Calendars over CalDAV: Nextcloud, iCloud, Google, generic

  • macOS · Linux · Windows secret stores

  • Outlook / Microsoft 365 via Microsoft Graph

  • Mail: IMAP / SMTP, same accounts and config

  • Files: WebDAV (Nextcloud, …)

🤝 Contributing

New providers, bug fixes and "it works with X" confirmations are all welcome. See CONTRIBUTING.md for dev setup, a throwaway local CalDAV server for testing, and how to add a provider.

Available Tools

8 tools
create_eventA

Create an event. start as a date makes an all-day event. Without end, timed events last 1 hour and all-day events 1 day.

Inputs: start (required), title (required), calendar (required), end, +6 more.

delete_eventA
Destructive

Delete an event. For recurring events pass scope ("instance" removes one occurrence, "series" removes all).

Inputs: id (required), scope.

find_free_timeA
Read-only

Free time windows of at least duration_minutes across all (or selected) calendars. Events marked free/transparent and cancelled events do not block time.

Inputs: end (required), start (required), duration_minutes (required), accounts, +2 more.

get_eventB
Read-only

Full details of one event (description, attendees, organizer, recurrence rule).

Inputs: id (required).

list_calendarsA
Read-only

List every calendar across all configured accounts (Nextcloud, iCloud, Google, …), with ids usable in other tools.

Inputs: no named parameters.

list_eventsA
Read-only

Events in a time range, merged across all calendars and sorted by start. Recurring events are expanded into occurrences. Defaults to today through the next 7 days.

Inputs: end, start, accounts, calendars.

search_eventsA
Read-only

Find events whose title, location or description contains the query (case-insensitive). Defaults to 90 days back through 365 days ahead.

Inputs: query (required), end, start, calendars.

update_eventA

Change an event. Only the fields you pass change; moving start alone keeps the duration. For recurring events pass scope.

Inputs: id (required), end, busy, rrule, +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool maps to a distinct retrieval or mutation strategy: list_events filters by time range, search_events filters by text query, and get_event fetches a single event by id. find_free_time and the create/update/delete trio are unmistakable. No two tools overlap in a way that would cause misselection.

    Naming Consistency5/5

    All eight tools follow the same snake_case verb_noun pattern (list_, search_, get_, find_, create_, update_, delete_). The verb choice matches the operation type consistently, and the resource noun is always the trailing token.

    Tool Count5/5

    Eight tools is well within the healthy 3-15 range and every tool earns its place: discovery, three read modes, availability lookup, and full mutation coverage. Nothing feels padded or redundant.

    Completeness4/5

    Event lifecycle is fully covered (list/search/get/create/update/delete) with sensible recurrence scope and availability handling. Minor gaps remain around attendee interactions — no RSVP/accept-decline tool and calendars themselves can only be listed, not created or modified.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI assistants to connect to calendar servers and manage events and tasks, including listing calendars, querying timeframes, creating, updating, completing, and deleting items through tools.
      732 npm
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI assistants to connect to CalDAV servers and manage calendars, events, and tasks through tools for listing, creating, updating, completing, and deleting items.
      732 npm
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Connects 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 npm
      MIT