Skip to main content
Glama
GlassyWorld

OmniFocus MCP Server

by GlassyWorld
README.md
# OmniFocus-Agent-MCP v1.0-personalized

基于 upstream OmniFocus MCP `v1.9.2` 构建的个人管理语义层,用于向 GPT 和其他 MCP 客户端提供稳定、只读优先的 OmniFocus Domain View,以及两个受控的 request-scoped mutation。

> Release status: `v1.0-personalized` — current frozen personalized architecture

## Current production surface

当前生产代码基线在 V4 `create_task` 之上已完成 S5B:`personal-production` 注册五个
read Tools(`get_task`、`get_project`、`get_completed_since`、`get_lean_snapshot`、
`search_tags`)和两个受控 mutation(`create_task`、`create_project_skeleton`),不注册 Resources 或 Prompts。

`create_task` 是仅在用户明确请求时调用的 request-scoped assisted mutation;它不是由
AI 分析、建议、计划或推断出的未来意图触发的自动写入。它支持 Inbox、exact Active
Project、fresh exact eligible ordinary Action Group,以及可选的既有 Active Tag canonical
IDs。严格 schema、canonical identity、无 fuzzy/fallback、feature gates、Ledger、lock、
exact readback 与保守错误语义都是 V4 的生产不变量。

`create_project_skeleton` 是另一条独立的 request-scoped assisted mutation:只在已有、符合资格的
Folder 下创建固定 Project + 1–5 个 Action Groups(每组一个 starter),总对象数上限为 11。
它不是 Folder 创建器、`create_tasks`、任意 Project tree 或 generic CRUD。完整 AI 调用合同见
[`docs/integration/CREATE_PROJECT_SKELETON_AI_CALL_GUIDE.md`](./docs/integration/CREATE_PROJECT_SKELETON_AI_CALL_GUIDE.md)。

Tree V5、Project P2/P3 和 P5 Canary 不属于当前生产能力。它们的本地实验历史与重新开启
条件见 [`docs/history/TREE_V5_EXPERIMENT_ARCHIVE.md`](./docs/history/TREE_V5_EXPERIMENT_ARCHIVE.md)。

## 1. Overview

本项目最初提供 OmniFocus 数据访问、通用查询和对象操作能力。个人化版本在该基础上增加了明确的 Domain Semantic Layer,使 AI 不必直接解释 OmniFocus Raw Object、继承日期或 Project root 的底层表示。

当前架构目标是:

```text
OmniFocus
    ↓
Domain Semantic Model
    ↓
MCP Tools
    ↓
AI Analysis
```

该版本的目标不是让 AI 自动管理任务,也不是让模型替用户做出执行决策,而是提供可验证、来源明确、结构稳定的事实视图,辅助用户分析个人执行系统。

核心原则:

- 默认只读:个性化工作流以读取和分析为默认模式。
- 事实先于解释:Domain 层表达 OmniFocus facts,不生成健康度、风险、优先级或行动建议。
- AI 负责分析:AI 可以归纳、比较和识别模式,但不自动修改 OmniFocus。
- 用户最终决策:任何确认、调整和执行都由用户本人控制。

### Version identity

| 项目 | 当前值 |
|---|---|
| 个性化版本 | `v1.0-personalized` |
| Upstream 基础版本 | `v1.9.2` |
| MCP transport | stdio |
| 运行平台 | macOS + OmniFocus |
| 个性化 read models 基线 | `get_task`、`get_project`、`get_completed_since`、`get_lean_snapshot` |

`v1.0-personalized` 是个性化语义层的 release label;npm/package 基础版本仍保留 upstream `1.9.2`。

---

## 2. v1.0-personalized Release Notes

`v1.0-personalized` 是当前已冻结的个人化架构基线。后续评审和演进应以本版本已经建立的 Domain Contract 和语义规则为起点。

### Completed

#### Task Domain

- 严格的 Raw Task Adapter。
- 稳定的 `TaskView`。
- `action`、`action_group`、`project_root` 三种 `TaskKind`。
- Due、Planned、Defer 的 direct/effective/source 表达。
- Completion、Drop、Flag 的 direct/inherited/none 表达。

#### Project Domain

