Skip to main content
Glama
mikemc

Todoist MCP Server

by mikemc

todoist_get_tasks

Retrieve filtered Todoist tasks by project ID, priority, natural language filters, or task limits to organize and manage your to-do list effectively.

Instructions

Get a list of tasks from Todoist with various filters

Args: project_id: Filter tasks by project ID (optional) filter: Natural language filter like 'today', 'tomorrow', 'next week', 'priority 1', 'overdue' (optional) priority: Filter by priority level (1-4) (optional) limit: Maximum number of tasks to return (optional)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filterNo
limitNo
priorityNo
project_idNo

Implementation Reference

  • Main handler function implementing the todoist_get_tasks tool. Fetches tasks from Todoist API supporting filters by project, section, parent, label, or IDs, with pagination handling up to nmax tasks.
    def todoist_get_tasks(
        ctx: Context,
        project_id: Optional[str] = None,
        section_id: Optional[str] = None,
        parent_id: Optional[str] = None,
        label: Optional[str] = None,
        ids: Optional[list[str]] = None,
        nmax: Optional[int] = 100,
        limit: int = 200
    ) -> str:
        """Get a list of tasks from Todoist with basic filters
    
        This is a wrapper around the Todoist API's get_tasks method that handles pagination
        automatically. By default, it will fetch up to 100 matching tasks. Set nmax=None
        to fetch ALL matching tasks across multiple API calls.
    
        For natural language filtering (like 'today', 'overdue'), use todoist_filter_tasks instead.
    
        Examples:
            # Get up to 100 tasks (default)
            todoist_get_tasks(ctx)
    
            # Get all tasks in a project (up to 100 by default)
            todoist_get_tasks(ctx, project_id="12345")
    
            # Get first 500 tasks total
            todoist_get_tasks(ctx, nmax=500)
    
            # Get ALL tasks (unlimited)
            todoist_get_tasks(ctx, nmax=None)
    
            # Get specific tasks by ID
            todoist_get_tasks(ctx, ids=["task1", "task2", "task3"])
    
        Args:
            project_id: Filter tasks by project ID (optional)
            section_id: Filter tasks by section ID (optional)
            parent_id: Filter tasks by parent task ID (optional)
            label: Filter tasks by label name (optional)
            ids: A list of the IDs of the tasks to retrieve (optional)
            nmax: Maximum total number of tasks to return. Set to None for ALL matching tasks (default: 100)
            limit: Number of tasks to fetch per API request (default: 200, max: 200)
        """
        todoist_client = ctx.request_context.lifespan_context.todoist_client
    
        try:
            logger.info(f"Getting tasks with project_id: {project_id}, section_id: {section_id}, parent_id: {parent_id}, label: {label}, nmax: {nmax}, limit: {limit}")
    
            # Early exit for zero requests to avoid unnecessary API calls
            if nmax is not None:
                if nmax == 0:
                    logger.info("nmax=0 specified, returning empty result")
                    return []
                elif nmax < 0:
                    logger.warning(f"Invalid nmax {nmax}, using default of 100")
                    nmax = 100
    
            if limit > 200:
                logger.warning(f"Limit {limit} exceeds API maximum of 200, using 200 instead")
                limit = 200
            elif limit <= 0:
                logger.warning(f"Invalid limit {limit}, using default of 200")
                limit = 200
    
            # Key optimization: match page size to actual need to reduce API payload
            effective_limit = limit
            if nmax is not None and nmax < limit:
                effective_limit = nmax
                logger.info(f"Optimized limit from {limit} to {effective_limit} to match nmax")
    
            params = {}
            if project_id:
                params["project_id"] = project_id
            if section_id:
                params["section_id"] = section_id
            if parent_id:
                params["parent_id"] = parent_id
            if label:
                params["label"] = label
            if ids:
                params["ids"] = ids
            params["limit"] = effective_limit
    
            tasks_iterator = todoist_client.get_tasks(**params)
            all_tasks = []
            pages_fetched = 0
    
            for task_batch in tasks_iterator:
                pages_fetched += 1
                all_tasks.extend(task_batch)
    
                logger.info(f"Fetched page {pages_fetched} with {len(task_batch)} tasks (total: {len(all_tasks)})")
    
                if nmax is not None and len(all_tasks) >= nmax:
                    # Trim excess - rare due to effective_limit optimization, but handles edge cases
                    all_tasks = all_tasks[:nmax]
                    logger.info(f"Reached nmax of {nmax} tasks, stopping pagination")
                    break
    
                # Todoist API signals end of results by returning fewer items than requested
                if len(task_batch) < effective_limit:
                    logger.info(f"Received {len(task_batch)} tasks (less than limit {effective_limit}), reached end of results")
                    break
    
            if not all_tasks:
                logger.info("No tasks found matching the criteria")
                return "No tasks found matching the criteria"
    
            logger.info(f"Retrieved {len(all_tasks)} tasks total across {pages_fetched} pages")
    
            if nmax is None:
                logger.info("Fetched ALL matching tasks (nmax=None specified)")
            elif len(all_tasks) == nmax:
                logger.info(f"Retrieved exactly the requested {nmax} tasks")
    
            return json.dumps([task.to_dict() for task in all_tasks], indent=2, default=str)
    
        except Exception as error:
            logger.error(f"Error getting tasks: {error}")
            return f"Error getting tasks: {str(error)}"
  • src/main.py:85-85 (registration)
    Registers the todoist_get_tasks handler as an MCP tool using FastMCP's decorator.
    mcp.tool()(todoist_get_tasks)
  • src/main.py:26-36 (registration)
    Imports the todoist_get_tasks function from tasks module for 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