Skip to main content
Glama
comments-enhanced.ts12.1 kB
import { ClickUpClient } from './index.js'; // import { processClickUpResponse } from '../utils/markdown.js'; import { prepareCommentForClickUp, clickUpCommentToMarkdown, ClickUpCommentBlock /* cleanClickUpCommentResponse */ } from '../utils/clickup-comment-formatter.js'; export interface Comment { id: string; comment: ClickUpCommentBlock[]; // ClickUp's structured comment format comment_text: string; // Plain text representation comment_markdown?: string; // Markdown version for display user: { id: number; username: string; email: string; color: string; profilePicture?: string; }; resolved: boolean; assignee?: { id: number; username: string; email: string; color: string; profilePicture?: string; }; assigned_by?: { id: number; username: string; email: string; color: string; profilePicture?: string; }; reactions?: { [key: string]: { count: number; users: Array<{ id: number; username: string; email: string; }>; }; }; date: string; start_date?: string; due_date?: string; parent?: string; replies_count?: number; } export interface GetTaskCommentsParams { start?: number; start_id?: string; } export interface CreateTaskCommentParams { comment_text: string; assignee?: number; notify_all?: boolean; } export interface GetChatViewCommentsParams { start?: number; start_id?: string; } export interface CreateChatViewCommentParams { comment_text: string; notify_all?: boolean; } export interface GetListCommentsParams { start?: number; start_id?: string; } export interface CreateListCommentParams { comment_text: string; assignee?: number; notify_all?: boolean; } export interface UpdateCommentParams { comment_text: string; assignee?: number; resolved?: boolean; } export interface GetThreadedCommentsParams { start?: number; start_id?: string; } export interface CreateThreadedCommentParams { comment_text: string; notify_all?: boolean; } /** * Process comment response to add markdown representation * SIMPLIFIED VERSION to avoid duplication issues */ function processCommentResponse(comment: any): Comment { // Skip the cleanClickUpCommentResponse and processClickUpResponse chain // that was causing duplication - just return the comment as-is with minimal processing const processed = { ...comment }; // Only add markdown conversion if we have structured comment data if (processed.comment && Array.isArray(processed.comment)) { try { processed.comment_markdown = clickUpCommentToMarkdown({ comment: processed.comment }); } catch (error) { console.warn('Failed to convert ClickUp comment to markdown:', error); // Fallback to comment_text if available processed.comment_markdown = processed.comment_text || ''; } } return processed; } /** * Prepare comment parameters for ClickUp API using structured comment format * This uses ClickUp's structured comment array format for proper markdown rendering */ /* function prepareCommentParams(params: any): any { if (params.comment_text) { // Use the structured comment format instead of plain comment_text const structuredComment = prepareCommentForClickUp(params.comment_text); return { notify_all: params.notify_all || false, assignee: params.assignee, resolved: params.resolved, ...structuredComment // This includes the 'comment' array }; } return params; } */ export class CommentsEnhancedClient { private client: ClickUpClient; constructor(client: ClickUpClient) { this.client = client; } /** * Get comments for a specific task * @param taskId The ID of the task to get comments for * @param params Optional parameters for pagination * @returns A list of comments with processed content and markdown representation */ async getTaskComments(taskId: string, params?: GetTaskCommentsParams): Promise<{ comments: Comment[] }> { const result = await this.client.get(`/task/${taskId}/comment`, params); // Process each comment's content if (result.comments && Array.isArray(result.comments)) { result.comments = result.comments.map((comment: any) => processCommentResponse(comment)); } return result; } /** * Create a new comment on a task * @param taskId The ID of the task to comment on * @param params The comment parameters (supports markdown in comment_text) * @returns The created comment with processed content */ /** * RAW API TEST - Bypass all processing and send exactly like ClickUp's official example */ async createTaskCommentRaw(taskId: string, commentText: string): Promise<any> { // Exact match to ClickUp's official Node.js example const payload = { notify_all: false, comment_text: commentText }; console.log('=== RAW API TEST ==='); console.log('URL:', `/task/${taskId}/comment`); console.log('Payload:', JSON.stringify(payload, null, 2)); console.log('==================='); // Send raw request without any processing const result = await this.client.post(`/task/${taskId}/comment`, payload); console.log('=== RAW API RESPONSE ==='); console.log('Response:', JSON.stringify(result, null, 2)); console.log('========================'); // Return raw response without any processing return result; } async createTaskComment(taskId: string, params: CreateTaskCommentParams): Promise<Comment> { // Convert comment_text to structured array format const structuredComment = prepareCommentForClickUp(params.comment_text); const payload = { notify_all: params.notify_all || false, assignee: params.assignee, ...structuredComment // This adds the 'comment' array, NOT comment_text }; // DEBUG: Log exactly what we're sending to ClickUp API console.log('=== DEBUG: Sending to ClickUp API ==='); console.log('URL:', `/task/${taskId}/comment`); console.log('Payload:', JSON.stringify(payload, null, 2)); console.log('====================================='); const result = await this.client.post(`/task/${taskId}/comment`, payload); // DEBUG: Log what ClickUp returns console.log('=== DEBUG: ClickUp API Response ==='); console.log('Raw Response:', JSON.stringify(result, null, 2)); console.log('==================================='); return processCommentResponse(result); } /** * Get comments for a chat view * @param viewId The ID of the chat view to get comments for * @param params Optional parameters for pagination * @returns A list of comments with processed content and markdown representation */ async getChatViewComments(viewId: string, params?: GetChatViewCommentsParams): Promise<{ comments: Comment[] }> { const result = await this.client.get(`/view/${viewId}/comment`, params); // Process each comment's content if (result.comments && Array.isArray(result.comments)) { result.comments = result.comments.map((comment: any) => processCommentResponse(comment)); } return result; } /** * Create a new comment on a chat view * @param viewId The ID of the chat view to comment on * @param params The comment parameters (supports markdown in comment_text) * @returns The created comment with processed content */ async createChatViewComment(viewId: string, params: CreateChatViewCommentParams): Promise<Comment> { // Convert comment_text to structured array format const structuredComment = prepareCommentForClickUp(params.comment_text); const payload = { notify_all: params.notify_all || false, ...structuredComment // This adds the 'comment' array, NOT comment_text }; const result = await this.client.post(`/view/${viewId}/comment`, payload); return processCommentResponse(result); } /** * Get comments for a list * @param listId The ID of the list to get comments for * @param params Optional parameters for pagination * @returns A list of comments with processed content and markdown representation */ async getListComments(listId: string, params?: GetListCommentsParams): Promise<{ comments: Comment[] }> { const result = await this.client.get(`/list/${listId}/comment`, params); // Process each comment's content if (result.comments && Array.isArray(result.comments)) { result.comments = result.comments.map((comment: any) => processCommentResponse(comment)); } return result; } /** * Create a new comment on a list * @param listId The ID of the list to comment on * @param params The comment parameters (supports markdown in comment_text) * @returns The created comment with processed content */ async createListComment(listId: string, params: CreateListCommentParams): Promise<Comment> { // Convert comment_text to structured array format const structuredComment = prepareCommentForClickUp(params.comment_text); const payload = { notify_all: params.notify_all || false, assignee: params.assignee, ...structuredComment // This adds the 'comment' array, NOT comment_text }; const result = await this.client.post(`/list/${listId}/comment`, payload); return processCommentResponse(result); } /** * Update an existing comment * @param commentId The ID of the comment to update * @param params The comment parameters to update (supports markdown in comment_text) * @returns The updated comment with processed content */ async updateComment(commentId: string, params: UpdateCommentParams): Promise<Comment> { // Convert comment_text to structured array format const structuredComment = prepareCommentForClickUp(params.comment_text); const payload = { assignee: params.assignee, resolved: params.resolved, ...structuredComment // This adds the 'comment' array, NOT comment_text }; const result = await this.client.put(`/comment/${commentId}`, payload); return processCommentResponse(result); } /** * Delete a comment * @param commentId The ID of the comment to delete * @returns Success message */ async deleteComment(commentId: string): Promise<{ success: boolean }> { return this.client.delete(`/comment/${commentId}`); } /** * Get threaded comments for a parent comment * @param commentId The ID of the parent comment * @param params Optional parameters for pagination * @returns A list of threaded comments with processed content and markdown representation */ async getThreadedComments(commentId: string, params?: GetThreadedCommentsParams): Promise<{ comments: Comment[] }> { const result = await this.client.get(`/comment/${commentId}/reply`, params); // Process each comment's content if (result.comments && Array.isArray(result.comments)) { result.comments = result.comments.map((comment: any) => processCommentResponse(comment)); } return result; } /** * Create a new threaded comment on a parent comment * @param commentId The ID of the parent comment * @param params The comment parameters (supports markdown in comment_text) * @returns The created threaded comment with processed content */ async createThreadedComment(commentId: string, params: CreateThreadedCommentParams): Promise<Comment> { // Convert comment_text to structured array format const structuredComment = prepareCommentForClickUp(params.comment_text); const payload = { notify_all: params.notify_all || false, ...structuredComment // This adds the 'comment' array, NOT comment_text }; const result = await this.client.post(`/comment/${commentId}/reply`, payload); return processCommentResponse(result); } } export const createCommentsEnhancedClient = (client: ClickUpClient): CommentsEnhancedClient => { return new CommentsEnhancedClient(client); };

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/Chykalophia/ClickUp-MCP-Server---Enhanced'

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