- 严格的 Raw Project Adapter。
- 稳定的 `ProjectView`。
- canonical Project ID。
- standard 与 single-actions Project 分类。
- Folder、状态、Task aggregate 和日期语义。

#### Completion Domain

- 稳定的 `CompletedTaskView`。
- 基于 direct `completionDate` 的完成事件流。
- 明确排除 Project root completion event。
- 支持 Action 与 Action Group completion。

#### Lean Snapshot Domain

- 稳定的 `LeanSnapshotView`。
- Active Projects、Planned Projects、Project Deadlines、Attention 和 Inbox sections。
- Project 与 root Task 的 canonical join。
- 完整计数、确定性排序和独立截断。

#### Planned Attention Semantics

- Direct Planned owner 产生 Planned visibility。
- inherited Planned facts 被保留,但不会生成重复 Attention。
- Project-level Planned owner 进入独立的 `projects.planned` section。

#### Due Attention Semantics

- Direct Due owner 产生 deadline signal。
- inherited Due facts 被保留,但不会生成重复 `dueSoon` 或 `overdue` Attention。
- Project-level Due owner 进入独立的 `projects.deadline` section。

#### MCP read tools(个性化基线)

- `get_task`
- `get_project`
- `get_completed_since`
- `get_lean_snapshot`

这四个 Tool 返回稳定 Domain JSON,而不是把通用查询结果直接暴露给 AI。当前生产还在
此基线上增加了只读 `search_tags`;完整 current surface 以本文开头和
`src/serverRegistration.test.ts` 为准。

### Frozen Design Principles

#### Domain-first architecture

个性化功能首先定义 Domain Contract,再定义 Tool 输出。MCP handler 不承担核心业务语义。

```text
Raw Query
    -> Strict Adapter
    -> Domain Semantics
    -> Mapper / Composer
    -> MCP Response
```

#### Semantic projection

Domain View 是对 OmniFocus facts 的明确投影,而不是 Raw Object dump。字段被固定选择、验证和解释,内部 Raw contract 不直接公开。

#### Direct ownership of management signals

Planned 和 Due 信号按 direct owner 粒度表达。容器继承产生的 effective value 是事实,但不是新的管理信号 owner。

#### Separation of fact and interpretation

Domain 层负责表达:

- 对象是什么。
- 值来自对象自身还是容器继承。
- 当前 OmniFocus native status 是什么。
- 对象之间的结构关系是什么。

Domain 层不负责表达:

- 应该先做什么。
- Project 是否健康。
- 哪个对象风险最高。
- 用户应该采取什么行动。

这些解释属于 AI Analysis 和用户决策层。

---

## 3. Architecture Overview

```mermaid
flowchart TD
    RAW["OmniFocus Raw Data<br/>Tasks / Projects / Folders"]
    BRIDGE["Primitive and Bridge Layer<br/>queryOmnifocus + JXA + osascript"]
    ADAPTERS["Strict Adapters<br/>Raw contract validation"]

    TASK["Task Domain<br/>TaskView"]
    PROJECT["Project Domain<br/>ProjectView"]
    COMPLETION["Completion Domain<br/>CompletedTaskView"]
    SNAPSHOT["Snapshot Domain<br/>LeanSnapshotView"]

    TOOLS["Personalized MCP Read Tools<br/>get_task / get_project<br/>get_completed_since / get_lean_snapshot"]
    AI["AI Analysis<br/>comparison, review, pattern recognition"]
    USER["User Decision<br/>final confirmation and execution"]

    RAW -->|读取原始事实| BRIDGE
    BRIDGE -->|固定字段映射| ADAPTERS

    ADAPTERS --> TASK
    ADAPTERS --> PROJECT
    ADAPTERS --> COMPLETION
    ADAPTERS --> SNAPSHOT

    TASK --> TOOLS
    PROJECT --> TOOLS
    COMPLETION --> TOOLS
    SNAPSHOT --> TOOLS

    TOOLS -->|稳定 Domain JSON| AI
    AI -->|分析结果,不自动写入| USER
```

主要实现路径:

```text
src/tools/primitives/queryOmnifocus.ts
    ↓
src/domain/{task,project,completion,snapshot}/
    ↓
src/tools/primitives/get*.ts
    ↓
src/tools/definitions/get*.ts
    ↓
src/server.ts
```

### Layer responsibilities

| Layer | 职责 |
|---|---|
| OmniFocus Raw Data | 提供 Task、Project、Folder、日期、状态和层级的原始事实 |
| Primitive / Bridge | 生成并执行只读 OmniJS 查询,映射固定字段和 canonical ID |
| Adapter | 严格校验 Raw item;不静默修复 malformed values |
| Domain | 分类、保留来源语义并构建稳定 View |
| Snapshot Composer | 跨 Task/Project 组合当前系统状态 |
| MCP Tool | 参数校验、稳定响应和错误分类 |
| AI Analysis | 基于事实进行解释,不承担事实生成和自动写入 |

---

## 4. Domain Model

### Task Domain

Task Domain 位于 `src/domain/task/`,对外读模型是 `TaskView`。

`TaskView` 包含:

- identity:`id`、`name`、`note`
- `TaskKind`
- native Task status
- completion、drop、flag semantics
- Due、Planned、Defer semantics
- Project context 与 Inbox location
- hierarchy、tags、repeat、estimate 和 timestamps

#### TaskKind

```ts
type TaskKind = "action" | "action_group" | "project_root";
```

分类规则:

```text
isProjectRoot = true  -> project_root
否则 hasChildren      -> action_group
否则                  -> action
```

- `action`:没有 children 的普通执行项。
- `action_group`:有 children、但不是 Project root 的 Task。
- `project_root`:OmniFocus Project 的 root Task 表示。

Action 当前属于 Task Domain,不是独立 Domain。当前代码没有独立 `ActionView`、Action aggregate 或 `get_action` Tool。

### Project Domain

Project Domain 位于 `src/domain/project/`,对外读模型是 `ProjectView`。

`ProjectView` 包含:

- canonical Project identity
- Project kind:`standard | single_actions`
- Active、OnHold、Done、Dropped 状态语义
- Folder context
- direct/effective Due 和 Defer
- direct Task IDs、全部 descendant Task IDs 和 native-status counts
- timestamps

#### Project Root semantics

OmniJS Project ID 与 Project root Task ID 属于不同 namespace。个性化 Domain 对外统一使用:

```text
canonical Project ID = project.task.id.primaryKey
```

因此同一个 canonical ID 可以从两个互补视角读取:

```text
get_project(projectId)
    -> Project aggregate、Folder、Project status、Task summary

get_task(projectId)
    -> 对应 project_root Task 的 Task facts
```

Snapshot 使用 canonical ID 将 `RawLeanProject` 与 `isProjectRoot = true` 的 `RawLeanTask` 精确连接。Project 是管理聚合;root Task 是它在 OmniFocus Task 模型中的表示。两者不是重复接口。

### Completion Domain

Completion Domain 位于 `src/domain/completion/`,对外读模型是 `CompletedTaskView`。

`CompletedTaskView` 表达一次直接完成事件:

- Action 或 Action Group identity
- direct `completedDate`
- Project/Inbox context
- tags
- created/modified timestamps

`get_completed_since` 读取 direct `completionDate` 位于指定闭区间内的完成事件,并按完成时间降序返回。

它不会通过以下值推导历史完成:

- `taskStatus`
- `modificationDate`
- `effectiveCompletedDate`

Project root completion event 被排除,Action Group completion 被保留。Completion Domain 是未来 Review Workflow、完成回顾和趋势分析的事实基础,但当前不自动生成 Review 结论。

### Snapshot Domain

Snapshot Domain 位于 `src/domain/snapshot/`,对外读模型是 `LeanSnapshotView`。

```text
LeanSnapshotView
├── generatedAt
├── scope = all
├── projects
│   ├── active
│   ├── planned
│   └── deadline
├── attention
└── inbox
```

每个 list section 均提供:

```text
total
returned
truncated
items
```

Lean Snapshot 不是完整数据库导出。它只读取当前 remaining Tasks 和 Active Projects,并输出当前管理视角需要的 compact facts:

