UNPKG

omnifocus-mcp

Version:

Model Context Protocol (MCP) server that integrates with OmniFocus for AI assistant interaction

53 lines (52 loc) 2.09 kB
#!/usr/bin/env node import { startDaemon } from './daemon.js'; import { resolveSocketPath } from './socketPath.js'; /** * Daemon entrypoint (issue #80). * * Normally spawned detached by the shim, but also runnable by hand — it is the * only way to watch the shared server's logs live: * * node dist/daemon/main.js * * Losing the startup race is an ordinary outcome, not an error: a burst of * clients means several of these can launch at once, and all but one should * notice a daemon already exists and quietly step aside. */ const socketPath = process.env.OMNIFOCUS_MCP_SOCKET ?? resolveSocketPath(); async function main() { let handle; try { handle = await startDaemon({ socketPath, // The shim took the lock before spawning us and handed over the critical // section; re-acquiring it would deadlock against our own parent. lockHeldByCaller: process.env.OMNIFOCUS_MCP_LOCK_HELD === '1', }); } catch (err) { if (err.code === 'EADDRINUSE') { console.error(`[omnifocus-mcp] daemon already running on ${socketPath}; exiting.`); process.exit(0); } console.error(`[omnifocus-mcp] daemon failed to start: ${err}`); process.exit(1); } console.error(`[omnifocus-mcp] daemon listening on ${handle.socketPath} (pid ${process.pid})`); // Unlink the socket on the way out. Skipping this is survivable — the next // daemon probes and reclaims a stale file — but it turns a clean restart into // a connect-timeout for whoever finds the corpse first. let closing = false; const shutdown = (signal) => async () => { if (closing) return; closing = true; console.error(`[omnifocus-mcp] daemon received ${signal}; shutting down.`); await handle.close(); process.exit(0); }; process.on('SIGTERM', () => void shutdown('SIGTERM')()); process.on('SIGINT', () => void shutdown('SIGINT')()); process.on('SIGHUP', () => void shutdown('SIGHUP')()); } void main();