Things MCP
The Things MCP server enables AI assistants to fully manage Tasks and Projects in Things 3 on macOS, supporting creation, reading, updating, and automation.
Write Operations
add-todo— Create to-dos with title, notes, scheduled date, deadline, tags, checklist items, and project/area assignment (supports multiple at once)add-project— Create projects with initial to-dos, notes, dates, tags, and area assignmentupdate-todo— Modify a to-do's title, notes, dates, tags, checklist, status (complete/canceled), or list assignment (requires auth token)update-project— Update a project's title, notes, dates, tags, area, or status (requires auth token)add-json— Create complex nested structures (projects with headings, to-dos, checklist items) using Things' JSON command format
Read Operations
get-todos— Retrieve to-dos by built-in list (Inbox, Today, Upcoming, Someday, etc.), project, area, or tagget-todo-by-id/get-project-by-id— Fetch a specific to-do or project by IDget-projects/get-areas/get-tags— List all projects, areas, or tagssearch-todos— Search to-dos by title or notes contentget-recent-todos— Get recently modified to-dos within a configurable number of days
Navigation & Search
show— Open Things to a specific list, project, area, tag, or individual to-dosearch— Open the Things search screen with an optional query
Automation
reschedule-distant-todos— Automatically move far-future tasks out of the Today list, with configurable threshold/buffer days and adryRunpreview mode (requires auth token)
Requirements: macOS, Things 3 (with URL Scheme enabled), Node.js >= 18. Compatible with Claude Desktop, Cursor, Codex, and Gemini CLI.
Enables management of the Things 3 task manager on macOS, allowing for the creation, retrieval, and modification of to-dos, projects, areas, and tags through AppleScript and URL schemes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Things MCP Add 'Review project proposal' to my Today list with a reminder at 4pm"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Things App MCP
English | 한국어
MCP server for Things 3 on macOS. It adds, reads, and updates to-dos through the Things URL scheme and JXA, and npm run sync copies the Today list into a Notion database.
The server talks to the client over stdio on your Mac.
Requirements
macOS
Node.js 18 or newer
Things URLs turned on: Things > Settings > General > Enable Things URLs
Automation permission for whichever app starts the server (Terminal, Claude, Cursor, or Codex).
osascripthas to be allowed to control Things.
Related MCP server: Things Cloud MCP
Install
git clone https://github.com/lucas-flatwhite/things-app-mcp.git
cd things-app-mcp
npm install
npm run buildYou can also skip the clone and let the client run npx -y things-app-mcp@latest. The configs below do that.
Connect a client
Adding and reading to-dos works without a token. Changing an existing item, or applying a reschedule, needs the Things auth token.
In Things: Settings > General > Enable Things URLs > Manage.
Set THINGS_AUTH_TOKEN in the client config. If you pass authToken on each call, that token lands in the client log. Replies strip the token, notes, and JSON data. The URL given to open still has the token for a moment. Things expects it there.
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"things": {
"command": "npx",
"args": ["-y", "things-app-mcp@latest"],
"env": {
"THINGS_AUTH_TOKEN": "your-token-here"
}
}
}
}Cursor
.cursor/mcp.json
{
"mcpServers": {
"things": {
"command": "npx",
"args": ["-y", "things-app-mcp@latest"],
"env": {
"THINGS_AUTH_TOKEN": "your-token-here"
}
}
}
}Codex
~/.codex/config.toml
[mcp_servers.things]
command = "npx"
args = ["-y", "things-app-mcp@latest"]
startup_timeout_sec = 20
tool_timeout_sec = 120
[mcp_servers.things.env]
THINGS_AUTH_TOKEN = "your-token-here"Gemini CLI
export THINGS_AUTH_TOKEN="your-token-here"
gemini mcp add things npx -y things-app-mcp@latestFor a local build, use node and the absolute path to dist/index.js instead of npx.
Tools
Writing
Tool | Description |
| New to-do: title, notes, when, deadline, tags, checklist, project, or area. |
| New project. Put to-do titles in |
| Change a to-do by id, including completing or canceling it. Needs the token. |
| Change a project by id. Needs the token. |
| Open a list, project, area, tag, or to-do in Things. |
| Open Things search. |
| Nested projects, headings, to-dos, and checklist items. Updates need the token. |
When a write succeeds, macOS has opened the URL. Read the item again if you need to see that Things saved it. add-todo does not return the new id.
Reading
Tool | Description |
| To-dos from one list, project, area, or tag. |
| One to-do by id. |
| Every project. |
| One project by id. |
| Every area. |
| Every tag. |
| To-dos whose title or notes contain the query. |
| To-dos changed in the last N days. Default is 7. |
Call get-todos with one of list, project, area, or tag. If you leave them all out, you get Today.
Lists: Inbox, Today, Anytime, Upcoming, Someday, Logbook.
Results include titles and notes.
Clearing Today
reschedule-distant-todos looks through Today for open items whose deadline is still far off, and moves the start date to a few days before that deadline.
No arguments means preview only, and only when a token is set. To apply:
{
"daysThreshold": 7,
"bufferDays": 3,
"dryRun": false,
"confirm": true
}daysThreshold(default 7): a closer deadline stays in Today.bufferDays(default 3): new start date, this many days before the deadline.An item you put on today yourself (
activationDateis today) stays where it is.dryRun: falsewithoutconfirm: truereturns an error and leaves Today unread.confirmis a tool argument. A client that readsdestructiveHintmay ask again before it runs.The update is one JSON batch.
update-todo, update-project, and updates through add-json do not take confirm. With the token set, those calls can edit or complete items.
Examples
Add a to-do:
{
"title": "Buy groceries",
"when": "today",
"tags": "Errand"
}Create a project and its to-dos:
{
"title": "Launch Website",
"area": "Work",
"todos": "Design mockups\nBuild frontend\nDeploy"
}Read Today:
{ "list": "Today" }Read one project:
{ "project": "Launch Website" }Complete a to-do once you have its id:
{
"id": "the-todo-id",
"completed": true
}Preview a reschedule, then apply it:
{ "dryRun": true }{ "dryRun": false, "confirm": true }Dates, lists, and JSON
Write tools follow the Things URL scheme.
When and deadline
Format | Example |
Named |
|
Date |
|
Date and time |
|
Natural language |
|
show list ids
inbox, today, anytime, upcoming, someday, logbook, tomorrow, deadlines, repeating, all-projects, logged-projects
add-json types
Type | What it is |
| A task: title, notes, when, deadline, tags, checklist items. |
| A project: title, notes, nested items. |
| A section in a project. |
| One line in a to-do. |
To update, set "operation": "update" and "id". That needs the auth token.
Layout
src/index.ts MCP tools
src/things-url.ts things:/// URLs, and stripping secrets from replies
src/applescript.ts JXA reads
src/reschedule-mode.ts preview versus apply
src/notion-sync.ts `npm run sync`, separate from the MCP server
src/notion-sync/ plan, Notion client, Things read and writeWrites build a things:/// URL and hand it to open. Reads run JXA through osascript.
Development
npm install
npm run build
npm run dev # tsc --watch
npm start # node dist/index.jsTesting
See TESTING.md.
# No Things required.
node scripts/test-unit.js
# Sync plan, hashes, and the Notion client. No network and no Things.
npm run test:sync
# macOS and Things 3. Writes stay off.
npm run test:tools
THINGS_MCP_TEST_ALLOW_WRITES=1 npm run test:toolsOne case in the unit script reads Today when Things is installed. Skip it with:
THINGS_UNIT_SKIP_LIVE=1 node scripts/test-unit.jsNotion sync
npm run sync copies the Things Today list into Notion database 9ac2752989a646918bfa93ab900dfb8c. That list is whatever Things is showing under Today: items for today, this evening, and overdue items still sitting there. Inbox, Upcoming, Anytime, and Someday are left as they are.
You start each run yourself.
Setup
Put the Notion token in the macOS keychain. Every run reads it from there.
security add-generic-password -s things-notion-sync -a "$USER" -wSet THINGS_AUTH_TOKEN when the plan changes a Things to-do. A run that only creates or edits Notion rows can go without it.
If a column is missing, the dry-run exits 2 and prints a database patch. This command adds the missing columns and then writes the plan:
npm run sync -- --apply --ensure-schema시작일 is the calendar formula. A missing column, or a column of some other type, prints a warning and the sync continues. Paste this into Notion:
if(test(prop("언제"), "^\d{4}-\d{2}-\d{2}"), parseDate(slice(prop("언제"), 0, 10)), parseDate(""))Run
npm run build
npm run sync # print the plan
npm run sync -- --apply # write itThe table columns are action, things_id, title, fields, and detail. With nothing to do, the command prints 변경 없음. The same text is appended to ~/Library/Logs/things-notion-sync.log, with ids, actions, and field names. Tokens and note text are stripped first.
Columns
Column | What the sync does |
제목, 메모, 마감일, 태그 | Copied both ways while the to-do is in Today. |
언제 | Copied both ways for |
상태 |
|
시작일 | Shown on a calendar. The sync skips this column. |
프로젝트, 프로젝트 id, 영역, 영역 id | Filled from the Things to-do. |
things_id | Things id for the row. The next run finds the row with this. |
동기화 해시 | Field hashes from the last write. The next run compares against this. Edit the hash and a later |
마지막 동기화 | When that write happened. |
A tag name Things has never seen is dropped. Checklists, headings, and repeat rules stay in Things. A repeat that is in Today is copied like any other to-do. If Things ignores a when or deadline change, that Things value is written back to the row.
Marking a to-do done
On the Notion page, set 상태 to 완료. Leave things_id and 동기화 해시 alone. Then run npm run sync -- --apply while the to-do is still in Today, and Things completes it. The same works the next day if it is still in Today when you run the command. 취소 cancels the to-do. 열림 opens it again.
After Things completes it, the to-do leaves Today and the row stays 완료. The next run fills any other differing fields from Things. From then on, edits to that row stay in Notion.
A new Notion row with an empty 언제, or with 오늘 or 오늘 저녁, is added to Today when you apply.
Deleting rows
Rows are matched by things_id. Delete an 열림 row while its to-do is still in Today, and the next run creates the row again. The to-do stays open.
Finished rows can stay in the database. A completed to-do has left Today, so that row is left alone. A row can also be deleted after its to-do moves to Inbox, Anytime, Upcoming, or Someday. It comes back if the to-do returns to Today.
License
MIT
Available Tools
15 toolsadd-jsonAdd via JSONA
Create complex projects and to-dos using the Things JSON command. Supports nested projects with headings, checklist items, and to-dos. The data should be an array of objects with "type" (to-do, project, heading, checklist-item) and "attributes" fields. For updates, include "operation": "update" and "id" fields, and provide auth-token.
Inputs: data (required), authToken, reveal.
add-projectAdd ProjectA
Create a new project in Things. Supports setting title, notes, when/deadline dates, tags, area assignment, and initial to-dos.
Inputs: title, notes, when, deadline, +9 more.
add-todoAdd To-DoA
Create a new to-do in Things. Supports setting title, notes, when/deadline dates, tags, checklist items, and assigning to projects/areas. Uses the Things URL scheme.
Inputs: title, titles, notes, when, +13 more.
get-areasGet AreasARead-only
Get all areas from Things. Uses AppleScript (macOS only).
Inputs: no named parameters.
get-project-by-idGet Project by IDARead-only
Get a specific project by its ID. Uses AppleScript (macOS only).
Inputs: id (required).
get-projectsGet ProjectsBRead-only
Get all projects from Things. Uses AppleScript (macOS only).
Inputs: no named parameters.
get-recent-todosGet Recent To-DosARead-only
Get recently modified to-dos. Uses AppleScript (macOS only).
Inputs: days.
get-tagsGet TagsBRead-only
Get all tags from Things. Uses AppleScript (macOS only).
Inputs: no named parameters.
get-todo-by-idGet To-Do by IDARead-only
Get a specific to-do by its ID. Uses AppleScript (macOS only).
Inputs: id (required).
get-todosGet To-DosARead-only
Get to-dos from Things by list, project, area, or tag. Specify exactly one source. Uses AppleScript (macOS only).
Inputs: list, project, area, tag.
searchSearch in ThingsARead-only
Open the search screen in Things with an optional search query.
Inputs: query.
search-todosSearch To-DosARead-only
Search for to-dos by title or notes content. Uses AppleScript (macOS only).
Inputs: query (required).
showShow in ThingsARead-only
Navigate to and show a list, project, area, tag, or to-do in Things. Built-in list IDs: inbox, today, anytime, upcoming, someday, logbook, tomorrow, deadlines, repeating, all-projects, logged-projects.
Inputs: id, query, filter.
update-projectUpdate ProjectB
Update an existing project in Things. Requires the project ID and your Things auth-token.
Inputs: authToken (required), id (required), title, notes, +14 more.
update-todoUpdate To-DoA
Update an existing to-do in Things. Requires the to-do ID and your Things auth-token. Supports changing title, notes, dates, tags, checklist, list assignment, and status.
Inputs: authToken (required), id (required), title, notes, +19 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Most tools are clearly distinct by resource and action, such as add-project vs. update-project. However, some potential confusion exists: 'search' opens the search screen, while 'search-todos' performs a specific search; 'get-todos' retrieves by source, and 'get-recent-todos' gets recent ones, which might overlap in use cases. Descriptions help clarify, but minor ambiguity remains.
Tool names follow a consistent verb_noun pattern throughout, with clear actions like 'add', 'get', 'update', and 'search' paired with specific nouns like 'project', 'todo', or 'areas'. All names use snake_case uniformly, making them predictable and easy to parse.
With 15 tools, this server is well-scoped for managing tasks and projects in Things. It covers core CRUD operations for projects and to-dos, plus additional utilities like listing areas and tags, which fits the domain appropriately without being overwhelming or insufficient.
The tool set provides strong coverage for the task management domain, including creation, retrieval, and updates for projects and to-dos, plus listing areas and tags. Minor gaps exist: there's no explicit delete tool for projects or to-dos, and 'add-json' might overlap with other add tools, but agents can likely work around these with updates or existing methods.
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Official Todoist MCP server. Manage tasks and projects. Hosted, no API key needed.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that allows AI assistants like Claude Code, Claude Desktop, and Cursor to interact with Things.app on macOS, enabling task creation, updates, viewing, scheduling, and organization through natural language.646 npm3MIT
- AlicenseBqualityDmaintenanceMCP server that gives AI agents read/write access to your Things3 tasks via the Things API.321Apache 2.0
- AlicenseNot gradedqualityCmaintenanceAn MCP server for Things 3 on macOS that enables AI assistants to manage tasks using the Getting Things Done (GTD) methodology, including capture, clarify, organize, reflect, and engage stages.14MIT
- AlicenseAqualityDmaintenanceAn MCP server that lets Claude read and write your Things 3 tasks on macOS via AppleScript.10MIT