Skip to main content
Glama

mstodo-mcp

CI

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

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

目录

Related MCP server: Todoist MCP Server

要求

  • 使用 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_lists、get_list、create_list、update_list、delete_list;list_tasks、get_task、create_task、update_task、delete_task、move_task。

  • 子资源 — 清单项和链接资源(各自可创建/列出/获取/更新/删除);附件(list_attachments、get_attachment、remove_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_list、get_pending_across_lists、get_recently_completed。

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

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

  • 配置 — get_list_config/set_list_config(分类模式、no_sync、sync_flagged_emails)、set_list_alias、get_link_rules/set_link_rules、get_attachment_config/set_attachment_config、extract_links。

  • 运维 — whoami、sync_status、resync。

工作原理

Claude.ai 通过 remote-MCP 连接到 Worker;Worker 负责向 Microsoft Graph API 发起请求(OAuth 授权码流程,使用 PKCE + 客户端密钥)。一个单例 TodoIndex Durable Object(Cloudflare 的有状态、强一致性计算原语)在其内置的 SQLite 数据库中维护你的列表和任务的 增量同步镜像,以及一个 FTS5 全文索引(FTS5 是 SQLite 内置的全文搜索引擎)。跨列表的 query_tasks、search_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 /me 的 mail/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_URL(wrangler.jsonc 中的变量)——此 Worker 的公共源(你的 workers.dev URL 或自定义域名),用于构建链接。如果未设置(或保留为占位符),create_upload_link 将返回 upload_disabled。

跨服务器下载(/download)

与上传相反:mint_download_link 返回一个短时(≤ 5 分钟)、单次使用的 URL,以及附件的元数据(filename、content_type、size)。预期消费者是另一个 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:owner 后 identity:owner(均在 TODO_CACHE 中)(身份标记最后清除,因此中途清除失败会在下次 /authorize 时重新触发清除,而不是静默跳过)。

  3. config:lists.aliases——尽力而为,因为别名是每个帐户的 Graph ID,切换后这些 ID 会解析为无效列表。分类 patterns、no_sync、sync_flagged_emails、config:link_rules 和 config: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 许可证 许可。发布历史见 变更日志。

Maintenance

ActivitySlowing
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A Cloudflare Worker-based MCP server that enables AI assistants to read and manage Todoist tasks through tools like get_tasks, add_task, update_task, complete_task, delete_task, and move_task.
    226 npm
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A hardened MCP server that lets you manage Microsoft To Do tasks via natural language in Claude Desktop, with OS-keychain token storage and no client secret.
    13
    ISC