keeper.sh
Calendar sync tool & universal calendar MCP server. Aggregate, sync and control calendars on Google, Outlook, Office 365, iCloud, CalDAV or ICS.
Install / Use
claude mcp add ridafkih -- npx -y github:ridafkih/keeper.shIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Development & EngineeringSupported Platforms
Skill content
View source on GitHub
About
Keeper.sh is a simple & open-source calendar syncing tool. It allows you to pull events from your Google Calendar, Outlook, iCloud, Fastmail, CalDAV server, or a remotely hosted iCal or ICS links, and push them to one or many calendars so the time slots can align across them all. It also serves as a global MCP server and API for you or your agents to manage all your calendars from one convenient interface. You can use the hosted version for convenience and zero-setup, or self-host to get Pro features free.
Features
- Aggregating calendar events from remote sources
- Event content agnostic syncing engine
- Push aggregate events to one or more calendars
- MCP (Model Context Protocol) server for AI agent calendar access
- Open source under AGPL-3.0
- Easy to self-host
- Easy-to-purge remote events
Bug Reports & Feature Requests
If you encounter a bug or have an idea for a feature, you may open an issue on GitHub and it will be triaged and addressed as soon as possible.
Contributing
High-value and high-quality contributions are appreciated. Before working on large features you intend to see merged, please open an issue first to discuss beforehand.
Local Development
The dev environment runs behind HTTPS at https://keeper.localhost using a Caddy reverse proxy with automatic TLS. The .localhost TLD resolves to 127.0.0.1 automatically per RFC 6761 — no /etc/hosts entry is needed.
Prerequisites
Getting Started
bun install
Generate and Trust a Root CA
The dev environment runs behind HTTPS via Caddy. You need to generate a local root certificate authority and trust it so your browser accepts the certificate.
mkdir -p .pki
openssl req -x509 -new -nodes \
-newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-keyout .pki/root.key -out .pki/root.crt \
-days 3650 -subj "/CN=Keeper.sh CA"
Then trust it on your platform:
macOS
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain .pki/root.crt
Linux
sudo cp .pki/root.crt /usr/local/share/ca-certificates/keeper-dev-root.crt
sudo update-ca-certificates
Start the Dev Environment
bun dev
This starts PostgreSQL, Redis, and a Caddy reverse proxy via Docker Compose, along with the API, web, MCP, and cron services locally. Once running, open https://keeper.localhost.
Architecture
| Service | Local Port | Accessed Via |
| -------- | ---------- | ------------------------------------ |
| Caddy | 443 | https://keeper.localhost |
| Web | 5173 | Proxied by Caddy |
| API | 3000 | Proxied by Web at /api |
| MCP | 3001 | Proxied by Web at /mcp |
| Postgres | 5432 | postgresql://postgres:postgres@localhost:5432/postgres |
| Redis | 6379 | redis://localhost:6379 |
Qs
Why does this exist?
Because I needed it. Ever since starting Sedna—the AI governance platform—I've had to work across three calendars. One for my business, one for work, and one for personal.
Meetings have landed on top of one-another a frustratingly high number of times.
Why not use this other service?
I've probably tried it. It was probably too finicky, ended up making me waste hours of my time having to delete stale events it didn't seem to want to track anymore, or just didn't sync reliably.
How does the syncing engine work?
- If we have a local event but no corresponding "source → destination" mapping for an event, we push the event to the destination calendar.
- If we have a mapping for an event, but the source ID is not present on the source any longer, we delete the event from the destination.
- Any events with markers of having been created by Keeper, but with no corresponding local tracking, we remove it. This is only done for backwards compatibility.
Events are flagged as having been created by Keeper either using a @keeper.sh suffix on the remote UID, or in the case of a platform like Outlook that doesn't support custom UIDs, we just put it in a "keeper.sh" category.
Cloud Hosted
I've made Keeper easy to self-host, but whether you simply want to support the project or don't want to deal with the hassle or overhead of configuring and running your own infrastructure cloud hosting is always an option.
Head to keeper.sh to get started with the cloud-hosted version. Use code README for 25% off.
| | Free | Pro (Cloud-Hosted) | Pro (Self-Hosted) | | --------------------- | ---------- | ------------------ | ----------------- | | Monthly Price | $0 USD | $5 USD | $0 | | Annual Price | $0 USD | $42 USD (-30%) | $0 | | Refresh Interval | 30 minutes | 1 minute | 1 minute | | Source Limit | 2 | ∞ | ∞ | | Destination Limit | 1 | ∞ | ∞ |
Self Hosted
By hosting Keeper.sh yourself, you get all premium features for free, can guarantee data governance and autonomy, and it's fun. If you'll be self-hosting, please consider supporting me and development of the project by sponsoring me on GitHub.
There are seven images currently available, two of them are designed for convenience, while the five are designed to serve the granular underlying services.
[!NOTE]
Migrating from a previous version? If you are upgrading from the older Next.js-based release, see the migration guide for environment variable changes. The new web server will also print a migration notice at startup if it detects old environment variables.
Environment Variables
| Name | Service(s) | Description |
| ------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DATABASE_URL | api, cron, worker, mcp | PostgreSQL connection URL.<br><br>e.g. postgres://user:pass@postgres:5432/keeper |
| REDIS_URL | api, cron, worker | Redis connection URL. Must be the same Redis instance across all services.<br><br>e.g. redis://redis:6379 |
| WORKER_JOB_QUEUE_ENABLED | cron | Required. Set to true to enqueue sync jobs to the worker queue, or false to disable. If unset, the cron service will exit with a migration notice. |
| BETTER_AUTH_URL | api, mcp | The base URL used for auth redirects.<br><br>e.g. http://localhost:3000 |
| BETTER_AUTH_SECRET | api, mcp | Secret key for session signing.<br><br>e.g. openssl rand -base64 32 |
| API_PORT | api | Port the Bun API listens on. Defaults to 3001 in container images. |
| ENV | web | Optional. Runtime environment. One of development, production, or test. Defaults to production. |
| PORT | web | Port the web server listens on. Defaults to 3000 in container images. |
| VITE_API_URL | web | The URL the web server uses to proxy requests to the Bun API.<br><br>e.g. http://api:3001 |
| COMMERCIAL_MODE | api, cron | Enable Polar billing flow. Set to true if using Polar for subscriptions. |
| POLAR_ACCESS_TOKEN | api, cron | Optional. Polar API token for subscription management. |
| POLAR_MODE | api, cron | Optional. Polar environment, sandbox or production. |
| POLAR_WEBHOOK_SECRET | api | Optional. Secret to verify Polar webhooks. |
| ENCRYPTION_KEY | api, cron, worker | Key for encrypting CalDAV credentials at rest.<br><br>e.g. openssl rand -base64 32 |
| RESEND_API_KEY | api | Optional. API key for sending emails via Resend. |
| PASSKEY_RP_ID | api | Optional. Relying party ID for passkey authentication. |
| PASSKEY_RP_NAME | api | Optional. Relying party display name for passkeys. |
| PASSKEY_ORIGIN | api | Optional. Origin allowed for passkey flows (e.g., https://keeper.example.com). |
| GOOGLE_CLIENT_ID | api, cron, worker | Optional. Required for Google Calendar integration. |
| GOOGLE_CLIENT_SECRET | api, cron, worker | Optional. Required for Google Calendar integration. |
| MICROSOFT_CLIENT_ID | api, cron, worker | Optional. Required for Microsoft Outlook integration. |
| MICROSOFT_CLIENT_SECRET | api, cron, worker | Optional. Required for Microsoft Outlook integration. |
| POSTGRES_PASSWORD | standalone | Optional. Custom password for the internal PostgreSQL database in keeper-standalone. If unset, defaults to keeper. The database is not exposed outside the container, so this is low risk, but can be set for defense in depth. |
| BLOCK_PRIVATE_RESOLUTION | api, cron | Optional. Set to true to block outbound fetches (ICS subscriptions, CalDAV servers) from resolving to private/reserved network addresses. Prevents SSRF. Defaults to false for backward compatibility
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
84.4kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
73.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ruflo
73.0k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
career-ops
72.4kOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)
