update_project
Update any property of an existing project in Things, from title and notes to schedule, deadline, tags, or completion status.
Instructions
Update an existing project in Things
Args: id: ID of the project to update title: New title notes: New notes when: New schedule (today, tomorrow, evening, anytime, someday, or YYYY-MM-DD). Use YYYY-MM-DD@HH:MM format to add a reminder (e.g., 2024-01-15@14:30) deadline: New deadline (YYYY-MM-DD) tags: New tags completed: Mark as completed canceled: Mark as canceled
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| title | No | ||
| notes | No | ||
| when | No | ||
| deadline | No | ||
| tags | No | ||
| completed | No | ||
| canceled | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/things_mcp/server.py:477-512 (handler)MCP tool handler that updates an existing project by delegating to url_scheme.update_project() and executing the URL via url_scheme.execute_url().
@mcp.tool async def update_project( id: str, title: str = None, notes: str = None, when: str = None, deadline: str = None, tags: List[str] = None, completed: bool = None, canceled: bool = None ) -> str: """Update an existing project in Things Args: id: ID of the project to update title: New title notes: New notes when: New schedule (today, tomorrow, evening, anytime, someday, or YYYY-MM-DD). Use YYYY-MM-DD@HH:MM format to add a reminder (e.g., 2024-01-15@14:30) deadline: New deadline (YYYY-MM-DD) tags: New tags completed: Mark as completed canceled: Mark as canceled """ url = url_scheme.update_project( id=id, title=title, notes=notes, when=when, deadline=deadline, tags=tags, completed=completed, canceled=canceled ) url_scheme.execute_url(url) return f"Updated project with ID: {id}" - src/things_mcp/url_scheme.py:191-220 (schema)URL construction function for update-project command, building parameter dict and delegating to construct_url with the 'update-project' command.
def update_project(id: str, title: Optional[str] = None, notes: Optional[str] = None, when: Optional[str] = None, deadline: Optional[str] = None, tags: Optional[list[str]] = None, completed: Optional[bool] = None, canceled: Optional[bool] = None) -> str: """Construct URL to update an existing project. Args: id: UUID of the project to update title: New title notes: New notes when: Reschedule the project. Accepts: - Keywords: "today", "tomorrow", "evening", "anytime", "someday" - Date: "yyyy-mm-dd" or natural language ("in 3 days", "next tuesday") - DateTime (adds reminder): "yyyy-mm-dd@HH:MM" (e.g., "2024-01-15@14:30") deadline: New deadline (yyyy-mm-dd) tags: New tags (replaces existing) completed: Mark as completed canceled: Mark as canceled """ params = { 'id': id, 'title': title, 'notes': notes, 'when': when, 'deadline': deadline, 'tags': tags, 'completed': completed, 'canceled': canceled } return construct_url('update-project', {k: v for k, v in params.items() if v is not None}) - src/things_mcp/server.py:477-477 (registration)Registered as an MCP tool via the @mcp.tool decorator on the FastMCP server instance.
@mcp.tool - src/things_mcp/url_scheme.py:43-53 (helper)Helper function that constructs the Things URL, including auth-token injection for 'update-project' commands and URL encoding of parameters.
def construct_url(command: str, params: Dict[str, Any]) -> str: """Construct a Things URL from command and parameters.""" # Start with base URL url = f"things:///{command}" # Get authentication token if needed if command in ['update', 'update-project']: token = things.token() if token: params['auth-token'] = token - src/things_mcp/url_scheme.py:31-41 (helper)Helper that executes a Things URL via subprocess, used by the update_project handler to actually trigger the Things app update.
def execute_url(url: str) -> None: """Execute a Things URL without bringing Things to the foreground. Security: validates the URL starts with 'things:///' before execution to prevent opening arbitrary URLs or executing unintended commands. Uses subprocess with argument list (no shell interpolation) to avoid command injection vectors. """ if not url.startswith("things:///"): raise ValueError(f"Invalid Things URL scheme: {url[:50]}") subprocess.run(['open', '-g', url], check=True, capture_output=True)