todoist_comment_create
Add comments to Todoist tasks or projects by providing task ID, name, or project ID. Supports markdown and file attachments.
Instructions
Add a comment to a task or project in Todoist. For task comments, provide task_id or task_name. For project comments, provide project_id.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| task_id | No | ID of the task to comment on (provide this OR task_name for task comments) | |
| task_name | No | Name/content of the task to comment on (provide this OR task_id for task comments) | |
| project_id | No | ID of the project to comment on (use this for project-level comments instead of task_id/task_name) | |
| content | Yes | Content of the comment (supports markdown) | |
| attachment | No | Optional file attachment |
Implementation Reference
- src/handlers/comment-handlers.ts:38-101 (handler)Main handler function that creates a comment on a task or project in Todoist. It validates content, resolves task by ID or name, supports project comments, optional attachments, and returns a formatted success message.
export async function handleCreateComment( todoistClient: TodoistApi, args: CreateCommentArgs ): Promise<string> { return ErrorHandler.wrapAsync("create comment", async () => { // Validate and sanitize content const sanitizedContent = validateCommentContent(args.content); const commentData: ExtendedCommentCreationData = { content: sanitizedContent, }; // Determine if this is a project comment or task comment if (args.project_id) { // Project-level comment commentData.projectId = args.project_id; } else if (args.task_id) { // Task comment by ID commentData.taskId = args.task_id; } else if (args.task_name) { // Search for task by name const result = await todoistClient.getTasks(); const tasks = extractArrayFromResponse<TodoistTask>(result); const matchingTask = tasks.find((task: TodoistTask) => task.content.toLowerCase().includes(args.task_name!.toLowerCase()) ); if (!matchingTask) { ErrorHandler.handleTaskNotFound(args.task_name!); } commentData.taskId = matchingTask.id; } else { throw new Error( "Either task_id, task_name, or project_id must be provided" ); } if (args.attachment) { commentData.attachment = { fileName: args.attachment.file_name, fileUrl: args.attachment.file_url, fileType: args.attachment.file_type, }; } const comment = await todoistClient.addComment( commentData as CommentCreationData ); // Clear cache after creating comment commentCache.clear(); // Use defensive typing for comment response const commentResponse = comment as CommentResponse; const targetType = args.project_id ? "project" : "task"; return `Comment added to ${targetType}:\nContent: ${commentResponse.content}${ commentResponse.attachment ? `\nAttachment: ${commentResponse.attachment.fileName} (${commentResponse.attachment.fileType})` : "" }\nPosted at: ${commentResponse.postedAt || new Date().toISOString()}`; }); } - src/types/comment-types.ts:8-18 (schema)TypeScript interface defining the input arguments for creating a comment: optional task_id, task_name, project_id, required content, and optional attachment.
export interface CreateCommentArgs { task_id?: string; task_name?: string; project_id?: string; content: string; attachment?: { file_name: string; file_url: string; file_type: string; }; } - src/tools/comment-tools.ts:4-52 (registration)Tool definition registration with name 'todoist_comment_create', description, and inputSchema specifying properties/validation rules.
export const CREATE_COMMENT_TOOL: Tool = { name: "todoist_comment_create", description: "Add a comment to a task or project in Todoist. For task comments, provide task_id or task_name. For project comments, provide project_id.", inputSchema: { type: "object", properties: { task_id: { type: "string", description: "ID of the task to comment on (provide this OR task_name for task comments)", }, task_name: { type: "string", description: "Name/content of the task to comment on (provide this OR task_id for task comments)", }, project_id: { type: "string", description: "ID of the project to comment on (use this for project-level comments instead of task_id/task_name)", }, content: { type: "string", description: "Content of the comment (supports markdown)", }, attachment: { type: "object", description: "Optional file attachment", properties: { file_name: { type: "string", description: "Name of the attached file", }, file_url: { type: "string", description: "URL of the attached file", }, file_type: { type: "string", description: "MIME type of the attached file", }, }, required: ["file_name", "file_url", "file_type"], }, }, required: ["content"], }, }; - src/router/legacy-router.ts:363-367 (registration)Router case that dispatches to handleCreateComment after validating arguments with isCreateCommentArgs type guard.
case "todoist_comment_create": if (!isCreateCommentArgs(args)) { throw new Error("Invalid arguments for todoist_comment_create"); } return await handleCreateComment(client, args); - Type guard function that validates the structure of arguments for the comment creation tool, ensuring content is a string and at least one of task_id, task_name, or project_id is provided.
export function isCreateCommentArgs(args: unknown): args is CreateCommentArgs { if (typeof args !== "object" || args === null) return false; const obj = args as Record<string, unknown>; // Must have content and at least one of: task_id, task_name, or project_id return ( "content" in obj && typeof obj.content === "string" && (obj.task_id === undefined || typeof obj.task_id === "string") && (obj.task_name === undefined || typeof obj.task_name === "string") && (obj.project_id === undefined || typeof obj.project_id === "string") && (obj.task_id !== undefined || obj.task_name !== undefined || obj.project_id !== undefined) ); }