OmniFocusSAFE
Model Context Protocol (MCP) server for OmniFocus on macOS, with Rust, Python, and TypeScript implementations
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://www.omnigroup.com/omnifocus) [](https://modelcontextprotocol.io) [](#implementations) [](LICENSE)
MCP server that gives AI assistants full control over OmniFocus on macOS.
45 tools, 3 resources, and 4 prompts covering tasks, projects, tags, folders, perspectives, forecast, notifications, and review workflows — all through the Model Context Protocol.
This project is not affiliated with, endorsed by, or associated with The Omni Group or OmniFocus. OmniFocus is a trademark of The Omni Group. This is an independent, non-commercial open-source project.
Quick Start
Install via Homebrew (if you don't have Homebrew, see the Homebrew installation guide):
brew tap vitalyrodnenko/omnifocus-mcp brew install omnifocus-mcp
Then add to your MCP client config (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"omnifocus": {
"command": "omnifocus-mcp",
"args": []
}
}
}That's it. The AI assistant now has full OmniFocus access.
What It Can Do
Tasks (23 tools)
Full lifecycle management for OmniFocus tasks:
- CRUD — create, get, update, delete individual tasks
- Batch operations — create, move, or delete multiple tasks in a single call
- Subtasks — create and list subtasks under any parent task
- Completion — mark complete, mark incomplete (supports repeating tasks)
- Search — full-text search across task names and notes with all filters applied
- Move and reparent — relocate tasks between projects, reparent tasks under other tasks, or move subtask
b59f18a2e80aOBSERVED · 2026-10-08Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control.
claude mcp add omnifocus-mcp-typescript -- npx -y [email protected]
{
"mcpServers": {
"omnifocus-mcp-typescript": {
"command": "npx",
"args": [
"-y",
"[email protected]"
]
}
}
}Exposed tools (48)
23 read · 15 write · 10 destructive. Blast radius: 10 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
add_notification | write | add a notification to a task by id. provide exactly one of absoluteDate or relativeOffset. |
append_to_note | read | append text to a task or project note by object id. |
complete_project | read | complete a project by id or name. use this for finished/closed projects (done/completed), not set_project_status(\ |
complete_task | read | mark a task complete by id. use this for done/completed task lifecycle updates. |
create_folder | write | create a folder with optional parent folder and return id/name. |
create_project | write | create a new project with optional folder, note, dates, and sequential mode. |
create_subtask | write | create a new subtask under an existing parent task by id. |
create_tag | write | create a tag with optional parent tag and return id/name. |
create_task | write | create a new task in inbox or a named project and return the created task summary. |
create_tasks_batch | write | create multiple tasks in one call and return created task summaries. |
delete_folder | destructive | delete a folder by id or name. warning: this permanently removes the folder. do not use delete+recreate for folder edits or renames; use update_folder instead. contained projects may be moved to top level by omnifocus, so confirm with the user before proceeding. |
delete_folders_batch | destructive | |
delete_project | destructive | |
delete_projects_batch | destructive | |
delete_tag | destructive | delete a tag by id or name. warning: tasks using this tag will lose the tag assignment. |
delete_tags_batch | destructive | delete multiple tags by id or exact name in a single omnijs call. destructive operation: this removes tags and unassigns them from linked tasks. use update_tag for non-destructive edits. before calling this tool, always show the user the target tag list and ask for explicit confirmation. |
delete_task | destructive | delete a task by id and return deletion status. destructive operation: use update_task or move_task for edits/reorganization, and never delete then recreate as a substitute for updating. ask for explicit user confirmation before proceeding. |
delete_tasks_batch | destructive | |
duplicate_task | read | duplicate a task with all its properties. if the task has subtasks, they are cloned too by default. |
get_folder | read | get a folder by id or name with direct child projects and subfolders. |
get_forecast | read | get forecast sections for overdue, due today, flagged, deferred, and due-this-week tasks. |
get_inbox | read | get inbox tasks from omnifocus. returns unprocessed tasks that have not been assigned to a project. |
get_project | read | get full details for one project by id or name. |
get_project_counts | read | get aggregate project counts by status without listing individual projects. |
get_task | read | get full details for one task by id. returns list_tasks fields plus children, parentName, sequential state, repetitionRule, and effective date/status fields. |
get_task_counts | read | get aggregate task counts for any filter combination without listing individual tasks. added_* and changed_* filters must be ISO 8601 date strings; changed means the task |
list_folders | read | list folder hierarchy and project counts. |
list_notifications | read | list active notifications for a task by id. |
list_perspectives | read | list available perspectives including built-in and custom perspectives. |
list_projects | read | list projects with optional folder and status filters. status semantics: completed means finished work, dropped means intentionally abandoned/cancelled, on_hold means paused, active means current. |
list_subtasks | read | list direct subtasks for a task id. |
list_tags | read | list tags with availability counts and optional status filter. |
list_tasks | read | |
move_project | write | move a project by id or name to a folder or top level. |
move_task | write | |
move_tasks_batch | write | |
remove_notification | destructive | remove one notification from a task by id. |
search_projects | read | search projects by query using omnifocus project matching. |
search_tags | read | search tags by query using omnifocus tag matching. |
search_tasks | read | |
set_project_status | write | set a project |
set_task_repetition | destructive | set or clear a task repetition rule by task id. |
uncomplete_project | read | reopen a completed project by id or name and return active status (undo complete_project). |
uncomplete_task | read | mark a completed task incomplete by id. |
update_folder | write | update a folder by id or name. |
update_project | write | update a project by id or name, modifying only provided fields. |
update_tag | write | update a tag by id or name. |
update_task | write | update one task with partial fields and return the updated task payload. |
Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (5)
delete_folder, delete_folders_batch, delete_project, delete_projects_batch, delete_tag, delete_tags_batch, delete_task, delete_tasks_batch, remove_notification, set_task_repetition
importlib.import_module(module_name), "run_omnijs", fake_run_omnijs
monkeypatch.setattr(importlib.import_module(module_name), "run_omnijs", fake_run_omnijs)
monkeypatch.setattr(importlib.import_module(module_name), "run_omnijs", fake_run_omnijs)
@modelcontextprotocol/sdk, zod, @types/node, typescript, vitest
Gates applied: no_behavioural_pass.
b59f18a2e80afull audit observations/trust-audit/mcp-server/vitalyrodnenko__omnifocus-5.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | b59f18a2e80a | SAFE | B | 89 | first audit |
Questions
What is the OmniFocus MCP server?
Model Context Protocol (MCP) server for OmniFocus on macOS, with Rust, Python, and TypeScript implementations
What tools does OmniFocus expose?
48 in total: 23 read-only, 15 that write, and 10 that can delete or overwrite (delete_folder, delete_folders_batch, delete_project, delete_projects_batch, delete_tag). Every one is listed on this page with its risk.
Is OmniFocus safe to connect to an agent?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean server reads B. Separately from the audit: 10 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does OmniFocus need?
No credential environment variables were found in its source, so it appears to need none.
How does OmniFocus run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as omnifocus-mcp-typescript at 0.1.0.
How current is this page?
The grade is for one exact copy of the source (b59f18a2e80a), read on 2026-10-08. The repository is watched and re-audited when it changes.