About pim-mcp
pim-mcp is a local MCP server that combines calendars from Nextcloud, iCloud, Google, and CalDAV services for agents to read and manage. It keeps credentials outside its TOML configuration and uses guardrails and ETag checks to limit risky or conflicting edits.
Key features
- 01Merge calendars into a sorted event view
- 02Search events and inspect full details
- 03Find free time and create events
- 04Update events with instance or series scope
- 05Protect deletion, invitations, and concurrent edits
Use cases
- 01Check events across multiple calendar accounts
- 02Find an available slot before scheduling
- 03Create or update a recurring calendar event
- 04Prevent overwriting changes made elsewhere
MCP support
Runs locally over stdio and exposes calendar tools to MCP clients, which start the process when needed. It connects to Nextcloud, iCloud, Google, and other CalDAV servers.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
Tools
8Saved tool list · updated 4d ago
This tool takes no parameters.
Details
From the project READMEOne thin, local MCP server for all your calendars.
Nextcloud · iCloud · Google · any CalDAV, merged into a single view your agent can read and manage.
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 |
🧳 Portable |
|
🪶 Thin and local |
🛡️ Safe by default |
🧭 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 |
🍎 macOS: login Keychain
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.
🐧 Linux: Secret Service (GNOME Keyring / KWallet)
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"
🪟 Windows: DPAPI
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
☁️ Nextcloud (any Nextcloud / ownCloud server)
- Nextcloud → Settings → Security → Devices & sessions → Create new app password
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"
🍎 iCloud
- account.apple.com → Sign-In and Security → App-Specific Passwords
pim-mcp secret set pim-mcp/icloud
[[accounts]]
id = "icloud"
provider = "icloud"
username = "[email protected]" # the email you sign into your Apple Account with
password = "keychain:pim-mcp/icloud"
📅 Google (one-time OAuth setup)
Google only allows OAuth for CalDAV:
- Google Cloud Console: create a project and enable the CalDAV API.
- 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.
- 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 pim-mcp auth google --account googleopens your browser and stores the refresh token in your OS secret store.
[[accounts]]
id = "google"
provider = "google"
username = "[email protected]"
client_id = "xxxx.apps.googleusercontent.com"
client_secret = "keychain:pim-mcp/google-client-secret"
refresh_token = "keychain:pim-mcp/google"
🌐 Any other CalDAV server
[[accounts]]
id = "fastmail"
provider = "caldav"
url = "https://caldav.fastmail.com/"
username = "[email protected]"
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:
🍎 macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"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.
🪟 Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"pim": { "command": "cmd", "args": ["/c", "npx", "-y", "pim-mcp"] }
}
}
npx is a batch script on Windows, so it runs through cmd /c.
🐧 Linux
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. |
| 🕐 | find_free_time | Free windows of at least N minutes, optionally within working hours. |
| ➕ | create_event | Timed or all-day, with recurrence, a reminder, 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. |
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 | ✅ tested | nextcloud · https://<host>/remote.php/dav |
| iCloud | ✅ tested | icloud · app-specific password |
| Google Calendar | 🧪 beta | google · OAuth. Not yet tried with a real account; reports welcome |
| Fastmail | 🟡 untested | caldav · https://caldav.fastmail.com/ |
| Yahoo | 🟡 untested | caldav · https://caldav.calendar.yahoo.com |
| mailbox.org | 🟡 untested | caldav · https://dav.mailbox.org/ |
| Posteo | 🟡 untested | caldav · https://posteo.de:8443/ |
| Radicale · Baïkal · SOGo · Synology | 🟡 untested | caldav · your server's DAV URL |
| Outlook · Microsoft 365 · Exchange | 🚧 wanted | no CalDAV; needs a Microsoft Graph backend |
| Proton Calendar | ❌ 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.
MIT © Aleksey Tkachenko · built for agents, readable by humans
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.