起因:为什么这么慢?

我用 Claude Code 搭建了一套 GTD 任务管理系统,通过 MCP(Model Context Protocol)连接滴答清单,让 AI 帮我自动处理收集箱里堆积的任务。

系统搭好后能用,但有个大问题:太慢了

比如我让 AI「完成这个任务」,要等大约 30 秒才有反应。批量处理 100 多个任务时更是煎熬。

我隐约觉得是 API 调用太多导致的,但具体慢在哪里?有没有更好的做法?于是我找了两个同样连接滴答清单的开源 MCP 项目来对比学习。

找到两个参考项目

我在 GitHub 上找到了两个滴答清单的 MCP 实现:

  1. evalor/Dida365MCP(TypeScript)

  2. Xrondev/mcp-dida365(Python)

我把两个项目都克隆到本地,逐个文件看了源码。

发现:大家用的 API 完全一样

看完源码后,第一个发现是:三个项目(包括我自己的)用的都是同一套滴答清单官方 API

没有什么「隐藏的加速接口」。完成一个任务就是调一次 POST /project/{项目ID}/task/{任务ID}/complete,一次 API 调用,不到 1 秒。

那为什么我的要 30 秒?

问题根源:每次操作都在「全城搜索」

打开我自己的代码一看就明白了。

当 AI 说「完成任务 XX」时,我的工具只收到了一个任务标题。但滴答清单的 API 需要项目ID + 任务ID才能操作。

所以我的工具内部做了这么一件事:

遍历全部 91 个项目 → 每个项目调一次 API 获取任务列表 → 在里面找标题匹配的任务 → 找到后再调 API 完成它

相当于为了完成 1 个任务,先调了 92 次 API。就像你想在一栋大楼里找一个人,结果你挨个敲了全部 91 个房间的门。

开源项目的做法:让调用方自己带 ID

再看 evalor 和 Xrondev 的设计,它们的完成任务工具长这样:

complete_task(project_id="xxx", task_id="yyy")

直接要求调用方提供项目 ID 和任务 ID。不搜索,不遍历,一步到位。

这个 ID 从哪来?AI 之前调用「获取任务列表」时,返回结果里就带着每个任务的 ID。AI 记住这些 ID,后续操作直接用就行了。

这就是关键差异:不是 API 慢,是我自己多做了 91 次没必要的搜索

我做了哪些优化

优化 1:新增「ID 直达」工具

新增了 3 个工具,直接接收 ID,跳过搜索:

  • complete_task_by_id(project_id, task_id) — 完成任务
  • update_task_by_id(task_id, project_id, ...) — 更新/移动任务
  • delete_task_by_id(project_id, task_id) — 删除任务

每个工具只需 1 次 API 调用。旧的工具保留了(万一 AI 只知道标题的时候还能用),但在说明里标注了「推荐用新版」。

优化 2:批量操作支持跨项目

之前的批量完成工具只能处理同一个项目的任务。参考 evalor 的设计,改成了支持传入不同项目的任务列表:

# 旧格式(只支持同一项目)
batch_complete_tasks(task_ids=["id1", "id2"], project_id="同一个项目ID")
 
# 新格式(支持跨项目)
batch_complete_tasks(tasks=[
    {"project_id": "项目A", "task_id": "id1"},
    {"project_id": "项目B", "task_id": "id2"},
])

两种格式都能用,旧的不会坏。

优化 3:串行改并发

之前批量操作是一个一个来的,每 80 个还要暂停 65 秒等 API 限流。

参考 evalor 的 batch.ts(它用了一个并发执行框架),我改成了 5 个并发,用 Python 的 ThreadPoolExecutor 实现。简单说就是同时跑 5 个请求,而不是排队等。

优化 4:项目列表加了缓存

「获取全部项目列表」这个操作被很多功能重复调用。加了个 5 分钟的缓存,同一段时间内只请求一次 API,后面直接用缓存结果。

优化效果

场景优化前优化后
完成 1 个任务~92 次 API(约 30 秒)1 次 API(不到 1 秒)
批量完成 100 个任务串行 + 暂停(数分钟)5 并发(约 10 秒)
批量完成跨项目任务不支持支持

总结

这次优化的核心教训只有一句话:

如果你已经知道答案(ID),就别再去搜索了。

技术上没有任何复杂的东西。不需要换 API,不需要换语言,不需要换框架。只是改了工具的输入参数设计——从「接收标题去搜索」变成「直接接收 ID 去操作」。

开源项目的价值不一定在于你要直接用它,而是看看别人是怎么设计的,找到自己的差距。

参考项目