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:
- The Todoist REST API does return
duration as { amount: number, unit: string } on tasks that have time blocking enabled.
- The MCP server already handles duration correctly when creating and updating tasks (in
handlers/task/crud.js, lines ~100-102 and ~318-320).
- 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
Feature Request: Display
durationfield informatTaskForDisplay()outputHi @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, thedurationfield is not included in the output, even though:durationas{ amount: number, unit: string }on tasks that have time blocking enabled.handlers/task/crud.js, lines ~100-102 and ~318-320).The only place it's missing is in the GET/read path β specifically in the
formatTaskForDisplay()utility function insrc/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)
Example: Expected output (with duration)
Solution
The fix requires changes to two files in
dist/utils/(or their source equivalents insrc/utils/):1.
api-helpers.ts(logic) β Add duration to the format outputBefore:
After:
2.
api-helpers.d.ts(type declaration) β Adddurationto the type signatureBefore:
After:
Changes summary
durationDisplayapi-helpers.jstask.duration.amountandtask.duration.unit, formats as human-readable stringreturnapi-helpers.js${durationDisplay}right after theDue:lineapi-helpers.d.tsTested locally β
I applied this patch to my local installation at:
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
Thanks for considering this! Happy to submit a PR if you prefer. π
api-helpers.js
api-helpers.d.ts