- 不读取 note 全文,只输出 `hasNote`。
- 不包含完成历史;完成历史由 Completion Domain 提供。
- 不包含 Waiting、health、risk、priority 或 recommendation。
- 不展开所有 Project Task details,只保留 Task counts 和 native-status aggregate。
- Project root 在内部用于语义解析,但不进入 Task Attention 或 Inbox。

它也不是普通查询接口。Snapshot Composer 会执行 Project/root join、ownership classification、完整计数、稳定排序和独立截断,从而形成一次性的系统级 current-state read model。

---

## 5. Semantic Rules

### Direct, effective, and source

Domain 日期语义统一表达为:

```ts
{
  direct: string | null;
  effective: string | null;
  source: "direct" | "inherited" | "none";
}
```

- `direct`:值直接设置在当前对象上。
- `effective`:OmniFocus 计算后的实际生效值,可能来自当前对象或上层容器。
- `source = direct`:当前对象直接拥有该值。
- `source = inherited`:当前对象只有从容器继承的 effective value。
- `source = none`:不存在对应事实。

该区分用于保留事实,同时防止把 inherited value 当作新的管理信号。

### Planned Attention

冻结规则:

> Direct Planned owner produces Planned visibility.

对于 Action 和 Action Group,`planned` Attention 需要:

```text
planned.source = direct
AND planned.direct <= generatedAt
AND taskStatus != Blocked
```

对于 Active Project,root Task 的 direct Planned 已到达时,Project 进入 `projects.planned`。

Inherited Planned values:

- 继续保留在 Domain dates 中。
- 不产生独立 `planned` Attention。
- 不把一个 Project-level workflow 展开为多个重复 child signals。

### Due Attention

冻结规则:

> Direct Due owner produces deadline signal.

对于 Action 和 Action Group:

```text
due.source = direct
AND native taskStatus = DueSoon | Overdue
```

对于 Active Project,root Task 直接拥有 Due 且 native status 为 `DueSoon` 或 `Overdue` 时,Project 进入 `projects.deadline`。

Inherited Due values:

- 继续保留在 Domain dates 中。
- 不产生独立 `dueSoon` 或 `overdue` Attention。
- 不因为多个 descendants 继承相同 Due 而产生重复 deadline signals。

系统使用 OmniFocus native `taskStatus` 判断 DueSoon/Overdue,不定义自有 DueSoon 时间窗口。

### Attention aggregation

Attention reasons 的固定顺序为:

```text
overdue -> dueSoon -> planned -> flagged
```

同一 Task 最多出现一次,但可以同时携带多个 reasons。Inbox 和 Attention 是独立 section,因此同一 Task 可以出现在两者中。

---

## 6. Current MCP Tools

本节描述当前生产的五个 read tools。它们不是简单数据查询,而是面向 AI 分析的领域投影。

### `get_task`

按 exact Task ID 或区分大小写的 exact name 读取单个 `TaskView`。

主要用途:

- 区分 action、action_group 和 project_root。
- 检查 direct/effective 日期来源。
- 检查 completion、drop 和 flag provenance。
- 获取 Project context、Inbox location 和 hierarchy。

它查询 OmniFocus Task 实体,但返回的是稳定 Task Domain View,而不是通用 Task query result。

### `get_project`

按 canonical Project ID 或区分大小写的 exact name 读取单个 `ProjectView`。

主要用途:

- 获取 Project status、kind 和 Folder context。
- 查看 direct/all Task relationships 和 native-status counts。
- 查看 Project Due/Defer provenance。
- 使用统一 canonical ID 连接 Project 和 root Task 视角。

它表达 Project aggregate,不替代选择性 `get_task` 读取。

### `get_completed_since`

读取 `{ since, until? }` 闭区间内的 direct completion events。

主要用途:

- 完成回顾。
- Review Workflow 的事实输入。
- 后续趋势或节奏分析。

`since` 和 `until` 必须是带 `Z` 或明确 UTC offset 的完整 ISO 8601 datetime;`until` 缺省为调用时刻。空结果是正常成功。

### `get_lean_snapshot`

读取当前全系统的 compact `LeanSnapshotView`。

主要用途:

- 查看全部 Active Projects 的摘要。
- 查看已经到达的 direct Planned Project owners。
- 查看 Project-level direct deadline owners。
- 查看 Task-level Attention reasons。
- 查看 Inbox 当前状态。

可选 `limitPerSection` 独立限制各 section,默认 `25`,允许 `1..100`。每个 section 在截断前计算完整 `total`。

### `search_tags`

对既有 OmniFocus Tag 执行结构化只读发现,默认只返回 Active。输出包含 canonical ID、exact
native status、完整 root-to-self path、children 与 mutual-exclusion facts;同名 Tag 必须按
完整 path 消歧。该 Tool 不创建或修改 Tag,结果也不是长期 mutation token;tagged creation 必须
在本次明确意图中以完整 path 确认候选,并只向 `create_task` 提交 canonical IDs。

### Upstream compatibility surface

仓库仍保留 upstream `v1.9.2` 的通用查询、Resource、Perspective、Tag 和 mutation tools。
它们只在显式选择 `upstream-full` 时由 `src/serverRegistration.ts` 注册,不属于
`v1.0-personalized` Domain Contract,也不进入默认 `personal-production` surface。

因此,仓库保留写入实现不等于默认实例可写;当前边界由 Server-side Profile registration
强制,而不是客户端 allowlist。`personal-production` 当前公开五个 read tools(含 `search_tags`)和
两个受控 mutation(`create_task`、`create_project_skeleton`),且无 Resources/Prompts;`upstream-full` 只能显式启用。

---

## 7. Current Design Boundaries

`v1.0-personalized` 当前不包含以下能力。

### Full Snapshot MCP

当前只有 Lean Snapshot。仓库中的 `dump_database` 是 upstream raw/full report 能力,不是一个经过稳定 Domain 建模的 Full Snapshot MCP。

### Action independent Domain

Action 与 Action Group 当前属于 Task Domain,通过 `TaskKind` 表达。不存在独立 Action Domain、`ActionView` 或 `get_action`。

### AI automatic decision making

Domain Tool 不判断优先级、风险、健康度或“下一步应该做什么”。AI 分析结果不等于系统决策。

### OmniFocus write automation

自动写入不是个性化架构的一部分。当前个性化 workflow 不会根据 Snapshot 或 AI 分析自动创建、编辑、完成或删除 OmniFocus 对象;`create_task` V4 仅响应用户新的、明确的单个 Task 创建请求;`create_project_skeleton` 仅响应用户明确确认的固定 Project Skeleton 创建请求。两者都绝不按名称解析、自动创建 Tag/Folder,或在目标不明确时 fallback。

Upstream mutation tools 仍存在于仓库中,但不属于个性化默认操作路径。

这些边界是当前冻结范围,不代表对应方向已经确定实现。

---

## 8. Future Roadmap

### Future Phase

未来评审可能考虑:

- Full Snapshot:在明确 Contract 和体积边界后,提供比 Lean Snapshot 更完整的 Domain read model。
- AI Review Workflow:组合 Snapshot 和 Completion facts,支持结构化回顾流程。
- Better semantic analysis:在不污染事实层的前提下,增强对执行系统模式的分析。

未来演进应继续保持:

- Raw facts 与解释分离。
- direct ownership 语义稳定。
- 写入行为不由分析结果自动触发。
- 新概念先定义 Domain boundary,再决定是否增加 MCP Tool。

---

## 9. Safety Model

### Default personal production profile

`personal-production` 是面向日常 ChatGPT App 的精选生产能力集合。当前精确接口为:

```text
get_task
get_project
get_completed_since
get_lean_snapshot
search_tags
create_task
create_project_skeleton
```

前五个是稳定 read tools;后两个是分别受 feature gate、显式授权、幂等、锁和 verification 保护的 mutation。该 Profile 不注册 Resources 或 Prompts。Skeleton 的完整调用规范见 [`docs/integration/CREATE_PROJECT_SKELETON_AI_CALL_GUIDE.md`](./docs/integration/CREATE_PROJECT_SKELETON_AI_CALL_GUIDE.md)。

### No automatic OmniFocus mutation

Snapshot、Attention 和 Completion 结果只作为分析输入,不会自动触发 OmniFocus 写入。AI 不应根据分析结果自行调用创建、编辑、完成、移动或删除操作。

### User retains final control

系统责任边界是:

