omnifocus-mcp-enhanced 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +18 -0
- package/CLAUDE.md +280 -0
- package/README.md +168 -0
- package/assets/omnifocus-mcp-logo.png +0 -0
- package/cli.cjs +9 -0
- package/dist/omnifocustypes.js +48 -0
- package/dist/server.js +42 -0
- package/dist/tools/definitions/addOmniFocusTask.js +67 -0
- package/dist/tools/definitions/addProject.js +61 -0
- package/dist/tools/definitions/addSubtask.js +66 -0
- package/dist/tools/definitions/batchAddItems.js +75 -0
- package/dist/tools/definitions/batchRemoveItems.js +74 -0
- package/dist/tools/definitions/dumpDatabase.js +249 -0
- package/dist/tools/definitions/editItem.js +88 -0
- package/dist/tools/definitions/getTaskById.js +66 -0
- package/dist/tools/definitions/removeItem.js +80 -0
- package/dist/tools/dumpDatabase.js +121 -0
- package/dist/tools/primitives/addOmniFocusTask.js +157 -0
- package/dist/tools/primitives/addProject.js +113 -0
- package/dist/tools/primitives/addSubtask.js +37 -0
- package/dist/tools/primitives/batchAddItems.js +87 -0
- package/dist/tools/primitives/batchRemoveItems.js +44 -0
- package/dist/tools/primitives/editItem.js +328 -0
- package/dist/tools/primitives/getTaskById.js +115 -0
- package/dist/tools/primitives/removeItem.js +124 -0
- package/dist/types.js +1 -0
- package/dist/utils/omnifocusScripts/omnifocusDump.js +223 -0
- package/dist/utils/scriptExecution.js +113 -0
- package/package.json +51 -0
- package/publish.sh +148 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"WebFetch(domain:github.com)",
|
|
5
|
+
"WebFetch(domain:discourse.omnigroup.com)",
|
|
6
|
+
"Bash(npm run build:*)",
|
|
7
|
+
"Bash(npx tsc:*)",
|
|
8
|
+
"Bash(npm install)",
|
|
9
|
+
"Bash(node:*)",
|
|
10
|
+
"Bash(osascript:*)",
|
|
11
|
+
"Bash(claude mcp:*)",
|
|
12
|
+
"Bash(chmod:*)",
|
|
13
|
+
"Bash(npm pack:*)",
|
|
14
|
+
"Bash(./publish.sh:*)"
|
|
15
|
+
],
|
|
16
|
+
"deny": []
|
|
17
|
+
}
|
|
18
|
+
}
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# OmniFocus MCP Enhanced - Claude Code 使用指南
|
|
2
|
+
|
|
3
|
+
这是一个增强版的 OmniFocus MCP 服务器,新增了完整的子任务功能支持。
|
|
4
|
+
|
|
5
|
+
## 🚀 新功能特性
|
|
6
|
+
|
|
7
|
+
### ✨ 子任务功能
|
|
8
|
+
- **通过父任务ID创建子任务**
|
|
9
|
+
- **通过父任务名称创建子任务**
|
|
10
|
+
- **专门的子任务创建工具**
|
|
11
|
+
- **批量子任务创建支持**
|
|
12
|
+
- **完整的任务层级管理**
|
|
13
|
+
|
|
14
|
+
### 🛠 新增工具
|
|
15
|
+
1. **`add_subtask`** - 专门的子任务创建工具
|
|
16
|
+
2. **`get_task_by_id`** - 任务信息查询工具
|
|
17
|
+
3. **增强的 `add_omnifocus_task`** - 支持父任务参数
|
|
18
|
+
4. **增强的 `batch_add_items`** - 支持批量创建子任务
|
|
19
|
+
|
|
20
|
+
## 📦 安装方式
|
|
21
|
+
|
|
22
|
+
### 方式1:NPM 发布版本安装(推荐)
|
|
23
|
+
|
|
24
|
+
如果已发布到 NPM:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# 1. 移除原有的 OmniFocus MCP(如果有)
|
|
28
|
+
claude mcp remove omnifocus
|
|
29
|
+
|
|
30
|
+
# 2. 一键安装增强版
|
|
31
|
+
claude mcp add omnifocus-enhanced -- npx -y omnifocus-mcp-enhanced
|
|
32
|
+
|
|
33
|
+
# 3. 验证安装
|
|
34
|
+
claude mcp list
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**或者全局安装:**
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g omnifocus-mcp-enhanced
|
|
40
|
+
claude mcp add omnifocus-enhanced -- omnifocus-mcp-enhanced
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 方式2:本地项目安装
|
|
44
|
+
|
|
45
|
+
如果你有项目源码:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 1. 移除原有的 OmniFocus MCP(如果有)
|
|
49
|
+
claude mcp remove omnifocus
|
|
50
|
+
|
|
51
|
+
# 2. 进入项目目录并构建
|
|
52
|
+
cd "/path/to/OmniFocus-MCP"
|
|
53
|
+
npm install
|
|
54
|
+
npm run build
|
|
55
|
+
|
|
56
|
+
# 3. 添加增强版 MCP
|
|
57
|
+
claude mcp add omnifocus-enhanced -- node "/path/to/OmniFocus-MCP/dist/server.js"
|
|
58
|
+
|
|
59
|
+
# 4. 验证安装
|
|
60
|
+
claude mcp list
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**实际安装命令示例:**
|
|
64
|
+
```bash
|
|
65
|
+
claude mcp add omnifocus-enhanced -- node "/Users/zhangte/Library/Mobile Documents/iCloud~md~obsidian/Documents/obsidian-zhangte/1-当前项目/claude code-研究/MCPS/omnifocus_mcp/OmniFocus-MCP/dist/server.js"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 方式3:多设备部署
|
|
69
|
+
|
|
70
|
+
如果你要在其他 Mac 上使用:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# 1. 打包项目(在原Mac上)
|
|
74
|
+
cd "/path/to/OmniFocus-MCP"
|
|
75
|
+
./deploy.sh pack
|
|
76
|
+
|
|
77
|
+
# 2. 传输到新Mac并解压安装
|
|
78
|
+
# 将生成的 .tar.gz 文件传输到目标Mac
|
|
79
|
+
./deploy.sh install omnifocus-mcp-enhanced-XXXXXXXX-XXXX.tar.gz
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 方式4:使用 CLI 脚本
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
claude mcp add omnifocus-enhanced -- "/path/to/OmniFocus-MCP/cli.cjs"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 🚀 发布到 NPM
|
|
89
|
+
|
|
90
|
+
如果你想发布到 NPM 供其他人使用:
|
|
91
|
+
|
|
92
|
+
### 发布步骤
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# 1. 检查发布准备状态
|
|
96
|
+
./publish.sh check
|
|
97
|
+
|
|
98
|
+
# 2. 更新版本(可选)
|
|
99
|
+
./publish.sh version patch # 或 minor, major
|
|
100
|
+
|
|
101
|
+
# 3. 发布到 NPM
|
|
102
|
+
./publish.sh release
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 发布前准备
|
|
106
|
+
|
|
107
|
+
1. **注册 NPM 账号** - https://www.npmjs.com/signup
|
|
108
|
+
2. **登录 NPM**:
|
|
109
|
+
```bash
|
|
110
|
+
npm login
|
|
111
|
+
```
|
|
112
|
+
3. **更新个人信息**:
|
|
113
|
+
- 修改 `package.json` 中的 `author` 信息
|
|
114
|
+
- 修改 `repository` URL 为你的 GitHub 仓库
|
|
115
|
+
4. **确保包名唯一**:
|
|
116
|
+
- 检查 NPM 是否已有同名包
|
|
117
|
+
- 必要时修改 `package.json` 中的 `name`
|
|
118
|
+
|
|
119
|
+
### 发布后使用
|
|
120
|
+
|
|
121
|
+
发布成功后,用户可以通过以下命令安装:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# 一键安装
|
|
125
|
+
claude mcp add omnifocus-enhanced -- npx -y your-package-name
|
|
126
|
+
|
|
127
|
+
# 或全局安装
|
|
128
|
+
npm install -g your-package-name
|
|
129
|
+
claude mcp add omnifocus-enhanced -- your-package-name
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 🎯 使用方法
|
|
133
|
+
|
|
134
|
+
### 1. 创建子任务
|
|
135
|
+
|
|
136
|
+
#### 方法A:使用增强的 add_omnifocus_task
|
|
137
|
+
```bash
|
|
138
|
+
# 通过父任务ID创建子任务
|
|
139
|
+
add_omnifocus_task {
|
|
140
|
+
"name": "分析竞争对手关键词",
|
|
141
|
+
"parentTaskId": "loK2xEAY4H1",
|
|
142
|
+
"note": "重点分析前10名竞争对手的关键词策略",
|
|
143
|
+
"dueDate": "2025-01-15",
|
|
144
|
+
"estimatedMinutes": 120,
|
|
145
|
+
"tags": ["SEO", "研究"]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# 通过父任务名称创建子任务
|
|
149
|
+
add_omnifocus_task {
|
|
150
|
+
"name": "制定内容发布计划",
|
|
151
|
+
"parentTaskName": "内容策略优化",
|
|
152
|
+
"flagged": true,
|
|
153
|
+
"estimatedMinutes": 60
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### 方法B:使用专门的 add_subtask 工具
|
|
158
|
+
```bash
|
|
159
|
+
add_subtask {
|
|
160
|
+
"name": "撰写SEO文章大纲",
|
|
161
|
+
"parentTaskName": "内容策略优化",
|
|
162
|
+
"note": "针对目标关键词撰写10篇文章大纲",
|
|
163
|
+
"dueDate": "2025-01-20",
|
|
164
|
+
"tags": ["内容", "写作"]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 2. 批量创建任务和子任务
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
batch_add_items {
|
|
172
|
+
"items": [
|
|
173
|
+
{
|
|
174
|
+
"type": "task",
|
|
175
|
+
"name": "网站技术优化",
|
|
176
|
+
"projectName": "谷歌SEO起量",
|
|
177
|
+
"note": "优化网站技术层面的SEO"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"type": "task",
|
|
181
|
+
"name": "页面速度优化",
|
|
182
|
+
"parentTaskName": "网站技术优化",
|
|
183
|
+
"estimatedMinutes": 180,
|
|
184
|
+
"flagged": true
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"type": "task",
|
|
188
|
+
"name": "移动端适配检查",
|
|
189
|
+
"parentTaskName": "网站技术优化",
|
|
190
|
+
"estimatedMinutes": 90
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"type": "task",
|
|
194
|
+
"name": "结构化数据添加",
|
|
195
|
+
"parentTaskName": "网站技术优化",
|
|
196
|
+
"estimatedMinutes": 120
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 3. 查询任务信息
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# 通过任务ID查询
|
|
206
|
+
get_task_by_id {
|
|
207
|
+
"taskId": "loK2xEAY4H1"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# 通过任务名称查询
|
|
211
|
+
get_task_by_id {
|
|
212
|
+
"taskName": "内容策略优化"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 4. 查看项目结构
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# 获取完整的OmniFocus数据库状态
|
|
220
|
+
dump_database {
|
|
221
|
+
"hideCompleted": false,
|
|
222
|
+
"hideRecurringDuplicates": true
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## ⚠️ 重要提示
|
|
227
|
+
|
|
228
|
+
### 参数限制
|
|
229
|
+
- **不能同时指定** `parentTaskId` 和 `parentTaskName`
|
|
230
|
+
- **不能同时指定** 父任务参数和 `projectName`(子任务自动继承父任务的项目)
|
|
231
|
+
- **子任务工具必须提供** `parentTaskId` 或 `parentTaskName` 其中之一
|
|
232
|
+
|
|
233
|
+
### 错误处理
|
|
234
|
+
- 父任务不存在时会返回清晰的错误信息
|
|
235
|
+
- AppleScript 执行失败时会提供详细的错误描述
|
|
236
|
+
- 参数冲突时会在调用前进行验证
|
|
237
|
+
|
|
238
|
+
## 🔧 开发和调试
|
|
239
|
+
|
|
240
|
+
### 重新构建
|
|
241
|
+
```bash
|
|
242
|
+
cd "/path/to/OmniFocus-MCP"
|
|
243
|
+
npm run build
|
|
244
|
+
# 重启 Claude Code 以使用最新版本
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 查看日志
|
|
248
|
+
AppleScript 执行日志会输出到 `console.error`,可以通过 Claude Code 的调试模式查看。
|
|
249
|
+
|
|
250
|
+
### 测试 AppleScript
|
|
251
|
+
```bash
|
|
252
|
+
# 测试查找项目
|
|
253
|
+
osascript -e 'tell application "OmniFocus" to tell front document to name of first flattened project where name contains "SEO"'
|
|
254
|
+
|
|
255
|
+
# 测试创建任务
|
|
256
|
+
osascript -e 'tell application "OmniFocus" to tell front document to set theProject to first flattened project where name = "谷歌SEO起量" ...'
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 📋 完整工具列表
|
|
260
|
+
|
|
261
|
+
1. **dump_database** - 获取OmniFocus数据库状态
|
|
262
|
+
2. **add_omnifocus_task** - 创建任务(增强版,支持父任务)
|
|
263
|
+
3. **add_project** - 创建项目
|
|
264
|
+
4. **remove_item** - 删除任务或项目
|
|
265
|
+
5. **edit_item** - 编辑任务或项目
|
|
266
|
+
6. **batch_add_items** - 批量添加(增强版,支持子任务)
|
|
267
|
+
7. **batch_remove_items** - 批量删除
|
|
268
|
+
8. **add_subtask** - 专门创建子任务(新增)
|
|
269
|
+
9. **get_task_by_id** - 查询任务信息(新增)
|
|
270
|
+
|
|
271
|
+
## 🎉 版本信息
|
|
272
|
+
|
|
273
|
+
- **基础版本**: 1.0.9
|
|
274
|
+
- **增强版本**: 1.1.0-enhanced
|
|
275
|
+
- **新增功能**: 完整子任务支持
|
|
276
|
+
- **兼容性**: 完全向后兼容原有功能
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
**享受更强大的 OmniFocus 任务管理体验!** 🚀
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# OmniFocus MCP Enhanced
|
|
2
|
+
|
|
3
|
+
An enhanced Model Context Protocol (MCP) server for OmniFocus with complete subtask support and advanced task management features.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **Complete Subtask Support** - Create subtasks by parent task ID or name
|
|
8
|
+
- **Advanced Task Management** - Enhanced task creation with parent-child relationships
|
|
9
|
+
- **Batch Operations** - Bulk create tasks and subtasks efficiently
|
|
10
|
+
- **Task Information Query** - Get detailed task information and hierarchy
|
|
11
|
+
- **Full Backward Compatibility** - All original features preserved
|
|
12
|
+
|
|
13
|
+
## 📦 Installation
|
|
14
|
+
|
|
15
|
+
### Quick Install with Claude Code
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
claude mcp add omnifocus-enhanced -- npx -y omnifocus-mcp-enhanced
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Manual Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g omnifocus-mcp-enhanced
|
|
25
|
+
claude mcp add omnifocus-enhanced -- omnifocus-mcp-enhanced
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 🎯 New Features
|
|
29
|
+
|
|
30
|
+
### Subtask Creation
|
|
31
|
+
|
|
32
|
+
Create subtasks using the enhanced `add_omnifocus_task` tool:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"name": "Research competitor keywords",
|
|
37
|
+
"parentTaskName": "SEO Strategy",
|
|
38
|
+
"note": "Analyze top 10 competitors",
|
|
39
|
+
"dueDate": "2025-01-15",
|
|
40
|
+
"estimatedMinutes": 120,
|
|
41
|
+
"tags": ["SEO", "Research"]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or use the dedicated `add_subtask` tool:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"name": "Write content outline",
|
|
50
|
+
"parentTaskId": "task-id-12345",
|
|
51
|
+
"flagged": true,
|
|
52
|
+
"estimatedMinutes": 60
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Batch Subtask Creation
|
|
57
|
+
|
|
58
|
+
Create multiple tasks and subtasks in one operation:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"items": [
|
|
63
|
+
{
|
|
64
|
+
"type": "task",
|
|
65
|
+
"name": "Website Optimization",
|
|
66
|
+
"projectName": "SEO Project"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "task",
|
|
70
|
+
"name": "Page Speed Optimization",
|
|
71
|
+
"parentTaskName": "Website Optimization",
|
|
72
|
+
"estimatedMinutes": 180
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "task",
|
|
76
|
+
"name": "Mobile Responsiveness Check",
|
|
77
|
+
"parentTaskName": "Website Optimization",
|
|
78
|
+
"estimatedMinutes": 90
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Task Information Query
|
|
85
|
+
|
|
86
|
+
Get detailed information about any task:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"taskId": "task-id-12345"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 🛠 Available Tools
|
|
95
|
+
|
|
96
|
+
1. **dump_database** - Get OmniFocus database state
|
|
97
|
+
2. **add_omnifocus_task** - Create tasks (enhanced with subtask support)
|
|
98
|
+
3. **add_project** - Create projects
|
|
99
|
+
4. **remove_item** - Delete tasks or projects
|
|
100
|
+
5. **edit_item** - Edit tasks or projects
|
|
101
|
+
6. **batch_add_items** - Bulk add items (enhanced with subtask support)
|
|
102
|
+
7. **batch_remove_items** - Bulk remove items
|
|
103
|
+
8. **add_subtask** - Dedicated subtask creation (NEW)
|
|
104
|
+
9. **get_task_by_id** - Query task information (NEW)
|
|
105
|
+
|
|
106
|
+
## 📋 Requirements
|
|
107
|
+
|
|
108
|
+
- **macOS** - OmniFocus is macOS-only
|
|
109
|
+
- **OmniFocus 3+** - The application must be installed and running
|
|
110
|
+
- **Node.js 18+** - For running the MCP server
|
|
111
|
+
- **Claude Code** - For MCP integration
|
|
112
|
+
|
|
113
|
+
## 🔧 Usage with Claude Code
|
|
114
|
+
|
|
115
|
+
After installation, you can use the enhanced features in Claude Code:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Create a subtask
|
|
119
|
+
add_subtask {
|
|
120
|
+
"name": "Design landing page mockup",
|
|
121
|
+
"parentTaskName": "Website Redesign",
|
|
122
|
+
"dueDate": "2025-01-20",
|
|
123
|
+
"tags": ["Design", "Web"]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Get task details
|
|
127
|
+
get_task_by_id {
|
|
128
|
+
"taskName": "Website Redesign"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Batch create with subtasks
|
|
132
|
+
batch_add_items {
|
|
133
|
+
"items": [
|
|
134
|
+
{
|
|
135
|
+
"type": "task",
|
|
136
|
+
"name": "Content Strategy",
|
|
137
|
+
"projectName": "Marketing Campaign"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "task",
|
|
141
|
+
"name": "Keyword Research",
|
|
142
|
+
"parentTaskName": "Content Strategy"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## 📖 Documentation
|
|
149
|
+
|
|
150
|
+
For detailed usage instructions, see [CLAUDE.md](./CLAUDE.md).
|
|
151
|
+
|
|
152
|
+
## 🤝 Contributing
|
|
153
|
+
|
|
154
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
155
|
+
|
|
156
|
+
## 📄 License
|
|
157
|
+
|
|
158
|
+
MIT License - see LICENSE file for details.
|
|
159
|
+
|
|
160
|
+
## 🔗 Links
|
|
161
|
+
|
|
162
|
+
- [OmniFocus](https://www.omnigroup.com/omnifocus/)
|
|
163
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
164
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
165
|
+
|
|
166
|
+
## 🙏 Acknowledgments
|
|
167
|
+
|
|
168
|
+
Based on the original OmniFocus MCP server by [themotionmachine](https://github.com/themotionmachine/omnifocus-mcp-server).
|
|
Binary file
|
package/cli.cjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// cli.cjs
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const childProcess = require('child_process');
|
|
5
|
+
|
|
6
|
+
const serverPath = path.join(__dirname, 'dist', 'server.js');
|
|
7
|
+
childProcess.spawn('node', ['--experimental-modules', serverPath], {
|
|
8
|
+
stdio: 'inherit'
|
|
9
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Core enums
|
|
2
|
+
export var Task;
|
|
3
|
+
(function (Task) {
|
|
4
|
+
let Status;
|
|
5
|
+
(function (Status) {
|
|
6
|
+
Status[Status["Available"] = 0] = "Available";
|
|
7
|
+
Status[Status["Blocked"] = 1] = "Blocked";
|
|
8
|
+
Status[Status["Completed"] = 2] = "Completed";
|
|
9
|
+
Status[Status["Dropped"] = 3] = "Dropped";
|
|
10
|
+
Status[Status["DueSoon"] = 4] = "DueSoon";
|
|
11
|
+
Status[Status["Next"] = 5] = "Next";
|
|
12
|
+
Status[Status["Overdue"] = 6] = "Overdue";
|
|
13
|
+
})(Status = Task.Status || (Task.Status = {}));
|
|
14
|
+
let RepetitionMethod;
|
|
15
|
+
(function (RepetitionMethod) {
|
|
16
|
+
RepetitionMethod[RepetitionMethod["DeferUntilDate"] = 0] = "DeferUntilDate";
|
|
17
|
+
RepetitionMethod[RepetitionMethod["DueDate"] = 1] = "DueDate";
|
|
18
|
+
RepetitionMethod[RepetitionMethod["Fixed"] = 2] = "Fixed";
|
|
19
|
+
RepetitionMethod[RepetitionMethod["None"] = 3] = "None";
|
|
20
|
+
})(RepetitionMethod = Task.RepetitionMethod || (Task.RepetitionMethod = {}));
|
|
21
|
+
})(Task || (Task = {}));
|
|
22
|
+
export var Project;
|
|
23
|
+
(function (Project) {
|
|
24
|
+
let Status;
|
|
25
|
+
(function (Status) {
|
|
26
|
+
Status[Status["Active"] = 0] = "Active";
|
|
27
|
+
Status[Status["Done"] = 1] = "Done";
|
|
28
|
+
Status[Status["Dropped"] = 2] = "Dropped";
|
|
29
|
+
Status[Status["OnHold"] = 3] = "OnHold";
|
|
30
|
+
})(Status = Project.Status || (Project.Status = {}));
|
|
31
|
+
})(Project || (Project = {}));
|
|
32
|
+
export var Folder;
|
|
33
|
+
(function (Folder) {
|
|
34
|
+
let Status;
|
|
35
|
+
(function (Status) {
|
|
36
|
+
Status[Status["Active"] = 0] = "Active";
|
|
37
|
+
Status[Status["Dropped"] = 1] = "Dropped";
|
|
38
|
+
})(Status = Folder.Status || (Folder.Status = {}));
|
|
39
|
+
})(Folder || (Folder = {}));
|
|
40
|
+
export var Tag;
|
|
41
|
+
(function (Tag) {
|
|
42
|
+
let Status;
|
|
43
|
+
(function (Status) {
|
|
44
|
+
Status[Status["Active"] = 0] = "Active";
|
|
45
|
+
Status[Status["Dropped"] = 1] = "Dropped";
|
|
46
|
+
Status[Status["OnHold"] = 2] = "OnHold";
|
|
47
|
+
})(Status = Tag.Status || (Tag.Status = {}));
|
|
48
|
+
})(Tag || (Tag = {}));
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
// Import tool definitions
|
|
5
|
+
import * as dumpDatabaseTool from './tools/definitions/dumpDatabase.js';
|
|
6
|
+
import * as addOmniFocusTaskTool from './tools/definitions/addOmniFocusTask.js';
|
|
7
|
+
import * as addProjectTool from './tools/definitions/addProject.js';
|
|
8
|
+
import * as removeItemTool from './tools/definitions/removeItem.js';
|
|
9
|
+
import * as editItemTool from './tools/definitions/editItem.js';
|
|
10
|
+
import * as batchAddItemsTool from './tools/definitions/batchAddItems.js';
|
|
11
|
+
import * as batchRemoveItemsTool from './tools/definitions/batchRemoveItems.js';
|
|
12
|
+
import * as addSubtaskTool from './tools/definitions/addSubtask.js';
|
|
13
|
+
import * as getTaskByIdTool from './tools/definitions/getTaskById.js';
|
|
14
|
+
// Create an MCP server
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: "OmniFocus MCP",
|
|
17
|
+
version: "1.0.0"
|
|
18
|
+
});
|
|
19
|
+
// Register tools
|
|
20
|
+
server.tool("dump_database", "Gets the current state of your OmniFocus database", dumpDatabaseTool.schema.shape, dumpDatabaseTool.handler);
|
|
21
|
+
server.tool("add_omnifocus_task", "Add a new task to OmniFocus", addOmniFocusTaskTool.schema.shape, addOmniFocusTaskTool.handler);
|
|
22
|
+
server.tool("add_project", "Add a new project to OmniFocus", addProjectTool.schema.shape, addProjectTool.handler);
|
|
23
|
+
server.tool("remove_item", "Remove a task or project from OmniFocus", removeItemTool.schema.shape, removeItemTool.handler);
|
|
24
|
+
server.tool("edit_item", "Edit a task or project in OmniFocus", editItemTool.schema.shape, editItemTool.handler);
|
|
25
|
+
server.tool("batch_add_items", "Add multiple tasks or projects to OmniFocus in a single operation", batchAddItemsTool.schema.shape, batchAddItemsTool.handler);
|
|
26
|
+
server.tool("batch_remove_items", "Remove multiple tasks or projects from OmniFocus in a single operation", batchRemoveItemsTool.schema.shape, batchRemoveItemsTool.handler);
|
|
27
|
+
server.tool("add_subtask", "Add a new subtask to an existing task in OmniFocus", addSubtaskTool.schema.shape, addSubtaskTool.handler);
|
|
28
|
+
server.tool("get_task_by_id", "Get information about a specific task by ID or name", getTaskByIdTool.schema.shape, getTaskByIdTool.handler);
|
|
29
|
+
// Start the MCP server
|
|
30
|
+
const transport = new StdioServerTransport();
|
|
31
|
+
// Use await with server.connect to ensure proper connection
|
|
32
|
+
(async function () {
|
|
33
|
+
try {
|
|
34
|
+
console.error("Starting MCP server...");
|
|
35
|
+
await server.connect(transport);
|
|
36
|
+
console.error("MCP Server connected and ready to accept commands from Claude");
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error(`Failed to start MCP server: ${err}`);
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
// For a cleaner shutdown if the process is terminated
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { addOmniFocusTask } from '../primitives/addOmniFocusTask.js';
|
|
3
|
+
export const schema = z.object({
|
|
4
|
+
name: z.string().describe("The name of the task"),
|
|
5
|
+
note: z.string().optional().describe("Additional notes for the task"),
|
|
6
|
+
dueDate: z.string().optional().describe("The due date of the task in ISO format (YYYY-MM-DD or full ISO date)"),
|
|
7
|
+
deferDate: z.string().optional().describe("The defer date of the task in ISO format (YYYY-MM-DD or full ISO date)"),
|
|
8
|
+
flagged: z.boolean().optional().describe("Whether the task is flagged or not"),
|
|
9
|
+
estimatedMinutes: z.number().optional().describe("Estimated time to complete the task, in minutes"),
|
|
10
|
+
tags: z.array(z.string()).optional().describe("Tags to assign to the task"),
|
|
11
|
+
projectName: z.string().optional().describe("The name of the project to add the task to (will add to inbox if not specified)"),
|
|
12
|
+
parentTaskId: z.string().optional().describe("The ID of the parent task to create this task as a subtask"),
|
|
13
|
+
parentTaskName: z.string().optional().describe("The name of the parent task to create this task as a subtask (alternative to parentTaskId)")
|
|
14
|
+
});
|
|
15
|
+
export async function handler(args, extra) {
|
|
16
|
+
try {
|
|
17
|
+
// Call the addOmniFocusTask function
|
|
18
|
+
const result = await addOmniFocusTask(args);
|
|
19
|
+
if (result.success) {
|
|
20
|
+
// Task was added successfully
|
|
21
|
+
let locationText;
|
|
22
|
+
if (args.parentTaskId || args.parentTaskName) {
|
|
23
|
+
const parentRef = args.parentTaskId || args.parentTaskName;
|
|
24
|
+
locationText = `as a subtask of "${parentRef}"`;
|
|
25
|
+
}
|
|
26
|
+
else if (args.projectName) {
|
|
27
|
+
locationText = `in project "${args.projectName}"`;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
locationText = "in your inbox";
|
|
31
|
+
}
|
|
32
|
+
let tagText = args.tags && args.tags.length > 0
|
|
33
|
+
? ` with tags: ${args.tags.join(', ')}`
|
|
34
|
+
: "";
|
|
35
|
+
let dueDateText = args.dueDate
|
|
36
|
+
? ` due on ${new Date(args.dueDate).toLocaleDateString()}`
|
|
37
|
+
: "";
|
|
38
|
+
return {
|
|
39
|
+
content: [{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: `✅ Task "${args.name}" created successfully ${locationText}${dueDateText}${tagText}.`
|
|
42
|
+
}]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Task creation failed
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: `Failed to create task: ${result.error}`
|
|
51
|
+
}],
|
|
52
|
+
isError: true
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const error = err;
|
|
58
|
+
console.error(`Tool execution error: ${error.message}`);
|
|
59
|
+
return {
|
|
60
|
+
content: [{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: `Error creating task: ${error.message}`
|
|
63
|
+
}],
|
|
64
|
+
isError: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { addProject } from '../primitives/addProject.js';
|
|
3
|
+
export const schema = z.object({
|
|
4
|
+
name: z.string().describe("The name of the project"),
|
|
5
|
+
note: z.string().optional().describe("Additional notes for the project"),
|
|
6
|
+
dueDate: z.string().optional().describe("The due date of the project in ISO format (YYYY-MM-DD or full ISO date)"),
|
|
7
|
+
deferDate: z.string().optional().describe("The defer date of the project in ISO format (YYYY-MM-DD or full ISO date)"),
|
|
8
|
+
flagged: z.boolean().optional().describe("Whether the project is flagged or not"),
|
|
9
|
+
estimatedMinutes: z.number().optional().describe("Estimated time to complete the project, in minutes"),
|
|
10
|
+
tags: z.array(z.string()).optional().describe("Tags to assign to the project"),
|
|
11
|
+
folderName: z.string().optional().describe("The name of the folder to add the project to (will add to root if not specified)"),
|
|
12
|
+
sequential: z.boolean().optional().describe("Whether tasks in the project should be sequential (default: false)")
|
|
13
|
+
});
|
|
14
|
+
export async function handler(args, extra) {
|
|
15
|
+
try {
|
|
16
|
+
// Call the addProject function
|
|
17
|
+
const result = await addProject(args);
|
|
18
|
+
if (result.success) {
|
|
19
|
+
// Project was added successfully
|
|
20
|
+
let locationText = args.folderName
|
|
21
|
+
? `in folder "${args.folderName}"`
|
|
22
|
+
: "at the root level";
|
|
23
|
+
let tagText = args.tags && args.tags.length > 0
|
|
24
|
+
? ` with tags: ${args.tags.join(', ')}`
|
|
25
|
+
: "";
|
|
26
|
+
let dueDateText = args.dueDate
|
|
27
|
+
? ` due on ${new Date(args.dueDate).toLocaleDateString()}`
|
|
28
|
+
: "";
|
|
29
|
+
let sequentialText = args.sequential
|
|
30
|
+
? " (sequential)"
|
|
31
|
+
: " (parallel)";
|
|
32
|
+
return {
|
|
33
|
+
content: [{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: `✅ Project "${args.name}" created successfully ${locationText}${dueDateText}${tagText}${sequentialText}.`
|
|
36
|
+
}]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Project creation failed
|
|
41
|
+
return {
|
|
42
|
+
content: [{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `Failed to create project: ${result.error}`
|
|
45
|
+
}],
|
|
46
|
+
isError: true
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const error = err;
|
|
52
|
+
console.error(`Tool execution error: ${error.message}`);
|
|
53
|
+
return {
|
|
54
|
+
content: [{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: `Error creating project: ${error.message}`
|
|
57
|
+
}],
|
|
58
|
+
isError: true
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|