Skip to content

How to be able to work with durations task in CodeΒ #70

@jrsalido

Description

@jrsalido

Feature Request: Display duration field in formatTaskForDisplay() output

Hi @greirson! First of all, great work on this MCP server β€” I've been using it daily and it's become an essential part of my workflow. πŸ™Œ

Problem

When retrieving tasks via todoist_task_get, the duration field is not included in the output, even though:

  1. The Todoist REST API does return duration as { amount: number, unit: string } on tasks that have time blocking enabled.
  2. The MCP server already handles duration correctly when creating and updating tasks (in handlers/task/crud.js, lines ~100-102 and ~318-320).
  3. The server even displays duration after create/update operations (lines ~128-129 and ~373-374 in the same file).

The only place it's missing is in the GET/read path β€” specifically in the formatTaskForDisplay() utility function in src/utils/api-helpers.ts.

This means that when you ask Claude "Show me my tasks for today", tasks with time blocking show their start time but not how long they last, which breaks the correlation between what the Todoist app displays and what Claude returns.

Example: Current output (without duration)

- Deep work session (ID: 6fwq74qRH4vjWRHh)
  Due: date=2026-02-07T09:00:00, phrase="7 feb 09:00"
  Priority: 4

Example: Expected output (with duration)

- Deep work session (ID: 6fwq74qRH4vjWRHh)
  Due: date=2026-02-07T09:00:00, phrase="7 feb 09:00"
  Duration: 180 minutes
  Priority: 4

Solution

The fix requires changes to two files in dist/utils/ (or their source equivalents in src/utils/):

1. api-helpers.ts (logic) β€” Add duration to the format output

Before:

export function formatTaskForDisplay(task) {
    const displayPriority = fromApiPriority(task.priority);
    const dueDetails = formatDueDetails(task.due);
    // Show assignment info (responsibleUid is the Todoist API field for assigned user)
    const assigneeDisplay = task.responsibleUid || task.assigneeId;
    const assignedByDisplay = task.assignedByUid;
    return `- ${task.content}${task.id ? ` (ID: ${task.id})` : ""}${task.description ? `\n  Description: ${task.description}` : ""}${dueDetails ? `\n  Due: ${dueDetails}` : ""}${task.deadline ? `\n  Deadline: ${task.deadline.date}` : ""}${displayPriority ? `\n  Priority: ${displayPriority}` : ""}${task.labels && task.labels.length > 0
        ? `\n  Labels: ${task.labels.join(", ")}`
        : ""}${assigneeDisplay ? `\n  Assigned To (User ID): ${assigneeDisplay}` : ""}${assignedByDisplay ? `\n  Assigned By (User ID): ${assignedByDisplay}` : ""}`;
}

After:

export function formatTaskForDisplay(task) {
    const displayPriority = fromApiPriority(task.priority);
    const dueDetails = formatDueDetails(task.due);
    // Show assignment info (responsibleUid is the Todoist API field for assigned user)
    const assigneeDisplay = task.responsibleUid || task.assigneeId;
    const assignedByDisplay = task.assignedByUid;
    const durationDisplay = task.duration
        ? `\n  Duration: ${task.duration.amount} ${task.duration.unit}${task.duration.amount !== 1 ? "s" : ""}`
        : "";
    return `- ${task.content}${task.id ? ` (ID: ${task.id})` : ""}${task.description ? `\n  Description: ${task.description}` : ""}${dueDetails ? `\n  Due: ${dueDetails}` : ""}${durationDisplay}${task.deadline ? `\n  Deadline: ${task.deadline.date}` : ""}${displayPriority ? `\n  Priority: ${displayPriority}` : ""}${task.labels && task.labels.length > 0
        ? `\n  Labels: ${task.labels.join(", ")}`
        : ""}${assigneeDisplay ? `\n  Assigned To (User ID): ${assigneeDisplay}` : ""}${assignedByDisplay ? `\n  Assigned By (User ID): ${assignedByDisplay}` : ""}`;
}

2. api-helpers.d.ts (type declaration) β€” Add duration to the type signature

Before:

export declare function formatTaskForDisplay(task: {
    id?: string;
    content: string;
    description?: string;
    due?: {
        string: string;
    } | null;
    deadline?: {
        date: string;
    } | null;
    priority?: number;
    labels?: string[];
    assigneeId?: string | null;
    assignedByUid?: string | null;
    responsibleUid?: string | null;
}): string;

After:

export declare function formatTaskForDisplay(task: {
    id?: string;
    content: string;
    description?: string;
    due?: {
        string: string;
    } | null;
    deadline?: {
        date: string;
    } | null;
    priority?: number;
    labels?: string[];
    assigneeId?: string | null;
    assignedByUid?: string | null;
    responsibleUid?: string | null;
    duration?: {
        amount: number;
        unit: string;
    } | null;
}): string;

Changes summary

What changed Where Description
New variable durationDisplay api-helpers.js Reads task.duration.amount and task.duration.unit, formats as human-readable string
Interpolation in return api-helpers.js Inserts ${durationDisplay} right after the Due: line
Type declaration api-helpers.d.ts Adds optional `duration?: { amount: number; unit: string }

Tested locally βœ…

I applied this patch to my local installation at:

~/Library/Application Support/Claude/Claude Extensions/local.mcpb.greison.todoist-mcp/server/utils/

After restarting Claude Desktop, tasks with time blocking now correctly display their duration alongside the due date. The fix is fully backward-compatible β€” tasks without duration simply show nothing extra (empty string fallback).

Why this matters

  • Time blocking is a core Todoist feature β€” many users rely on it to plan their day with specific time slots.
  • Without duration in GET responses, Claude cannot accurately represent a user's schedule, calculate end times, detect overlapping tasks, or build daily agendas.
  • The data is already there β€” the Todoist API returns it, and this server already handles it for create/update. This just closes the loop for read operations.
  • Minimal change, high impact β€” only 4 lines added across 2 files.

Thanks for considering this! Happy to submit a PR if you prefer. πŸš€

api-helpers.js
api-helpers.d.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions