things-mcp-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,187 @@
1
+ # things-mcp-server
2
+
3
+ A local MCP server for controlling [Things](https://culturedcode.com/things/) on macOS.
4
+
5
+ ## Features
6
+
7
+ - Read:
8
+ - `things_get_server_status`
9
+ - `things_list_todos`
10
+ - `things_list_projects`
11
+ - `things_list_areas`
12
+ - `things_list_area_items`
13
+ - `things_list_project_todos`
14
+ - `things_search_todos`
15
+ - `things_get_todo`
16
+ - Write:
17
+ - `things_add_area`
18
+ - `things_add_todo`
19
+ - `things_add_project`
20
+ - `things_update_todo`
21
+ - `things_complete_todo`
22
+ - `things_move_todo`
23
+ - `things_delete_todo`
24
+ - UI helper:
25
+ - `things_show_item`
26
+
27
+ ## Security Model
28
+
29
+ - Strict command whitelist: only `osascript` and `open` are executable.
30
+ - No shell interpolation: subprocesses run with `shell: false`.
31
+ - Things URL command whitelist: only approved commands (`add`, `add-project`, `update`, `show`, `search`).
32
+ - Input validation for IDs, dates, title/notes/tag sizes.
33
+ - All write/modify operations require `confirm=true`.
34
+ - Sensitive strings (auth token) are redacted from tool error output.
35
+
36
+ ## Requirements
37
+
38
+ - macOS with Things installed (`Things3` AppleScript app name)
39
+ - Node.js 20+
40
+ - Things URL Scheme auth token (`THINGS_AUTH_TOKEN`) for URL-scheme write operations
41
+
42
+ Get auth token in Things:
43
+
44
+ 1. Open Things.
45
+ 2. Go to Settings/Preferences.
46
+ 3. Open URL scheme settings and copy the token.
47
+
48
+ ## Setup
49
+
50
+ ```bash
51
+ pnpm install
52
+ pnpm build
53
+ pnpm test
54
+ ```
55
+
56
+ ## Run
57
+
58
+ ```bash
59
+ THINGS_AUTH_TOKEN=your_token_here pnpm start
60
+ ```
61
+
62
+ Use the same Node runtime for install/build/start and MCP host process. Native dependency (`better-sqlite3`) must match Node ABI.
63
+
64
+ Or in development:
65
+
66
+ ```bash
67
+ THINGS_AUTH_TOKEN=your_token_here pnpm dev
68
+ ```
69
+
70
+ ## MCP Config (Local Source Checkout)
71
+
72
+ This repository includes `mcp.config.example.json` for running the built local server:
73
+
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "things": {
78
+ "command": "/opt/homebrew/bin/node",
79
+ "args": ["/Users/your-user/Code/things-mcp/dist/index.js"],
80
+ "env": {
81
+ "THINGS_AUTH_TOKEN": "your-token-here"
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ Notes:
89
+
90
+ - Run `pnpm build` first so `dist/index.js` exists.
91
+ - Update `args[0]` to your actual local absolute path.
92
+ - Keep `command` aligned with the same Node runtime used for install/build to avoid `better-sqlite3` ABI mismatch.
93
+
94
+ ## Publish and Install (No Source Checkout)
95
+
96
+ You can publish to npm and run it via `npx`, so client machines do not need this source repo.
97
+
98
+ Publish:
99
+
100
+ ```bash
101
+ pnpm test
102
+ pnpm publish --access public
103
+ ```
104
+
105
+ MCP config example (installed on demand from npm):
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "things": {
111
+ "command": "npx",
112
+ "args": ["-y", "things-mcp-server"],
113
+ "env": {
114
+ "THINGS_AUTH_TOKEN": "your-token-here"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ Optional SQLite read path override:
122
+
123
+ ```bash
124
+ THINGS_DB_PATH="/Users/you/Library/Group Containers/JLMPQHK86H.com.culturedcode.ThingsMac/ThingsData-XXXX/Things Database.thingsdatabase/main.sqlite"
125
+ ```
126
+
127
+ By default, the server auto-discovers Things databases under Group Containers, including backup bundles. In most setups, `THINGS_DB_PATH` is not required.
128
+
129
+ Troubleshooting recurring items with missing date:
130
+
131
+ 1. Call `things_get_server_status` and verify `sqlite.enabled=true`.
132
+ 2. If false, inspect `resolvedPath`, `existingCandidateCount`, and `lastOpenError` from `things_get_server_status`.
133
+ 3. If still false, set `THINGS_DB_PATH` explicitly to your `main.sqlite`.
134
+ 4. If `lastOpenError` indicates permissions, grant your MCP host app (for example Alma) Full Disk Access.
135
+ 5. Restart the MCP server and reconnect client.
136
+
137
+ If `lastOpenError` includes `NODE_MODULE_VERSION` mismatch:
138
+
139
+ 1. Align Node runtime used by MCP host and by local install.
140
+ 2. Rebuild native module with that runtime: `pnpm rebuild better-sqlite3`.
141
+ 3. In MCP host config, prefer absolute Node path in `command` (for example `/opt/homebrew/bin/node`) instead of plain `node`.
142
+
143
+ ## Tool Safety Notes
144
+
145
+ - `things_add_area`, `things_add_todo`, `things_add_project`, `things_update_todo`, `things_complete_todo`, `things_move_todo`, and `things_delete_todo` all require `confirm=true`.
146
+ - This server does not execute arbitrary scripts.
147
+ - Reads are done via AppleScript.
148
+ - URL-scheme-supported operations use Things URL scheme (`add_todo`, `add_project`, `update_todo`, `move_todo`, `complete_todo`, `show_item`).
149
+ - AppleScript is used for unsupported write operations (`add_area`, `delete_todo`) and read operations.
150
+
151
+ ## Read Detail Fields
152
+
153
+ `things_get_todo` returns extended metadata, including:
154
+
155
+ - `dueDate`, `activationDate`
156
+ - `creationDate`, `modificationDate`, `completionDate`, `cancellationDate`
157
+ - `reminderTime` (best-effort, extracted from private JSON when available)
158
+ - `tagNames`, `project`, `area`, `contactName`
159
+ - `rawJson` (best-effort from Things private experimental JSON field when available)
160
+
161
+ `things_list_todos`, `things_search_todos`, `things_list_area_items`, and `things_list_project_todos` also return:
162
+
163
+ - `inferredDate`: fallback date inferred from direct fields or recurring metadata
164
+ - `isRepeating` / `recurrenceRule`: best-effort recurring task hints
165
+ - `recurrence`: structured recurring info (`mode`, `nextDate`, `interval`, `frequency`, `byDay`, `byMonthDay`, `byMonth`, `byWeekNo`, `byYearDay`, `bySetPos`, `byHour`, `byMinute`, `bySecond`, `weekStart`, `count`, `until`, `anchorDate`, `offsets`, `rrule`, `rruleParts`, `rawFields`)
166
+
167
+ Read path strategy:
168
+
169
+ - AppleScript is still used to preserve Things list/search semantics.
170
+ - SQLite (read-only) is used to enrich due/start/reminder/recurrence details, especially repeating templates.
171
+ - If SQLite is unavailable, the server automatically falls back to AppleScript-only reads.
172
+
173
+ Container support:
174
+
175
+ - `things_add_area` creates a new area.
176
+ - `things_add_project` supports creating projects inside area via `area` or `areaId`.
177
+ - `things_add_todo` supports direct placement via `list/listId` and optional `heading/headingId`.
178
+ - `things_move_todo` supports moving into standard list, project, area, or heading.
179
+
180
+ ## Known Limitations
181
+
182
+ - AppleScript access requires first-run macOS Automation permission approval.
183
+ - If Things is not running, macOS may launch it during tool execution.
184
+ - URL scheme writes are asynchronous from Things' perspective; tool success means request dispatch succeeded.
185
+ - Advanced recurring metadata is parsed from Things hidden `_private_experimental_ json` and may change across app versions.
186
+ - SQLite recurrence internals (`rt1_*`) are private implementation details and can also change across Things versions.
187
+ - Some repeating tasks may not expose a concrete upcoming date in public fields; in those cases `nextDate` can be empty while `recurrence`/`rawFields` still provide rule details.