关于 Google Calendar MCP Server (Python)
Google Calendar MCP Server 是一个基于 Python 的 MCP 服务,让 LLM 客户端可以读写 Google Calendar 并通过自然语言完成日程操作。它提供 23 个工具,并内置了解工作时间的日程规划功能。认证采用 Google OAuth 2.0 桌面应用流程,令牌本地缓存并自动刷新。
主要功能
- 0123 个带结构化输出的日历读写工具
- 02多账号登录,可按调用指定账号
- 03空闲时段查找与专注时间预订
- 04跨多个账号的重复预订冲突检测
- 05按工作时间与指标统计的时间审计
- 06HTTP 传输模式,默认无认证层
适用场景
- 01让 LLM 查询日程并创建或修改事件
- 02为深度工作预留一段专注时间
- 03检查工作与个人日历之间是否存在重复预订
- 04统计一段时间内会议占用的时长
MCP 相关
该项目是一个 MCP 服务,向 MCP 客户端暴露日历与日程规划相关工具,支持 stdio 和 streamable HTTP 两种传输方式。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx calendar-mcp-serverGOOGLE_CLIENT_IDOAuth 2.0 client ID for a Google Cloud project with the Google Calendar API enabled.GOOGLE_CLIENT_SECRET密钥OAuth 2.0 client secret matching GOOGLE_CLIENT_ID.TOKEN_FILE_PATH密钥Path to the saved OAuth token file written by 'calendar-mcp auth'.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
15收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| min_access_role | any | 否 |
详细介绍
calendar-mcp
一个 MCP 服务,让大模型客户端可以读写你的 Google Calendar。它以单个进程运行——默认使用 stdio,可选 streamable HTTP——并暴露 23 个带结构化输出的工具:列出和搜索日历与事件,创建、更新、移动、回复邀请(RSVP)和删除事件,空闲/忙碌查询,忙碌度分析,重复事件投影,以及查找共同空闲时段并预订。除此之外,它还有一个了解你工作时间的日程安排大脑:查找并预订专注时间,一次性检测多个账号之间的双重预订,为会议提议更好的时间,并审计你的一周实际花在了哪里。身份验证使用 Google OAuth 2.0(桌面应用流程);令牌会按账号缓存在本地,并自动刷新。
一个日历任务,端到端
合成示例,由离线测试支持;没有真实日历数据或实时预订。 假设周四的工作时间为 09:00–17:00 UTC,11:00–12:00 有一个会议, 没有午餐或缓冲时间,最短专注块为 60 分钟。
“在 2026 年 1 月 1 日找出六小时的专注时间。先给我看这些时间块。”
MCP 客户端可以调用:
{
"tool": "block_focus_time",
"arguments": {
"time_min": "2026-01-01T00:00:00Z",
"time_max": "2026-01-02T00:00:00Z",
"hours_needed": 6,
"dry_run": true
}
}
预览会选择 09:00–10:00 和 12:00–17:00:共六小时,最后一个
选中的时间块被裁剪到剩余的一小时。两个事件都有 created: false。
在用户批准这些时间后,客户端可以用 dry_run: false 调用;
在创建事件之前会再次读取可用性。预览不会预留时段。
设计决策:未知可用性不等于空闲时间。 如果被检查的日历
返回访问错误、从响应中消失,或有无法读取的忙碌区间,
专注时间搜索和预订会在写入任何内容之前返回错误。
同样的检查也保护共同日程安排和重新安排建议/应用。
例如,对 [email protected] 的 notFound 响应会变成:
Availability is unknown: [email protected]: notFound. No scheduling changes were made.
Restore calendar access or retry the query.
无需 Google 凭据即可复现预览和安全回归 (在开发安装之后):
pytest -q tests/test_scheduling.py -k 'focus_time_dry_run or focus_refuses_unknown'
该回归测试验证:在预览和预订两种模式下,部分、缺失和出错的
可用性都绝不会调用 create_event。成功的空忙碌列表仍然
意味着真正的空闲时间。可用性检查和写入是分开的 Google API 调用,
因此另一个客户端仍可能在这两者之间预订一个冲突事件。
快速开始
1. 创建 Google OAuth 凭据。 在 Google Cloud 控制台中,启用 Google Calendar API,然后创建一个类型为 桌面应用 的 OAuth 客户端 ID。复制客户端 ID 和密钥。(详情见 Google Cloud 设置。)
2. 将它们设置到你的环境中,或设置到你运行所在目录的 .env 文件中(见 example.env):
GOOGLE_CLIENT_ID='...'
GOOGLE_CLIENT_SECRET='...'
3. 登录一次,然后把该服务添加到你的客户端:
uvx calendar-mcp-server auth
这会打开浏览器并在配置目录中保存一个令牌(见账号);如果你已有 .gcp-saved-tokens.json 或设置了 TOKEN_FILE_PATH,则改用该文件。用 calendar-mcp check 验证。用 calendar-mcp auth --account work 添加更多 Google 账号。之后该服务以非交互方式运行——除非你设置 CALENDAR_MCP_ALLOW_BROWSER_AUTH=1,否则它绝不会自行打开浏览器。
PyPI 发行包是
calendar-mcp-server。它会安装两个相同的控制台脚本,calendar-mcp和calendar-mcp-server,因此uvx calendar-mcp-server和本地的calendar-mcp是同一个命令。
客户端配置
Claude Code
claude mcp add calendar \
--env GOOGLE_CLIENT_ID=... \
--env GOOGLE_CLIENT_SECRET=... \
-- uvx calendar-mcp-server
Claude Desktop —— claude_desktop_config.json:
{
"mcpServers": {
"calendar": {
"command": "uvx",
"args": ["calendar-mcp-server"],
"env": {
"GOOGLE_CLIENT_ID": "...",
"GOOGLE_CLIENT_SECRET": "...",
"TOKEN_FILE_PATH": "/absolute/path/to/.gcp-saved-tokens.json"
}
}
}
}
Cursor —— .cursor/mcp.json(项目)或 ~/.cursor/mcp.json(全局):与上面相同的 mcpServers 块。
任何其他客户端,只要它使用标准的 mcpServers JSON,都采用相同的条目。TOKEN_FILE_PATH 现在是可选的,因为令牌默认存放在操作系统配置目录中,这不依赖于客户端选择的工作目录——但如果你确实设置了它,请使用绝对路径。
远程 / HTTP 模式
calendar-mcp --transport http --host 127.0.0.1 --port 8000
此时 MCP 端点为 http://127.0.0.1:8000/mcp(用 --path 修改路径)。
HTTP 传输上目前还没有认证层。 任何能访问该端点的人都能完全访问已保存令牌所属的日历。请将其绑定到回环地址,或仅将其暴露在会进行认证的可信反向代理之后,或私有网络(如 tailnet)中。不要将其放在公网接口上。
工具
只读工具永远不会更改任何内容。“写入”工具会创建或修改事件;
delete_event 是唯一会销毁数据的工具。
日历与事件
| 工具 | 描述 | |
|---|---|---|
list_calendars | 读取 | 列出用户可见的日历,包含 ID 和时区。 |
find_events | 读取 | 在日历中搜索事件,并将重复系列展开为实例。 |
check_attendee_status | 读取 | 报告谁接受、拒绝或尚未回复邀请。 |
query_free_busy | 读取 | 一个或多个日历的忙碌时间段,不含事件详情。 |
analyze_busyness | 读取 | 某时间段内每日事件数量和总日程分钟数。 |
project_recurring_events | 读取 | 根据重复规则计算未来的发生时间。 |
create_calendar | 写入 | 创建新的次级日历。 |
create_event | 写入 | 创建具有明确开始/结束时间和可选参与者的事件。 |
quick_add_event | 写入 | 根据自然语言短语创建事件,由 Google 解析。 |
update_event | 写入 | 更改事件字段;省略的字段保持不变。 |
move_event | 写入 | 重新安排事件时间,和/或将其移动到另一个日历。 |
add_attendee | 写入 | 邀请一人或多人参加现有事件。 |
respond_to_event | 写入 | 设置自己的 RSVP(accepted/declined/tentative/needsAction)。 |
schedule_mutual | 写入 | 找到所有人都空闲的第一个时间段,然后预订。 |
delete_event | 销毁 | 永久删除事件。在支持时,通过 elicitation 请求客户端确认。 |
调度大脑 — 这些工具会读取你保存的偏好设置(工作时间、午餐、缓冲时间、最短专注时段)。
| 工具 | 描述 | |
|---|---|---|
find_focus_time | 读取 | 某时间窗口内可用于深度工作的不间断时间段,按从长到短排序。 |
detect_conflicts | 读取 | 跨所有已登录账户,找出重复预订和过于紧凑的衔接。 |
time_audit | 读取 | 时间都去哪儿了:会议时长,按规模、领域、重复和人员分类。 |
suggest_reschedule | 写入 (可选启用) | 为现有会议推荐更合适的备选时间,按优先级排序。仅建议,除非 apply: true。 |
block_focus_time | 写入 | 将最佳空闲时间段预订为专注时间。使用 dry_run: true 预览。 |
本地配置 — 不调用 Google,没有 account 参数。
| 工具 | 描述 | |
|---|---|---|
list_accounts | 读取 | 你已登录的账户,以及哪个是默认账户。 |
get_preferences | 读取 | 工作时间、午餐、缓冲时间、最短专注时段、专注日历。 |
set_preferences | 写入 | 更新并保存这些偏好设置。仅限本地文件。 |
每个日历工具都接受一个可选的末尾 account 参数(detect_conflicts
接受 accounts,是一个列表,因为同时检查多个账户正是其目的)。所有时间
都是 ISO 8601 字符串——不带时区的时间戳会按目标日历自身的时区进行解释。
调度大脑
这五个调度工具共享同一个理念:你的日历并不等同于你的空闲时间。它们从你的工作时间出发,减去午餐时间,减去已有安排,再减去你希望在会议前后留出的缓冲时间——然后对剩余时间进行推理。
用于测试它们的提示词:
- “帮我找出下周六小时的专注时间并预订下来——先把时间段给我看看。”
- “这周我的工作日历和个人日历之间有重复预订吗?”
- “我周四的安排一个接一个。给设计评审建议更好的时间。”
- “上个月我的时间都花在哪了?我都在和谁相处?”
- “我需要在周五之前有一个 90 分钟的深度工作时段。有吗?”
find_focus_time 报告现有的空闲时间;block_focus_time 通过创建事件来守护它(忙碌、关闭提醒、不通知任何人),并裁剪最后一个时间段,使其正好预订你要求的时长,而不是整个下午。detect_conflicts 将真正的重叠与仅仅打破你缓冲时间的紧凑过渡区分开来,并忽略你已拒绝的事件、标记为空闲的事件,以及(默认情况下)全天事项。suggest_reschedule 保持会议时长不变,按参会者冲突最少对候选时间段排序,并优先选择事件当前所在的日期;除非你传入 apply: true,否则不会移动任何内容。
时间审计
time_audit 一次性回答“我这一周有多少时间花在会议上?”,可按 day 或 week 分组:
2026-08-01 .. 2026-09-01, Europe/Berlin, grouped by week
Meetings: 41.5 h across 63 meetings
Working hours: 152.0 h available (lunch removed)
In working hours: 38.0 h -> 25% of the week
Busiest week: 2026-W34, 14.0 h
Heaviest day: 2026-08-20, 6.5 h
By size: 1:1 18.0 h | small 15.5 h | large 8.0 h
By recurrence: recurring 26.0 h | one-off 15.5 h
Top people: [email protected] 9.0 h | [email protected] 7.5 h
已拒绝的会议、标记为空闲的事件和全天事项默认被排除;include_declined 和 include_all_day 可将它们重新纳入。
安全
delete_event是唯一的破坏性工具。 当客户端支持时,它会通过 MCP elicitation 请求客户端确认;不支持时则正常继续。block_focus_time接受dry_run。 用dry_run: true运行它,即可在写入任何内容之前查看它将预订的具体时间段。目标日历始终包含在可用性检查中。- 调度在可用性未知时采用失败关闭策略。 专注时间搜索/预订、两条互相调度路径,以及重新安排建议/应用,都要求每个被检查的日历具有可读取的可用性。错误会在写入之前返回,而不是在预订之后作为警告。请恢复访问权限或重试后再调度。默认的专注日历发现也会拒绝不完整、分页的日历列表;在这种情况下,请通过
calendar_ids/check_calendar_ids提供明确的完整列表。 suggest_reschedule默认不移动任何内容。apply为false,必须在用户同意某个时间后显式设置。- 其他所有写入操作都是增量式的——创建或编辑事件——并且
update_event会保留你省略的字段不变。 list_accounts、get_preferences和set_preferences从不接触 Google。 它们读写配置目录中的本地文件。
账户
你可以登录多个 Google 账户,并在每次调用时从中选择。
calendar-mcp auth # the default account
calendar-mcp auth --account work # a second, named account
calendar-mcp accounts # list them, with token paths and sign-in state
每个日历工具都接受一个可选的 account 参数,用于指定其中一个账户(“我明天的工作日历上有什么?”)。省略该参数时,服务将使用默认值:如果设置了 CALENDAR_MCP_DEFAULT_ACCOUNT 则使用它,否则使用名为 default 的账户,否则使用你唯一登录的账户。list_accounts 返回与 CLI 打印相同的列表,因此模型可以自行发现这些名称。
账户名称必须匹配 [A-Za-z0-9][A-Za-z0-9_-]{0,63}。
文件存放位置。 令牌和偏好设置存储在操作系统用户配置目录中 —— Windows 上为 %LOCALAPPDATA%\calendar-mcp,Linux 上为 ~/.config/calendar-mcp,macOS 上为 ~/Library/Application Support/calendar-mcp —— 每个账户在 accounts/ 下有一个令牌文件。可通过 CALENDAR_MCP_CONFIG_DIR 覆盖整个目录。
向后兼容。 TOKEN_FILE_PATH 仍然有效,现在表示默认账户的令牌。如果设置了它,或者工作目录中存在 .gcp-saved-tokens.json,则该文件将用于 default 账户,其他文件不会移动。具名账户始终位于配置目录中。
偏好设置
服务会记住你希望一周如何安排,这样调度工具就无需猜测。使用 get_preferences 读取它们,使用 set_preferences 修改它们(“我从 8 点开始,会议之间要留 15 分钟”)。偏好设置是全局的 —— 它们描述的是你,而不是某个账户 —— 并以 preferences.json 的形式存储在配置目录中。
| 字段 | 默认值 | 含义 |
|---|---|---|
timezone | 未设置 | 工作时间所用的 IANA 时区,例如 Europe/Berlin。 |
working_hours | 周一至周五 09:00–17:00 | 按星期几(mon…sun),一个 ["HH:MM", "HH:MM"] 时间段的列表。 |
buffer_minutes | 0 | 提议时间时,会议前后要留出的间隔。 |
min_focus_block_minutes | 60 | 仍然算作可用专注时间的最短空闲时段。 |
lunch | 未设置 | 从工作时间内划出的每日休息时间。 |
focus_calendar_id | primary | 预订专注时间块的日历。 |
{
"timezone": "Europe/Berlin",
"working_hours": {
"mon": [["09:00", "12:00"], ["13:00", "18:00"]],
"tue": [["09:00", "17:00"]],
"wed": [["09:00", "17:00"]],
"thu": [["09:00", "17:00"]],
"fri": [["09:00", "15:00"]],
"sat": [],
"sun": []
},
"buffer_minutes": 15,
"min_focus_block_minutes": 90,
"lunch": ["12:30", "13:15"],
"focus_calendar_id": "primary"
}
set_preferences 采用合并方式:只有你传入的参数会改变,合并后的结果在写入前会经过验证,因此被拒绝的更改不会影响已保存的文件。唯一的例外是 working_hours,它是整个日程的替换 —— 你在字典中省略的星期几将变为非工作日。传入 clear_lunch: true 可移除午休时间。
配置
| 变量 | 默认值 | 用途 |
|---|---|---|
GOOGLE_CLIENT_ID | — | OAuth 客户端 ID(必填)。 |
GOOGLE_CLIENT_SECRET | — | OAuth 客户端密钥(必填)。 |
TOKEN_FILE_PATH | .gcp-saved-tokens.json | 默认账户的 OAuth 令牌缓存位置。 |
CALENDAR_MCP_CONFIG_DIR | 操作系统用户配置目录 | 存放各账户令牌(accounts/)和 preferences.json 的目录。 |
CALENDAR_MCP_DEFAULT_ACCOUNT | default | 当工具的 account 参数被省略时使用的账户。 |
CALENDAR_SCOPES | https://www.googleapis.com/auth/calendar | 请求的范围。只读请使用 .../auth/calendar.readonly。 |
OAUTH_CALLBACK_PORT | 8080 | calendar-mcp auth 期间 OAuth 回调的本地端口。 |
CALENDAR_MCP_ALLOW_BROWSER_AUTH | 未设置 | 设为 1 以允许服务本身在无令牌时打开浏览器。默认关闭,这样 stdio 服务永远不会挂起。 |
CALENDAR_MCP_LOG_FILE | 未设置 | 将 stderr 日志镜像到此文件。 |
CALENDAR_MCP_LOG_LEVEL | INFO | DEBUG/INFO/WARNING/ERROR/CRITICAL。覆盖 --log-level。 |
HOST | 127.0.0.1 | HTTP 模式下 --host 的默认值。 |
PORT | 8000 | HTTP 模式下 --port 的默认值。 |
工作目录中的 .env 文件会在启动时加载。日志绝不会输出到 stdout —— 在 stdio 模式下,stdout 是 MCP 协议通道。
命令
calendar-mcp [--transport {stdio,http}] [--host H] [--port P] [--path /mcp] [--log-level L]
calendar-mcp serve ... # explicit form of the default
calendar-mcp auth [--account NAME] [--no-browser]
calendar-mcp accounts # list known accounts; exit 1 if none is signed in
calendar-mcp check [--account NAME] # token status + calendar list; exit 1 if no valid token
calendar-mcp --version
python -m calendar_mcp 接受相同的参数。
Google Cloud 设置
- 创建或选择一个项目,并启用 Google Calendar API。
- APIs & Services → Credentials → Create credentials → OAuth client ID → Application type: Desktop app。 复制 client ID 和 secret。没有需要保留的 JSON 下载文件。
- Desktop app 客户端没有 "Authorized redirect URIs" 字段——Google 允许此类客户端在任意端口使用
http://localhost,这正是OAUTH_CALLBACK_PORT上的本地回调所使用的。此处无需配置任何内容。 - 在 OAuth consent screen 中:User Type 选择 External,填写应用名称和联系人邮箱,添加
https://www.googleapis.com/auth/calendar权限范围,并将你自己的 Google 账号添加为测试用户。若缺少最后一步,登录将被拒绝。
开发
git clone https://github.com/deciduus/calendar-mcp
cd calendar-mcp
uv venv
uv pip install -e ".[dev]"
pytest
目录结构:calendar_mcp/server.py(MCPServer、共享辅助函数和凭据提供程序)、tools/(每个工具领域一个模块——即工具函数本身)、calendar_actions.py(Google API 调用)、analysis.py、timeutil.py(纯区间计算)、accounts.py(多账号 token 路径)、preferences.py(已保存的日程)、models.py(pydantic 输入/输出模型)、auth.py(OAuth)、cli.py(calendar-mcp 命令)。scripts/smoke_stdio.py 会启动一个真实的 stdio 服务,并检查握手和工具列表。
从 1.0 升级
不会有任何破坏。全部 15 个原有工具保留其名称和现有参数;每个工具只是新增了一个可选的末尾 account 参数。你现有的 TOKEN_FILE_PATH 仍然有效,现在它指定的是默认账号的 token。调度安全性:不可用、缺失或格式错误的忙/闲数据现在会导致专注时间搜索、预览、互相调度和重新调度返回错误。在可用性信息不完整时,不会自动进行任何调度变更。
新增内容:多账号、已保存的调度偏好,以及八个新工具(find_focus_time、block_focus_time、detect_conflicts、suggest_reschedule、time_audit、list_accounts、get_preferences、set_preferences)。
从 0.x 升级
- 包和命令已重命名。 发行包现在名为
calendar-mcp-server,并安装calendar-mcp(以及一个完全相同的calendar-mcp-server别名)。请将你的客户端指向uvx calendar-mcp-server,而不是python /path/to/run_server.py。 run_server.py仍然可用——它现在只是 CLI 之上的一层薄垫片——但已弃用,并将在未来版本中移除。- FastAPI/uvicorn HTTP API 已移除。 不再有 REST 端点、没有
/health,也没有单独的 stdio 桥接进程;该服务是基于 MCP SDK 的单一进程。如果你需要 HTTP,现在是在/mcp上的 MCP streamable HTTP。 - 认证不再隐式发生。 运行一次
calendar-mcp auth;除非设置CALENDAR_MCP_ALLOW_BROWSER_AUTH=1,否则服务不会打开浏览器。 - 工具名称未变,因此现有提示词仍然可用。结果现在是结构化输出,而不是塞进文本里的 JSON。
- 三个新工具:
move_event、respond_to_event和project_recurring_events(最后一个此前仅作为内部逻辑存在)。 - 已移除的环境变量:
RELOAD、MCP_API_HOST。HOST/PORT现在适用于 MCP HTTP 传输。
许可证
本项目采用双许可模式,以同时支持开源协作与可持续发展:
-
GNU Affero 通用公共许可证 v3.0(AGPL-3.0):
- 在 AGPLv3 许可证条款下,本软件可自由使用、修改和分发。
- 关键条件包括:衍生作品(包括通过网络使用的修改版本)也必须以 AGPLv3 许可,并公开其源代码。
- 该许可证适用于开源项目或能够满足 AGPLv3 合规要求的内部使用场景。
- 完整文本请参见 LICENSE 文件。
-
商业许可证:
- 如果 AGPLv3 的条款不适合您的具体使用场景(例如,在不遵守 AGPLv3 源代码共享要求的情况下,将本软件集成到专有的闭源商业产品或服务中),可另行获取商业许可证。
- 有关商业许可方案的咨询,请联系 [email protected]。
使用、修改或分发本软件,即表示您同意接受 AGPLv3 或另行协商的商业许可证条款的约束。
mcp-name: io.github.deciduus/calendar-mcp
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。