Skip to main content
Glama
mikemc

Todoist MCP Server

by mikemc

todoist_update_task

Modify an existing task in Todoist by updating its title, description, labels, priority, due date, assignee, duration, or deadline. Ensure tasks stay organized and up-to-date.

Instructions

Update an existing task in Todoist

Args: task_id: ID of the task to update content: New content/title for the task (optional) description: New description for the task (optional) labels: New labels for the task (optional) priority: New priority level from 1 (normal) to 4 (urgent) (optional) due_string: New due date in natural language like 'tomorrow', 'next Monday' (optional) due_date: New specific date in YYYY-MM-DD format (optional) due_datetime: New specific date and time in RFC3339 format in UTC (optional) due_lang: 2-letter code specifying language in case due_string is not written in English (optional) assignee_id: The responsible user ID or null to unset (for shared tasks) (optional) duration: A positive integer for the amount of duration_unit the task will take (optional) duration_unit: The unit of time that the duration field represents (minute or day) (optional) deadline_date: Specific date in YYYY-MM-DD format relative to user's timezone (optional) deadline_lang: 2-letter code specifying language of deadline (optional)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
assignee_idNo
contentNo
deadline_dateNo
deadline_langNo
descriptionNo
due_dateNo
due_datetimeNo
due_langNo
due_stringNo
durationNo
duration_unitNo
labelsNo
priorityNo
task_idYes

Implementation Reference

  • The core handler function for the 'todoist_update_task' tool. It updates an existing Todoist task with optional parameters like content, description, labels, priority, due dates, assignee, and duration. Includes input validation, date parsing, and error handling.
    def todoist_update_task(
        ctx: Context,
        task_id: str,
        content: Optional[str] = None,
        description: Optional[str] = None,
        labels: Optional[list[str]] = None,
        priority: Optional[int] = None,
        due_string: Optional[str] = None,
        due_date: Optional[str] = None,
        due_datetime: Optional[str] = None,
        due_lang: Optional[str] = None,
        assignee_id: Optional[str] = None,
        duration: Optional[int] = None,
        duration_unit: Optional[str] = None,
        deadline_date: Optional[str] = None,
        deadline_lang: Optional[str] = None
    ) -> str:
        """Update an existing task in Todoist
    
        Args:
            task_id: ID of the task to update
            content: New content/title for the task (optional)
            description: New description for the task (optional)
            labels: New labels for the task (optional)
            priority: New priority level from 1 (normal) to 4 (urgent) (optional)
            due_string: New due date in natural language like 'tomorrow', 'next Monday' (optional)
            due_date: New specific date in YYYY-MM-DD format (optional)
            due_datetime: New specific date and time in RFC3339 format in UTC (optional)
            due_lang: 2-letter code specifying language in case due_string is not written in English (optional)
            assignee_id: The responsible user ID or null to unset (for shared tasks) (optional)
            duration: A positive integer for the amount of duration_unit the task will take (optional)
            duration_unit: The unit of time that the duration field represents (minute or day) (optional)
            deadline_date: Specific date in YYYY-MM-DD format relative to user's timezone (optional)
            deadline_lang: 2-letter code specifying language of deadline (optional)
        """
        todoist_client = ctx.request_context.lifespan_context.todoist_client
    
        try:
            logger.info(f"Updating task with ID: {task_id}")
    
            # Verify task exists before attempting update to provide better error messages
            try:
                task = todoist_client.get_task(task_id=task_id)
                original_content = task.content
            except Exception as error:
                logger.warning(f"Error getting task with ID: {task_id}: {error}")
                return f"Could not verify task with ID: {task_id}. Update aborted."
    
            update_data = {}
    
            # Apply same parameter filtering strategy as create
            optional_params = {
                "content": content,
                "description": description,
                "labels": labels,
                "due_string": due_string,
                "due_lang": due_lang,
                "assignee_id": assignee_id,
                "deadline_lang": deadline_lang,
            }
    
            for key, value in optional_params.items():
                if value is not None:
                    update_data[key] = value
    
            # Apply same date transformation logic as create for consistency
            if due_date is not None:
                from datetime import date
                if isinstance(due_date, str):
                    update_data["due_date"] = date.fromisoformat(due_date)
                else:
                    update_data["due_date"] = due_date
    
            if due_datetime is not None:
                from datetime import datetime
                if isinstance(due_datetime, str):
                    if due_datetime.endswith('Z'):
                        due_datetime = due_datetime[:-1] + '+00:00'
                    update_data["due_datetime"] = datetime.fromisoformat(due_datetime)
                else:
                    update_data["due_datetime"] = due_datetime
    
            if deadline_date is not None:
                from datetime import date
                if isinstance(deadline_date, str):
                    update_data["deadline_date"] = date.fromisoformat(deadline_date)
                else:
                    update_data["deadline_date"] = deadline_date
    
            if priority is not None and 1 <= priority <= 4:
                update_data["priority"] = priority
    
            if duration is not None and duration_unit is not None:
                if duration > 0 and duration_unit in ["minute", "day"]:
                    update_data["duration"] = duration
                    update_data["duration_unit"] = duration_unit
                else:
                    logger.warning("Invalid duration parameters: duration must be > 0 and unit must be 'minute' or 'day'")
    
            if len(update_data) == 0:
                return f"No update parameters provided for task: {original_content} (ID: {task_id})"
    
            updated_task = todoist_client.update_task(task_id, **update_data)
    
            logger.info(f"Task updated successfully: {task_id}")
            return json.dumps(updated_task.to_dict(), indent=2, default=str)
        except Exception as error:
            logger.error(f"Error updating task: {error}")
            return f"Error updating task: {str(error)}"
  • src/main.py:88-88 (registration)
    Registers the todoist_update_task handler as an MCP tool using the FastMCP decorator.
    mcp.tool()(todoist_update_task)
  • src/main.py:26-36 (registration)
    Imports the todoist_update_task function from tasks.py module for use in main.py registration.
    from .tasks import (
        todoist_get_task,
        todoist_get_tasks,
        todoist_filter_tasks,
        todoist_add_task,
        todoist_update_task,
        todoist_complete_task,
        todoist_uncomplete_task,
        todoist_move_task,
        todoist_delete_task,
    )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mikemc/todoist-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server