Skip to main content
Glama
README.md
# Things App MCP

An MCP (Model Context Protocol) server for [Things 3](https://culturedcode.com/things/) on macOS. Enables AI assistants like Claude to create, read, update, and manage your tasks directly in Things.

## Features

### Write Operations (Things URL Scheme)

| Tool | Description |
|------|-------------|
| `add-todo` | Create a new to-do with title, notes, dates, tags, checklist, project/area assignment |
| `add-project` | Create a new project with to-dos, notes, dates, tags, area assignment |
| `update-todo` | Update an existing to-do (requires auth-token) |
| `update-project` | Update an existing project (requires auth-token) |
| `show` | Navigate to a list, project, area, tag, or specific to-do |
| `search` | Open the Things search screen |
| `add-json` | Create complex structures via the Things JSON command |

### Read Operations (AppleScript/JXA)

| Tool | Description |
|------|-------------|
| `get-todos` | Get to-dos from a list (Inbox, Today, etc.), project, area, or by tag |
| `get-todo-by-id` | Get a specific to-do by its ID |
| `get-projects` | Get all projects |
| `get-project-by-id` | Get a specific project by its ID |
| `get-areas` | Get all areas |
| `get-tags` | Get all tags |
| `search-todos` | Search to-dos by title/notes content |
| `get-recent-todos` | Get recently modified to-dos |

### Automation (Batch Operations)

| Tool | Description |
|------|-------------|
| `reschedule-distant-todos` | Move distant-deadline to-dos out of Today. Finds items whose deadline is far away and reschedules their start date to a few days before the deadline, keeping your Today list focused on what matters now. Requires auth-token. |

**Key behaviors of `reschedule-distant-todos`:**
- Items explicitly scheduled for today (`activationDate` = today) are always preserved
- Uses a single JSON batch update for atomic, reliable rescheduling
- `daysThreshold` (default: 7) controls how many days away a deadline must be to qualify
- `bufferDays` (default: 3) controls how many days before the deadline to set the new start date
- Supports `dryRun` mode to preview changes without applying them
- Annotated with `destructiveHint: true` so MCP clients can prompt for user confirmation

## Requirements

- **macOS** (required for AppleScript/JXA and `open` command)
- **Things 3** installed
- **Node.js** >= 18
- **Things URL Scheme** enabled (Things > Settings > General > Enable Things URLs)

## Installation

```bash
# Clone and build
git clone <repository-url>
cd things-app-mcp
npm install
npm run build
```

Or install globally:

```bash
npm install -g things-app-mcp
```

## Configuration

### Claude Desktop

Add to your Claude Desktop configuration file:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "things": {
      "command": "npx",
      "args": ["-y", "things-app-mcp@latest"]
    }
  }
}
```

### Cursor

Add to your Cursor MCP settings (`.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "things": {
      "command": "npx",
      "args": ["-y", "things-app-mcp@latest"]
    }
  }
}
```

### Codex

Add to `~/.codex/config.toml`:

```toml
[mcp_servers.things]
command = "npx"
args = ["-y", "things-app-mcp@latest"]
startup_timeout_sec = 20
tool_timeout_sec = 120
```

### Gemini CLI

Run the following command to register the MCP server:

```bash
gemini mcp add things npx -y things-app-mcp@latest
```

### Auth Token Configuration

To use `update-todo`, `update-project`, and `reschedule-distant-todos`, you need your Things auth-token.

**Option 1: Environment Variable (Recommended)**

Set the `THINGS_AUTH_TOKEN` environment variable in your MCP client configuration. This avoids needing to pass the token with every request.

**Claude Desktop:**
```json
{
  "mcpServers": {
    "things": {
      "command": "npx",
      "args": ["-y", "things-app-mcp@latest"],
      "env": {
        "THINGS_AUTH_TOKEN": "your-token-here"
      }
    }
  }
}
```

**Codex (`~/.codex/config.toml`):**
```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:**
Set the environment variable in your shell configuration or pass it when running:
```bash
export THINGS_AUTH_TOKEN="your-token-here"
```

**Option 2: Parameter**

If the environment variable is not set, you must pass the token as the `authToken` parameter when calling update tools:

1. Open Things on Mac
2. Go to **Things > Settings > General > Enable Things URLs > Manage**
3. Copy your authorization token
4. Pass it as the `authToken` parameter when calling update tools

## Usage Examples

### Adding a To-Do

