mcpField
M
microsoft-calendar-sync

microsoft-calendar-sync

github.com/timerise-ai开发03 次安装3 天前更新
代码仓库

关于 microsoft-calendar-sync

microsoft-calendar-sync 是为使用 Microsoft 365 或 Outlook.com 的应用开发者提供的集成技能,帮助将日历忙碌时段同步到可用性数据,并将预订写入 Outlook。它着重处理 Graph 通知、订阅续期、时区、令牌轮换及事件标记等同步细节。

主要功能

  1. 01将 Outlook 忙碌时段同步为数据记录
  2. 02将预订事件写入并从 Outlook 删除
  3. 03通过 Graph 通知触发忙碌时间同步
  4. 04续订日历订阅并处理失效情况
  5. 05支持 Teams 会议链接及邮箱时区
  6. 06提供 Firestore 与 Supabase 存储实现

适用场景

  1. 01将主办人的 Outlook 日程用于可用性判断
  2. 02把已确认预订同步至主办人的日历
  3. 03预订取消时删除对应日历事件
  4. 04排查 Graph 订阅过期或通知遗漏

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/timerise-ai/microsoft-calendar-sync --skill microsoft-calendar-sync

安装后在 Claude Code 中输入/microsoft-calendar-sync确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.gitattributes
LICENSE
CHANGELOG.md
CLAUDE.md
README.md
.github/workflows/
agent-eval.yml
evals/
prompts.md
references/
booking-events.md
busy-sync.md
firestore-backend.md
calendars-and-settings.md
operations.md
data-model.md
supabase-backend.md
subscriptions.md
provenance.md
graph-api.md
oauth-and-tokens.md
http-routes.md
test-flows.md
time-zones.md
test-suite.md
testing.md

详细介绍

Microsoft Calendar Sync

两个方向,各有一条规则。入站:Outlook 是主持人其他日程安排的真实来源,因此忙碌时段只是某个时间窗口的临时镜像,由完整重新同步重建,绝不手动编辑。出站:预订存储是预订信息的真实来源,因此写入 Outlook 的事件会带有包含预订 ID 的私有标记,可通过该标记再次找到,并且绝不会被读回为忙碌时段。与 Google 不同,Graph 会指定事件 ID,要求在 3 秒内响应,并且每个日历只能有一个订阅。

适用场景

  • 主持人连接 Microsoft 365 或 Outlook.com,并选择用于屏蔽可用时间的日历。
  • 预订会显示在主持人的 Outlook 日历中,可选择创建 Teams 会议;取消后则会消失。
  • 审查现有的 Graph 集成:一小时后失效、订阅无响应、遗漏假期。
  • 在 Firestore 与 Supabase/Postgres 之间迁移同步功能。

不适用场景

  • Google Calendar:使用 google-calendar-sync。架构和记录形状相同,但 API 不同。
  • 生成可预订时段、扣除忙碌时间:使用 time-slot-generator。此技能会生成它所消耗的忙碌时段。
  • **使用 Microsoft 登录用户(SSO)**属于身份验证范畴;此技能为已登录用户请求日历访问权限。
  • 会议室和资源邮箱,或无需逐用户授权的组织范围访问需要管理员同意的应用程序权限,设计方式也不同。
  • 本地部署的 Exchange Server使用 EWS,而不是 Graph。

架构

          connect (PKCE, single-use state) -> callback -> id token tid:oid + encrypted tokens + mailbox zone -> rows
                                                                                        |
 inbound   Graph -- POST {value[]} -> /notifications -> verify clientState -> 202 -> defer(syncBusy) -> calendarView pages
              ^                                                                       -> toBusyBlock -> diffBusy -> busy blocks
              +-- subscription <-- cron: PATCH renew, 404 replace, 409 clear, resync every busy calendar
 outbound  booking confirmed -> find by marker -> unchanged? skip : PATCH - none? POST (transactionId) -> Teams link back
           booking cancelled -> find by marker -> DELETE each (404 = done)

关键事实

  1. 保存每次令牌响应中的刷新令牌。 Microsoft 每次刷新时都会轮换刷新令牌。 Node 版 MSAL 会将其保存在自己的缓存中,且不会返回,因此如果集成保存的是 MSAL 的 结果,就不会有刷新令牌,并会在第一个访问令牌过期时失效,通常约一小时后。
  2. clientState 最多 128 个字符。 否则 Graph 会拒绝订阅。仅 Outlook 日历 ID 就约有 150 个字符。只放入经签名的订阅 ID。
  3. 在 3 秒内响应通知,然后再同步。 如果端点响应较慢,Graph 会将其标记为慢速,延迟通知,随后永久丢弃。验证后返回 202,并在响应后运行同步。
  4. 每个日历只能有一个订阅;在原订阅上续订。 对同一资源发起第二次 POST 会返回 409,因此 Google 的先建新订阅再删旧订阅的续订方式不适用。PATCH 更新到期时间;如果返回 404,表示 Graph 已删除该订阅,只有此时才创建新订阅。
  5. 全天事件采用浮动时间。 Graph 会以你请求的时区将其作为午夜到午夜返回,因此转换为 UTC 后,日期正确,但具体时刻不对。应以邮箱的时区为准,而 Outlook 通常会返回 Windows 格式的时区名称。
  6. Graph 会分配事件 ID。 通过单值扩展属性重新查找预订对应的事件。先查找再创建;合并重复事件;如果没有任何变化就跳过写入,因为对有与会者的会议执行每次 PATCH 都会发送邮件。
  7. 与会者会收到邮件;没有关闭选项。 邀请访客会从主持人的 Outlook 向其发送邀请,删除事件则会发送取消通知。inviteAttendees 决定列出哪些人。

