Skip to main content
Glama

mstodo-mcp

CI

用自然语言从 Claude(或任何 MCP 客户端)使用你的 Microsoft To Do 任务。 这是一个个人自托管的服务器,运行在你自己的 Cloudflare Worker 上,将 Claude.ai 连接到你的 Microsoft To Do 帐户——因此你可以让 Claude 在不离开聊天的情况下,跨所有列表查找、创建、更新、完成、搜索和组织任务。它会维护一个快速的本地镜像,包含你的列表和任务,因此跨列表搜索和查询都很快,而且不会在每次请求时都去频繁请求 Microsoft。

按设计为单用户:一次部署恰好服务一个 Microsoft 帐户(其他人都会被所有者身份门禁拒绝),所以它用于运行你自己的私有实例——而不是共享/多租户服务。

目录

要求

  • 使用 Microsoft To Do 的 Microsoft 365(M365) 或个人 Microsoft 帐户。

  • Cloudflare 帐户 — 免费套餐适合小型帐户;一旦你有 数千个任务,建议使用 Workers Paid(请参阅部署指南中的套餐说明)。

  • Microsoft Entra 应用注册 — 免费,只需创建一次(操作指南见部署指南)。

  • Node 18+ 和 Cloudflare 的 Wrangler CLI,用于部署。

  • Claude.ai(或其他 MCP 客户端),用于连接已部署的服务器。

➡️ 设置与部署: 请参阅 DEPLOYMENT.md 获取完整的逐步指南(包括 Microsoft Entra 应用注册)、自定义域名设置和故障排查。配置参考见下文。

工具

服务器通过 MCP 暴露了一个 Microsoft To Do 工具面。亮点包括:

  • 列表与任务(CRUD)list_listsget_listcreate_listupdate_listdelete_listlist_tasksget_taskcreate_taskupdate_taskdelete_taskmove_task

  • 子资源 — 清单项和链接资源(各自可创建/列出/获取/更新/删除);附件(list_attachmentsget_attachmentremove_attachment)。

  • 附件上传create_upload_link 生成一个短时、一次性使用的网页链接,用户可在浏览器中打开它,将文件附加到特定任务。数据字节直接从浏览器 → Worker → Microsoft(每个 ≤ 25 MB,内联或分块上传会话),绝不经过模型。请参阅下文的 Web 上传

  • 附件下载mint_download_link 生成一个短时(≤ 5 分钟)、一次性使用的 URL,用于提供某个附件的字节,供服务器间传输(例如将该 URL 交给另一个 MCP 服务器的 url-ingest 工具)。字节由服务端获取,绝不经过模型。默认开启;设置 ENABLE_DOWNLOAD_LINKS="false" 可禁用。请参阅下文的 跨服务器下载

  • 跨列表查询与搜索(由本地 TodoIndex 镜像回答):

    • query_tasks — 按列表、状态、日期范围、重要性、has-checklist、has_open_checklist_item(存在未勾选项的任务 — “正在等待某事”过滤器)筛选;types/exclude_types(按列表分类包含/排除);completed 便捷参数(与 status 互斥);支持分页。

    • search_tasks — 使用 FTS5(SQLite 内置全文搜索引擎)对任务标题/正文进行全文搜索;支持相同的 lists/status/types/exclude_types/completed 过滤器。exclude_types:["excluded"] 可从结果中去掉噪音(例如标记的电子邮件列表),而不会删除任何内容。当清单缓存开启时,默认还会匹配清单项(子任务/步骤)文本(include_checklist,在标题/正文匹配之后分层)。

    • find_task_listget_pending_across_listsget_recently_completed

  • 清单跟进(可选加入) — 由 ENABLE_CHECKLIST_CACHE=true 控制。将任务的清单项镜像到一个可查询的表中,这样你可以把清单项用作轻量级跟进系统(添加一个“等待 Acme 回复”的项,然后查找还有哪些未完成)。search_checklist_items 对清单文本进行 FTS 搜索;或者,在无查询时列出待处理项,按 最旧优先 排列(即你等待最久的事项),并按任务分组。与 query_taskshas_open_checklist_item 过滤器配合使用。默认关闭(它会为每个任务增加一次性的回填);之后缓存会在常规增量同步周期中保持最新。仅覆盖 未完成任务 — 已完成的任务被有意排除在跨任务清单查询之外(get_task 仍可实时显示任何任务的清单项),被跳过的列表(no_sync/标记电子邮件)不会被缓存。

  • My Day 与手动排序(可选加入,Substrate) — 由 ENABLE_MY_DAY=true 控制(这些功能使用 To Do Web 应用使用的未公开 Substrate 端点,因为 My Day 和手动拖拽重排位置在 Graph 中不可见):list_my_day_tasksadd_to_my_dayremove_from_my_daylist_tasks_by_manual_order(某个列表按应用手动顺序排列)和 reorder_task(将任务移动到顶部/底部、另一个任务之前/之后,或某个从 1 开始的位置)。

  • 配置get_list_config/set_list_config(分类模式、no_syncsync_flagged_emails)、set_list_aliasget_link_rules/set_link_rulesget_attachment_config/set_attachment_configextract_links

  • 运维whoamisync_statusresync

