Skip to main content
Glama

update_comments

Modify existing comments in Todoist tasks by updating their content with markdown-formatted text and hyperlinks.

Instructions

Update comments in Todoist

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
itemsYes

Implementation Reference

  • Core batch handler logic for update_comments: processes array of items, resolves IDs by name if needed, validates path parameters, constructs path '/comments/{id}', calls todoistApi.post(finalPath, {content}), returns batched results with success summary.
    const handler = async (args: z.infer<typeof batchSchema>): Promise<any> => { const { items } = args; // For modes other than create, check if name lookup is needed let allItems: any[] = []; const needsNameLookup = options.mode !== 'create' && options.nameField && options.findByName && items.some(item => item[options.nameField!] && !item[options.idField!]); if (needsNameLookup) { // Determine the base path for fetching all items // Example: /tasks from /tasks/{id} const lookupPath = options.basePath || (options.path ? options.path.split('/{')[0] : ''); allItems = await todoistApi.get(lookupPath, {}); } const results = await Promise.all( items.map(async item => { if (options.validateItem) { const validation = options.validateItem(item); if (!validation.valid) { return { success: false, error: validation.error || 'Validation failed', item, }; } } try { let finalPath = ''; const apiParams = { ...item }; // For modes where need id if (options.mode !== 'create' && options.idField) { let itemId = item[options.idField]; let matchedName = null; let matchedContent = null; // If no ID but name is provided, search by name if (!itemId && item[options.nameField!] && options.findByName) { const searchName = item[options.nameField!]; const matchedItem = options.findByName(searchName, allItems); if (!matchedItem) { return { success: false, error: `Item not found with name: ${searchName}`, item, }; } itemId = matchedItem.id; matchedName = searchName; matchedContent = matchedItem.content; } if (!itemId) { return { success: false, error: `Either ${options.idField} or ${options.nameField} must be provided`, item, }; } // Apply security validation to itemId before using in path const safeItemId = validatePathParameter(itemId, options.idField || 'id'); if (options.basePath && options.pathSuffix) { finalPath = `${options.basePath}${options.pathSuffix.replace('{id}', safeItemId)}`; } else if (options.path) { finalPath = options.path.replace('{id}', safeItemId); } delete apiParams[options.idField]; if (options.nameField) { delete apiParams[options.nameField]; } let result; switch (options.method) { case 'GET': result = await todoistApi.get(finalPath, apiParams); break; case 'POST': result = await todoistApi.post(finalPath, apiParams); break; case 'DELETE': result = await todoistApi.delete(finalPath); break; } const response: any = { success: true, id: itemId, result, }; if (matchedName) { response.found_by_name = matchedName; response.matched_content = matchedContent; } return response; } // Create mode else { finalPath = options.path || options.basePath || ''; let result; switch (options.method) { case 'GET': result = await todoistApi.get(finalPath, apiParams); break; case 'POST': result = await todoistApi.post(finalPath, apiParams); break; case 'DELETE': result = await todoistApi.delete(finalPath); break; } return { success: true, created_item: result, }; } } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error), item, }; } }) ); const successCount = results.filter(r => r.success).length; return { success: successCount === items.length, summary: { total: items.length, succeeded: successCount, failed: items.length - successCount, }, results, }; };
  • Registers the 'update_comments' MCP tool using createBatchApiHandler, specifying POST /comments/{id} for updates with id and content schema.
    createBatchApiHandler({ name: 'update_comments', description: 'Update comments in Todoist', itemSchema: { id: z.string(), content: z.string().describe('Markdown-formatted text and hyperlinks'), }, method: 'POST', path: '/comments/{id}', mode: 'update', idField: 'id', });
  • Input schema for update_comments: requires 'id' (string) and 'content' (markdown string).
    itemSchema: { id: z.string(), content: z.string().describe('Markdown-formatted text and hyperlinks'), },
  • TodoistClient.post method: executes the actual HTTP POST request to Todoist REST API v2 endpoint (e.g., /comments/{id}) with JSON body (e.g., {content}).
    async post(endpoint: string, data: Record<string, any> = {}): Promise<any> { const url = `${API_BASE_URL}${endpoint}`; log(`Making POST request to: ${url} with data:`, JSON.stringify(data, null, 2)); const response = await fetch(url, { method: 'POST', headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); }

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/stanislavlysenko0912/todoist-mcp-server'

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