```
"Add a to-do called 'Buy groceries' scheduled for today with tags 'Errand'"
```

The AI will call `add-todo` with:
```json
{
  "title": "Buy groceries",
  "when": "today",
  "tags": "Errand"
}
```

### Creating a Project with To-Dos

```
"Create a project called 'Launch Website' in the Work area with to-dos: Design mockups, Build frontend, Deploy"
```

The AI will call `add-project` with:
```json
{
  "title": "Launch Website",
  "area": "Work",
  "todos": "Design mockups\nBuild frontend\nDeploy"
}
```

### Complex Project via JSON

```
"Create a vacation planning project with headings for Travel, Accommodation, and Activities"
```

The AI will call `add-json` with structured JSON data containing nested headings and to-dos.

### Reading To-Dos

```
"What's on my Today list?"
```

The AI will call `get-todos` with `{ "list": "Today" }` and return the structured data.

### Updating a To-Do

```
"Mark the 'Buy groceries' todo as complete"
```

The AI will first search/get the to-do to find its ID, then call `update-todo` with the auth-token.

### Cleaning Up Today

```
"My Today list is too cluttered. Move everything that isn't due soon to later."
```

The AI will call `reschedule-distant-todos` with `{ "dryRun": true }` first to preview, then apply:
```json
{
  "daysThreshold": 7,
  "bufferDays": 3,
  "dryRun": false
}
```

Items with deadlines 7+ days away will be rescheduled to 3 days before their deadline. Items you explicitly set to today are always preserved.

### Previewing Reschedule Changes

```
"Show me which todos would be moved out of Today without actually changing anything"
```

The AI will call `reschedule-distant-todos` with `{ "dryRun": true }` and return a list of what would change.

## Things URL Scheme Reference

This MCP server implements the full [Things URL Scheme v2](https://culturedcode.com/things/support/articles/2803573/):

### Date Formats

| Format | Example | Description |
|--------|---------|-------------|
| Named | `today`, `tomorrow`, `evening`, `anytime`, `someday` | Built-in schedule options |
| Date | `2026-03-15` | Specific date |
| Date + Time | `2026-03-15@14:00` | Date with reminder |
| Natural language | `next friday`, `in 3 days` | English natural language (parsed by Things) |

### Built-in List IDs (for `show` tool)

`inbox`, `today`, `anytime`, `upcoming`, `someday`, `logbook`, `tomorrow`, `deadlines`, `repeating`, `all-projects`, `logged-projects`

### JSON Command Object Types

| Type | Description |
|------|-------------|
| `to-do` | A task with title, notes, when, deadline, tags, checklist-items |
| `project` | A project with title, notes, items (to-dos and headings) |
| `heading` | A section heading within a project |
| `checklist-item` | A checklist item within a to-do |

## Architecture

```
things-app-mcp/
  src/
    index.ts          # MCP server entry point with all tool registrations
    things-url.ts     # Things URL scheme builder (URL construction)
    applescript.ts    # AppleScript/JXA executor (read operations)
  scripts/
    test-client.js    # Basic MCP server connectivity test
    test-all-tools.js # Integration tests for all 16 tools
    test-unit.js      # Unit tests for logic, URL builders, and edge cases (122 tests)
  dist/               # Compiled JavaScript output
  package.json
  tsconfig.json
```

### How It Works

- **Write operations** construct `things:///` URLs and open them via macOS `open` command. Things processes the URL and creates/updates items accordingly.
- **Read operations** use JXA (JavaScript for Automation) scripts executed via `osascript` to query the Things database directly and return structured JSON data.

## Development

```bash
# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run dev

# Run directly
npm start
```

## Testing

See [TESTING.md](TESTING.md) for full details.

```bash
# Unit tests (date utilities, URL builders, reschedule logic, edge cases)
# Runs anywhere - no macOS or Things 3 required
node scripts/test-unit.js

# Integration tests (all 16 tools via MCP protocol)
# Requires macOS + Things 3 for full coverage
npm run test:tools

# With write operations enabled
THINGS_MCP_TEST_ALLOW_WRITES=1 npm run test:tools

# Full suite with auth token
THINGS_AUTH_TOKEN=your-token \
THINGS_MCP_TEST_TODO_ID=some-id \
THINGS_MCP_TEST_PROJECT_ID=some-id \
npm run test:tools
```

## License

MIT

TDQS

A3.8/5.0

Scored across 15 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues