UNPKG

omnifocus-mcp-enhanced

Version:

🚀 NEW: Native Custom Perspective Access! Enhanced MCP server with OmniFocus custom perspective support, hierarchical task display, AI-optimized tool selection, and comprehensive task management

184 lines (146 loc) 6 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Development Commands - `npm run build` - 编译 TypeScript 并复制脚本文件到 dist/ 目录 - `npm run dev` - 开发模式,监听文件变化并实时编译 - `npm start` - 运行编译后的服务器 - `npm run copy-files` - 复制 OmniFocus 脚本文件到 dist 目录 - `npm test` - 运行测试(当前只是占位符,需要手动测试) ## Architecture Overview 这是一个基于 TypeScript 的 Model Context Protocol (MCP) 服务器,专门用于 OmniFocus 集成。 你给用户输出的东西,不要包含表情符号,这是一个严肃的项目 ### 核心架构层次: 1. **服务器层** (`src/server.ts`) - MCP 服务器主入口,注册所有工具 2. **工具定义层** (`src/tools/definitions/`) - 定义工具的 schema 和处理器 3. **基础功能层** (`src/tools/primitives/`) - 实际的业务逻辑实现 4. **脚本执行层** (`src/utils/scriptExecution.ts`) - JXA/OmniJS 脚本执行引擎 5. **OmniFocus 脚本层** (`src/utils/omnifocusScripts/`) - 具体的 OmniFocus 操作脚本 ### 工具分类: - **数据库管理**: dump_database - **任务管理**: add_omnifocus_task, remove_item, edit_item, get_task_by_id - **项目管理**: add_project - **批量操作**: batch_add_items, batch_remove_items - **透视图**: get_inbox_tasks, get_flagged_tasks, get_forecast_tasks, get_tasks_by_tag - **高级过滤**: filter_tasks - **自定义透视图**: list_custom_perspectives (基于 OmniJS Perspective.Custom.all API) - **完成任务**: get_today_completed_tasks ## 重要约束 - 不要使用 AppleScript 来解决问题,使用 JXA (JavaScript for Automation) 或 OmniJS - 仅支持 macOS 平台(依赖 OmniFocus 应用) - 需要 Node.js 18+ 环境 - 所有脚本文件必须在构建时复制到 dist/ 目录 - **CLAUDE.md 是私人约定文件,不要提交到 git** ## 代码结构规范 ### 添加新工具的步骤: 1.`src/tools/definitions/` 创建工具定义文件 2.`src/tools/primitives/` 实现具体功能 3.`src/server.ts` 中注册新工具 4. 如需要,在 `src/utils/omnifocusScripts/` 添加相应的 JXA 脚本 ### 工具定义模式: ```typescript // 在 definitions/ 文件中 export const schema = z.object({...}); export const handler = async (args: any) => { // 调用 primitives/ 中的实现 }; ``` ## 脚本执行机制 使用 `src/utils/scriptExecution.ts` 来执行 JXA/OmniJS 脚本: - JXA 脚本通过 `osascript -l JavaScript` 执行 - OmniJS 脚本通过 OmniFocus 的脚本引擎执行 - 脚本文件必须保存在 `src/utils/omnifocusScripts/` 目录 ## 类型定义 所有类型定义在 `src/types.ts` 中,包括: - OmniFocus 对象类型(Task, Project, Context等) - 工具参数和返回值类型 - 脚本执行结果类型 ## 踩坑记录和解决方案 ### ❌ 重大错误:executeOmniFocusScript 返回值处理 **错误现象**: 工具返回 "脚本执行返回了无效的结果" **问题根源**: `executeOmniFocusScript` 函数可能返回两种类型: 1. **JSON 对象** - 当脚本执行成功且 JSON.parse 成功时 2. **字符串** - 当 JSON.parse 失败时,返回原始 stdout **我犯的错误**: ```typescript // ❌ 只处理了字符串情况,忽略了对象类型 if (typeof result === 'string') { const data = JSON.parse(result); // 处理... } throw new Error('脚本执行返回了无效的结果'); // 对象类型会跳到这里! ``` **正确处理方式**: ```typescript // ✅ 同时处理字符串和对象两种情况 let data: any; if (typeof result === 'string') { try { data = JSON.parse(result); } catch (parseError) { throw new Error(`解析字符串结果失败: ${result}`); } } else if (typeof result === 'object' && result !== null) { data = result; // 直接使用已解析的对象 } else { throw new Error(`脚本执行返回了无效的结果类型: ${typeof result}, 值: ${result}`); } ``` **调试技巧**: - 先用 console.log 打印 result 的类型和值 - 添加详细的错误信息,包含实际的返回值 - 不要假设返回类型,要做完整的类型检查 ### ✅ OmniJS 脚本最佳实践 **统一的脚本格式模板**: ```javascript (() => { try { // 获取数据的业务逻辑 const customPerspectives = Perspective.Custom.all; // 格式化结果 const perspectives = customPerspectives.map(p => ({ name: p.name, identifier: p.identifier })); // 返回统一格式 const result = { success: true, count: perspectives.length, perspectives: perspectives }; return JSON.stringify(result); } catch (error) { // 错误处理 const errorResult = { success: false, error: error.message || String(error), count: 0, perspectives: [] }; return JSON.stringify(errorResult); } })(); ``` **关键要点**: - 用 IIFE `(() => {})()` 包装避免全局污染 - 统一返回 JSON 字符串格式 - 必须包含 `success` 字段指示成功/失败 - 错误处理要完整,包含错误信息 - 数据结构要一致,便于 TypeScript 处理 ### 🔧 工具开发流程教训 **正确的开发顺序**: 1. 先写 OmniJS 脚本并单独测试 2. 实现 primitive 函数,处理返回值 3. 创建工具定义,定义 schema 4. 在 server.ts 中注册新工具 5. 编译测试,逐步调试 **重要提醒**: - 遇到错误先加详细的 console.log 调试日志 - 不要积累太多问题,每一步都要测试 - 错误信息要包含实际的数据类型和值 - primitive 函数要处理所有可能的返回类型 ### 🎯 成功案例:list_custom_perspectives 基于 `Perspective.Custom.all` API 成功实现的工具: - OmniJS 脚本:使用原生 API 获取透视列表 - 支持 simple 和 detailed 两种格式 - 完整的错误处理和类型检查 - 编译和运行都正常