工作原理

Claude.ai 通过 remote-MCP 连接到 Worker;Worker 负责向 Microsoft Graph API 发起请求(OAuth 授权码流程,使用 PKCE + 客户端密钥)。一个单例 TodoIndex Durable Object(Cloudflare 的有状态、强一致性计算原语)在其内置的 SQLite 数据库中维护你的列表和任务的 增量同步镜像,以及一个 FTS5 全文索引(FTS5 是 SQLite 内置的全文搜索引擎)。跨列表的 query_taskssearch_tasks 和聚合工具都从该本地镜像读取数据,而不是在每次调用时重新遍历 Graph;*/15 的 cron 任务保持同步,所有者身份门禁保证隐私。

默认情况下,该镜像还会订阅 Graph 变更通知(每个列表一个),因此在任何 To Do 客户端中的编辑都会在大约 2 分钟内落入缓存——接近即时,就像原生应用一样——而不是等待下一个定时周期。这是增量同步的 触发器,而不是替代品:定时周期仍然作为兜底(Graph 不保证任务通知不丢失)。它复用了现有的 Tasks.ReadWrite 权限范围(无需额外同意),需要一个可访问的 SERVICE_BASE_URL(Graph 会向 ${SERVICE_BASE_URL}/webhook 发送 POST),并可通过 ENABLE_TASK_SUBSCRIPTIONS 切换("false" ⇒ 仅定时器,无公开 webhook)。通知还会通过一次定向的 Substrate 读取,仅刷新已变更任务的 My Day 字段——webhook 路径从不会写回 Microsoft,因此不会产生循环。

小而变动缓慢的状态——你的 OAuth 令牌、所有者身份记录以及下面的配置块——存放在 Cloudflare KV(键值存储) 中。大型且频繁查询的任务语料库存放在 Durable Object 的 SQLite 中,而不是 KV 中。

安全模型

该服务器严格单用户,这是设计使然,有几个不变量是承重墙——值得集中说明:

  • 单一所有者,失败关闭。 每次登录都在 OAuth 回调处被门禁:Microsoft /memail/userPrincipalName 必须等于 OWNER_EMAIL 机密,身份不匹配会在存储任何令牌之前403 拒绝。缺失或拼写错误的 OWNER_EMAIL 会使检查对所有人失败——它会锁住所有者,绝不会开放访问。

  • 授权前绑定主机。 每个 Graph 和 Substrate URL 在附加 Bearer 令牌之前都固定到其预期主机,因此恶意 @odata.nextLink 无法重定向已认证的请求并窃取令牌。令牌只出现在 Authorization 头中——绝不会出现在 URL 或日志行中。

  • 单一令牌刷新器。 单例 TodoIndex Durable Object 是 Microsoft 令牌端点的唯一调用者;并发会话通过单一刷新

该链接是一个能力令牌:一个不可猜测的随机 ID(来自 CSPRNG 的 32 字节)。目标作用域(列表/任务 ID、文件名、文件数量)存储在服务端 OAUTH_KV 中,与该 ID 关联并带有 TTL;链接中的 ID 不泄露任何信息。持有该 ID 即授权一次上传,且仅限所作用的任务——通过 KV 查找验证,受 TTL 过期限制,使用后即被消耗(删除)。无需配置签名密钥或共享机密:该 ID 就是 nonce。

要启用它,请设置 SERVICE_BASE_URLwrangler.jsonc 中的变量)——此 Worker 的公共源(你的 workers.dev URL 或自定义域名),用于构建链接。如果未设置(或保留为占位符),create_upload_link 将返回 upload_disabled

