Install
$ agentstack add mcp-psufka-omnifocus-mcp-plus ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
OmniFocus MCP Plus
MCP server and CLI for OmniFocus 4
Originally forked from jqlts1/omnifocus-mcp-enhanced. Additional tools inspired by vitalyrodnenko/OmnifocusMCP.
Installation
Requires macOS with OmniFocus 4 and Node.js 22+. API documentation lookup requires OmniFocus 4.9+ (which requires macOS 15.2+). Existing task tools continue to work on OmniFocus 4.8.13.
From Source
git clone https://github.com/psufka/omnifocus-mcp-plus.git
cd omnifocus-mcp-plus
npm install && npm run build
npm test # all tests should pass
claude mcp add omnifocus -- node "$(pwd)/dist/server.js"
Restart Claude Code to pick up the new server.
CLI, diagnostics and reliable writes
The CLI uses the same validation, normalization and dispatcher as MCP:
node dist/cli.js doctor
node dist/cli.js list
node dist/cli.js call filter_tasks '{"countOnly":true,"dateMode":"effective"}'
node dist/cli.js call batch_edit_items --stdin < edits.json
The installed binary is omnifocus-mcp. Tool results include readable text and structuredContent: {success, tool, data, meta?} with output schemas. Use server_info to confirm the version, commit/build hash, Node executable, OmniFocus version and connectivity. batch_edit_items previews or applies up to 100 edits with per-item verification. Creates accept idempotencyKey to coordinate retries across clients.
Compatibility changes in 0.6: task queries exclude project root tasks by default; includeProjectRoots: true opts in. Filters/counts/analytics default to dateMode: "direct", forecast to "effective". Every week filter now starts Sunday unless weekStartsOn: "monday" is supplied; completion weeks used Monday previously. Tag assignments accept IDs or unique paths, and ambiguous names fail before writes.
Read [the operations guide](docs/skills/omnifocus/reliability.md) for result shapes, request-key recovery, rollback states, freshness and process coordination.
OmniFocus 4.9 support (0.7.0)
Search the running application's own API reference, including TypeScript declarations and comments, without executing any returned code:
node dist/cli.js call search_automation_api '{"query":"Task.RepetitionRule","maxCharacters":12000}'
Use nextOffset as the next call's offset when truncated is true. Searches return at most 40,000 UTF-16 characters per page (default 12,000). The generated timestamp and setup preamble are omitted; API comments are retained. An unmatched query returns empty text. This is documentation lookup, not task search or an arbitrary-script execution tool. A process-local cache retains up to 16 queries / 1,000,000 characters for five minutes. Every call checks the running app's version and build; refresh: true bypasses the cache. server_info reports omnifocus.capabilities.automationApiLookup. Older apps return a clear unsupported-feature error for this tool while other tools remain available.
Structured monthly repetition now supports next-to-last weekdays and calendar days:
{"task_id":"TASK_ID","schedule_type":"regularly","frequency":"monthly","daysOfWeek":[{"day":"friday","position":-2}]}
For the next-to-last calendar day, use daysOfMonth: [-2] instead of daysOfWeek. -1 still means last. Repetition writes retain read-back verification and restore the previous rule when that verification fails. See OmniFocus 4.9 release notes and Omni's API lookup announcement.
Tools (53)
Task Management
| Tool | Description | |------|-------------| | add_omnifocus_task | Add a new task with dates, tags, project, parent task | | edit_item | Edit task/project: rename, dates, flags, status, tags, move | | remove_item | Remove a task or project (duplicate-name safe) | | move_task | Move task to project, parent task, or inbox | | duplicate_task | Duplicate a task with note, dates, flags, tags; optionally into a different project | | get_task_by_id | Get task details by ID or name | | list_subtasks | List children (subtasks), optionally recursive for full hierarchy | | complete_task | Mark a task as completed | | uncomplete_task | Mark a completed task as incomplete | | set_task_repetition | Set/clear repeating schedule — structured fields ("2nd Tuesday monthly") or raw iCal RRULE | | append_to_note | Append text to a task or project note | | batch_add_items | Add multiple tasks/projects in one call — tempId hierarchy, dryRun, atomic rollback | | batch_edit_items | Preview or apply up to 100 task/project edits with per-item verification | | batch_remove_items | Remove multiple items in one call (dryRun supported) | | batch_move_tasks | Move multiple tasks to a destination in one call (dryRun supported) | | reorder_task | Reorder task within its container: before/after sibling, or beginning/ending | | convert_task_to_project | Promote a task (with subtasks, tags, note) into a project | | find_similar_tasks | Duplicate detection before create — ranked similarity matches with ids | | manage_attachments | List/read/add/remove file attachments on a task or project |
Task Queries
| Tool | Description | |------|-------------| | filter_tasks | Advanced filtering: status, all date fields, folder tree, tags, regex, and/or/not clauses, countOnly, paging | | search_items | One search across tasks, projects, folders, and tags | | analyze | Evidence-only analytics: health snapshot, velocity, overdue clusters, stalled projects | | get_inbox_tasks | Get inbox tasks | | get_flagged_tasks | Get flagged tasks with optional project filter | | get_forecast_tasks | Get due/deferred tasks in date range | | get_tasks_by_tag | Get tasks by tag name | | get_today_completed_tasks | Get tasks completed today | | get_task_counts | Aggregate counts: total, available, completed, overdue, due soon, flagged | | get_custom_perspective_tasks | Get tasks from a custom perspective | | list_custom_perspectives | List all custom perspectives (includeRules returns their filter rules) | | update_perspective_rules | Edit a custom perspective's filter rules — validated, read-back verified, undo-able | | dump_database | Full database export |
Notifications
| Tool | Description | |------|-------------| | list_notifications | List all notifications (reminders) on a task | | add_notification | Add absolute or relative notification to a task | | remove_notification | Remove a notification by index |
Projects
| Tool | Description | |------|-------------| | add_project | Create a new project | | list_projects | List/filter projects by folder, status, stalled state | | search_projects | Search projects by name | | get_project_counts | Aggregate counts by status | | manage_reviews | GTD review workflow: list due, mark reviewed (batch-capable), set schedule |
App Control
| Tool | Description | |------|-------------| | app_control | Sync, undo/redo (confirm-gated), window focus get/set/clear, reveal an item |
Folders
| Tool | Description | |------|-------------| | list_folders | List all folders with project counts | | get_folder | Get folder details including projects and subfolders | | create_folder | Create a folder, optionally nested | | update_folder | Update folder name or status | | delete_folder | Delete a folder (and all projects inside it) |
Tags
| Tool | Description | |------|-------------| | list_tags | List tags with task counts, filter by status | | search_tags | Search tags by name | | create_tag | Create a tag, optionally nested | | update_tag | Update tag name or status | | delete_tag | Delete a tag |
Diagnostics
| Tool | Description | |------|-------------| | server_info | Report build/executable details and probe OmniFocus connectivity/capabilities | | search_automation_api | Search installed API documentation with pagination and version-aware caching (OmniFocus 4.9+) |
MCP Surface & Environment
Beyond tools, the server exposes 4 prompts (weekly_review, inbox_processing, daily_planning, task_health_scan — surfaced as slash commands in Claude Code), 4 resources (omnifocus://inbox, today, flagged, stats), tool annotations (readOnly/destructive/idempotent hints on all 53 tools), and handshake instructions that steer clients toward the cheap tools. A Claude Code skill lives at docs/skills/omnifocus/ (install: ln -s "$(pwd)/docs/skills/omnifocus" ~/.claude/skills/omnifocus).
All MCP/CLI clients share two execution slots for the macOS user. Environment variables: OMNIFOCUS_MCP_MAX_CONCURRENT (local limit, default 2, range 1–8; still subject to the two shared slots), OMNIFOCUS_MCP_STATE_DIR (shared lock/request directory, default ~/.omnifocus-mcp), OMNIFOCUS_SCRIPT_TIMEOUT_MS (default 120000), OMNIFOCUS_SCRIPT_MAX_OUTPUT_BYTES (default 50MB).
Usage Examples
All tools are called automatically by Claude via MCP. The examples below show the tool parameters for common operations.
Tasks
Add a task with a due date and tags:
{
"name": "Review quarterly report",
"dueDate": "2026-03-15T17:00:00-05:00",
"tags": ["Work", "Urgent"],
"projectName": "Q1 Review"
}
Set a task to repeat every weekday:
{
"task_id": "abc123",
"rule_string": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
"schedule_type": "regularly"
}
Set a task to repeat 3 days after completion:
{
"task_id": "abc123",
"rule_string": "FREQ=DAILY;INTERVAL=3",
"schedule_type": "from_completion"
}
Append to a task's note (without overwriting):
{
"object_type": "task",
"object_id": "abc123",
"text": "\nUpdated 2026-03-10: waiting on response"
}
Projects
List stalled projects (active but stuck):
{ "stalledOnly": true }
List projects in a folder sorted by remaining tasks:
{
"folder": "Work",
"status": "active",
"sortBy": "remainingTaskCount",
"sortOrder": "desc"
}
Folders & Tags
Create a nested folder:
{ "name": "Q2 Projects", "parent": "Work" }
Create a nested tag:
{ "name": "Urgent", "parent": "Priority" }
Put a tag on hold:
{ "name_or_id": "Waiting", "status": "on_hold" }
Filtering
Get overdue tasks in a specific project:
{
"overdue": true,
"projectFilter": "Home Renovation"
}
Get tasks due this week with a specific tag:
{
"dueThisWeek": true,
"tagFilter": "Work"
}
Date Format
Use valid ISO calendar dates or timestamps. Bare dates such as 2026-03-15 mean local midnight. Full timestamps with an offset or Z pin an instant. Impossible dates such as 2026-02-31 are rejected. Empty strings clear dates only in edit fields. Readable results show local time; structured results may use ISO instants or epoch milliseconds.
"2026-03-15T17:00:00-05:00" (CDT)
"2026-03-15T17:00:00-06:00" (CST)
RRULE Reference
The set_task_repetition tool uses iCal RRULE syntax:
| Pattern | RRULE | |---------|-------| | Daily | FREQ=DAILY;INTERVAL=1 | | Every 3 days | FREQ=DAILY;INTERVAL=3 | | Weekly on Mon/Wed/Fri | FREQ=WEEKLY;BYDAY=MO,WE,FR | | Biweekly | FREQ=WEEKLY;INTERVAL=2 | | Monthly on the 1st | FREQ=MONTHLY;BYMONTHDAY=1 | | Yearly | FREQ=YEARLY;INTERVAL=1 |
Architecture
All tools use OmniJS via JXA — inline JavaScript executed inside OmniFocus via runOmniJs(). No AppleScript escaping issues, native access to all OmniJS APIs. Query tools use external .js scripts in src/utils/omnifocusScripts/ loaded via executeOmniFocusScript(). The core task/project CRUD tools (add, edit, remove) were migrated from AppleScript to OmniJS in v0.3.0.
Changelog
Current version: 0.6.0. See [CHANGELOG.md](CHANGELOG.md) for the full release history.
Known Limitations
- Cache scope — GUI edits and other processes’ writes become visible on TTL expiry; use
fresh: trueon cacheable reads when current data is required. - Uncertain creates — Request keys are durable and never expire automatically. A pending record requires inspection rather than an automatic second create.
- Notification API — Relative notification offset retrieval may not work on all OmniFocus versions. Absolute notifications are fully supported.
Contributing
PRs welcome! All tools use OmniJS — write inline JavaScript that runs inside OmniFocus via runOmniJs(). No escaping issues, full access to the OmniJS API. See src/tools/primitives/folderTools.ts for examples.
To add a new tool:
- Create a primitive in
src/tools/primitives/yourTool.ts - Create a definition in
src/tools/definitions/yourTool.ts(Zod schema + handler) - Register in
src/server.ts npm run build && npm test
Credits
- jqlts1/omnifocus-mcp-enhanced — original MCP server with perspective support
- vitalyrodnenko/OmnifocusMCP — reference implementation for folder/tag CRUD, project listing, and OmniJS patterns
License
MIT
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: psufka
- Source: psufka/omnifocus-mcp-plus
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.