A local stdio MCP server for reading and updating Things 3 on macOS. This fork is hardened for use by Butler and other local agents: mutation tools validate ambiguous input, describe their side effects accurately, and never report an unverified Things change as successful.
- macOS with Things 3 installed and opened at least once
- Python 3.12 or newer
uv
Reads come from Things' local SQLite database through things-py. Mutations
are submitted to the Things URL scheme through macOS.
uv sync --frozen
uv run python src/main.pyFor update operations, the server first uses THINGS_TOKEN when it was set at
process startup. Otherwise it asks things-py to read the enabled Things URL
authorization token from the local database. Keep this token out of source
control and logs.
Example MCP configuration:
{
"mcpServers": {
"things3": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/things-3-mcp",
"run",
"python",
"src/main.py"
],
"env": {
"THINGS_TOKEN": "your-enabled-things-url-token"
}
}
}
}The environment entry is optional when things-py can read the token locally.
The server provides tools for Things lists, areas, projects, tags, task lookup, text search, and Markdown exports. It also provides create and update tools for to-dos and projects.
Important operational boundaries:
- Read tools query the database state last written by Things. Today is partly
predicted by
things-py, but repeating tasks are not predicted. searchmatches task, project, heading, and related area text. It does not search tag records.get_completed(last="3d")filters by completion date, not creation date.- Markdown exports explicitly fetch project children with the requested status, including completed and canceled children when requested.
- Create and update tools return
status: "submitted"andverified: false. This means macOS accepted the URL launch only. Callers that need confirmation must read Things again and match the expected state. - Append operations are not idempotent. Retrying
append_notes,add_tags, orappend_checklist_itemsmay duplicate content. - Update tools reject empty updates, simultaneous completed/canceled fields, and simultaneous replacement/append variants of the same field.
- Broad read and Markdown tools are not paginated. Use narrow area/project/task reads when the result could be large.
The server intentionally does not expose deletion, restore, recurrence, individual checklist completion, or batch mutation.
The test suite mocks database and URL-launch boundaries; it does not read or modify personal Things data.
uv run python -m unittest discover -s tests -vThis repository is a fork of
vimtor/things-3-mcp.