Skip to main content
Glama
CalDAV MCP Forwarder
by Isaac-To

CalDAV MCP 转发器

一个完全无状态的模型上下文协议服务器,用于从 Cloudflare Workers 将日历操作转发到 CalDAV 服务器。

源代码和部署指南可在 GitHub 仓库 中找到。

状态: 功能完善的首个版本。该 Worker 支持日历发现、事件列表/搜索、事件检索、创建、更新、删除以及空闲/忙碌查询。

三步连接

  1. 在浏览器中打开 https://caldavmcp.anpc.work。

  2. 输入你的 CalDAV 服务器、用户名和应用程序密码,然后点击 测试连接。将 日历 URL 留空可自动发现日历。

  3. 如果需要,选择一个默认日历,创建安全令牌,然后将生成的 MCP URL 或配置复制到你的 AI 助手中。

默认情况下,公共页面会创建无过期时间的加密令牌,实现一次性设置、永久连接。你也可以选择更短的生存期。凭据通过 HTTPS 发送到 Worker 进行加密,且永远不会在浏览器中解码。如果需要撤销令牌,请轮换 CONNECTION_TOKEN_KEY。

助手可以列出、搜索、读取、创建、更新和删除事件,以及查询空闲/忙碌信息。每个请求都是独立的;不会存储任何日历、凭据或会话。

Related MCP server: calendar-mcp

安全模型

不要将原始密码、应用程序密码或访问令牌直接放在 URL 中。URL 可能被浏览器历史、反向代理、分析系统和访问日志保留。

连接令牌是经过 AES-GCM 加密的值:

POST https://caldavmcp.anpc.work/mcp/<encrypted-connection-token>

令牌代表如下连接详情:

{
  "serverUrl": "https://caldav.example.com",
  "calendarUrl": "https://caldav.example.com/calendars/user/work/",
  "username": "user@example.com",
  "password": "app-password",
  "expiresAt": 1797700000
}

Worker 为每个请求解密一个令牌,之后立即丢弃连接详情。令牌不会过期,除非在创建时选择了过期时间;轮换 CONNECTION_TOKEN_KEY 可撤销所有使用旧密钥创建的令牌。事件和空闲/忙碌 URL 必须属于配置的 CalDAV 服务器。将其配置为 Worker 机密。密钥必须是一个 URL 安全的 base64 编码的 128 位、192 位或 256 位 AES 密钥。

建议使用特定于提供商的应用程序密码或 OAuth 访问令牌,而不是主账户密码。切勿将令牌或凭据提交到此仓库。

连接 MCP 客户端

部署 Worker 后,使用 Worker URL 配置你的 MCP 客户端。具体配置因客户端而异,但端点是:

https://caldavmcp.anpc.work/mcp/<encrypted-connection-token>

对于接受远程 HTTP 服务器的 MCP 客户端配置,请使用该端点作为服务器 URL。例如:

{
  "mcpServers": {
    "caldav": {
      "type": "http",
      "url": "https://caldavmcp.anpc.work/mcp/<encrypted-connection-token>"
    }
  }
}

不要将上述示例令牌粘贴到真实客户端中。请将其替换为为目标 CalDAV 账户和日历生成的令牌。

助手将能够调用诸如以下工具:

  • list_calendars

  • list_events

  • search_events

  • get_event

  • create_event

  • update_event

  • delete_event

助手可以处理的示例请求:

  • “我明天的工作日历上有什么?”

  • “下周二十点创建一个牙科预约。”

  • “将我的下午三点会议移到周五。”

  • “取消名为‘项目评审’的活动。”

  • “查找所有提及季度计划会议的 events。”

在调用相应工具之前,助手应确认重要的破坏性操作,尤其是删除事件。

工具输出格式

工具响应使用紧凑的 JSON,仅包含下一步操作所需的信息:

  • 日历列表包含 url,以及可用的 displayName、description、timezone 和 color。

  • 事件列表和 get_event 包含 url、可选的 etag 以及当前的 iCalendar data。

  • create_event 返回创建的事件 url。

  • update_event 返回更新后的事件 url。

  • delete_event 返回已删除的事件 url 和 deleted: true。

  • get_free_busy 仅返回空闲/忙碌的 iCalendar data。

响应不包括 HTTP 状态码、原始 CalDAV 元数据或演示格式。

部署

安装依赖:

npm install

在本机运行 Worker:

npm run dev

对项目进行类型检查:

npm run typecheck

运行单元测试

npm test

运行带覆盖率的测试

npm run coverage

覆盖率阈值设定为语句、行和函数 90%,分支 85%。当前可进行单元测试的源模块在四个类别中均报告 100%。Cloudflare Worker 入口点被排除在外,因为它需要 Workers 运行时和外部 CalDAV 服务;请通过部署或 wrangler dev 冒烟测试进行验证。

部署到 Cloudflare Workers:

npx wrangler login
npm run deploy

该 Worker 配置为 Cloudflare 自定义域 caldavmcp.anpc.work。当该区域在同一个 Cloudflare 账户中处于活跃状态时,Wrangler 将创建域和证书。部署前请设置所需的机密:

npx wrangler secret put CONNECTION_TOKEN_KEY
npm run deploy

该域必须在 Cloudflare DNS 中处于活跃状态。不要为 caldavmcp.anpc.work 添加冲突的 CNAME 记录;自定义域会管理 DNS 记录。

将加密密钥设置为 Cloudflare Worker 机密:

npx wrangler secret put CONNECTION_TOKEN_KEY

对于本地开发,请从 .dev.vars.example 创建 .dev.vars,并将占位符替换为生成的密钥。Wrangler 在运行 npm run dev 时会自动加载 .dev.vars;不要提交该文件。

cp .dev.vars.example .dev.vars
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='

切勿将加密密钥放入 wrangler.jsonc、源代码或客户端配置中。

可用工具

所有工具都作用于令牌中 calendarUrl 所选的日历,或者在适当情况下接受显式的 calendarUrl。

工具

用途

list_calendars

发现账户中的日历。

list_events

列出指定 start/end 范围内的事件。如果没有 calendarUrl,则搜索所有日历。

search_events

按文本搜索事件数据。如果没有 calendarUrl,则搜索所有日历。

get_event

通过对象 URL 获取事件。

create_event

使用摘要、开始时间和结束时间创建事件。

update_event

使用当前 iCalendar 数据和对象 URL 更新事件。

delete_event

删除事件,可选择提供其 ETag。

get_free_busy

查询某个时间段的空闲/忙碌数据。

日期应为 ISO 8601 字符串,例如 2026-08-20T10:00:00Z。事件更新需要当前的 iCalendar data,以便保留未知的特定于提供商的属性。

针对代理的工具行为

  • 当可用日历 URL 未知时,首先调用 list_calendars。

  • list_events 和 search_events 需要 start 和 end。显式的 calendarUrl 选择一个日历。如果没有,则使用令牌配置的日历;如果未配置,则搜索所有日历。

  • search_events 对每个事件的 iCalendar 数据执行不区分大小写的文本搜索,而不仅仅是事件标题。

  • get_event 需要事件当前的 HTTPS 对象 URL。

  • create_event 需要 summary、start 和 end;日历选择顺序为显式 URL、令牌日历,然后是第一个可用日历。

  • update_event 需要当前事件 data;仅发送应更改的字段,因为省略的字段会被保留。

  • delete_event 永久删除事件。请先与用户确认删除,并在可用时传递当前 ETag。

  • get_free_busy 返回请求时间段的 iCalendar 空闲/忙碌数据,不列出事件详情。

无状态请求流程

MCP client
   |
   | POST /mcp/<encrypted-token>
   v
Cloudflare Worker
   | decrypt token in memory
   | create request-scoped CalDAV client
   | perform one operation
   | discard credentials and response data
   v
CalDAV server

此 Worker 不保留任何日历数据或 MCP 会话状态。请求体、凭据和 CalDAV 响应仅在请求期间存在。

提供商说明

不同的 CalDAV 实现有所不同。你可能需要应用程序密码或特定于提供商的端点:

  • Nextcloud: 通常支持应用程序密码和日历集合 URL。

  • Fastmail: 使用应用专用密码和 Fastmail 提供的 CalDAV 端点。

  • iCloud: 通常需要应用专用密码和账户的 CalDAV 端点。

  • Google Calendar: 本机 CalDAV 支持有限;如果 CalDAV 兼容性不足,请改用 Google 的 API。

始终使用目标提供商测试日历发现、重复事件、时区、与会者、ETag 和删除行为。

技术栈

  • Cloudflare Workers

  • TypeScript

  • @modelcontextprotocol/sdk

  • tsdav

  • ical.js

  • zod

限制

该服务转发请求,不会成为日历同步服务。它不维护本地事件索引、不跨日历去重事件,也不将工作排队以备后续执行。如果 CalDAV 提供商不可用,请求将失败,不会从持久存储中重试。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Provider-agnostic CalDAV calendar MCP server that connects any CalDAV calendar to AI assistants, enabling calendar operations like listing, creating, updating, and deleting events.
    21 PyPI
    AGPL 3.0
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for Apple Calendar and CalDAV providers. Enables listing, creating, updating, deleting events, and checking free/busy status with per-calendar write protection.
    6
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    An MCP server that gives AI assistants read/write access to any CalDAV calendar, enabling natural language management of events, attendees, and calendar queries across Nextcloud, Radicale, iCloud, and more.
    6
    MIT