# Keeper.sh

Calendar sync across Google, Outlook, iCloud, Fastmail and CalDAV, with an MCP server and REST API from the Builder.

Keeper.sh pulls events from any connected calendar and pushes them to one or many destinations so busy slots line up, with per-source privacy templates and a combined iCal feed. It ships an MCP server (OAuth 2.1) and a /api/v1 REST API that share handlers with the dashboard: list calendars, read and create events, RSVP, find free time, trigger or pause sync. Self-hosting unlocks Pro features; the hosted edition has a free plan and a USD 5 Pro plan.

Alternative to: OneCal, CalendarBridge

- Capabilities: adaptable, operable
- Vertical: scheduling-staffing
- Shape: product
- Form factor: web-app
- Execution model: deterministic
- Provenance: unknown (recorded, never ranked)
- Repo: https://github.com/ridafkih/keeper.sh (AGPL-3.0), 1272 stars, last commit 2026-09-02
- Last activity: 2026-09-02
- Page: apps/ridafkih--keeper.sh.html
- JSON: apps/ridafkih--keeper.sh.json

## Use it when

- I juggle a work calendar, a business calendar and a personal one and keep getting double-booked
- I want my agent to see one true picture of my availability and book into it through MCP

## Gotchas

- AGPL-3.0 copyleft
- Self-hosting means registering your own Google and Microsoft OAuth apps; Google calendar scopes need app verification for non-test users
- Cloud Free: 2 linked accounts, 3 sync mappings, 30-minute refresh and 25 API requests per day
- The Bun rewrite changed environment variable names; migration notes are in issue #140
- Missing TRUSTED_ORIGINS fails CSRF checks for any origin other than http://localhost

## Editions

- Self-hosted: Free, open source
  - source: https://github.com/ridafkih/keeper.sh
  - container: docker run -d -p 80:80 -v keeper-data:/var/lib/postgresql/data --env-file .env ghcr.io/ridafkih/keeper-standalone:2
- Cloud Free: $0 per month, closed source
  - hosted: https://www.keeper.sh/register
- Cloud Pro: $5 per month, closed source
  - hosted: https://www.keeper.sh/

## Adaptable: make it yours

Effort: config-only (19 things to edit)

For the standalone image, generate BETTER_AUTH_SECRET and ENCRYPTION_KEY, set TRUSTED_ORIGINS to every origin you will use, and add GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET and MICROSOFT_CLIENT_ID/MICROSOFT_CLIENT_SECRET from your own OAuth apps. Split deployments add DATABASE_URL, REDIS_URL, BETTER_AUTH_URL, MCP_PUBLIC_URL and MCP_PORT; WEBHOOK_PUBLIC_URL turns on realtime push; RESEND_API_KEY enables email. Sources, destinations and privacy templates are configured in the dashboard.

- Env vars: BETTER_AUTH_SECRET, ENCRYPTION_KEY, TRUSTED_ORIGINS, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET, DATABASE_URL, REDIS_URL, BETTER_AUTH_URL, MCP_PUBLIC_URL, MCP_PORT, WEBHOOK_PUBLIC_URL, RESEND_API_KEY, COMMERCIAL_MODE, WORKER_JOB_QUEUE_ENABLED, BLOCK_PRIVATE_RESOLUTION
- Config files: .env, compose.yaml
- Prompt files: none
- Accounts you'll need: Google Cloud (OAuth app, optional); Microsoft Entra (OAuth app, optional); Keeper.sh (hosted editions only)

## Operable: what an agent can drive

Operability: official. Interface: mcp at https://github.com/ridafkih/keeper.sh#mcp-model-context-protocol (published by the builder, both).

### Reach (partial coverage)

- List connected accounts and calendars: reachable. services/mcp/src/toolset.ts: list_accounts, list_calendars
- Read events and counts in a date range: reachable. toolset.ts: get_events, get_event, get_event_count
- Create, update and delete events: reachable. toolset.ts: create_event, update_event, delete_event
- Respond to invitations: reachable. toolset.ts: rsvp_event, get_pending_invites
- Find free time with working hours: reachable. toolset.ts: find_free_time; REST GET /api/v1/events/free-time
- Trigger or pause sync: reachable. toolset.ts: trigger_sync, pause_sync; throttled to one run per minute
- Get the combined iCal feed URL: reachable. toolset.ts: get_ical_feed
- Connect a new Google or Outlook account: not reachable. OAuth consent runs in the web dashboard; token management at /api/tokens needs a browser session
- Create or edit sync mappings and privacy templates: not reachable. no mapping tool in toolset.ts or the /api/v1 route table
- Configure event filters: not reachable. Pro feature set in the dashboard; not in the tool list

## Code stack

- Languages: TypeScript
- Frameworks: Bun, Vite SSR, BullMQ, better-auth, Caddy
- Package manager: bun
- Database: PostgreSQL, Redis
- Hosting target: docker

## Model stack

- Providers: any MCP client
- Models: none
- Keys you need (names only): none
- Prompts live in: none
- Tools: list_calendars, list_accounts, get_events, get_event, get_event_count, create_event, update_event, delete_event, rsvp_event, get_pending_invites, find_free_time, trigger_sync, pause_sync, get_ical_feed

## Evidence and confidence

- formFactor: README: web dashboard plus API, MCP, cron and worker services in Docker images (confidence 0.95)
- executionModel: no model at runtime; MCP exposes data to external agents (confidence 0.95)
- operability: services/mcp in the Builder's repo; README says /api/v1 is the same interface the dashboard and MCP use (confidence 0.9)
- effort: README environment variable table and compose examples (confidence 0.95)
- editions: README pricing table: Free USD 0, Pro USD 5 per month or USD 45 per year, self-hosted Pro at USD 0 (confidence 0.95)
- active: shortlist pushedAt 2026-09-02
- reach:  (confidence 0.9)

## Open questions

- Triage called this native; recorded as official because the dashboard remains the primary interface and MCP is one of three callers. Curator to decide
- Is the hosted MCP endpoint available on the Cloud Free plan within the 25 requests per day cap?

## Sources

- https://github.com/ridafkih/keeper.sh (sourcing:scheduling-staffing:curated)
- https://www.keeper.sh/ (sourcing:scheduling-staffing:curated)
- https://github.com/ridafkih/keeper.sh/blob/main/services/mcp/src/toolset.ts (analysis:scheduling-staffing)
