Skip to main content
Glama
webhook-tools-setup.ts13 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { /* createClickUpClient */ } from '../clickup-client/index.js'; import { WebhooksEnhancedClient } from '../clickup-client/webhooks-enhanced.js'; import { CreateWebhookSchema, UpdateWebhookSchema, WebhookFilterSchema, ValidateWebhookSignatureSchema, ProcessWebhookSchema, WebhookPayloadSchema } from '../schemas/webhook-schemas.js'; // Create clients // const clickUpClient = createClickUpClient(); const webhooksClient = new WebhooksEnhancedClient(process.env.CLICKUP_API_TOKEN!); export function setupWebhookTools(server: McpServer): void { // ======================================== // WEBHOOK MANAGEMENT OPERATIONS // ======================================== server.tool( 'clickup_create_webhook', 'Create a new webhook in a ClickUp workspace. Webhooks allow real-time notifications when events occur.', { workspace_id: z.string().min(1).describe('The ID of the workspace to create the webhook in'), endpoint: z.string().url().describe('The URL endpoint that will receive webhook notifications'), events: z.array(z.enum([ 'taskCreated', 'taskUpdated', 'taskDeleted', 'taskStatusUpdated', 'taskAssigneeUpdated', 'taskDueDateUpdated', 'taskCommentPosted', 'taskCommentUpdated', 'taskTimeTracked', 'taskTimeUpdated', 'listCreated', 'listUpdated', 'listDeleted', 'folderCreated', 'folderUpdated', 'folderDeleted', 'spaceCreated', 'spaceUpdated', 'spaceDeleted', 'goalCreated', 'goalUpdated', 'goalDeleted', 'goalTargetUpdated' ])).describe('Array of events to subscribe to'), health_check_url: z.string().url().optional().describe('Optional URL for webhook health checks'), secret: z.string().optional().describe('Optional secret for HMAC signature validation') }, async (args) => { try { const request = CreateWebhookSchema.parse(args); const result = await webhooksClient.createWebhook(request); return { content: [{ type: 'text', text: `Webhook created successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error creating webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_webhooks', 'Get all webhooks for a workspace with optional filtering by status or event type.', { workspace_id: z.string().min(1).describe('The ID of the workspace to get webhooks from'), status: z.enum(['active', 'inactive']).optional().describe('Filter webhooks by status'), event_type: z.string().optional().describe('Filter webhooks by event type') }, async (args) => { try { const filter = WebhookFilterSchema.parse(args); const result = await webhooksClient.getWebhooks(filter); return { content: [{ type: 'text', text: `Webhooks for workspace ${args.workspace_id}:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting webhooks: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_webhook', 'Get detailed information about a specific webhook by its ID.', { webhook_id: z.string().min(1).describe('The ID of the webhook to get') }, async (args) => { try { const result = await webhooksClient.getWebhook(args.webhook_id); return { content: [{ type: 'text', text: `Webhook details:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_update_webhook', 'Update an existing webhook\'s configuration including endpoint, events, and status.', { webhook_id: z.string().min(1).describe('The ID of the webhook to update'), endpoint: z.string().url().optional().describe('The new URL endpoint for webhook notifications'), events: z.array(z.enum([ 'taskCreated', 'taskUpdated', 'taskDeleted', 'taskStatusUpdated', 'taskAssigneeUpdated', 'taskDueDateUpdated', 'taskCommentPosted', 'taskCommentUpdated', 'taskTimeTracked', 'taskTimeUpdated', 'listCreated', 'listUpdated', 'listDeleted', 'folderCreated', 'folderUpdated', 'folderDeleted', 'spaceCreated', 'spaceUpdated', 'spaceDeleted', 'goalCreated', 'goalUpdated', 'goalDeleted', 'goalTargetUpdated' ])).optional().describe('New array of events to subscribe to'), health_check_url: z.string().url().optional().describe('New URL for webhook health checks'), secret: z.string().optional().describe('New secret for HMAC signature validation'), status: z.enum(['active', 'inactive']).optional().describe('New status for the webhook') }, async (args) => { try { const request = UpdateWebhookSchema.parse(args); const result = await webhooksClient.updateWebhook(request); return { content: [{ type: 'text', text: `Webhook updated successfully:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error updating webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_delete_webhook', 'Delete a webhook from ClickUp. This will stop all notifications to the webhook endpoint.', { webhook_id: z.string().min(1).describe('The ID of the webhook to delete') }, async (args) => { try { const result = await webhooksClient.deleteWebhook(args.webhook_id); return { content: [{ type: 'text', text: `Webhook deleted successfully: ${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error deleting webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_webhook_event_history', 'Get the event history for a webhook including delivery status and response codes.', { webhook_id: z.string().min(1).describe('The ID of the webhook to get event history for'), limit: z.number().positive().optional().describe('Maximum number of events to return') }, async (args) => { try { const result = await webhooksClient.getWebhookEventHistory(args.webhook_id, args.limit); return { content: [{ type: 'text', text: `Webhook event history:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting webhook event history: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_ping_webhook', 'Send a test ping to a webhook endpoint to verify it\'s working correctly.', { webhook_id: z.string().min(1).describe('The ID of the webhook to ping') }, async (args) => { try { const result = await webhooksClient.pingWebhook(args.webhook_id); return { content: [{ type: 'text', text: `Webhook ping result:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error pinging webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_validate_webhook_signature', 'Validate the HMAC signature of a webhook payload to ensure authenticity.', { payload: z.string().describe('The raw webhook payload as a string'), signature: z.string().describe('The signature header from the webhook request'), secret: z.string().describe('The webhook secret used for signature generation') }, async (args) => { try { const request = ValidateWebhookSignatureSchema.parse(args); const isValid = webhooksClient.validateWebhookSignature(request); const result = { valid: isValid }; return { content: [{ type: 'text', text: `Webhook signature validation result:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error validating webhook signature: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_process_webhook', 'Process an incoming webhook payload and extract structured information about the event.', { payload: z.any().describe('The webhook payload object'), validate_signature: z.boolean().default(true).describe('Whether to validate the webhook signature'), signature: z.string().optional().describe('The signature header for validation'), secret: z.string().optional().describe('The webhook secret for signature validation') }, async (args) => { try { // Parse the payload if it's a string let payload = args.payload; if (typeof payload === 'string') { payload = JSON.parse(payload); } const parsedPayload = WebhookPayloadSchema.parse(payload); const request = ProcessWebhookSchema.parse({ ...args, payload: parsedPayload }); const result = await webhooksClient.processWebhook(request); return { content: [{ type: 'text', text: `Webhook processing result:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error processing webhook: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_get_webhook_stats', 'Get statistics about webhook performance including success rate and response times.', { webhook_id: z.string().min(1).describe('The ID of the webhook to get statistics for'), days: z.number().positive().optional().describe('Number of days to include in statistics (default: 30)') }, async (args) => { try { const result = await webhooksClient.getWebhookStats(args.webhook_id, args.days); return { content: [{ type: 'text', text: `Webhook statistics:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting webhook statistics: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } ); server.tool( 'clickup_retry_webhook_events', 'Retry failed webhook events for a specific webhook.', { webhook_id: z.string().min(1).describe('The ID of the webhook to retry events for'), event_ids: z.array(z.string()).optional().describe('Optional array of specific event IDs to retry. If not provided, all failed events will be retried.') }, async (args) => { try { const result = await webhooksClient.retryWebhookEvents(args.webhook_id, args.event_ids); return { content: [{ type: 'text', text: `Webhook events retry result:\n\n${JSON.stringify(result, null, 2)}` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error retrying webhook events: ${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