硬性规则

绝不能从 OAuth 回调 URL 获取用户 ID。 state 是服务器端一次性记录的键,有效期为十分钟。否则,任何人都能将自己的日历关联到他人的账户。

绝不能在响应通知之前进行同步。 将工作交给 defer;cron 是安全保障。

在验证 clientState 并确认其中标明了通知所属的订阅之前,绝不能信任通知。 该端点是公开的;经过签名的 clientState 是唯一凭证。

绝不能以明文存储令牌。 刷新令牌拥有长期的日历读写权限。

绝不能让 Outlook 故障导致预订失败。 出站写入只记录日志并返回;预订仍然有效。

适配契约

此表是衔接契约;该技能没有 adaptation.md。重命名对照表见 data-model.md,工作顺序见下方快速入门。

衔接项技能提供宿主提供
领域实体Connection、LinkedCalendar、WatchSubscription、BusyBlock、BookingForCalendar宿主使用的名称(员工、资源、预约)
租户范围每位用户:每个 userId 对应一个 Microsoft 账户宿主的用户 ID;组织范围仍由其守卫处理
身份验证守卫authenticate(request),返回 userId | nullSession、Clerk、NextAuth、Firebase、Supabase
数据访问CalendarStore + Firestore 和 Supabase 实现宿主的 ORM 或 SDK
预约BookingSource + pushBookingEvent / removeBookingEvent在预约状态流程中调用这些接口
可用时间每位用户的忙碌时间块、listHostBusy 查询宿主的时段引擎(time-slot-generator)
时区邮箱时区;hostTimeZone(userId);defaultTimeZone宿主的业务时区
HTTPWeb Request/Response 处理程序Next.js 路由处理程序、Express 适配器
后台工作用于通知的 defer;每 12 小时运行一次 renewSubscriptionsafter()、waitUntil、Cloud Scheduler、Vercel Cron
字符串describeBooking(事件标题/正文)、错误代码宿主的 i18n
密钥客户端 ID/密钥、clientState 密钥、32 字节令牌密钥、标记 GUID宿主的密钥管理器
测试node:test 测试套件、内存存储、模拟 Graph宿主的运行器

快速入门

  1. 在 Entra ID 中注册应用并生成标记 GUID: oauth-and-tokens.md。
  2. 复制类型并确定重命名方案:data-model.md。
  3. 复制 Graph 客户端:graph-api.md;以及时区映射: time-zones.md。
  4. 复制入站同步:busy-sync.md;出站同步: booking-events.md;订阅: subscriptions.md;日历列表和开关: calendars-and-settings.md。
  5. 选择存储:firestore-backend.md 或 supabase-backend.md。
  6. 挂载路由、defer 和 cron:http-routes.md。
  7. 复制测试套件,并在两个 TZ 值下运行:testing.md、 test-suite.md、test-flows.md。
  8. 向运维人员提供健康状态视图:operations.md。
  9. 要修复现有的 Graph 集成?修复顺序见 provenance.md。

参考目录

场景触发关键词参考资料
实体、存储契约、重命名LinkedCalendar、WatchSubscription、BusyBlock、CalendarStore、mutateCalendar、versiondata-model.md
连接账户Entra ID、app registration、redirect URI、tenant、organizations、common、scopes、PKCE、id_token、tid、oid、refresh token rotation、invalid_grant、interaction_required、admin consent、AES-256-GCMoauth-and-tokens.md
与 Graph 通信fetch、calendarView、Prefer outlook.timezone、@odata.nextLink、$filter extended property、429、Retry-After、subscriptions、MSALgraph-api.md
邮箱时区mailboxSettings、Windows time zone、"W. Europe Standard Time"、IANA、CLDR windowsZonestime-zones.md
忙碌时间同步入站toBusyBlock、showAs、free、workingElsewhere、oof、tentative、declined、isCancelled、isAllDay、diffBusy、lease、horizonbusy-sync.md
预订事件同步出站singleValueExtendedProperties、marker GUID、transactionId、attendees、invitations、Teams、isOnlineMeeting、joinUrl、backfillbooking-events.md
订阅clientState、128 characters、expirationDateTime、10080 minutes、PATCH renew、404、409 Conflict、lifecycle、subscriptionRemoved、missedsubscriptions.md
日历列表和开关canEdit、isDefaultCalendar、shared calendar、syncBusy、syncBookings、planTransitionscalendars-and-settings.md
路由和 webhookvalidationToken、text/plain、202、3 seconds、defer、after、waitUntil、callback redirect、consent_required、cron secret、Expresshttp-routes.md
Firestorefirebase-admin、runTransaction、batch 500、composite index、security rulesfirestore-backend.md
Supabase / Postgresschema.sql、RLS、service role、optimistic concurrency、23505、PostgREST 1000 rowssupabase-backend.md
验证方法node:test、memory store、fake Graph、TZ=、mutation checktesting.md、test-suite.md、test-flows.md
运行health、stale、subscription-expired、env vars、throttling、runbook、tunnel、localhostoperations.md
这样设计的原因provenance、defects、kept deliberately、fix orderprovenance.md

本目录属于 Timerise Skills 索引,该索引列出了相关的其他技能。

评论

支持 Markdown