跨服务器下载(/download

与上传相反:mint_download_link 返回一个短时(≤ 5 分钟)、单次使用的 URL,以及附件的元数据(filenamecontent_typesize)。预期消费者是另一个 MCP 服务器的 url-ingest 工具——它在服务端获取 URL,因此字节在服务器之间传输,永远不会进入模型的上下文。能力机制与上传相同(OAUTH_KV 中带 download: 前缀的不可猜测 ID,作用域限定为一个附件),并且该链接在第一次可达的 GET 时即被烧毁,无论结果如何——因此即使之后出现在对话历史中,也无法重放。(对诚实消费者而言是单次使用;与 /upload 一样,它不是事务性的——两个真正并发的 GET 可能发生竞争。)元数据在铸造时从附件集合读取,因此 /download 仅对字节进行一次 Graph 调用,并且不信任任何请求头。

返回的 size 是 Graph 报告的元数据,可能高估实际字节数——权威大小是下载的 Content-Length。所提供的字节与源数据逐字节一致(已验证至 4 MiB 的上传会话附件),因此即使 size 不匹配,传输也是忠实的。大附件也可用(Graph 在单个 GET 上返回 contentBytes,无论内联创建上限如何);实际限制是 Graph 约 25 MB 的附件最大值,因为 /download 会在 Worker 内存中缓冲文件。

此功能默认开启;设置 ENABLE_DOWNLOAD_LINKS="false"(变量)可同时禁用 mint_download_link/download,如果不需要它,可缩小攻击面。它还需要 SERVICE_BASE_URL(与上传相同);未设置/占位符 ⇒ download_disabled

重置

三个范围,从小到大。从项目根目录运行;如果你希望在 wrangler dev 使用的 miniflare 本地 KV 存储上操作,请将 --remote 替换为 --local

1. 测试迭代之间的软重置

最常见的情况:在不销毁基础设施的情况下重新触发 Microsoft OAuth 流程。身份变更自动清除(内置于 /auth/microsoft/callback)将在你下次以不同的 Microsoft 365 (M365) 帐户授权时自动清除按身份缓存,但你也可以手动清除。

# Wipe the stored Microsoft refresh token. Forces the next /authorize to
# re-run the full code-exchange flow.
npx wrangler kv key delete --binding=TODO_CACHE --remote tokens:owner

# Also wipe the stored identity record if you want to "forget" which
# account was last seen (this disables the identity-change wipe trigger
# the next time you sign in — useful when you want to test the wipe).
npx wrangler kv key delete --binding=TODO_CACHE --remote identity:owner

# Wipe all Claude.ai-side OAuth grants (DCR sessions) — forces every
# previously-paired Claude.ai client to re-add this MCP from scratch:
npx wrangler kv key list --binding=OAUTH_KV --remote \
  | jq -r '.[].name' \
  | xargs -I {} npx wrangler kv key delete --binding=OAUTH_KV --remote {}

如果你还希望 Microsoft 重新提示同意(而不是因为同意已存档而静默地重新签发令牌),可以在 M365 侧从用户帐户权限页面撤销该应用,或者——一旦我们提供该选项——向 /authorize 传递 &prompt=consent

2. 轮换凭据

使用新值编辑 .dev.vars,然后一次性将它们全部推送到 Cloudflare:

bash scripts/push-secrets.sh

该脚本从 .dev.vars 读取每个名称,并将值通过 stdin 传递给 wrangler secret put,因此值永远不会出现在 argv、环境、终端回滚或 AI 记录中。使用 npx wrangler secret list 验证。

.dev.vars 中的任何值都可以改为1Password 机密引用,其形式为 op://<vault>/<item>/<field>——该脚本在推送时通过 op CLI 解析它(需要 op signin,或用于无人值守使用的 OP_SERVICE_ACCOUNT_TOKEN),并像任何其他机密一样将解析后的值通过 stdin 传递。字面值仍然可以保持不变,因此你可以将部分或全部机密排除在文件之外:

MS_CLIENT_SECRET=op://Private/MS To-Do MCP/credential

若要手动推送单个机密:

npx wrangler secret put MS_CLIENT_SECRET     # prompts for value

旧客户端机密仍然有效,除非你还在 Azure 门户中将其删除——wrangler secret put 只会更新 Worker 侧。

轮换后,执行一次上面的软重置,以便下次 /authorize 使用新身份。

3. 完全从零开始

用于发布前的可发布性检查,或从损坏状态中恢复:

npx wrangler delete --name=mstodo-mcp                       # nukes Worker + all DO state
npx wrangler kv namespace delete --binding=OAUTH_KV
npx wrangler kv namespace delete --binding=TODO_CACHE
# Then re-create namespaces + update wrangler.jsonc + redeploy (see DEPLOYMENT.md).

这就是“我希望这个帐户看起来像一个全新的 fork”的路径。请注意,wrangler delete 具有破坏性且不可恢复

身份变更自动清除(内置)

/auth/microsoft/callback 针对与先前存储的 identity:owner.id 不同的 me.id 完成时,Worker 会在存储新令牌之前自动清除按身份状态。这可以防止静默混合来自两个 M365 帐户的任务。

自动清除按顺序清除以下内容(故障关闭——Durable Object 重置首先运行,因此如果它抛出异常,则不会发生其他任何事情,并且 /authorize 在存储新令牌之前中止,绝不会留下清除一半的混合状态):

  1. TodoIndex DO 重置——删除所有已索引任务、列表名册以及每个增量 sync_state 游标(任务语料库位于 DO 的 SQLite 中,而非 KV 中)。

  2. tokens:owneridentity:owner(均在 TODO_CACHE 中)(身份标记最后清除,因此中途清除失败会在下次 /authorize 时重新触发清除,而不是静默跳过)。

  3. config:lists.aliases——尽力而为,因为别名是每个帐户的 Graph ID,切换后这些 ID 会解析为无效列表。分类 patternsno_syncsync_flagged_emailsconfig:link_rulesconfig:attachments保留(与帐户无关的意图)。

OAUTH_KV 授权受自动清除影响——你的 Claude.ai 配对在 MS 帐户切换后仍然有效。如果你也希望 Claude.ai 客户端从头开始重新认证,请运行上面软重置块中的 OAUTH_KV 清除。

当自动清除触发时,会输出一条结构化日志行:

{"level":"warn","event":"identity_change_wipe","prev_id":"…","prev_mail":"…","new_id":"…","new_mail":"…","hint":"…"}

你可以在测试期间使用 wrangler tail 来观察它。

需要重新审视的设计决策

记录在此,以便未来的维护者在使用模式表明需要不同的权衡时重新考虑。

list_tasks 分页——实时逐页获取,无快照缓存

Phase 2 的 list_tasks 工具直接对 Graph 进行分页($top + @odata.nextLink)。返回给调用方的 next_cursor 是不透明的 Graph nextLink URL;后续调用通过标准 GraphClient 令牌/刷新路径 GET 该 URL。tasks:{listId} 不会由此工具写入——Phase 5 增量同步是该缓存键的唯一写入者。

这是对 Phase 2 计划中“使用 ETag 将快照缓存到 tasks:{listId}”说明的有据可查的偏差。选项 A(已选择)与 选项 B(首次调用时获取所有页面,缓存快照,之后从缓存切分为页面):

维度

A(实时,已选择)

B(快照)

Graph 调用

每个用户页面 1 次(随导航深度线性增长)

首次调用时 1 次全集合获取;之后为缓存读取

首页延迟

最佳——单个 GET

最差——响应前必须遍历所有 nextLinks

后续页面延迟

与首页相同

亚毫秒(KV 读取)

跨页面一致性

如果任务在遍历过程中发生变化,则出现标准 REST 分页撕裂

跨页面快照一致性,但快照会老化

游标形状

不透明的 Graph URL,透传(对照 graph.microsoft.com/v1.0/me/todo/lists/ 进行前缀验证)

我们自己的不透明令牌(偏移量或类似物)

步骤 7 中的代码

约 30 行

约 80–100 行

Phase 5 交互

Phase 5 增量是 tasks:{listId} 的唯一写入者;缓存形状的唯一所有者

Phase 5 继承步骤 7 的缓存写入;如果增量需要不同的布局,则存在形状迁移问题

经验可观察性

每次调用都会展现真实的 Graph 分页行为

首次调用执行分页;后续调用读取缓存

重新考虑选项 B,如果 wrangler tail 之后显示 LLM 在短时间内反复对大型列表进行深入分页——预先获取 + 缓存读取将端到端节省 Graph 配额,但代价是首页延迟。截至 Phase 2,典型的 To Do 使用是突发且浅层的;实时分页总体更便宜,并且让我们将缓存形状的承诺推迟到 Phase 5,届时它会成为关键要素。

附件上传——Web /upload,而非 MCP 工具调用

文件字节实际上无法通过 MCP 工具调用传输: Claude 的每次调用输出/令牌预算将工具参数限制在几 KB,因此除了微不足道的上传之外,所有上传在甚至到达 Graph 之前就会失败(在构建同级 obsidian-mcp-cloudflare 项目时已确认)。内联 3072 KiB 的 Graph 上限从来都不是制约因素——MCP 传输才是。

因此,原始的 create_attachment 工具(工具调用中的内联 base64)被移除,并被 Web 上传流程取代:create_upload_link + 公共 /upload 端点(参见 Web 上传)。字节从浏览器 → Worker → Graph,对于 ≤ 3072 KiB 的文件以内联方式附加,对于最大 25 MB 的较大文件则通过分块上传会话附加。链接是能力令牌——一个不可猜测的随机 ID,其任务作用域存在于 OAUTH_KV 中并带有 TTL——任务作用域、单次使用、绝不通用(每个链接都针对一个特定任务)。不涉及签名密钥或共享机密。Worker 在 POST 期间同步转发字节,因此不需要 R2 存储桶或临时 blob 存储。从 obsidian-mcp-cloudflare(其 src/upload/*)移植,适配 To Do 附件 API,并简化为无密钥的能力令牌。

作者

David Szpunar 构建。根据 MIT 许可证 许可。发布历史见 变更日志

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

  • Hosted MCP server for personal tools: budgets, savings goals, spaced repetition, tips, countdowns.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/qaq112233/mstodo-cloudflare'

If you have feedback or need assistance with the MCP directory API, please join our Discord server