```text
OmniFocus 提供事实
    ↓
Domain Layer 解释事实来源和结构
    ↓
AI 分析事实
    ↓
用户确认、决策并执行
```

用户始终保持最终控制权。

### Deployment profiles

ChatGPT Developer App、ChatGPT Web / iPhone 和 Secure MCP Tunnel 当前使用:

```bash
OMNIFOCUS_MCP_PROFILE=personal-production
```

该 Profile 当前在 Server capability registration 层只公开 `get_lean_snapshot`、
`get_project`、`get_task`、`get_completed_since`、`search_tags`、`create_task` 和 `create_project_skeleton`,不注册 generic read tools、
其他 mutation tools 或 MCP Resources。因此当前能力边界不依赖客户端 Tool allowlist。
`create_task` V4 和 `create_project_skeleton` 只允许各自合同定义的 request-scoped creation;不能从 Profile 名称或任一 Tool 推断、自动获得任何其他写入能力。当前代码的 global、Project、Parent、Tag、Skeleton gates 均为 fail-closed;任何实际 loaded flag 或 Tunnel 状态属于运行时事实,必须单独实时检查,不能由本文断言。Tag creation 仍必须使用 fresh `search_tags` canonical IDs,并通过写前 Active ancestor、去重和互斥验证。

T2-D tagged Inbox 与 tagged Project Canary 均已通过一次性隔离进程完成单次创建、服务器侧
exact ID-set/placement 验证、用户人工确认/删除与 ID/name 双 `not_found`;Project 计数恢复到
创建前值,Tag projection、Ledger/audit/lock 终检通过。公开 Tunnel 在 T2-D 期间始终保持
Tag flag=`false`;T2-E 随后按 fail-closed reload 正式启用,配置过程零 mutation。

环境变量未设置或为空时安全默认进入 `personal-production`。`upstream-full` 只能通过
`OMNIFOCUS_MCP_PROFILE=upstream-full` 显式启用;完整模式继续注册仓库现有的全部 Tool
和 Resources,包括 mutation tools,不作为日常 ChatGPT App 默认 Profile。任何其他
Profile 值(包括旧的 `personal-readonly`)都会在 Server connect 前导致启动失败,并列出允许值。

---

## Maintenance Reference

当前 Domain 设计与冻结语义主要位于:

```text
src/domain/task/
src/domain/project/
src/domain/completion/
src/domain/snapshot/

engineer_log/GET_TASK_ENGINEERING_LOG.md
engineer_log/GET_PROJECT_ENGINEERING_LOG.md
engineer_log/GET_COMPLETED_SINCE_ENGINEERING_LOG.md
engineer_log/GET_LEAN_SNAPSHOT_ENGINEERING_LOG.md
engineer_log/GET_LEAN_SNAPSHOT_PLANNED_CORRECTION_ENGINEERING_LOG.md
engineer_log/GET_LEAN_SNAPSHOT_DUE_ATTENTION_GRANULARITY_ENGINEERING_LOG.md
```

后续维护者和 AI Agent 应优先以类型定义、Domain tests 和工程日志中的冻结规则判断当前行为,不应从通用 Tool 文案推断 Domain semantics。

- [项目文档导航](./docs/README.md)
- [Domain Tool 开发规范](./docs/DEVELOPMENT.md)
- [Tunnel 日常维护与 Tool 发布手册](./tunnel/docs/OmniFocus-MCP-Tunnel日常维护与新增Tool操作手册.md)
- [v1 个性化实现与验收历史](./docs/history/personalization-v1-implementation-and-acceptance.md)

## License

MIT

TDQS

A3.9/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: create_task is the only mutation, while read-only tools cover specific retrievals (projects, tasks, tags, completed items) and a broad snapshot. No overlaps exist.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with lowercase and underscores (e.g., create_task, get_project). The naming is predictable and well-structured.

Tool Count5/5

With 6 tools covering creation and various read operations, the count is well-scoped for an OmniFocus integration. Each tool earns its place and the set feels neither sparse nor bloated.

Completeness2/5

The tool surface misses critical CRUD operations like update, delete, and complete tasks. The descriptions explicitly unsupport many common actions, leaving significant gaps for a task management server.

Maintenance

ActivitySlowing
ResponsivenessNo issues