Skip to main content
Glama

things-mcp

An MCP server that lets Claude (claude.ai, the Claude mobile and desktop apps, Claude Code) read and edit your Things 3 to-dos. It talks to Things Cloud directly, the sync service the Things apps use, so it works with none of your devices switched on, and changes reach them like any other edit.

It isn't affiliated with Cultured Code. Things Cloud has no public API: this relies on a protocol learned from the apps' own traffic, which can change without notice. Writes copy the exact shapes Things 3.24 sends, because Things trusts its sync history completely and a malformed write can break sync on every device. Use it at your own risk.

Tools

Tool

What it does

overview

Today's date, Inbox/Today/Upcoming counts, areas with their projects, tags

list_todos

Inbox, Today, Upcoming, Anytime, Someday, Logbook or Trash, filtered by project, area or tag; the Logbook takes a date range

search_todos

Title and notes search

get_todo

Notes, checklist, dates; a project's to-dos under their headings

create_todo

With notes, schedule, deadline, reminder, tags, checklist, and optionally a repeat rule

create_project, create_heading, create_tag, create_area

update_todo

Title, notes, schedule (when or shift_days), deadline, reminder, tags, project/heading/area

update_todos

The same change on up to 200 to-dos in one commit, all or nothing

set_repeat

Make a to-do repeat, change its rule, or stop it

set_status

Complete, cancel or reopen (a project's open to-dos follow)

trash

Move to the Trash or restore; nothing is ever deleted permanently

add_checklist_items, update_checklist_item

set_timezone

Which day "today" is; Things uses each device's local date

Repeat rules cover what Things' Repeat dialog offers: daily, weekly on chosen days, monthly (a day, the last day, or "2nd Tue"), yearly, every N, after completion, until a date or N times, deadlines with an early start, and a reminder.

Related MCP server: Things MCP

How Things Cloud works

  • Each account has a history key. GET /version/1/history/{key}/items?start-index=N returns the history as a list of commits; POST /version/1/history/{key}/commit?ancestor-index=N appends one, and answers 409 if another device committed first. The password is only needed once, to look the key up (GET /version/1/account/{email} with Authorization: Password …).

  • Pages are capped at about 58 KB. current-item-index is the head of the history, not the end of the page: the next page starts at start-index + items.length.

  • A commit maps object ids to {t, e, p}: the action (0 create, 1 modify, 2 delete), the entity (Task7, ChecklistItem3, Area3, Tag4, Tombstone2) and the changed properties. The server replays the history into the current state, and keeps a snapshot on disk.

  • Ids are 16 random bytes in Base58 with leading-zero padding. Things.app crashes on any id that doesn't decode to exactly 16 bytes, so every id is checked before a write.

  • Calendar days are stored as midnight UTC of the user's local date.

src/model.ts documents the task properties and src/repeat.ts the repeat rule encoding (days, weekdays and months there are zero-based). Each repeat shape was captured by setting the rule up in Things' Repeat dialog and reading back the commit it wrote.

Safety rules

src/writes.ts only writes what was verified against Things for Mac:

  • creates carry the same 34 properties Things sends;

  • start state, start date and Today date always agree; projects and headings never go to the Inbox;

  • each copy of a repeating to-do is an ordinary to-do. Templates only change the way the Repeat dialog changes them, plus renames, moves, reminders and trash. Devices create the copies themselves when their date arrives;

  • nothing is ever deleted permanently. Making a to-do repeat moves the original to the Trash, where Things itself would delete it.

Setup

You need Node 24 and a Things Cloud account. The scripts are for macOS, where secrets live in the Keychain.

  1. Look up your history key and save it in the Keychain (the password is sent once and never stored):

    npm install
    scripts/things-login.sh
  2. Try it against your data without any server:

    node scripts/call.ts --list
    node scripts/call.ts list_todos '{"view":"today"}'

Hosting it for Claude

The server speaks MCP over HTTP behind a small OAuth sign-in: approving a client takes a passphrase only you have, and sign-ins are only handed back to Claude (claude.ai, claude.com) or to localhost. With flyctl installed and logged in:

  1. cp fly.example.toml fly.toml, pick an app name, and set PUBLIC_URL to where it will be served (https://<app>.fly.dev, or your own domain with flyctl certs add) and THINGS_TZ to your time zone. fly.toml is ignored by git.

  2. flyctl apps create <app> and flyctl volumes create things_data --region cdg --size 1.

  3. scripts/setup-hosted.sh: creates the passphrase and a token-signing secret in your Keychain and sends them, with your history key, to fly as secrets, without printing any of them.

  4. flyctl deploy --remote-only (also after code changes).

  5. On claude.ai: Settings → Connectors → Add custom connector, with your PUBLIC_URL followed by /mcp. When the sign-in page asks, paste the passphrase: security find-generic-password -s things-mcp-passphrase -w | pbcopy

To sign every client out, delete the Keychain item things-mcp-auth-secret and rerun step 3.

Configuration

Variable

Default

Purpose

THINGS_HISTORY_KEY

–

Things Cloud history key

PUBLIC_URL

http://localhost:$PORT

Where the server is reachable

MCP_PASSPHRASE

–

Approves clients on the sign-in page (at least 12 characters)

AUTH_SECRET

–

Signs sign-ins (at least 32 characters)

THINGS_TZ

UTC

Time zone that decides "today"; set_timezone overrides it

OAUTH_REDIRECT_HOSTS

claude.ai,claude.com

Hosts allowed to receive sign-ins (loopback always is)

DATA_DIR

–

Where to keep the history snapshot and the time zone setting

PORT

8080

HTTP port

Development

npm test                      # unit tests (ids, history replay, notes, repeat rules)
npm run check                 # type check
BASE=http://localhost:8080 PASSPHRASE=… node scripts/oauth-smoke.ts

oauth-smoke.ts walks a local server through the whole sign-in and an MCP call. The code runs on Node's built-in TypeScript support, without a build step.

Limits

  • Things for Mac pulls changes lazily in the background (1–3 minutes in testing); opening the app syncs right away.

  • Repeating to-dos' copies are created by your devices. Until one of them syncs on the day, a due copy shows in Today as pending.

  • Not supported: renaming or deleting areas and tags, switching a repeat between "after completion" and "on a schedule" (stop it and create a new one), permanent deletion.

  • claude.ai shows custom connectors with the favicon Google has for the parent domain, so the server's own icon only appears in clients that read it.

Credits

Knowledge of the protocol builds on arthursoares/things-cloud-sdk (and nicolai86/things-cloud-sdk before it), notably its notes on Base58 ids and crash-causing payloads, and on evanpurkhiser/things3-cloud. No code was copied.

License

MIT, see LICENSE. Things is a trademark of Cultured Code GmbH & Co. KG.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers