
Keeper.sh
io.github.ridafkih由 GitHub 帳號 ridafkih 發布v1.0.0更新於 Oct 29, 2026
Keeper.sh calendar sync: read and book events, RSVP and find free time across synced calendars.
概覽
Keeper.sh 的 MCP 伺服器經 OAuth 授權後讓助理存取已同步的行事曆:查看活動、建立與修改行程、回覆邀請並尋找空檔。
- 可以做什麼
- 列出已連接的行事曆與帳號,並依行事曆暫停或恢復同步
- 依日期範圍讀取活動、單一活動與活動數量,列出尚未回覆的邀請
- 建立、更新、刪除活動,並以接受、拒絕或暫定回覆邀請
- 跨所有已同步行事曆尋找符合時長的空檔,支援時區與工作時間設定
- 立即觸發同步,並取得 iCal 訂閱網址
- 適用情境
- 適合讓助理直接操作你在 Google、Outlook、iCloud、Fastmail 或 CalDAV 上的真實行事曆:查詢空檔、安排會議、回覆邀請或整理行程,不必切換應用程式。
- 執行需求
- 遠端 MCP 端點,位於 Keeper.sh 主機的 /mcp 路徑;需完成 OAuth 授權,授予行事曆資料的讀寫權限。需要一個已連接行事曆的 Keeper.sh 帳號。自架部署需執行 MCP 元件並設定 MCP_PUBLIC_URL、BETTER_AUTH_URL 與 BETTER_AUTH_SECRET。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Keeper.sh,將其新增到工作區。
- 連接 所需的 憑證。它們會被私密儲存,絕不會在公開頁面上展示。
- 為需要使用其工具的對話啟用該服務。
Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。
交給代理程式安裝
把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。
閱讀 https://sourceweft.com/mcp/io.github.ridafkih%2Fkeeper-sh/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。其他 MCP 客戶端
把它新增到你客戶端的 mcpServers 設定中。 客戶端會在首次連接時完成 OAuth 登入。
{
"mcpServers": {
"keeper-sh": {
"type": "http",
"url": "https://www.keeper.sh/mcp"
}
}
}README
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 remotely hosted iCal and ICS links, and push them to one or many calendars so the time slots can align across them all. Google, Outlook, iCloud, Fastmail, and CalDAV are first-class integrations that can each be used as a source or as a destination, while iCal and ICS links are pull-only. It also serves as a global MCP server and API for you or your agents to manage all your calendars from one convenient interface.
The recommended way to run it is the hosted version at keeper.sh: the same code, minus the server, the domain, the upgrades, the backups and the Google and Microsoft sign-in apps you would otherwise register yourself. Self-hosting is a first-class path and every Pro feature is included when you self-host — that is not a trial, and it is not going away. It costs you the upkeep instead of the $5.
Features
- First-class Google Calendar, Outlook, iCloud, Fastmail, and CalDAV integrations, each usable as a source or a destination
- Pull-only ingestion of remotely hosted iCal and ICS links
- Incremental syncing on Google and Outlook using provider sync tokens rather than refetching everything
- Event content agnostic syncing engine
- Push aggregate events to one or more calendars
- Per-source privacy controls to strip event names, descriptions, and locations, replacing the title with a
{{calendar_name}}or{{event_name}}template - REST API under
/api/v1authenticated with API tokens - MCP (Model Context Protocol) server for AI agent calendar access
- Combined iCal feed you can subscribe to from any calendar app
- 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
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.
Then trust it on your platform:
macOS
Linux
Start the Dev Environment
This starts PostgreSQL, Redis, and a Caddy reverse proxy via Docker Compose, along with the API, web, MCP, cron, and worker services locally. Once running, open https://keeper.localhost.
Architecture
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?
Use one if it already works for you. This one exists because of the two things I kept hitting: events deleted at the source that stayed on the destination forever, and no way to read the code that was handling my calendar.
Both are addressed by design here. A deletion is tracked by a mapping row that outlives the event it pointed at, so the remote copy still gets removed on a later pass, and the cleanup sweep only ever touches events Keeper.sh created — it will not delete an event you made yourself. And the engine is AGPL-3.0, so you can check that claim rather than take it.
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.sh, 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.sh 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.
How is the syncing split up?
There are two halves, and they run on separate schedules.
Ingestion pulls from your sources into Keeper.sh's own database once a minute, regardless of plan. Google and Outlook are fetched incrementally using the provider's own sync token and delta link respectively, so a run only asks for what changed since the last one. CalDAV, iCloud, and Fastmail are refetched and diffed against the event state Keeper.sh already has stored, and iCal/ICS links are refetched and diffed against the last stored snapshot.
Pushing to destinations is what the refresh interval in the pricing table refers to. The cron service enqueues a job per destination onto a Redis-backed queue every minute for Pro and every thirty minutes for free, and the worker service reconciles the destination calendar. This is polling on our side rather than provider push notifications, so nothing needs to reach your instance from the outside.
Neither half is schedule-only. POST /api/v1/sync, or trigger_sync over MCP, clears the ingest backoff so your sources are re-polled on the next pass and enqueues the push half straight away, throttled to one request per minute per user so a client cannot hammer your providers. A calendar paused with pause_sync is skipped by both halves until it is resumed.
Cloud Hosted
This is the version I would point most people at, including people perfectly capable of running it themselves. It is the same engine on hardware I keep running, so the hours go into your calendar instead of your infrastructure — and paying for it is what funds the work on both versions.
Head to keeper.sh to get started with the cloud-hosted version.
The two limits that bite first are counted separately. A linked account is one connected Google, Outlook, iCloud, Fastmail, or CalDAV account, or one iCal/ICS subscription, and free is capped at two of them however many calendars each exposes. A sync mapping is one source calendar wired to one destination calendar, and free is capped at three, so a single source fanning out to three destinations uses the whole allowance. The refresh interval is how often Keeper.sh pushes to your destinations; ingestion from your sources runs every minute on every plan.
Self Hosted
By hosting Keeper.sh yourself, you are on the Pro tier by default — every Pro feature, no subscription — and you can guarantee data governance and autonomy, and it's fun. What it costs instead is a server, a domain, upgrades, backups, your own Google and Microsoft OAuth apps, and being the person paged when it stops. 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 designed for convenience, and five that serve the granular underlying services. If you have no reason to prefer otherwise, start with keeper-standalone behind a reverse proxy — it is the path with the fewest moving parts to get wrong.
[!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
The following environment variables are read by the web server at runtime and serialized into the page as public runtime configuration. All of them are optional.
[!NOTE]
keeper-standaloneauto-configures everything internally — both the web server and Bun API sit behind a single Caddy reverse proxy on port80.keeper-servicesruns the web, API, cron, and worker services inside one container. The web server proxies/apirequests internally, so only port3000needs to be exposed.- For individual images, only the
webcontainer needs to be exposed. The API is accessed internally viaVITE_API_URL.
Images
[!TIP]
Pin your images to a major.minor version tag (e.g.,
2.13) rather thanlatest. This prevents breaking changes from automatically applying when you pull new images.
Prerequisites
Docker & Docker Compose
In order to install Docker Compose, please refer to the official Docker documentation..
Google OAuth Credentials
[!TIP]
This is optional, although you will not be able to set Google Calendar as a destination without this.
Reference the official Google Cloud Platform documentation to generate valid credentials for Google OAuth. You must grant your consent screen the calendar.events, calendar.calendarlist.readonly, and userinfo.email scopes.
Once this is configured, set the client ID and client secret as the GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables at runtime.
Microsoft Azure Credentials
[!TIP]
Once again, this is optional. If you do not configure this, you will not be able to configure Microsoft Outlook as a destination.
The clearest non-legacy walkthrough for configuring OAuth is this community thread.. The required scopes are Calendars.ReadWrite, User.Read, and offline_access. The client ID and secret for Microsoft go into the MICROSOFT_CLIENT_ID and MICROSOFT_CLIENT_SECRET environment variables respectively.
If people will sign in with work or school (Entra ID) accounts, add the xms_edov optional claim to the app registration under Token configuration → Add optional claim → ID → xms_edov. Entra sets it when the tenant has verified the domain of the account's email, and Keeper.sh uses it to record that email as verified. Without it, a work or school sign-in is recorded as unverified and can't be linked automatically to an existing account with the same email; it can still be linked from settings while signed in. Personal Microsoft accounts don't need the claim.
OIDC / SSO
Self-hosters can delegate sign-in to any OIDC-compliant identity provider (Authentik, Keycloak, Pocket ID, Zitadel, ...). Nothing changes until the variables below are set.
Register a confidential client with your provider using this redirect URI:
Then pass the client to the container running the API (keeper-standalone, keeper-services, or keeper-api):
OIDC_ISSUER_URL must match the issuer your provider publishes, including any path, such as https://auth.example.com/realms/keeper for Keycloak or https://authentik.example.com/application/o/keeper/ for Authentik. OIDC_PROVIDER_NAME labels the sign-in button and defaults to SSO. OIDC_SCOPES is a comma-separated list that defaults to openid,profile,email.
Signing in with the provider for the first time creates a new Keeper.sh account. It is never merged into an existing account automatically: if the provider's email address already belongs to a Keeper.sh account, the sign-in is refused instead. To move an existing account to SSO, sign in the usual way and choose Link SSO in settings; from then on either method signs in to the same account.
Once everyone who needs one has linked their account, you can turn off username and password sign-in:
This turns off username and password sign-in and sign-up on the server, not just in the interface. Google and Microsoft sign-in aren't affected: they stay available while GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET or MICROSOFT_CLIENT_ID/MICROSOFT_CLIENT_SECRET are set, which calendar sync with those providers also needs. It only takes effect when the OIDC client is fully configured, so setting it alone can't lock you out.
Standalone Container
keeper-standalone:2 is the recommended starting point for a single-instance deployment. This container contains the cron, worker, web, api services as well as a configured redis, database, and caddy instance that puts everything behind the same port. Split the services out later if you need to scale them independently, run your own Postgres and Redis, or place them on separate hosts.
Generate keeper-standalone Environment Variables
The following will generate a .env file that contains the key used to generate sessions, as well as the key that is used to encrypt CalDAV credentials at rest.
[!IMPORTANT]
If you plan on accessing Keeper.sh from a URL other than http://localhost, you will need to set the
TRUSTED_ORIGINSenvironment variable. This should be a comma-delimited list of protocol-hostname inclusive origins you will be using.Here is an example where we would be accessing Keeper.sh from the LAN IP and where we are routing Keeper.sh through a reverse proxy that hosts it at https://keeper.example.com/
Without this, you will fail CSRF checks on the
better-authpackage.
Run keeper-standalone with Docker
If you'd like to just run using the Docker CLI, you can use the following command. I would however recommend using a compose.yaml file.
Run keeper-standalone with Docker Compose
If you'd prefer to use a compose.yaml file, the following is an example. Remember to populate your .env file first.
Once that's configured, you can launch Keeper.sh using the following command.
With all said and done, you can access Keeper.sh at http://localhost/. You can use a reverse-proxy like Nginx or Caddy to put Keeper.sh behind a domain on your network.
Collective Services Image
If you'd like to bring your own Redis and PostgreSQL, you can use the keeper-services image. This contains the cron, worker, web and api services in one.
Generate keeper-services Environment Variables
Run keeper-services with Docker Compose
Once you've populated your environment variables, you can choose to run redis and postgres alongside the keeper-services image to get up and running.
Once that's configured, you can launch Keeper.sh using the following command.
Individual Service Images
Running each service in its own image gives you the most control over scaling and placement, at the cost of a much longer configuration. Reach for this when keeper-standalone or keeper-services no longer fits, not before.
Generate Individual Service Environment Variables
Configure Individual Service compose.yaml
Once that's configured, you can launch Keeper.sh using the following command.
REST API
Keeper.sh exposes a REST API under /api/v1. It is the same interface the dashboard and the MCP server use, so anything an agent can do through MCP you can do with curl.
Authentication
Create an API token from Settings → API Tokens in the dashboard. Tokens are prefixed with kpr_ and the full value is only returned once, at creation time. Pass it as a bearer token.
/api/v1 routes also accept a logged-in browser session or an MCP OAuth access token, so all three callers hit the same handlers. Token management itself lives at /api/tokens and requires a browser session rather than an API token.
Endpoints
Range parameters from and to are ISO 8601 datetimes. If omitted, from defaults to now and to defaults to a week after from. A range may not exceed 732 days.
On POST and PATCH /api/v1/events, a startTime or endTime without a UTC offset is read in timezone, which is then required; times with Z or an offset are used as given, and all-day events take the calendar date as written.
/api/v1/events/free-time treats events marked free or working-elsewhere as non-blocking and everything else, including all-day events, as busy; pass ignoreAllDayEvents=true to stop all-day events blocking. workingHoursStart and workingHoursEnd are 24-hour local times such as 09:00, and workingDays is a comma-delimited list where 0 is Sunday. All three are read against timezone, so the hours hold across daylight saving transitions.
POST /api/v1/sync clears the ingest backoff on your sources so they are re-polled on the next pass, and enqueues a push to every destination. Exceeding the throttle returns 429 with a Retry-After header rather than queueing a second run.
[!NOTE]
On the free plan the API is capped at 25 requests per day, after which requests return
429. Pro is uncapped, and self-hosted instances running withoutCOMMERCIAL_MODEare treated as Pro.
MCP (Model Context Protocol)
Keeper.sh includes an optional MCP server that lets AI agents (such as Claude) access your calendar data through a standardized protocol. The MCP server authenticates via OAuth 2.1 with a consent flow hosted by the web application.
Available Tools
Connecting an MCP Client
To connect an MCP-compatible client (e.g. Claude Code, Claude Desktop), point it at your MCP server URL. The client will be guided through the OAuth consent flow to authorize read and write access to your calendar data — the toolset can create, update, delete, and RSVP to events, find open time, and pause or force a sync, not just read them.
Example Claude Code MCP configuration:
Self-Hosted MCP Setup
[!NOTE]
MCP is fully optional. All MCP-related environment variables are optional across every service and image. If they are not set, Keeper.sh starts normally without MCP functionality. Existing self-hosted deployments are unaffected.
The MCP server is proxied through the web service at /mcp, the same way the API is proxied at /api.
keeper-standalone bundles the MCP server and serves it at /mcp on the port you already publish, with no extra configuration. It derives MCP_PUBLIC_URL from BETTER_AUTH_URL, so as long as BETTER_AUTH_URL is your instance URL, your MCP client points at that same URL with /mcp appended.
MCP is not bundled in keeper-services or the individual service images. To enable it there:
- Run the
keeper-mcpcontainer withMCP_PORT,MCP_PUBLIC_URL,DATABASE_URL,BETTER_AUTH_SECRET, andBETTER_AUTH_URL. - Set
MCP_PUBLIC_URLon theapiservice to the same value (e.g.https://keeper.example.com/mcp). - Set
VITE_MCP_URLon thewebservice to the internal URL of the MCP container (e.g.http://mcp:3002).
Registry Manifest
server.json at the repository root describes the hosted server for the official MCP Registry. It carries a single streamable-http remote pointing at https://www.keeper.sh/mcp, and takes the sh.keeper namespace, which is authenticated by proving ownership of keeper.sh rather than by a GitHub account.
Publishing is a manual step run with the mcp-publisher CLI and is deliberately not automated: a published version is permanent, so the manifest is reviewed here first and the version it carries can never be reused. Self-hosted instances do not need this file — it describes the hosted instance only.
Because the entry is permanent, publish only after every URL it names resolves in production — websiteUrl, both icons[].src, and the streamable-http remote. A websiteUrl pointing at a page that has not shipped yet is stuck at a 404 until the next version bump.
Modules
Applications
Services
Modules
來源:README.md,提交 1dd8550
工具
0版本歷史
1- v1.0.0最新Oct 29, 2026
評分
已滿足適用檢查項的 85%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通必需25 分
- 已宣告認證方式必需10 分
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分