TL;DR: Things MCP for reads. AppleScript for every write. Verify the write with
get_projectsvia MCP — not with AppleScript's ownto dos of p. This is now a standing rule in my stack.
The Setup
I run my life and client work out of Things 3, my task manager.
And I have Apollo, my AI assistant, drive it — creating tasks, setting up project lists, reordering priorities. At first, all of that went through the Things MCP (Model Context Protocol server — the thing that gives Claude live, structured access to Things data).
Reads, writes, reorders. All MCP.
Big mistake.
What Burned Me
I was having Apollo build out an ecommerce client's Security Remediation project — 8 tasks, ordered by priority.
I added them in reverse (#8 down to #1), expecting the most recent insertion to land on top.
That's how I'd seen it work before.
Wrong.
get_projects showed me the truth: #8 was at the top. #1 was at the bottom. The MCP's add_todo had been APPENDING this whole time — newest at the bottom, not the top. The behavior I thought I knew was from a move operation. Create and move are completely different, and I'd conflated them.
That's when I started auditing the rest of the MCP's write behavior…
add_todosilently drops thetagsparam. Pass tags all you want. They won't show up. No error.- Invalid
list_idmoves return"success"and do nothing. get_projectscan serve a stale snapshot — what you read isn't always what Things is showing.
These aren't bugs exactly. The MCP routes through Things' URL scheme, which is deliberately limited. It was never designed to be a full scripting API.
But it looks like one. And that's where it gets you.
The Fix
AppleScript is the real Things API.
It uses the full scripting dictionary — set any property, handle schedule and due date independently, and reorder via a dead-simple recipe: repeat (count of to dos of p) times / delete first to do of p / end repeat, then make new to do at end of p for #1 through #N. First-created lands on top. Deterministic every time.
Even my Apollo Dashboard (a standalone Python server, no MCP access at all) reads Things straight through AppleScript — ~55x faster than any web-layer call. That tool forced the right choice from day one. I should've taken the hint sooner on the write side.
My standing rule, baked into Apollo's memory on June 16th:
Read Things3: MCP. Write anything: AppleScript. No exceptions.
The Verification Strategy
After any write, verify via the MCP — specifically get_projects(include_items=true).
Not AppleScript's to dos of p. That returns a non-display collection order and will give you a false read.
get_projects reflects the true SQLite index order — the actual display order in the app. The MCP is unreliable for writes, but it's the oracle for confirming your AppleScript write landed correctly.
Two tools, one job each. That split is the whole point.
Why This Matters to Me
I was flying blind for a while, trusting "success" responses that meant nothing.
The lesson here isn't "MCP bad" — the Things MCP is genuinely great for reads. Fast, structured, exactly what I need for surfacing task data.
The lesson is: silent failures are the worst kind. They don't stop you. They let you keep going, confidently, in the wrong direction.
Now when I'm automating anything, the question I ask is: what does a successful write actually prove, and what independent check confirms it?
AppleScript to write. MCP to verify. No surprises.