内容
ocus-sync-mcp
一款无界面 [MCP](https://modelcontextprotocol.io) 服务器,通过 WebDAV 直接与 Omni Sync Server 通信,读取和写入 OmniFocus 数据,无需 Mac 或运行 OmniFocus 应用程序。它使用 TypeScript 实现 OmniFocus 的客户端端到端加密,因此可以在任何 Node 运行的环境中运行(例如 Linux NAS、容器、云盒)。
与其他 OmniFocus MCP 服务器服务器Script/JXA 自动执行本地 macOS 应用程序,而本服务器直接使用云同步协议,这使其可以无界面运行。
> Alpha / 使用风险自负。** 该程序直接与您的实际任务数据库通信。读取和写入路径已针对实时 Omni Sync Server 帐户进行端到端验证(添加和删除事务可以正确往返),并且加密和解析有离线测试套件 — 但尚未在所有 OmniFocus 版本或边缘情况下进行测试。**请备份**(在 OmniFocus 中:文件 → 备份数据库),并在评估期间考虑使用一个测试账户。参见 [安全性](#安全性)。
## 工作原理
Omni步存储是一个 WebDAV 集合(`OmniFocus.ofocus/`),包含:
- 基线事务和增量事务链,每个事务是一个 `.zip` 文件,包含一个 `contents.xml` 文件,描述对象创建/更新/删除;
- `.client` 文件注册每个设备及其同步到的事务“尾部”;
- 一个 `encrypted` plist 文件,包含包装的文档密钥。
:
1. **解析分片** — `sync.omnigroup.com` 将每个帐户重 `syncN.omnigroup机;客户端跟随重定向。
2. **身份验证** 使用 HTTP Digest(Omni 协商)。
3. **解密** 使用 OmniFileStore 格式:PBKDF2 从密码短语中导出包装密钥,RFC4 解包文档密钥槽,每个文件都是 AES-128-MAC-SHA256,大小64 KiB 分段后 MAC)。
4. **重放** 事务链到内存对象模型中。
5. **写入** 通过构建新的 `contents.xml`,压缩,加密,`PUT` 为新的事务,从当前部递增,并刷新其 `.client` 注册,以便其他客户端将其视为真实参与者。
加密和格式重新实现自 Omni 的**开源框架**([OmniGroup/OmniGroup](https://github.com/omnigroup/OmniGroup),特别是 `OmniFileStore/EncryptionFormat.md` 和 `DecryptionExample.py`)以及社区逆向工程([tomzx/ofocus-format](https://github.com/tomzx/ofocus-format),[rubyfocus](https://github.com/jyruzicka/rubyfocus))。参见 [致谢](#致谢)。
```bash
git clone https://github.com/rossk/omnifocus-sync-mcp.git
cd omnifocus-sync-mcp
npm install
npm run build
```
## 配置
通过环境变量设置凭证(参见 [`.env.example`](./.env.example)):
| 变量 | 必需 | 描述 |
| --- | --- | --- |
| `OMNIFOCUS_SYNC_USERNAME` | 是 | Omni Sync Server 账户名称 |
| `OMNIFOCUS_SYNC_PASSWORD` | 是 | Omni Sync Server 账户密码 |
| `OMNIFOCUS_ENCRYPTION_PASSPHRASE` | 否 | 默认使用同步密码(OmniFocus 默认值) |
| `OMNIFOCUS_SYNC_URL` | 否 | 默认 `https://sync.omnigroup.com` |
| `OMNIFOCUS_DATABASE` | 否 | 默认 `OmniFocus.ofocus` |
| `OMNIFOCUS_CLIENT_NAME` | 否 | 此客户端的 `.client` 文件显示名称 |
| `OMNIFOCUS_CLIENT_STATE_FILE` | 否 | 存储稳定客户端 ID 的位置 |
| `OMNIFOCUS_READ_ONLY` | 否 | `1`/`true` 拒绝所有写入 |
## 在没有 MCP 客户端的情况下试用
一个诊断 CLI 直接测试同步路径:
```bash
export OMNIFOCUS_SYNC_USERNAME=... OMNIFOCUS_SYNC_PASSWORD=...
npm run probe -- sync # 显示数据库计数
npm run probe -- list flagged # 列出标记的任务
npm run probe -- projects # 列出项目
npm run probe -- add "购买牛奶" # 添加一个待办事项
```
## 作为 MCP 服务器使用
通过 stdio 运行。示例 Claude Desktop / Claude Code 配置:
```json
{
mcpServers": {
"omnifocus": {
"command": "node",
"args": ["/绝对路径/to/omnifocus-sync-mcp/dist/index.js"],
"env": {
"OMNIFOCUS_SYNC_USERNAME": "您的账户",
"OMNIFOCUS_SYNC_PASSWORD": "您的密码"
}
}
}
}
```
### 工具
| 工具 | 描述 |
| --- | --- |
| `of_sync` | 从服务器重新加载数据库;返回计数 |
| `of_list_tasks` | 列出任务(`remaining`、`available`、`flagged`、`inbox`、`due_soon`、`all`),带有项目/标签/搜索筛选器 |
| `of_get_task` | 通过 ID 获取一个任务的完整详细信息 |
| `of_list_projects` | 列出项目,带有文件夹路径和状态 |
| `of_add_task` | 创建一个任务(在待办事项或项目中)_task` | 标记任务完成 |
| `of_edit_task` | 编辑名称/标记/截止日期/延期;清除日期 |
|_delete_task` | 通过 |
## 安全性
- **备份**,并在路径之前**使用测试账户**。
- 以 `OMNIFOCUS_READ_ONLY=1` 开启,以安全地进行探索。
- 写入是仅追加的事务;错误的写入会分叉历史记录,而不是销毁数据,OmniFocus 会在其下一次同步时合并分叉 — 但这是安全网,而不是保证。
- 机密仅来自环境;此仓库中不写入任何内容。客户端身份文件 (`client.json`) 不包含机密。
## 开发
```bash
npm test # 离线测试套件(加密往返、解析/写入、摘要)
npm run ... # 通过 tsx 运行 CLI,无需构建
```
测试涵盖了风险较高的部分,无需网络或真实账户:OmniFileStore 加密/解密往返测试,在每个分段边界进行,MAC 篡改检测,密码短语→PBKDF2→密钥解包管道,`contents.xml` 构建/解析往返测试,部分更新合并语义,以及完整的 zip→加密→解密→解析读取路径。
## 致谢
通过重新实现记录和开源的格式而
- [OmniGroup/OmniGroup](https://github.com/omnigroup/OmniGroup) — Omni 自己的框架;`OmniFileStore/EncryptionFormat.md` 和 `DecryptionExample.py` 是权威的加密规范,`OmniFoundation/XML/OFXMLIdentifier.m` 是 ID 格式。
- [tomzx/ofocus-format](https://github.com/tomzx/ofocus-format) — `.ofocus` 事务/格式文档。
- [jyruzicka/rubyfocus](https://github.com/jyruzicka/rubyfocus),[kumpelblase2/focus](https://github.com/kumpelblase2/focus) — 先前的解析器。
不隶属于或得到 Omni Group 的认可。“OmniFocus”是其商标。
## 许可证
MIT — 参见 [LICENSE](./LICENSE)。