Skip to main content
Glama
chat-tools.ts25.6 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { ChatEnhancedClient } from '../clickup-client/chat-enhanced.js'; import { CreateChannelSchema, CreateChannelOnParentSchema, CreateDirectMessageSchema, UpdateChannelSchema, GetChannelsFilterSchema, SendMessageSchema, UpdateMessageSchema, CreateReplySchema, GetMessagesFilterSchema, GetRepliesFilterSchema, CreateReactionSchema, DeleteReactionSchema, AddChannelMemberSchema, RemoveChannelMemberSchema, ReactionTypeSchema } from '../schemas/chat-schemas.js'; // Create enhanced chat client const chatClient = new ChatEnhancedClient(process.env.CLICKUP_API_TOKEN!); export function setupChatTools(server: McpServer): void { // ======================================== // CHANNEL MANAGEMENT OPERATIONS // ======================================== server.tool( 'clickup_get_chat_channels', 'Retrieve all chat channels in a workspace with optional filtering by type and archived status.', { workspace_id: z.string().min(1).describe('The ID of the workspace to get channels from'), archived: z.boolean().optional().describe('Whether to include archived channels'), type: z.enum(['public', 'private', 'direct']).optional().describe('Filter by channel type') }, async (args) => { try { const filter = GetChannelsFilterSchema.parse(args); const result = await chatClient.getChannels(filter); return { content: [{ type: 'text', text: `Found ${result.channels.length} channels:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting chat channels: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_create_chat_channel', 'Create a new chat channel in a workspace with specified name, description, and privacy settings.', { workspace_id: z.string().min(1).describe('The ID of the workspace to create the channel in'), name: z.string().min(1).max(255).describe('The name of the channel'), description: z.string().optional().describe('Optional description of the channel'), type: z.enum(['public', 'private', 'direct']).default('public').describe('The type of channel'), members: z.array(z.number()).optional().describe('Array of user IDs to add as initial members'), is_private: z.boolean().optional().describe('Whether the channel is private') }, async (args) => { try { const request = CreateChannelSchema.parse(args); const result = await chatClient.createChannel(request); return { content: [{ type: 'text', text: `Channel created successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating chat channel: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_create_chat_channel_on_parent', 'Create a chat channel on a specific space, folder, or list for contextual discussions.', { parent_id: z.string().min(1).describe('The ID of the parent (space, folder, or list)'), parent_type: z.enum(['space', 'folder', 'list']).describe('The type of parent container'), name: z.string().min(1).max(255).describe('The name of the channel'), description: z.string().optional().describe('Optional description of the channel'), type: z.enum(['public', 'private', 'direct']).default('public').describe('The type of channel'), members: z.array(z.number()).optional().describe('Array of user IDs to add as initial members'), is_private: z.boolean().optional().describe('Whether the channel is private') }, async (args) => { try { const request = CreateChannelOnParentSchema.parse(args); const result = await chatClient.createChannelOnParent(request); return { content: [{ type: 'text', text: `Channel created on ${args.parent_type} successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating channel on parent: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_create_direct_message', 'Create a direct message channel between specific users for private conversations.', { workspace_id: z.string().min(1).describe('The ID of the workspace'), members: z.array(z.number()).min(2).describe('Array of user IDs to include in the direct message (minimum 2)'), name: z.string().optional().describe('Optional name for the direct message channel') }, async (args) => { try { const request = CreateDirectMessageSchema.parse(args); const result = await chatClient.createDirectMessage(request); return { content: [{ type: 'text', text: `Direct message channel created successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating direct message: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_chat_channel', 'Retrieve detailed information about a specific chat channel by its ID.', { channel_id: z.string().min(1).describe('The ID of the channel to retrieve') }, async (args) => { try { const result = await chatClient.getChannel(args.channel_id); return { content: [{ type: 'text', text: `Channel details:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting channel: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_update_chat_channel', 'Update a chat channel\'s name, description, or privacy settings.', { channel_id: z.string().min(1).describe('The ID of the channel to update'), name: z.string().min(1).max(255).optional().describe('New name for the channel'), description: z.string().optional().describe('New description for the channel'), is_private: z.boolean().optional().describe('Update privacy setting') }, async (args) => { try { const request = UpdateChannelSchema.parse(args); const result = await chatClient.updateChannel(request); return { content: [{ type: 'text', text: `Channel updated successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error updating channel: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); // ======================================== // CHANNEL MEMBERS & FOLLOWERS // ======================================== server.tool( 'clickup_get_chat_channel_followers', 'Retrieve all followers of a chat channel who receive notifications about channel activity.', { channel_id: z.string().min(1).describe('The ID of the channel to get followers for') }, async (args) => { try { const result = await chatClient.getChannelFollowers(args.channel_id); return { content: [{ type: 'text', text: `Channel followers (${result.followers.length}):\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting channel followers: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_chat_channel_members', 'Retrieve all members of a chat channel with their roles and join dates.', { channel_id: z.string().min(1).describe('The ID of the channel to get members for') }, async (args) => { try { const result = await chatClient.getChannelMembers(args.channel_id); return { content: [{ type: 'text', text: `Channel members (${result.members.length}):\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting channel members: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_add_chat_channel_member', 'Add a user as a member to a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel'), user_id: z.number().describe('The ID of the user to add as a member') }, async (args) => { try { const request = AddChannelMemberSchema.parse(args); await chatClient.addChannelMember(request); return { content: [{ type: 'text', text: `User ${args.user_id} added to channel ${args.channel_id} successfully` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error adding channel member: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_remove_chat_channel_member', 'Remove a user from a chat channel membership.', { channel_id: z.string().min(1).describe('The ID of the channel'), user_id: z.number().describe('The ID of the user to remove from the channel') }, async (args) => { try { const request = RemoveChannelMemberSchema.parse(args); await chatClient.removeChannelMember(request); return { content: [{ type: 'text', text: `User ${args.user_id} removed from channel ${args.channel_id} successfully` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error removing channel member: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); // ======================================== // MESSAGE MANAGEMENT // ======================================== server.tool( 'clickup_get_chat_channel_messages', 'Retrieve messages from a chat channel with pagination and filtering options.', { channel_id: z.string().min(1).describe('The ID of the channel to get messages from'), limit: z.number().min(1).max(100).optional().describe('Maximum number of messages to return (1-100)'), before: z.string().optional().describe('Get messages before this message ID'), after: z.string().optional().describe('Get messages after this message ID') }, async (args) => { try { const filter = GetMessagesFilterSchema.parse(args); const result = await chatClient.getChannelMessages(filter); return { content: [{ type: 'text', text: `Retrieved ${result.messages.length} messages:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting channel messages: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_send_chat_message', 'Send a message to a chat channel with optional mentions and attachments.', { channel_id: z.string().min(1).describe('The ID of the channel to send the message to'), text: z.string().min(1).describe('The text content of the message'), mentions: z.array(z.number()).optional().describe('Array of user IDs to mention in the message'), attachments: z.array(z.string()).optional().describe('Array of attachment IDs to include'), reply_to: z.string().optional().describe('ID of the message this is replying to') }, async (args) => { try { const request = SendMessageSchema.parse(args); const result = await chatClient.sendMessage(request); return { content: [{ type: 'text', text: `Message sent successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error sending message: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_update_chat_message', 'Update the text content and mentions of an existing chat message.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to update'), text: z.string().min(1).describe('The new text content of the message'), mentions: z.array(z.number()).optional().describe('Updated array of user IDs to mention') }, async (args) => { try { const request = UpdateMessageSchema.parse(args); const result = await chatClient.updateMessage(request); return { content: [{ type: 'text', text: `Message updated successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error updating message: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_delete_chat_message', 'Delete a message from a chat channel. This action cannot be undone.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to delete') }, async (args) => { try { await chatClient.deleteMessage(args.channel_id, args.message_id); return { content: [{ type: 'text', text: `Message ${args.message_id} deleted successfully from channel ${args.channel_id}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error deleting message: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); // ======================================== // MESSAGE REPLIES // ======================================== server.tool( 'clickup_get_chat_message_replies', 'Retrieve all replies to a specific message in a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to get replies for'), limit: z.number().min(1).max(100).optional().describe('Maximum number of replies to return (1-100)'), before: z.string().optional().describe('Get replies before this reply ID'), after: z.string().optional().describe('Get replies after this reply ID') }, async (args) => { try { const filter = GetRepliesFilterSchema.parse(args); const result = await chatClient.getMessageReplies(filter); return { content: [{ type: 'text', text: `Retrieved ${result.replies.length} replies:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting message replies: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_create_chat_message_reply', 'Create a reply to a specific message in a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to reply to'), text: z.string().min(1).describe('The text content of the reply'), mentions: z.array(z.number()).optional().describe('Array of user IDs to mention in the reply'), attachments: z.array(z.string()).optional().describe('Array of attachment IDs to include') }, async (args) => { try { const request = CreateReplySchema.parse(args); const result = await chatClient.createReply(request); return { content: [{ type: 'text', text: `Reply created successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating reply: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); // ======================================== // MESSAGE REACTIONS // ======================================== server.tool( 'clickup_get_chat_message_reactions', 'Retrieve all reactions on a specific message in a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to get reactions for') }, async (args) => { try { const result = await chatClient.getMessageReactions(args.channel_id, args.message_id); return { content: [{ type: 'text', text: `Message reactions:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting message reactions: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_create_chat_message_reaction', 'Add a reaction to a message in a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to react to'), reaction: ReactionTypeSchema.describe('The type of reaction to add') }, async (args) => { try { const request = CreateReactionSchema.parse(args); await chatClient.createReaction(request); return { content: [{ type: 'text', text: `Reaction ${args.reaction} added to message ${args.message_id} successfully` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating reaction: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_delete_chat_message_reaction', 'Remove a reaction from a message in a chat channel.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to remove reaction from'), reaction: ReactionTypeSchema.describe('The type of reaction to remove') }, async (args) => { try { const request = DeleteReactionSchema.parse(args); await chatClient.deleteReaction(request); return { content: [{ type: 'text', text: `Reaction ${args.reaction} removed from message ${args.message_id} successfully` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error deleting reaction: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); // ======================================== // TAGGED USERS & UTILITY // ======================================== server.tool( 'clickup_get_chat_message_tagged_users', 'Retrieve all users tagged/mentioned in a specific message.', { channel_id: z.string().min(1).describe('The ID of the channel containing the message'), message_id: z.string().min(1).describe('The ID of the message to get tagged users for') }, async (args) => { try { const result = await chatClient.getTaggedUsers(args.channel_id, args.message_id); return { content: [{ type: 'text', text: `Tagged users in message:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting tagged users: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_search_chat_channels', 'Search for chat channels by name within a workspace.', { workspace_id: z.string().min(1).describe('The ID of the workspace to search in'), query: z.string().min(1).describe('The search query to match against channel names') }, async (args) => { try { const result = await chatClient.searchChannels(args.workspace_id, args.query); return { content: [{ type: 'text', text: `Found ${result.channels.length} channels matching "${args.query}":\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error searching channels: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_chat_channel_stats', 'Get statistics for a chat channel including message count, member count, and last activity.', { channel_id: z.string().min(1).describe('The ID of the channel to get statistics for') }, async (args) => { try { const result = await chatClient.getChannelStats(args.channel_id); return { content: [{ type: 'text', text: `Channel statistics:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting channel stats: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_mark_chat_channel_as_read', 'Mark all messages in a chat channel as read for the current user.', { channel_id: z.string().min(1).describe('The ID of the channel to mark as read') }, async (args) => { try { await chatClient.markChannelAsRead(args.channel_id); return { content: [{ type: 'text', text: `Channel ${args.channel_id} marked as read successfully` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error marking channel as read: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_chat_channel_unread_count', 'Get the number of unread messages in a chat channel for the current user.', { channel_id: z.string().min(1).describe('The ID of the channel to get unread count for') }, async (args) => { try { const result = await chatClient.getUnreadCount(args.channel_id); return { content: [{ type: 'text', text: `Unread messages in channel ${args.channel_id}: ${result.unread_count}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting unread count: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); }

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