get-todos
Retrieve tasks from Things 3 with filters for projects, lists, areas, status, and search queries to organize your workflow.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_uuid | No | Optional UUID of a specific project | |
| include_items | No | Include checklist items | |
| list | No | Built-in list name like Inbox, Today, Anytime | |
| area | No | Optional area UUID or title filter | |
| status | No | Optional status filter | |
| query | No | Optional title/notes search | |
| detail | No | Response detail level. Defaults to compact. | |
| limit | No | Maximum number of todos to return |
Implementation Reference
- src/index.ts:1177-1240 (handler)The "get-todos" MCP tool is registered and implemented in src/index.ts. It filters tasks from the Things 3 database based on optional parameters like project, list (built-in lists), area, status, and query, and returns them formatted as a task view.
"get-todos", { project_uuid: z.string().optional().describe("Optional UUID of a specific project"), include_items: z.boolean().optional().describe("Include checklist items"), list: z.string().optional().describe("Built-in list name like Inbox, Today, Anytime"), area: z.string().optional().describe("Optional area UUID or title filter"), status: z.string().optional().describe("Optional status filter"), query: z.string().optional().describe("Optional title/notes search"), detail: z.enum(["compact", "full"]).optional().describe("Response detail level. Defaults to compact."), limit: z.number().int().positive().optional().describe("Maximum number of todos to return"), }, async ({ project_uuid, include_items, list, area, status, query, detail, limit }) => { const requestedDetail = detail ?? "compact"; const todos = await withDatabase((db) => { const tasks = getAllTasks(db); let result = tasks.filter((task) => task.type === "to-do" && !task.trashed); if (project_uuid) { result = result.filter((task) => task.projectId === project_uuid); } if (list) { const normalized = list.toLowerCase(); if (normalized === "inbox") result = getInboxTodos(tasks); if (normalized === "today") result = getTodayTodos(tasks); if (normalized === "upcoming") result = getUpcomingTodos(tasks); if (normalized === "anytime") result = getAnytimeTodos(tasks); if (normalized === "someday") result = getSomedayTodos(tasks); if (normalized === "logbook") result = getLogbookTodos(tasks); if (normalized === "trash") result = getTrashItems(tasks).filter((task) => task.type === "to-do"); } if (area) { const lower = area.toLowerCase(); result = result.filter( (task) => task.areaId?.toLowerCase() === lower || task.areaTitle?.toLowerCase() === lower ); } if (status) { result = result.filter((task) => task.status === status.toLowerCase()); } if (query) { result = result.filter((task) => matchesQuery(task, query)); } result = applyLimit(result, limit); return result.map((task) => toTaskView(task, requestedDetail, { includeChecklist: include_items !== false, }) ); }); return buildTextResponse(`Found ${todos.length} todos`, { todos, detail: requestedDetail, limit: limit ?? null, }); } );