Model Context Protocol server for Things 3 task management integration
This server exposes 43 tools for Things 3 task management with a STDIO-only transport. Tool names follow verb_noun conventions (get_todos, add_todo, etc.), which is good. However, descriptions are inconsistent in quality: some provide context (e.g., get_todos mentions 'AppleScript for projects'), while others are terse (e.g., get_projects 'Get all projects directly from database' lacks guidance on when to use it vs. get_areas). Parameter descriptions exist for most tools but lack granularity, many params like 'kwargs' (in add_todo, update_todo, add_project, update_project, add_area, update_area) are documented as 'Optional parameters like project, area, tags, due date, etc.' without enumerating valid keys, constraints, or format guidance. No tool explicitly declares output schemas, making it unclear what fields an LLM should expect. Error handling is not documented, no guidance on retryability, user-fixability, or recovery paths. Destructive tools (delete_todo, bulk_delete_todos) lack dry-run/confirmation patterns. Security consideration: tools accept direct IDs without validation or injection guards mentioned. The 'kwargs' pattern is a red flag, it obscures required vs. optional fields and invites LLMs to hallucinate parameters. Overall, the server is functional but lacks the precision and guardrails expected of production agent tools.
Add a new area.
Add checklist items to an existing todo.
Add a new project using AppleScript.
Add a new todo with optional parameters.
Mark multiple todos as canceled.
Mark multiple todos as completed.
Delete multiple todos permanently.
Update multiple todos with the same values.
Opaque kwargs parameters hide required vs. optional fields. Tools add_todo, update_todo, add_project, update_project, add_area, update_area accept a 'kwargs' object documented only as 'Optional parameters like project, area, tags, due date, etc.' LLMs cannot determine which keys are valid, what formats they accept, or what side effects occur. This violates constrained-input and param-description patterns.
No output schemas documented. Tools return objects (e.g., get_todos, get_projects) but LLMs do not know what fields to expect, preventing them from chaining operations or extracting required IDs for downstream calls. This violates the response-shaper pattern and breaks tool composition.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 54 | <=2025-11-25 | v2 |
| 2026-03-09 | D | 53 | - | v1 |
Mark a todo as canceled.
Mark a todo as completed.
Delete a todo permanently.
Get todos activating within specified days.
Get anytime items directly from database.
Get all areas directly from database.
Get todos due within specified days.
Get inbox items directly from database.
Get completed (and, by default, canceled) items directly from database.
Get the heading structure of a project, in Things' display order.
Get all projects directly from database.
Get recent items. Defaults to all statuses, to-dos + projects (no headings unless type='heading' is passed explicitly).
Get someday items directly from database.
Get per-tag usage counts (open/total), sorted by usage, for tag cleanup.
Get items with a specific tag directly from database.
Get all tags with counts or items - super fast with things.py.
Get today items directly from database.
Get a specific todo by ID directly from database.
Get todos with hybrid approach: AppleScript for projects, things.py otherwise.
Get todos activating within specified days.
Get todos due within specified days.
Get todos due or activating within specified days.
Get trashed items directly from database with pagination.
Get upcoming items. If days is specified, returns todos due/activating within that timeframe.
Move multiple todos to a specific area.
Move multiple todos to a specific list (Inbox, Today, Upcoming, Anytime, Someday).
Move multiple todos to a specific project.
Prepend checklist items to an existing todo.
Replace all checklist items in a todo.
Advanced search - delegate to AppleScript scheduler with limit support.
Search todos directly in database with optional limit, offset, and status filter.
Reopen a completed todo.
Update an existing area.
Update an existing project using AppleScript.
Update an existing todo with new values.
Destructive tools (delete_todo, bulk_delete_todos) lack confirmation or dry-run patterns. An LLM can irreversibly delete tasks without being asked to confirm, increasing risk of accidental destruction.
Tool search_advanced has vague input (filters as arbitrary object) and minimal description ('Advanced search - delegate to AppleScript scheduler with limit support'). LLMs cannot infer what filter keys are valid or what the scheduler actually supports.
Multiple tools perform overlapping queries without clear disambiguation. get_todos, get_logbook, get_trash, get_recent all retrieve items but differ subtly in scope, period, and default status. Descriptions do not guide LLMs on which to call first or when to prefer one over the other.
Duplicate tool names with subtle differences. get_due_in_days vs. get_todos_due_in_days, get_activating_in_days vs. get_todos_activating_in_days. These confuse LLMs, what is the difference? Why are there two? Documentation does not explain.
No error handling guidance. Tools do not document recovery paths, e.g., if delete_todo fails, is it retryable? Should the LLM ask the user? If search_todos returns no results, is that a user error or a bug? Without classification, agents cannot reason about next steps.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). The server marks risks (READ_ONLY, WRITE, DESTRUCTIVE) in metadata but does not expose them via MCP tool annotations. LLMs cannot dynamically reason about safety without explicit hints.
Tools return unbounded lists. get_todos, get_projects, get_areas, get_tags have limit/offset parameters but no documented defaults or caps. An LLM can request thousands of items, exhausting memory and context windows. Enforce sensible defaults (limit=50) and document them.