Things 3, from any AI chat.
Things Cloud has no public API. Things Orchestrator uses its sync protocol from a small server you run, so your agent can add tasks, read Today, and check things off without keeping a Mac awake. Connect it to Claude Code, Codex, Cursor, Hermes, or any MCP client.
Set it upOpen source · Self-hosted
Works with
HermesClaude Code
Cursor
Codex
No Mac in the loop.
Your agent talks to a small server you run. The server writes to Things Cloud and reads the account back before reporting success. Your Mac can stay asleep and sync later, just like your iPhone. Choose whether the server runs on your Mac, a private tailnet host, or a public HTTPS host.
A small Linux box on your Tailscale network, running the service around the clock. Nothing sits on the public internet, and your Things password never leaves that box.
On the host
The only machine that ever holds your Things password.
1Install
Pinned to a release tag. It only updates when you tell it to.
$ uv tool install \
"git+https://github.com/matsvarn/things3-orchestrator.git@v0.9.0"
2Sign in
Asks for your Things Cloud email and password, then creates the key
your agent will use. The password stays on your Mac.
$ things-orchestrator login
3Run it as a service
A launchd agent on loopback. Survives restarts and logouts.
$ things-orchestrator service install
4Check it
Two green lines and the host is done.
$ things-orchestrator doctor --wait
mcp: ok (http://127.0.0.1:8787/mcp; 8 tools; commit 8ac76a563c67)
service: current
1Install
Pinned to a release tag. It only updates when you tell it to.
$ uv tool install \
"git+https://github.com/matsvarn/things3-orchestrator.git@v0.9.0"
2Sign in
MACHINE.TAILNET is the server's MagicDNS name. Asks for your Things Cloud
email and password, then creates the key your agent will use.
$ things-orchestrator login --url https://MACHINE.TAILNET.ts.net \
--timezone Europe/Berlin
3Run it as a service, open it to your tailnet
Serve, not Funnel, so only your devices can reach it. Tailscale may
ask once to enable HTTPS for your tailnet.
$ things-orchestrator service install
$ sudo tailscale serve --bg 8787
4Check it
Two green lines and the host is done.
$ things-orchestrator doctor --wait --url https://MACHINE.TAILNET.ts.net
mcp: ok (https://MACHINE.TAILNET.ts.net/mcp; 8 tools; commit 8ac76a563c67)
service: current
1Install
Pinned to a release tag. It only updates when you tell it to.
$ uv tool install \
"git+https://github.com/matsvarn/things3-orchestrator.git@v0.9.0"
2Sign in
Asks for your Things Cloud email and password, then creates the key
your agent will use.
$ things-orchestrator login --url https://mcp.example.com \
--timezone Europe/Berlin
3Run it as a service behind Caddy
Caddy handles HTTPS on your domain. The server stays on loopback
port 8787. Keep that port closed to the internet.
$ things-orchestrator service install
$ sudo apt install caddy
$ things-orchestrator print-config --client caddy \
| sudo tee /etc/caddy/Caddyfile >/dev/null
$ sudo systemctl reload caddy
4Check it
Two green lines and the host is done.
$ things-orchestrator doctor --wait --url https://mcp.example.com
mcp: ok (https://mcp.example.com/mcp; 8 tools; commit 8ac76a563c67)
service: current
In your agent
The host prints a ready-made config for your client. Only the URL and the key leave the host.
# On the host, print the config for this client.
$ things-orchestrator print-config --client claude-code
# It prints one command. Run it on the machine where Claude Code runs.
claude mcp add --transport http things https://MACHINE.TAILNET.ts.net/mcp \
--header 'Authorization: Bearer <mcp_token>'
# On the host, print the config for this client.
$ things-orchestrator print-config --client hermes
# Merge what it prints into your active Hermes profile,
# then start a new session.
mcp_servers:
things:
url: "https://MACHINE.TAILNET.ts.net/mcp"
headers:
Authorization: "Bearer <mcp_token>"
tools:
resources: false
prompts: false
skills:
external_dirs:
- "the path things-orchestrator skill-path prints"
# The Things skill ships with the install; its path belongs
# on the machine running Hermes.
# On the host, print the config for this client.
$ things-orchestrator print-config --client codex
# Merge what it prints into ~/.codex/config.toml
[mcp_servers.things]
url = "https://MACHINE.TAILNET.ts.net/mcp"
http_headers = { Authorization = "Bearer <mcp_token>" }
# On the host, print the config for this client.
$ things-orchestrator print-config --client cursor
# Merge the things entry into ~/.cursor/mcp.json
{
"mcpServers": {
"things": {
"url": "https://MACHINE.TAILNET.ts.net/mcp",
"headers": {
"Authorization": "Bearer <mcp_token>"
}
}
}
}
# Every MCP client over streamable HTTP needs the same two values:
# the URL and the bearer header. This prints them in the JSON shape
# most clients read (Windsurf, Gemini CLI, OpenCode, VS Code, …).
$ things-orchestrator print-config --client cursor
# Merge the things entry into your client's MCP config file.
{
"mcpServers": {
"things": {
"url": "https://MACHINE.TAILNET.ts.net/mcp",
"headers": {
"Authorization": "Bearer <mcp_token>"
}
}
}
}
# If your client uses its own format, carry over those two values.
# Hosted agents outside your network need the public server.
One thing left on your list.
Want to see exactly what it touches before you install? Trust notes
Not yet. This one only counts once your own server reads it back from Things Cloud. Four steps, just above.