@torsday/omnifocus-mcp 1.2.2 → 1.5.3
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/CHANGELOG.md +226 -0
- package/README.md +30 -727
- package/dist/index.js +1421 -759
- package/package.json +17 -8
package/README.md
CHANGED
|
@@ -17,19 +17,9 @@
|
|
|
17
17
|
- [Why this exists](#why-this-exists)
|
|
18
18
|
- [Quick start](#quick-start)
|
|
19
19
|
- [Security & trust](#security--trust)
|
|
20
|
-
- [Example interactions](#example-interactions)
|
|
21
|
-
- [Prompts](#prompts)
|
|
22
|
-
- [If you are an AI agent](#if-you-are-an-ai-agent)
|
|
23
|
-
- [Tools](#tools)
|
|
24
|
-
- [Resources](#resources)
|
|
25
|
-
- [Transport text DSL](#transport-text-dsl)
|
|
26
20
|
- [Architecture at a glance](#architecture-at-a-glance)
|
|
27
21
|
- [Status and roadmap](#status-and-roadmap)
|
|
28
|
-
- [
|
|
29
|
-
- [Environment variables](#environment-variables)
|
|
30
|
-
- [Troubleshooting](#troubleshooting)
|
|
31
|
-
- [Client setup guides](#client-setup-guides)
|
|
32
|
-
- [Design documents](#design-documents)
|
|
22
|
+
- [Reference docs](#reference-docs)
|
|
33
23
|
- [Contributing](#contributing)
|
|
34
24
|
- [License](#license)
|
|
35
25
|
|
|
@@ -68,10 +58,14 @@ OmniFocus is a powerful GTD tool, but it's an island. Your tasks sit there while
|
|
|
68
58
|
|
|
69
59
|
The server is built to a single-user local-first standard: no network surface, no cloud sync, typed errors with agent-readable remediation hints, safe by default.
|
|
70
60
|
|
|
61
|
+
See [`docs/examples.md`](./docs/examples.md) for concrete prompt-to-tool-call sequences and [`docs/prompts.md`](./docs/prompts.md) for the bundled MCP prompt templates (`daily-review`, `weekly-review`, `capture-meeting`, `project-planning`).
|
|
62
|
+
|
|
71
63
|
---
|
|
72
64
|
|
|
73
65
|
## Quick start
|
|
74
66
|
|
|
67
|
+
**Prerequisites:** macOS 13 (Ventura) or later · OmniFocus 3.x or 4.x (4.x recommended; some tools require 4.x — see [version compatibility](./docs/troubleshooting.md#omnifocus-version-compatibility)) · Node 24+ (not required for Homebrew install)
|
|
68
|
+
|
|
75
69
|
1. **Install**
|
|
76
70
|
```bash
|
|
77
71
|
# Homebrew (no Node required)
|
|
@@ -89,7 +83,7 @@ The server is built to a single-user local-first standard: no network surface, n
|
|
|
89
83
|
env: OMNIFOCUS_LOG_LEVEL=info # optional; "debug" is verbose
|
|
90
84
|
```
|
|
91
85
|
|
|
92
|
-
|
|
86
|
+
Two common cases inline; full per-client guides at [`docs/clients/`](./docs/clients/) (Claude Code, Claude Desktop, Codex, OpenCode, Pi, generic stdio).
|
|
93
87
|
|
|
94
88
|
<details>
|
|
95
89
|
<summary><strong>Claude Code</strong> (CLI; no file edit)</summary>
|
|
@@ -97,8 +91,7 @@ The server is built to a single-user local-first standard: no network surface, n
|
|
|
97
91
|
```bash
|
|
98
92
|
claude mcp add omnifocus omnifocus-mcp
|
|
99
93
|
```
|
|
100
|
-
|
|
101
|
-
Detailed guide: [`docs/clients/claude-code.md`](./docs/clients/claude-code.md)
|
|
94
|
+
Detailed: [`docs/clients/claude-code.md`](./docs/clients/claude-code.md)
|
|
102
95
|
</details>
|
|
103
96
|
|
|
104
97
|
<details>
|
|
@@ -115,98 +108,14 @@ The server is built to a single-user local-first standard: no network surface, n
|
|
|
115
108
|
}
|
|
116
109
|
}
|
|
117
110
|
```
|
|
118
|
-
|
|
119
|
-
Detailed guide: [`docs/clients/claude-desktop.md`](./docs/clients/claude-desktop.md)
|
|
120
|
-
</details>
|
|
121
|
-
|
|
122
|
-
<details>
|
|
123
|
-
<summary><strong>Cline</strong> (VS Code extension) — extension settings (JSON)</summary>
|
|
124
|
-
|
|
125
|
-
In VS Code, open the Cline extension's MCP settings panel and add:
|
|
126
|
-
|
|
127
|
-
```json
|
|
128
|
-
{
|
|
129
|
-
"mcpServers": {
|
|
130
|
-
"omnifocus": {
|
|
131
|
-
"command": "omnifocus-mcp",
|
|
132
|
-
"args": [],
|
|
133
|
-
"env": { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Cline's settings UI may surface the same fields as labelled inputs rather than raw JSON; the values are identical. Verify the panel location against the current Cline docs.
|
|
140
|
-
</details>
|
|
141
|
-
|
|
142
|
-
<details>
|
|
143
|
-
<summary><strong>OpenAI Codex CLI</strong> — <code>~/.codex/config.toml</code> (TOML)</summary>
|
|
144
|
-
|
|
145
|
-
```toml
|
|
146
|
-
[mcp_servers.omnifocus]
|
|
147
|
-
command = "omnifocus-mcp"
|
|
148
|
-
args = []
|
|
149
|
-
env = { OMNIFOCUS_LOG_LEVEL = "info" }
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Detailed guide: [`docs/clients/codex.md`](./docs/clients/codex.md)
|
|
153
|
-
</details>
|
|
154
|
-
|
|
155
|
-
<details>
|
|
156
|
-
<summary><strong>Cursor</strong> — <code>~/.cursor/mcp.json</code> (JSON)</summary>
|
|
157
|
-
|
|
158
|
-
```json
|
|
159
|
-
{
|
|
160
|
-
"mcpServers": {
|
|
161
|
-
"omnifocus": {
|
|
162
|
-
"command": "omnifocus-mcp",
|
|
163
|
-
"args": [],
|
|
164
|
-
"env": { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Verify the path against the current Cursor docs — recent versions also accept project-scoped `.cursor/mcp.json` at the repo root.
|
|
171
|
-
</details>
|
|
172
|
-
|
|
173
|
-
<details>
|
|
174
|
-
<summary><strong>Windsurf</strong> — <code>~/.codeium/windsurf/mcp_config.json</code> (JSON)</summary>
|
|
175
|
-
|
|
176
|
-
```json
|
|
177
|
-
{
|
|
178
|
-
"mcpServers": {
|
|
179
|
-
"omnifocus": {
|
|
180
|
-
"command": "omnifocus-mcp",
|
|
181
|
-
"args": [],
|
|
182
|
-
"env": { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Verify the path against the current Windsurf docs — Codeium occasionally relocates config under `~/.codeium/`.
|
|
189
|
-
</details>
|
|
190
|
-
|
|
191
|
-
<details>
|
|
192
|
-
<summary><strong>Generic stdio client</strong> (anything else that speaks MCP/stdio)</summary>
|
|
193
|
-
|
|
194
|
-
Use your client's MCP config form. The shape is:
|
|
195
|
-
|
|
196
|
-
```text
|
|
197
|
-
command: "omnifocus-mcp"
|
|
198
|
-
args: []
|
|
199
|
-
env: { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Detailed guide: [`docs/clients/generic-stdio.md`](./docs/clients/generic-stdio.md)
|
|
111
|
+
Detailed: [`docs/clients/claude-desktop.md`](./docs/clients/claude-desktop.md)
|
|
203
112
|
</details>
|
|
204
113
|
|
|
205
114
|
3. **Grant macOS Automation permission** on first use — the app running the MCP server will prompt to control OmniFocus; click **OK**. If denied by mistake: **System Settings → Privacy & Security → Automation → [app] → OmniFocus** ✓
|
|
206
115
|
|
|
207
116
|
4. **Verify** — ask your assistant: *"Use the internal_status tool and tell me what it returns."*
|
|
208
117
|
|
|
209
|
-
|
|
118
|
+
Stuck? See [`docs/troubleshooting.md`](./docs/troubleshooting.md).
|
|
210
119
|
|
|
211
120
|
---
|
|
212
121
|
|
|
@@ -214,8 +123,6 @@ Detailed per-client guides: [`docs/clients/`](./docs/clients/)
|
|
|
214
123
|
|
|
215
124
|
`omnifocus-mcp` is a **local-only** Node.js process that drives a **local** OmniFocus app via Apple's `osascript` runtime. Installing this package does not introduce cloud connectivity, telemetry, or network egress that wasn't already on your machine.
|
|
216
125
|
|
|
217
|
-
### Data flow
|
|
218
|
-
|
|
219
126
|
```
|
|
220
127
|
OmniFocus DB (local) ─→ JXA / OmniJS via osascript (local) ─→ MCP server (local stdio)
|
|
221
128
|
│
|
|
@@ -272,443 +179,7 @@ Three recipes that take seconds; you don't have to take this README's word for a
|
|
|
272
179
|
|
|
273
180
|
The threat model deliberately excludes anything outside this codebase: vulnerabilities in OmniFocus itself, Apple's JXA / OmniJS / `osascript` runtimes, transitive npm-dependency CVEs (track and patch via `npm audit` / Dependabot, but not part of this project's guarantees), and any attacker with root-equivalent local access (who could replace `osascript`, the MCP server binary, or your shell). See [SECURITY.md § Scope](./SECURITY.md#scope).
|
|
274
181
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
- [`SECURITY.md`](./SECURITY.md) — vulnerability reporting, scope
|
|
278
|
-
- [`DESIGN.md` § 18 Security posture](./DESIGN.md#18-security-posture) — full threat model
|
|
279
|
-
- [ADR-0004](./docs/adr/0004-raw-script-escape-hatch.md) — raw-script gating decision
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## Example interactions
|
|
284
|
-
|
|
285
|
-
**"What's in my inbox right now?"**
|
|
286
|
-
|
|
287
|
-
The assistant calls `task_list` with `{ "available": true, "limit": 20 }` and returns a formatted list of actionable inbox tasks with their IDs, due dates, and flags.
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
**"Create a task to 'review Q2 budget' due Friday, flagged, in the Finance project."**
|
|
292
|
-
|
|
293
|
-
1. Calls `project_list` to find the Finance project ID.
|
|
294
|
-
2. Calls `task_create` with `{ "name": "review Q2 budget", "projectId": "<id>", "dueDate": "end-of-week", "flagged": true }`.
|
|
295
|
-
3. Returns the created task with its persistent ID and confirms the due date resolved to the correct Friday.
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
**"Mark all my overdue tasks as deferred to tomorrow."**
|
|
300
|
-
|
|
301
|
-
1. Calls `task_list` with `{ "dueBefore": "today", "available": true }` to find overdue items.
|
|
302
|
-
2. Calls `task_batch_update` with `{ "deferDate": "tomorrow" }` for all of them in one atomic call.
|
|
303
|
-
3. Reports: *"Deferred 7 overdue tasks to tomorrow. Call sync_trigger if you want iCloud to update immediately."*
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
**"Show me what's due this week in the Work perspective."**
|
|
308
|
-
|
|
309
|
-
1. Calls `perspective_list` to find the "Work" perspective ID.
|
|
310
|
-
2. Calls `perspective_evaluate` with `{ "perspectiveId": "<id>" }` to get tasks in that perspective.
|
|
311
|
-
3. Filters and presents items with due dates within the current week.
|
|
312
|
-
|
|
313
|
-
---
|
|
314
|
-
|
|
315
|
-
**"I just finished the sprint — complete all tasks in the Mobile App project."**
|
|
316
|
-
|
|
317
|
-
1. Calls `project_get` to retrieve the project and its tasks.
|
|
318
|
-
2. Calls `task_batch_complete` with the full list of task IDs in one call.
|
|
319
|
-
3. Confirms the count and suggests calling `sync_trigger` for cross-device visibility.
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## Prompts
|
|
324
|
-
|
|
325
|
-
`omnifocus-mcp` ships four **MCP prompt templates** — structured workflows you can invoke by name from any MCP client that surfaces `prompts/list` (most clients with a prompt picker UI).
|
|
326
|
-
|
|
327
|
-
### `daily-review` — triage your day
|
|
328
|
-
|
|
329
|
-
Loads your snapshot, overdue tasks, and today's forecast; reschedules or drops overdue items; confirms due-today tasks; processes the inbox. No parameters needed.
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
Use the daily-review prompt
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### `weekly-review` — walk your projects
|
|
336
|
-
|
|
337
|
-
Loads every project whose review date has arrived; checks each one for stale tasks; marks it reviewed or completes/drops it. No parameters needed.
|
|
338
|
-
|
|
339
|
-
```
|
|
340
|
-
Use the weekly-review prompt
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### `capture-meeting` — extract action items
|
|
344
|
-
|
|
345
|
-
Takes raw meeting notes and creates OmniFocus tasks for every commitment, follow-up, and decision point. Pass the notes as text and optionally a project ID.
|
|
346
|
-
|
|
347
|
-
```
|
|
348
|
-
Use the capture-meeting prompt with notes="Sync with Alice: she'll send the report by Thursday.
|
|
349
|
-
Bob to review the contract. Need to schedule follow-up call."
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
Results in two inbox tasks: "Send report to [person]" and "Review contract" with the source sentences as notes.
|
|
353
|
-
|
|
354
|
-
### `project-planning` — decompose a brief
|
|
355
|
-
|
|
356
|
-
Creates a new project and populates it with a set of concrete, ordered, one-day tasks derived from a free-text brief.
|
|
357
|
-
|
|
358
|
-
```
|
|
359
|
-
Use the project-planning prompt with name="Q3 Marketing Site" brief="Redesign the marketing
|
|
360
|
-
site landing page and pricing page. New brand colors, updated copy, responsive mobile layout.
|
|
361
|
-
Launch by end of July."
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
Results in a new OmniFocus project with 8–12 tasks covering design, copy, development, and review phases, ready to schedule and assign.
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
## If you are an AI agent
|
|
369
|
-
|
|
370
|
-
This section is written for you. It covers the conventions you need to use this MCP effectively without trial and error.
|
|
371
|
-
|
|
372
|
-
### IDs, not names
|
|
373
|
-
|
|
374
|
-
Every OmniFocus resource — tasks, projects, tags, folders — is identified by a **persistent opaque ID** (e.g. `"hKx9vLmNp2"`). Names collide and change; IDs don't. Always resolve names to IDs with the corresponding `*_list` tool before calling any other tool.
|
|
375
|
-
|
|
376
|
-
### Error codes and what to do next
|
|
377
|
-
|
|
378
|
-
Every error carries a stable `code`, a human-readable `suggestion`, and a machine-readable `remediationClass`:
|
|
379
|
-
|
|
380
|
-
| `remediationClass` | Meaning | Your action |
|
|
381
|
-
|--------------------|---------|-------------|
|
|
382
|
-
| `environment` | OmniFocus is not running, permissions denied, or a Pro/version feature is missing | Stop. Surface `suggestion` to the user; do not retry automatically |
|
|
383
|
-
| `input` | Bad ID, invalid field value, schema violation, or loop detected | Fix the input using `details` for specifics; retry |
|
|
384
|
-
| `transient` | Timeout, rate limit, queue full, or circuit open | Wait `details.retryAfterMs` ms, then retry once |
|
|
385
|
-
| `infrastructure` | JXA or OmniJS script failed | Retry once; if still failing, surface to user |
|
|
386
|
-
| `lifecycle` | Server is shutting down | Reconnect to a fresh server instance |
|
|
387
|
-
|
|
388
|
-
`RateLimited` and `CircuitOpen` always include `details.retryAfterMs` (default `60000` ms). Do not poll faster than that.
|
|
389
|
-
|
|
390
|
-
### Dates
|
|
391
|
-
|
|
392
|
-
All date inputs accept either **ISO-8601 with UTC offset** (`"2026-04-22T09:00:00-07:00"`) or a **relative shortcut**:
|
|
393
|
-
|
|
394
|
-
`today` · `tomorrow` · `yesterday` · `this-week` · `next-week` · `end-of-week` · `end-of-month`
|
|
395
|
-
|
|
396
|
-
Shortcuts resolve to midnight in the server's local timezone.
|
|
397
|
-
|
|
398
|
-
### Mutations and sync
|
|
399
|
-
|
|
400
|
-
Every write tool returns the full updated domain object, not just an acknowledgement. The response `meta.syncPending` is `true` immediately after a write — OmniFocus has saved locally but not yet synced to iCloud. Call `sync_trigger` if cross-device visibility matters; otherwise sync happens automatically within a few minutes.
|
|
401
|
-
|
|
402
|
-
### Null consistency
|
|
403
|
-
|
|
404
|
-
All optional scalar fields are **always present** in responses, set to `null` when unset. You can safely destructure without null-checks on field presence.
|
|
405
|
-
|
|
406
|
-
### Idempotency — safe retries
|
|
407
|
-
|
|
408
|
-
`project_create`, `project_update`, and `project_delete` accept an optional `idempotency_key?: string`. If you supply one and the call succeeds, replaying the exact same key within 5 minutes returns the cached result with `meta.idempotentReplay: true` and skips the OmniFocus call. Use a deterministic key scoped to your session and intent (e.g. `"session-abc/create-project-finance"`).
|
|
409
|
-
|
|
410
|
-
### Dry-run — validate before committing
|
|
411
|
-
|
|
412
|
-
`task_update` and `project_update` accept `dry_run?: boolean`. When `true`, input is fully validated and the would-be result is returned, but nothing is written to OmniFocus. `meta.dryRun: true` is set on the response.
|
|
413
|
-
|
|
414
|
-
### Additive tag edits — no read-modify-write needed
|
|
415
|
-
|
|
416
|
-
`task_update` accepts `addTags`, `removeTags`, and `setFlagged` patch fields alongside the existing full-replacement `tagIds` field. Prefer these for incremental edits — they apply a diff atomically inside the write queue with no race against concurrent user edits.
|
|
417
|
-
|
|
418
|
-
### Conflict detection — optimistic concurrency
|
|
419
|
-
|
|
420
|
-
`task_update` accepts `expectedModifiedAt`. If the task was modified since your read, the server returns `OF_CONFLICT` (`remediationClass: "input"`). Re-read with `task_get`, merge your changes, and retry with the fresh `modifiedAt`.
|
|
421
|
-
|
|
422
|
-
### Loop detection — don't get stuck
|
|
423
|
-
|
|
424
|
-
If you call the same tool with identical arguments 5+ times in a 60-second window, the server appends `WARN_LOOP_DETECTED` to `meta.warnings`. At 10 repetitions it throws `OF_LOOP_DETECTED` (`remediationClass: "input"`). Act on the result of your previous call rather than repeating it.
|
|
425
|
-
|
|
426
|
-
### Capabilities pre-flight
|
|
427
|
-
|
|
428
|
-
Read `omnifocus://capabilities` once at session start. It returns OF version, edition (Standard/Pro), transport availability, and feature flags (`customPerspectives`, `forecastTag`, `rawScriptTools`). Use it to skip Pro-gated tools rather than discovering unavailability via error.
|
|
429
|
-
|
|
430
|
-
### Rate limit state — self-throttle before hitting the wall
|
|
431
|
-
|
|
432
|
-
Every response includes `meta.rateLimit?: { remaining: number; resetAt: string }`. Check this after each call. If `remaining < 10`, slow down. If `remaining === 0`, do not call before `meta.rateLimit.resetAt`. The default limit is 120 calls/min per tool.
|
|
433
|
-
|
|
434
|
-
### Structured warnings — act on `meta.warnings[].code`
|
|
435
|
-
|
|
436
|
-
Non-fatal issues appear in `meta.warnings` as `{ code, message, suggestion?, details? }`. Switch on `code`, not `message`:
|
|
437
|
-
|
|
438
|
-
| `code` | Means | Action |
|
|
439
|
-
|---|---|---|
|
|
440
|
-
| `WARN_IDS_NOT_FOUND` | Some IDs in a bulk call were not found | Check `details.missing` |
|
|
441
|
-
| `WARN_RESULT_TRUNCATED` | Response hit size limit; more items exist | Follow pagination cursor |
|
|
442
|
-
| `WARN_SYNC_PENDING` | Write saved locally; iCloud sync not yet triggered | Call `sync_trigger` if needed |
|
|
443
|
-
| `WARN_LOOP_DETECTED` | Same tool+args called ≥5 times in 60s | Act on previous result before repeating |
|
|
444
|
-
|
|
445
|
-
### Incremental sync — `updatedSince`
|
|
446
|
-
|
|
447
|
-
`task_list` accepts `updatedSince?: string` (ISO-8601 or relative shortcut). Use it to fetch only changed items after your initial load:
|
|
448
|
-
|
|
449
|
-
```jsonc
|
|
450
|
-
// First call: full load
|
|
451
|
-
{ "available": true, "limit": 200 }
|
|
452
|
-
|
|
453
|
-
// Subsequent calls: only changes
|
|
454
|
-
{ "available": true, "updatedSince": "2026-04-21T10:00:00-07:00", "limit": 200 }
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
Note: deleted items cannot be surfaced via `updatedSince` — compare `meta.snapshot` counts if you need to detect deletions.
|
|
458
|
-
|
|
459
|
-
### Navigation hints — follow `_links`
|
|
460
|
-
|
|
461
|
-
Every `Task` response includes `_links` with resource URIs for related objects:
|
|
462
|
-
|
|
463
|
-
```jsonc
|
|
464
|
-
{
|
|
465
|
-
"id": "hKx9vLmNp2",
|
|
466
|
-
"_links": {
|
|
467
|
-
"self": "omnifocus://task/hKx9vLmNp2",
|
|
468
|
-
"project": "omnifocus://project/pXY3",
|
|
469
|
-
"tags": ["omnifocus://tag/tABC"]
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
Pass the ID fragment to `task_get`, `project_get`, etc. You never need to construct a URI manually.
|
|
475
|
-
|
|
476
|
-
### Response envelope
|
|
477
|
-
|
|
478
|
-
All responses have this shape:
|
|
479
|
-
|
|
480
|
-
```jsonc
|
|
481
|
-
// success
|
|
482
|
-
{ "data": { … }, "meta": { "correlationId": "…", "durationMs": 12, "cacheHit": false, "transport": "jxa", "syncPending": false } }
|
|
483
|
-
|
|
484
|
-
// error
|
|
485
|
-
{ "error": { "code": "OF_NOT_FOUND", "remediationClass": "input", "message": "…", "suggestion": "…", "details": { … } }, "meta": { … } }
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
### Where to start
|
|
489
|
-
|
|
490
|
-
- **Daily work**: `task_list` (inbox or today filter) → `task_create` / `task_update` / `task_complete`
|
|
491
|
-
- **Projects**: `project_list` → `project_create` / `project_update`
|
|
492
|
-
- **Finding things**: `task_search` (keyword + optional tag/project/date filters); `tag_list` for available tags
|
|
493
|
-
- **Bulk ops**: `task_batch_create` / `task_batch_update` / `task_batch_complete` for up to 50 items atomically
|
|
494
|
-
- **Sync**: `sync_trigger` after bulk mutations; `internal_status` to check server health
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## Tools
|
|
499
|
-
|
|
500
|
-
Tools are organized by domain — tasks, projects, tags, folders, perspectives, forecast, review, search, notes, attachments, sync, export, and observability. See [`docs/tools.md`](./docs/tools.md) for the full auto-generated reference with the live registered count, input schemas, example calls, and example responses.
|
|
501
|
-
|
|
502
|
-
### App lifecycle
|
|
503
|
-
| Tool | Description |
|
|
504
|
-
|---|---|
|
|
505
|
-
| `app_launch` | Explicitly launch OmniFocus (idempotent) |
|
|
506
|
-
|
|
507
|
-
### Tasks
|
|
508
|
-
| Tool | Description |
|
|
509
|
-
|---|---|
|
|
510
|
-
| `task_list` | List tasks with filters (available, flagged, due, project, tag, updatedSince) |
|
|
511
|
-
| `task_get` | Get a single task by ID |
|
|
512
|
-
| `task_get_many` | Get multiple tasks by ID in one call |
|
|
513
|
-
| `task_create` | Create a task (project, tags, due, defer, flag, note, repeat) |
|
|
514
|
-
| `task_update` | Update a task (addTags/removeTags, dry_run, expectedModifiedAt) |
|
|
515
|
-
| `task_complete` | Mark a task complete |
|
|
516
|
-
| `task_uncomplete` | Unmark a completed task |
|
|
517
|
-
| `task_delete` | Delete a task |
|
|
518
|
-
| `task_drop` | Drop (defer indefinitely) a task |
|
|
519
|
-
| `task_undrop` | Restore a dropped task |
|
|
520
|
-
| `task_move` | Reparent a task to a different project or parent task |
|
|
521
|
-
| `task_reorder` | Reorder a task among its siblings |
|
|
522
|
-
| `task_duplicate` | Duplicate a task (optionally recursive) |
|
|
523
|
-
| `task_find_by_name` | Find tasks by exact or fuzzy name match |
|
|
524
|
-
| `task_search` | Full-text search across task names and notes, with optional tag/project/date/availability filters |
|
|
525
|
-
| `task_set_repetition` | Set a repeat rule on a task |
|
|
526
|
-
| `task_clear_repetition` | Remove a repeat rule from a task |
|
|
527
|
-
| `task_parse_transport_text` | Parse transport text DSL → structured tasks (no side effects) |
|
|
528
|
-
| `task_batch_create` | Create up to 50 tasks atomically |
|
|
529
|
-
| `task_batch_update` | Update up to 50 tasks atomically |
|
|
530
|
-
| `task_batch_complete` | Complete up to 50 tasks atomically |
|
|
531
|
-
|
|
532
|
-
### Projects
|
|
533
|
-
| Tool | Description |
|
|
534
|
-
|---|---|
|
|
535
|
-
| `project_list` | List projects with filters (folder, status) |
|
|
536
|
-
| `project_get` | Get a single project by ID |
|
|
537
|
-
| `project_create` | Create a project (idempotency_key supported) |
|
|
538
|
-
| `project_update` | Update a project (dry_run, idempotency_key, expectedModifiedAt) |
|
|
539
|
-
| `project_complete` | Mark a project complete |
|
|
540
|
-
| `project_delete` | Delete a project (idempotency_key supported) |
|
|
541
|
-
| `project_drop` | Drop (defer indefinitely) a project |
|
|
542
|
-
| `project_move` | Move a project to a different folder |
|
|
543
|
-
| `project_mark_reviewed` | Mark a project as reviewed (alias for review_mark_reviewed) |
|
|
544
|
-
|
|
545
|
-
### Folders
|
|
546
|
-
| Tool | Description |
|
|
547
|
-
|---|---|
|
|
548
|
-
| `folder_list` | List folders |
|
|
549
|
-
| `folder_get` | Get a single folder by ID |
|
|
550
|
-
| `folder_create` | Create a folder |
|
|
551
|
-
| `folder_update` | Rename a folder |
|
|
552
|
-
| `folder_delete` | Delete a folder |
|
|
553
|
-
| `folder_move` | Move a folder to a parent folder |
|
|
554
|
-
|
|
555
|
-
### Tags
|
|
556
|
-
| Tool | Description |
|
|
557
|
-
|---|---|
|
|
558
|
-
| `tag_list` | List tags |
|
|
559
|
-
| `tag_get` | Get a single tag by ID |
|
|
560
|
-
| `tag_create` | Create a tag |
|
|
561
|
-
| `tag_update` | Rename a tag |
|
|
562
|
-
| `tag_delete` | Delete a tag |
|
|
563
|
-
| `tag_move` | Move a tag under a parent tag |
|
|
564
|
-
| `tag_set_status` | Set tag status (active/on-hold/dropped) |
|
|
565
|
-
| `tag_set_allows_next_action` | Toggle "allows next action" on a tag |
|
|
566
|
-
| `tag_get_location` | Get a tag's location in the hierarchy |
|
|
567
|
-
| `tag_set_location` | Set a tag's location in the hierarchy |
|
|
568
|
-
|
|
569
|
-
### Notes
|
|
570
|
-
| Tool | Description |
|
|
571
|
-
|---|---|
|
|
572
|
-
| `note_get` | Get a task or project note (plain text) |
|
|
573
|
-
| `note_get_html` | Get a task or project note (HTML) |
|
|
574
|
-
| `note_set` | Set a task or project note (plain text, replaces) |
|
|
575
|
-
| `note_set_html` | Set a task or project note (HTML, replaces) |
|
|
576
|
-
| `note_append` | Append text to a task or project note |
|
|
577
|
-
|
|
578
|
-
### Attachments
|
|
579
|
-
| Tool | Description |
|
|
580
|
-
|---|---|
|
|
581
|
-
| `attachment_list` | List attachments on a task or project |
|
|
582
|
-
| `attachment_add` | Embed a local file as an attachment |
|
|
583
|
-
| `attachment_remove` | Remove an attachment by ID |
|
|
584
|
-
| `attachment_save_to_path` | Save an attachment's bytes to a local file |
|
|
585
|
-
|
|
586
|
-
### Perspectives
|
|
587
|
-
| Tool | Description |
|
|
588
|
-
|---|---|
|
|
589
|
-
| `perspective_list` | List all perspectives (built-in and custom) |
|
|
590
|
-
| `perspective_evaluate` | Evaluate a perspective and return its tasks |
|
|
591
|
-
|
|
592
|
-
### Forecast & search
|
|
593
|
-
| Tool | Description |
|
|
594
|
-
|---|---|
|
|
595
|
-
| `forecast_get` | Get today's forecast grouped by overdue / due today / due later / inbox |
|
|
596
|
-
| `search_query` | Full-text search across tasks and projects |
|
|
597
|
-
|
|
598
|
-
### Review
|
|
599
|
-
| Tool | Description |
|
|
600
|
-
|---|---|
|
|
601
|
-
| `review_list_due` | List projects whose next review date is today or past |
|
|
602
|
-
| `review_mark_reviewed` | Mark a project as reviewed and set the next review date |
|
|
603
|
-
| `review_set_interval` | Set the review interval (days) for a project |
|
|
604
|
-
|
|
605
|
-
### Sync & app
|
|
606
|
-
| Tool | Description |
|
|
607
|
-
|---|---|
|
|
608
|
-
| `sync_trigger` | Trigger an OmniFocus iCloud sync |
|
|
609
|
-
| `sync_status` | Get the last sync timestamp and status |
|
|
610
|
-
|
|
611
|
-
### Plug-ins
|
|
612
|
-
| Tool | Description |
|
|
613
|
-
|---|---|
|
|
614
|
-
| `plugin_invoke` | Invoke an installed Omni Automation plug-in by bundle identifier |
|
|
615
|
-
|
|
616
|
-
### Export & import
|
|
617
|
-
| Tool | Description |
|
|
618
|
-
|---|---|
|
|
619
|
-
| `export_opml` | Export a project (or all projects) as OPML |
|
|
620
|
-
| `export_taskpaper` | Export a project (or all projects) as TaskPaper |
|
|
621
|
-
| `import_opml` | Import tasks from an OPML string into OmniFocus |
|
|
622
|
-
| `import_taskpaper` | Import tasks from a TaskPaper string into OmniFocus |
|
|
623
|
-
|
|
624
|
-
### Observability
|
|
625
|
-
| Tool | Description |
|
|
626
|
-
|---|---|
|
|
627
|
-
| `internal_status` | Server health: transport status, queue depths, cache stats, rate limits |
|
|
628
|
-
|
|
629
|
-
### Raw scripts _(opt-in, off by default)_
|
|
630
|
-
| Tool | Description |
|
|
631
|
-
|---|---|
|
|
632
|
-
| `run_jxa_script` | Execute arbitrary JXA — requires `OMNIFOCUS_ALLOW_RAW_SCRIPT=1` |
|
|
633
|
-
| `run_omnijs_script` | Execute arbitrary OmniJS — requires `OMNIFOCUS_ALLOW_RAW_SCRIPT=1` |
|
|
634
|
-
|
|
635
|
-
---
|
|
636
|
-
|
|
637
|
-
## Resources
|
|
638
|
-
|
|
639
|
-
The server registers resources under the `omnifocus://` scheme. Resources are read-only, URI-addressable, and enumerable via `resources/list`. Templated URIs follow [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570) and accept the listed parameters as query strings or path segments.
|
|
640
|
-
|
|
641
|
-
**Static URIs** — read with no parameters:
|
|
642
|
-
|
|
643
|
-
| URI | Returns |
|
|
644
|
-
|---|---|
|
|
645
|
-
| `omnifocus://capabilities` | Server capabilities: OF version, edition, transport status, feature flags, calendar-bridge availability |
|
|
646
|
-
| `omnifocus://snapshot` | Orientation counts: inbox, flagged, overdue, dueToday, reviewDue, syncStatus |
|
|
647
|
-
| `omnifocus://inbox` | Inbox tasks as `Task[]` |
|
|
648
|
-
| `omnifocus://tasks/inbox` | Inbox tasks (alias of `omnifocus://inbox`) |
|
|
649
|
-
| `omnifocus://forecast/today` | Today's forecast grouped by overdue / dueToday / deferredToday / flagged |
|
|
650
|
-
| `omnifocus://overdue` | All overdue tasks sorted by dueDate ASC |
|
|
651
|
-
| `omnifocus://flagged` | All flagged available tasks |
|
|
652
|
-
| `omnifocus://review-due` | Projects with nextReviewDate ≤ today |
|
|
653
|
-
| `omnifocus://intents` | User-phrase → tool-sequence map: a small set of human-meaningful verbs that compose the full tool surface |
|
|
654
|
-
| `omnifocus://stats` | Database-wide rollup: counts by project, tag, completion state |
|
|
655
|
-
| `omnifocus://taxonomy-audit` | Structural audit — inconsistent tag/folder usage, orphans, drift signals |
|
|
656
|
-
| `omnifocus://waiting-on` | Every task carrying a `waiting-on` fence, sorted by daysOverdue DESC |
|
|
657
|
-
|
|
658
|
-
**Templated URIs** — accept parameters:
|
|
659
|
-
|
|
660
|
-
| URI Template | Parameters | Returns |
|
|
661
|
-
|---|---|---|
|
|
662
|
-
| `omnifocus://project/{id}` | `id` | Single project + full task tree |
|
|
663
|
-
| `omnifocus://tag/{id}` | `id` | Single tag + its active tasks |
|
|
664
|
-
| `omnifocus://perspective/{id}` | `id` | Perspective evaluation result (same shape as `perspective_evaluate`); Pro only |
|
|
665
|
-
| `omnifocus://tasks/project/{projectId}` | `projectId` | Active tasks under a project |
|
|
666
|
-
| `omnifocus://tasks/tag/{tagId}` | `tagId` | Active tasks carrying a tag |
|
|
667
|
-
| `omnifocus://recent-activity{?hours}` | `hours` (default: 24) | Tasks completed/dropped/created in the last N hours |
|
|
668
|
-
| `omnifocus://retrospective{?from,to}` | `from`, `to` (ISO-8601) | Closed-task aggregation for a date range — weekly review fuel |
|
|
669
|
-
| `omnifocus://velocity{?weeks}` | `weeks` (default: 4) | Per-week throughput: completed counts, completion rate trend |
|
|
670
|
-
| `omnifocus://burndown/{projectId}` | `projectId` | Per-project burndown vs naive linear ideal; needs project dueDate |
|
|
671
|
-
| `omnifocus://project-health{?staleDays}` | `staleDays` (default: 14) | Triage list: stalled projects, no-activity, review-overdue |
|
|
672
|
-
| `omnifocus://calendar{?from,to}` | `from`, `to` (ISO-8601, defaults to today local) | macOS Calendar events from EventKit; needs Calendar TCC grant |
|
|
673
|
-
| `omnifocus://agenda{?date}` | `date` (ISO-8601, defaults to today local) | Merged daily timeline: calendar events + OF forecast, kind-tagged |
|
|
674
|
-
|
|
675
|
-
---
|
|
676
|
-
|
|
677
|
-
## Transport text DSL
|
|
678
|
-
|
|
679
|
-
`task_parse_transport_text` parses a lightweight DSL inspired by OmniFocus Mail Drop into structured task objects. **No tasks are created** — pass the returned `tasks[]` to `task_create` or `task_batch_create` separately.
|
|
680
|
-
|
|
681
|
-
### Token syntax
|
|
682
|
-
|
|
683
|
-
| Token | Example | Meaning |
|
|
684
|
-
|---|---|---|
|
|
685
|
-
| `@tag` | `@work` | Assign a tag by name |
|
|
686
|
-
| `#date` | `#2026-05-01` or `#today` | Due date |
|
|
687
|
-
| `::date` | `::tomorrow` | Defer date |
|
|
688
|
-
| `!!` | `!!` | Flag the task |
|
|
689
|
-
| `//text` | `//Call back before noon` | Append as task note |
|
|
690
|
-
| `Project: Name` | `Project: Finance` | Set project context for subsequent tasks |
|
|
691
|
-
|
|
692
|
-
### Date shortcuts
|
|
693
|
-
|
|
694
|
-
`today` · `tomorrow` · `yesterday` — resolved to midnight local time.
|
|
695
|
-
|
|
696
|
-
Full ISO-8601 dates (`YYYY-MM-DD`) are also accepted. Unparseable dates emit a `warnings[]` entry.
|
|
697
|
-
|
|
698
|
-
### Example
|
|
699
|
-
|
|
700
|
-
```
|
|
701
|
-
Project: Work
|
|
702
|
-
Prepare Q2 report @work #end-of-week !!
|
|
703
|
-
Send draft to Alice @work @email #tomorrow //attach spreadsheet
|
|
704
|
-
Follow up with Bob ::next-week
|
|
705
|
-
|
|
706
|
-
Project: Personal
|
|
707
|
-
Buy groceries @errands #today
|
|
708
|
-
Call dentist @phone ::tomorrow !! //ask about X-ray appointment
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
Tag names and project names are raw strings — resolve to IDs with `tag_list` and `project_list` before passing to `task_create`.
|
|
182
|
+
Full threat model: [`SECURITY.md`](./SECURITY.md), [`docs/design/security.md`](./docs/design/security.md).
|
|
712
183
|
|
|
713
184
|
---
|
|
714
185
|
|
|
@@ -739,7 +210,7 @@ flowchart LR
|
|
|
739
210
|
- **30s LRU read cache** — invalidated on every write. Mutations are never served stale.
|
|
740
211
|
- **Middleware stack** — every registered tool runs through: `assertNotShuttingDown` → `circuitBreaker` → `rateLimitMeta` → `loopDetection`.
|
|
741
212
|
|
|
742
|
-
The full layered diagram with queues, circuit breakers, and the test adapter lives in [`
|
|
213
|
+
The full layered diagram with queues, circuit breakers, and the test adapter lives in [`docs/design/architecture.md`](./docs/design/architecture.md).
|
|
743
214
|
|
|
744
215
|
---
|
|
745
216
|
|
|
@@ -760,194 +231,26 @@ Track open issues and future enhancements on the [**GitHub Project board**](http
|
|
|
760
231
|
|
|
761
232
|
---
|
|
762
233
|
|
|
763
|
-
##
|
|
764
|
-
|
|
765
|
-
**Homebrew** (recommended for non-Node users):
|
|
766
|
-
```bash
|
|
767
|
-
brew install torsday/tap/omnifocus-mcp
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
**npm** (recommended if you already have Node 24+):
|
|
771
|
-
```bash
|
|
772
|
-
# Global install
|
|
773
|
-
npm install -g @torsday/omnifocus-mcp
|
|
774
|
-
|
|
775
|
-
# Or run without installing (npx)
|
|
776
|
-
npx -y @torsday/omnifocus-mcp
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
**Any stdio MCP client** — add to your client's MCP server config (exact key name varies by client):
|
|
780
|
-
```json
|
|
781
|
-
{
|
|
782
|
-
"mcpServers": {
|
|
783
|
-
"omnifocus": {
|
|
784
|
-
"command": "omnifocus-mcp",
|
|
785
|
-
"args": [],
|
|
786
|
-
"env": { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
**npx (no global install)**:
|
|
793
|
-
```json
|
|
794
|
-
{
|
|
795
|
-
"mcpServers": {
|
|
796
|
-
"omnifocus": {
|
|
797
|
-
"command": "npx",
|
|
798
|
-
"args": ["-y", "@torsday/omnifocus-mcp"],
|
|
799
|
-
"env": { "OMNIFOCUS_LOG_LEVEL": "info" }
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
```
|
|
804
|
-
|
|
805
|
-
On first run, macOS asks the app running the server for permission to automate OmniFocus. Click **OK**. If you denied it by mistake: **System Settings → Privacy & Security → Automation → [app] → OmniFocus** ✓
|
|
806
|
-
|
|
807
|
-
See the [troubleshooting guide](./docs/troubleshooting.md) and per-client guides in [`docs/clients/`](./docs/clients/) for detailed setup.
|
|
808
|
-
|
|
809
|
-
---
|
|
810
|
-
|
|
811
|
-
## Environment variables
|
|
812
|
-
|
|
813
|
-
| Variable | What | Default |
|
|
814
|
-
|---|---|---|
|
|
815
|
-
| `OMNIFOCUS_LOG_LEVEL` | `trace`\|`debug`\|`info`\|`warn`\|`error` — logs go to stderr | `info` |
|
|
816
|
-
| `OMNIFOCUS_CACHE_TTL_MS` | Read-cache TTL in milliseconds | `30000` |
|
|
817
|
-
| `OMNIFOCUS_READ_POOL_SIZE` | Concurrent `osascript` processes for reads | `2` |
|
|
818
|
-
| `OMNIFOCUS_WRITE_QUEUE_CAP` | Max pending writes before `QueueFull` error | `50` |
|
|
819
|
-
| `OMNIFOCUS_JXA_TIMEOUT_MS` | Per-call JXA hard timeout in milliseconds | `30000` |
|
|
820
|
-
| `OMNIFOCUS_OMNIJS_TIMEOUT_MS` | Per-call OmniJS hard timeout in milliseconds | `45000` |
|
|
821
|
-
| `OMNIFOCUS_ATTACHMENT_PATHS` | Colon-separated allowlist of absolute path prefixes for attachment ops | `$HOME` |
|
|
822
|
-
| `OMNIFOCUS_MAX_ATTACHMENT_MB` | Maximum attachment file size in MB (0 = no cap) | `100` |
|
|
823
|
-
| `OMNIFOCUS_TOOL_RATE_LIMIT` | Per-tool rate limit in `N/SECONDS` format | `120/60` |
|
|
824
|
-
| `OMNIFOCUS_ALLOW_RAW_SCRIPT` | Set to `1` to register `run_jxa_script` / `run_omnijs_script` | unset |
|
|
825
|
-
| `OMNIFOCUS_INTEGRATION` | Set to `1` to enable the integration test suite | unset |
|
|
826
|
-
|
|
827
|
-
Full table with override semantics: [`DESIGN.md §22`](./DESIGN.md#22-configuration--environment).
|
|
828
|
-
|
|
829
|
-
### Running integration tests
|
|
830
|
-
|
|
831
|
-
Integration tests run against a live OmniFocus install:
|
|
832
|
-
|
|
833
|
-
```bash
|
|
834
|
-
# 1. Make sure OmniFocus is running and Automation permission is granted
|
|
835
|
-
# 2. Seed fixture data (idempotent — safe to re-run):
|
|
836
|
-
node scripts/seed-integration-db.js
|
|
837
|
-
|
|
838
|
-
# Optional: wipe and re-create all fixtures from scratch:
|
|
839
|
-
node scripts/seed-integration-db.js --clean
|
|
840
|
-
|
|
841
|
-
# 3. Run the integration suite:
|
|
842
|
-
OMNIFOCUS_INTEGRATION=1 pnpm test:integration
|
|
843
|
-
```
|
|
844
|
-
|
|
845
|
-
The seed script creates `mcp-fixture:` prefixed items (folders, projects, tasks, tags) that integration tests rely on.
|
|
846
|
-
|
|
847
|
-
---
|
|
848
|
-
|
|
849
|
-
## Troubleshooting
|
|
850
|
-
|
|
851
|
-
### OmniFocus is not running
|
|
852
|
-
|
|
853
|
-
**Error:** `OF_NOT_RUNNING` — OmniFocus must be open for most operations.
|
|
854
|
-
|
|
855
|
-
**Fix:** Launch OmniFocus manually, or call `app_launch` to open it via MCP.
|
|
856
|
-
|
|
857
|
-
---
|
|
858
|
-
|
|
859
|
-
### macOS Automation permission denied
|
|
860
|
-
|
|
861
|
-
**Symptom:** Every tool call returns `OF_PERMISSION_DENIED`.
|
|
862
|
-
|
|
863
|
-
**Fix:**
|
|
864
|
-
1. Open **System Settings → Privacy & Security → Automation**.
|
|
865
|
-
2. Find the app running the MCP server (Terminal, your AI client app, or your CI runner's shell).
|
|
866
|
-
3. Enable the **OmniFocus** checkbox.
|
|
867
|
-
4. Restart omnifocus-mcp.
|
|
868
|
-
|
|
869
|
-
```bash
|
|
870
|
-
bash scripts/check-automation-permission.sh
|
|
871
|
-
```
|
|
872
|
-
|
|
873
|
-
---
|
|
874
|
-
|
|
875
|
-
### First-call timeout / slow startup
|
|
876
|
-
|
|
877
|
-
JXA starts an `osascript` subprocess on each call. The first call after a system sleep or a fresh OmniFocus launch can take 5–15 seconds while the database loads. This is normal.
|
|
878
|
-
|
|
879
|
-
If calls consistently time out:
|
|
880
|
-
```bash
|
|
881
|
-
OMNIFOCUS_JXA_TIMEOUT_MS=60000 omnifocus-mcp
|
|
882
|
-
```
|
|
883
|
-
|
|
884
|
-
---
|
|
885
|
-
|
|
886
|
-
### `run_jxa_script` / `run_omnijs_script` not available
|
|
887
|
-
|
|
888
|
-
**Error:** `ValidationError: run_jxa_script is not available in this adapter configuration`
|
|
889
|
-
|
|
890
|
-
**Fix:** The raw-script tools are opt-in. Start the server with:
|
|
891
|
-
```bash
|
|
892
|
-
OMNIFOCUS_ALLOW_RAW_SCRIPT=1 omnifocus-mcp
|
|
893
|
-
```
|
|
894
|
-
|
|
895
|
-
See [`docs/adr/0004-raw-script-escape-hatch.md`](./docs/adr/0004-raw-script-escape-hatch.md) for the security rationale.
|
|
896
|
-
|
|
897
|
-
---
|
|
898
|
-
|
|
899
|
-
### Stale data after a write
|
|
900
|
-
|
|
901
|
-
Writes are saved locally and show up immediately in subsequent tool calls. Changes don't reach other devices until iCloud sync runs. Call `sync_trigger` after bulk mutations or when cross-device visibility matters.
|
|
902
|
-
|
|
903
|
-
---
|
|
904
|
-
|
|
905
|
-
### More help
|
|
906
|
-
|
|
907
|
-
- [`docs/troubleshooting.md`](./docs/troubleshooting.md) — expanded troubleshooting guide
|
|
908
|
-
- [`docs/clients/`](./docs/clients/) — per-client setup guides
|
|
909
|
-
|
|
910
|
-
---
|
|
911
|
-
|
|
912
|
-
## Client setup guides
|
|
913
|
-
|
|
914
|
-
| Client | Guide |
|
|
915
|
-
|---|---|
|
|
916
|
-
| Claude Code (CLI) | [`docs/clients/claude-code.md`](./docs/clients/claude-code.md) |
|
|
917
|
-
| Claude Desktop | [`docs/clients/claude-desktop.md`](./docs/clients/claude-desktop.md) |
|
|
918
|
-
| OpenAI Codex CLI | [`docs/clients/codex.md`](./docs/clients/codex.md) |
|
|
919
|
-
| Generic stdio client | [`docs/clients/generic-stdio.md`](./docs/clients/generic-stdio.md) |
|
|
920
|
-
|
|
921
|
-
---
|
|
922
|
-
|
|
923
|
-
## Design documents
|
|
924
|
-
|
|
925
|
-
- **[`SPEC.md`](./SPEC.md)** — functional scope and non-functional requirements; resolved v1 decisions
|
|
926
|
-
- **[`DESIGN.md`](./DESIGN.md)** — 28-section architecture; options evaluated; R/S/M assessment; example tool implementation
|
|
927
|
-
- **[`docs/security.md`](./docs/security.md)** — attack surface, mitigations, and test coverage
|
|
928
|
-
- **[`docs/domain-reference.md`](./docs/domain-reference.md)** — OmniFocus glossary, canonical schemas, lossiness matrix for export/import
|
|
929
|
-
- **[`docs/adr/`](./docs/adr/)** — Architecture Decision Records covering every load-bearing choice:
|
|
234
|
+
## Reference docs
|
|
930
235
|
|
|
931
|
-
|
|
|
236
|
+
| Doc | What |
|
|
932
237
|
|---|---|
|
|
933
|
-
| [
|
|
934
|
-
| [
|
|
935
|
-
| [
|
|
936
|
-
| [
|
|
937
|
-
| [
|
|
938
|
-
| [
|
|
939
|
-
| [
|
|
940
|
-
| [
|
|
941
|
-
| [
|
|
942
|
-
| [
|
|
943
|
-
| [
|
|
944
|
-
| [
|
|
945
|
-
| [
|
|
946
|
-
| [
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
| [0017](./docs/adr/0017-mutation-testing-release-gate.md) | Stryker mutation testing as release-time hard gate |
|
|
950
|
-
| [0018](./docs/adr/0018-calendar-bridge-eventkit-only.md) | Calendar bridge — EventKit-only via Swift-binary subprocess |
|
|
238
|
+
| [`docs/tools.md`](./docs/tools.md) | Auto-generated reference for every tool — input schemas, examples, responses |
|
|
239
|
+
| [`src/tools/INDEX.md`](./src/tools/INDEX.md) | One-line-per-tool index grouped by domain (cheaper than grepping) |
|
|
240
|
+
| [`docs/examples.md`](./docs/examples.md) | Concrete prompt → tool-call sequences |
|
|
241
|
+
| [`docs/prompts.md`](./docs/prompts.md) | Bundled MCP prompt templates (`daily-review`, `weekly-review`, `capture-meeting`, `project-planning`) |
|
|
242
|
+
| [`AGENTS.md`](./AGENTS.md) | Agent-facing guide — engineering conventions for contributors AND calling conventions for clients (IDs, error codes, dates, idempotency, `_links`, response envelope, `meta.warnings`, rate limits) |
|
|
243
|
+
| [`docs/clients/`](./docs/clients/) | Per-client setup guides (Claude Code, Claude Desktop, Codex, OpenCode, Pi, generic stdio) |
|
|
244
|
+
| [`docs/troubleshooting.md`](./docs/troubleshooting.md) | OmniFocus not running, Automation permission, slow startup, raw-script gating, sync staleness |
|
|
245
|
+
| [`docs/domain-reference.md`](./docs/domain-reference.md) | OmniFocus glossary, canonical schemas, lossiness matrix for export/import |
|
|
246
|
+
| [`docs/security.md`](./docs/security.md) | Attack surface, mitigations, test coverage |
|
|
247
|
+
| [`SECURITY.md`](./SECURITY.md) | Vulnerability reporting, scope |
|
|
248
|
+
| [`SPEC.md`](./SPEC.md) | Functional scope and resolved v1 decisions |
|
|
249
|
+
| [`DESIGN.md`](./DESIGN.md) | Index of the per-area design files under [`docs/design/`](./docs/design/) — architecture, envelope, IDs/dates, security, testing, observability, configuration, distribution, example tool, resources |
|
|
250
|
+
| [`docs/adr/`](./docs/adr/) | Architecture Decision Records — every load-bearing choice (TypeScript+Node 24, dual transport, namespacing, raw-script gating, scripts-as-files, LRU cache, ISO-8601 dates, branded IDs, pool+queue, stdio transport, semver, npx distribution, response envelope, E2E adapter switch, NL envelope, webhooks, Stryker mutation gate, EventKit calendar bridge, cross-transport ID interop, JXA helper inlining, reactive runtime spike, envelope text/structured split) |
|
|
251
|
+
| [`CHANGELOG.md`](./CHANGELOG.md) | Release history per [Keep a Changelog](https://keepachangelog.com/) |
|
|
252
|
+
|
|
253
|
+
For the **full environment-variable surface** with override semantics see [`docs/design/configuration.md`](./docs/design/configuration.md); the load-bearing knobs are `OMNIFOCUS_LOG_LEVEL`, `OMNIFOCUS_CACHE_TTL_MS`, `OMNIFOCUS_ALLOW_RAW_SCRIPT`, and `OMNIFOCUS_ATTACHMENT_PATHS`.
|
|
951
254
|
|
|
952
255
|
---
|
|
953
256
|
|
|
@@ -959,4 +262,4 @@ This is a single-developer project; external contributions are not currently sol
|
|
|
959
262
|
|
|
960
263
|
## License
|
|
961
264
|
|
|
962
|
-
|
|
265
|
+
MIT — see [`LICENSE`](./LICENSE).
|