ClickUp Webhooks Pipeline (Produce & Consume)
This document explains the internal architecture for receiving, producing, and consuming ClickUp webhook events in clickup_mcp.
See also
It is intended for developers extending or integrating the library. For end-user usage, see the endpoint reference at:
Docs → API References → Web Server → Endpoints → ClickUp Webhooks.
High-level overview
- The HTTP endpoint (
POST /webhook/clickup) validates payloads with DTOs, normalizes to a domain event, and forwards to an Event Sink. - The sink implementation is selected by
QUEUE_BACKEND:local→ handle in-process via registry and user handlers.- non-
local→ publish to a queue viaabstract-backend, and a separate consumer dispatches to the same handlers.
Core modules
clickup_mcp/web_server/event/models/dto.py: Pydantic DTOs for webhook requests.clickup_mcp/web_server/event/models/enums.py:ClickUpWebhookEventTypefor all supported event types.clickup_mcp/web_server/event/models/models.py: Domain event models (ClickUpWebhookEvent,ClickUpWebhookContext).clickup_mcp/web_server/event/handler/: Registry + OOP and decorator handler styles.clickup_mcp/web_server/event/sink.py: EventSink abstraction and selection.clickup_mcp/web_server/event/mq.py: Queue sink, serialize/deserialize, and consumer loop.clickup_mcp/web_server/event/bootstrap.py: Import handler modules listed in env variables.clickup_mcp/web_server/event/webhook.py: HTTP endpoint implementation.
Sequence diagrams
Local (in-process) mode
Queue-backed mode
Event Sink abstraction
EventSinkinterface andLocalEventSinklive inevent/sink.py.get_event_sink()selects implementation based onQUEUE_BACKEND.- Queue sink is provided by
QueueEventSinkinevent/mq.py.
# event/sink.py
class EventSink(ABC):
@abstractmethod
async def handle(self, event: ClickUpWebhookEvent) -> None: ...
class LocalEventSink(EventSink):
async def handle(self, event: ClickUpWebhookEvent) -> None:
await get_registry().dispatch(event)
Queue integration (abstract-backend)
- Module:
event/mq.py - Topic name:
clickup.webhooks. - Loader:
abstract_backend.queue.load_queue_backend(falls back toload_backendif needed). - Producer API:
backend.produce(topic, key, value)(async or sync). - Consumer API:
async for msg in backend.consume(topic=...).