Send notifications across 23 channels with 36 AI-ready tools. One API, zero boilerplate.
NotifyHub MCP Server (io.github.GabrielBBaldez/notify-hub)
This MCP server provides notification capabilities across 23 channels using 36 AI-ready tools. It exposes a unified interface described as “One API, zero boilerplate,” targeting Java and Spring Boot applications, with the library positioned as a unified notification solution.
🛠️ Key Features
23 notification channels
36 AI-ready tools
Unified notification library for Java and Spring Boot
“One API” interface concept
🚀 Use Cases
Sending notifications across multiple channels from one integration
Integrating notification delivery in Java and Spring Boot 3.x projects
⚡ Developer Benefits
Reduced integration effort via “zero boilerplate”
Tooling designed as AI-ready for downstream use
⚠️ Limitations
Source data does not specify authentication, deployment, or supported transport/runtime details
Stop writing different code for each notification channel. NotifyHub gives you a single fluent API to send notifications via Email, SMS, WhatsApp, Slack, Telegram, Discord, Microsoft Teams, Firebase Push, Webhooks, WebSocket, Google Chat, Twitter/X, LinkedIn, Notion, Twitch, YouTube, Instagram, SendGrid, TikTok Shop, Facebook, AWS SNS, Mailgun, PagerDuty, Kick — or any custom channel you create.
notify.to(user)
.via(Channel.EMAIL)
.via(Channel.SLACK)
.via(Channel.TEAMS)
.subject("Security Alert")
.content("Login from a new device detected")
.sendAll();
Async Sending
Send notifications without blocking:
java
// Fire and forget
notify.to(user)
.via(Channel.EMAIL)
.template("welcome")
.sendAsync();
// Or wait for result
CompletableFuture<Void> future = notify.to(user)
.via(Channel.EMAIL)
.via(Channel.SLACK)
.content("Deploy complete!")
.sendAllAsync();
future.thenRun(() -> log.info("All notifications sent!"));
Retry with Backoff
Automatic retry with exponential or fixed backoff:
notify:tracking:enabled:truetype:memory# or "jpa" for database persistence
java
// Send and get a receiptDeliveryReceiptreceipt= notify.to(user)
.via(Channel.EMAIL)
.content("Hello!")
.sendTracked();
System.out.println(receipt.getStatus()); // SENT
System.out.println(receipt.getId()); // uuid
System.out.println(receipt.getTimestamp()); // 2025-01-15T10:30:00Z
For database persistence, add the JPA tracker module:
Manage multiple versions of templates for A/B testing or gradual rollouts:
code
templates/notify/
├── order-confirmed.html ← default version
├── order-confirmed@v1.html ← version v1
├── order-confirmed@v2.html ← version v2
├── order-confirmed_pt_BR@v2.html ← v2 with i18n
└── order-confirmed.txt ← text default
java
// Use a specific version
notify.to(user).via(EMAIL)
.template("order-confirmed")
.templateVersion("v2")
.param("orderId", "123")
.send();
// No version = default template (backward compatible)
notify.to(user).via(EMAIL)
.template("order-confirmed")
.send();
// A/B testingStringversion= abTestService.getVariant(user, "email-template");
notify.to(user).via(EMAIL)
.template("welcome")
.templateVersion(version) // "v1" or "v2"
.send();
Send notifications to multiple destinations per channel using named aliases. Instead of one hardcoded webhook URL or chat ID, configure as many as you need:
// Send to a named alias
notify.to("alerts").via(DISCORD).content("Server is down!").send();
notify.to("engineering").via(SLACK).content("Deploy complete").send();
notify.to("devops").via(TELEGRAM).content("CPU at 95%").send();
// Send to default (no alias)
notify.to("user").via(DISCORD).content("Hello!").send();
// Pass a raw URL directly (no alias needed)
notify.to("https://discord.com/api/webhooks/444/ddd").via(DISCORD).content("Direct!").send();
Use with the MCP Server (AI Agents):
code
send_discord(recipient="alerts", body="Server is down!")
send_slack(recipient="engineering", body="Deploy complete")
send_telegram(recipient="devops", body="CPU at 95%")
Environment variables for MCP/Docker:
bash
# Default webhook
NOTIFY_CHANNELS_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/111/aaa
# Named recipients (RECIPIENTS_<NAME>)
NOTIFY_CHANNELS_DISCORD_RECIPIENTS_ALERTS=https://discord.com/api/webhooks/222/bbb
NOTIFY_CHANNELS_DISCORD_RECIPIENTS_DEVOPS=https://discord.com/api/webhooks/333/ccc
# Same pattern for all channels
NOTIFY_CHANNELS_SLACK_RECIPIENTS_ENGINEERING=https://hooks.slack.com/services/XXX
NOTIFY_CHANNELS_TELEGRAM_RECIPIENTS_ALERTS=-1001234567890
NOTIFY_CHANNELS_TEAMS_RECIPIENTS_GENERAL=https://outlook.office.com/webhook/XXX
NOTIFY_CHANNELS_GOOGLE_CHAT_RECIPIENTS_TEAM=https://chat.googleapis.com/v1/spaces/XXX
Resolution order: alias match in recipients map > raw URL/value passthrough > default from config.
Supported on: Discord, Slack, Telegram, Teams, Google Chat.
Message Queue (RabbitMQ / Kafka)
Decouple notification sending with async message queues. NotifyHub provides two modules:
@Autowired KafkaNotificationProducer producer;
// Same API as RabbitMQ — just different transport
producer.enqueue(QueuedNotification.builder()
.recipient("+5548999999999")
.channelName("sms")
.rawContent("Your code is 1234")
.priority("URGENT")
.build());
Both modules support: templates, priority, deduplication keys, delivery tracking, and phone number routing for SMS/WhatsApp.
Circuit Breaker
Per-channel circuit breaker prevents cascading failures. If a channel fails repeatedly, the circuit opens and short-circuits further attempts:
java
// Without Spring BootNotifyHubnotify= NotifyHub.builder()
.channel(emailChannel)
.circuitBreaker(CircuitBreakerConfig.defaults()) // 5 failures → open for 30s
.build();
// Custom thresholdsNotifyHubnotify= NotifyHub.builder()
.channel(emailChannel)
.circuitBreaker(CircuitBreakerConfig.custom()
.failureThreshold(3)
.openDuration(Duration.ofMinutes(1))
.windowSize(Duration.ofSeconds(30))
.build())
.build();
yaml
# Spring Bootnotify:circuit-breaker:enabled:truefailure-threshold:5open-duration:30swindow-size:60s
States: CLOSED (normal) → OPEN (rejecting) → HALF_OPEN (testing recovery). The health endpoint includes circuit breaker status per channel.
Bulkhead (Concurrency Isolation)
Limit concurrent sends per channel to prevent resource exhaustion:
java
NotifyHubnotify= NotifyHub.builder()
.channel(emailChannel)
.bulkhead(BulkheadConfig.defaults()) // 10 concurrent per channel
.bulkhead(BulkheadConfig.perChannel(5)) // or custom limit
.build();
Multi-Channel Orchestration
Build escalation workflows that promote through channels if the user doesn't engage:
java
notify.to(user)
.orchestrate()
.first(Channel.EMAIL)
.template("order-update")
.ifNoOpen(Duration.ofHours(24))
.then(Channel.PUSH)
.content("You have an unread order update")
.ifNoOpen(Duration.ofHours(48))
.then(Channel.SMS)
.content("Order update waiting — check your email")
.execute();
Each step waits for the specified duration before escalating to the next channel.
A/B Testing
Built-in deterministic A/B testing for notifications. Variant assignment is hash-based (SHA-256) — the same recipient always gets the same variant:
java
notify.to(user)
.via(Channel.EMAIL)
.subject("Welcome!")
.abTest("welcome-experiment")
.variant("control", b -> b.template("welcome-v1"))
.variant("new-design", b -> b.template("welcome-v2"))
.split(50, 50);
Supports any number of variants with weighted splits. Deterministic hashing ensures consistent experiences across sends.
Cron Scheduling
Schedule recurring notifications with cron expressions:
java
ScheduledNotificationjob= notify.to(user)
.via(Channel.EMAIL)
.template("weekly-digest")
.cron("0 9 * * MON"); // Every Monday at 9 AM
Supports standard 5-field cron syntax: minute, hour, day-of-month, month, day-of-week. Includes ranges, lists, steps, and named days/months.
Quiet Hours
Respect user preferences for notification timing:
java
publicclassUserimplementsNotifiable {
@Overridepublic QuietHours getQuietHours() {
return QuietHours.between(
LocalTime.of(22, 0), // 10 PM
LocalTime.of(8, 0), // 8 AM
ZoneId.of("America/Sao_Paulo")
);
}
@Overridepublic Set<Channel> getOptedOutChannels() {
return Set.of(Channel.SMS); // User opted out of SMS
}
}
Notifications sent during quiet hours are delayed to the next allowed window. Opted-out channels are silently skipped.
Testing Utilities
TestNotifyHub provides a test-friendly wrapper with capturing channels for all built-in channel types:
Status: UP (all channels available), DEGRADED (some down), DOWN (all down). When circuit breaker is configured, each channel also reports its circuit state.
management:tracing:sampling:probability:1.0# 100% sampling (adjust for production)otlp:tracing:endpoint:http://localhost:4318/v1/traces
Creates observations (spans):
notifyhub.send (tags: channel, template, outcome)
notifyhub.schedule (tags: channel, outcome)
Compatible with Jaeger, Zipkin, Grafana Tempo, Datadog, and any OTLP-compatible collector.
Webhook HMAC Signing
The Status Webhook listener supports HMAC-SHA256 request signing for security. When configured, every webhook POST includes a X-NotifyHub-Signature header that your server can use to verify the request came from NotifyHub.
yaml
notify:status-webhook:url:https://your-server.com/webhooksigning-secret:${WEBHOOK_SECRET}# any secret string
Each request includes the header:
code
X-NotifyHub-Signature: sha256=<hex-encoded HMAC-SHA256 of request body>
Only notify-core + channel modules needed. No Spring dependency.
MCP Server (AI Agents)
NotifyHub includes an MCP (Model Context Protocol) server that exposes all notification channels as tools for AI agents like Claude Desktop, Claude Code, Cursor, and any MCP-compatible client.
How it works
The notify-mcp module is a standalone Java application that communicates via STDIO using the JSON-RPC protocol. AI agents discover the available tools and can send notifications through any configured channel.
Setup
1. Build the MCP server:
bash
mvn clean package -pl notify-mcp -am -DskipTests
2. Configure in Claude Desktop (claude_desktop_config.json):
Each handler can short-circuit (e.g., dedup skips duplicates, circuit breaker rejects when open). The pipeline is fully optional — handlers are skipped when their dependency is null.
Design Principles
notify-core has zero Spring dependency — use it in any Java project
Channels are pluggable — implement NotificationChannel, register as a Spring bean
Slack, Telegram, Discord, Teams, WebSocket, Google Chat use zero external SDKs — only JDK java.net.http.HttpClient
Template engine is replaceable — implement TemplateEngine interface
Spring Boot starter auto-configures everything — just add the dependency
Async support — sendAsync() and sendAllAsync() with CompletableFuture
Conditional auto-config — channel beans only load when their module is on classpath
Unified event system — NotificationEventBus replaces scattered listener calls, backward-compatible via LegacyListenerAdapter
Maven Central
NotifyHub is published on Maven Central. No extra repositories needed.
Below is every module, what it does, when you need it, and how to add it.
notify-spring-boot-starter — The Main Dependency
What it does: Auto-configures NotifyHub inside a Spring Boot application. Automatically discovers channel beans, wires retry policies, tracking, rate limiting, DLQ, Micrometer metrics, OpenTelemetry tracing, Actuator health checks, and Spring events. Includes notify-core and notify-email transitively.
When to use: You're building a Spring Boot app and want automatic setup. This is the only required dependency for most projects.
What it does: Contains the entire fluent API (NotifyHub, NotificationBuilder, Channel, Notification, Priority, Attachment, RetryPolicy), plus interfaces for channels, templates, tracking, DLQ, rate limiting, and routing. Has zero Spring dependency — uses only SLF4J and Mustache.
When to use: You want to use NotifyHub in a plain Java project without Spring Boot, or you're building a library/framework on top of it.
What it does: Sends emails via any SMTP server (Gmail, Outlook, Amazon SES, Mailtrap, etc). Supports HTML and plain text, file attachments, TLS/SSL, and custom sender name. Uses Jakarta Mail internally.
When to use: You want to send email notifications. Already included by notify-spring-boot-starter.
What it does: Sends messages to Telegram chats/groups/channels via the Bot API. Supports a default chat ID and per-notification targeting. Uses the JDK HttpClient.
When to use: You want to send Telegram messages. Requires a bot token from @BotFather.
What it does: Sends push notifications to mobile devices (Android/iOS) and web apps via Firebase Cloud Messaging. Uses the Firebase Admin SDK with service account credentials.
When to use: You want to send push notifications to mobile apps. Requires a Firebase project with a service account JSON credentials file.
What it does: Sends notifications to any HTTP endpoint (REST APIs, PagerDuty, Datadog, custom services). Supports configurable payload templates with {{recipient}}, {{subject}}, {{content}} placeholders, custom headers, PUT/POST methods, and timeouts.
When to use: You want to integrate with any external service that has an HTTP API, or create custom webhook integrations.
What it does: Sends notifications over WebSocket connections using the JDK java.net.http.WebSocket API. Supports configurable message format with {{recipient}}, {{subject}}, {{content}} placeholders, custom headers, auto-reconnect with backoff, and connection timeout. Zero external dependencies.
When to use: You want to send real-time notifications over WebSocket to a server (e.g., live dashboards, chat systems, or custom WebSocket consumers).
What it does: Sends messages to Google Chat spaces via Incoming Webhooks. Posts JSON payloads using the JDK HttpClient — no external SDK needed.
When to use: You want to send notifications to a Google Chat space. Requires a Google Chat webhook URL (space Settings > Apps & integrations > Webhooks).
What it does: Sends transactional emails via SendGrid API with built-in delivery event tracking (delivered, opened, clicked, bounced). Uses the JDK HttpClient — no external SDK needed.
When to use: You want email delivery tracking beyond basic SMTP, or you already use SendGrid as your email provider.
What it does: Sends messages to TikTok Shop sellers via the TikTok Shop API. Handles HMAC-SHA256 request signing automatically. Uses the JDK HttpClient.
When to use: You want to send notifications to TikTok Shop sellers (order updates, customer messages).
What it does: Sends chat messages to Kick channels via the Kick Public API. Supports bot and user message types with OAuth 2.1 authentication and token refresh.
When to use: You want to send chat messages to Kick streaming channels from your notification pipeline.
What it does: Persists delivery receipts to a relational database (MySQL, PostgreSQL, H2, etc.) using Spring Data JPA. Stores notification ID, channel, recipient, status, timestamp, and error messages. Provides query methods for filtering and counting.
When to use: You want delivery tracking data to survive restarts (instead of the default in-memory tracker). Requires Spring Data JPA and a database on the classpath.
What it does: Provides a built-in web UI at /notify-admin with 4 pages: Dashboard (overview metrics), Tracking (delivery receipts), DLQ (failed notifications), and Channels (status). Built with Thymeleaf, dark theme, fully responsive.
When to use: You want a visual admin panel to monitor your notification system without building one from scratch. Requires notify.admin.enabled=true in your config.
What it does: Adds async notification processing via RabbitMQ. Includes a producer (enqueue notifications), a consumer (reads from queue and sends via NotifyHub), and Spring Boot auto-configuration with exchange/queue/binding setup.
When to use: You need to decouple notification sending from your main application flow, or you're in a microservice architecture where one service enqueues and another sends.
What it does: Same as RabbitMQ module but uses Apache Kafka as the message broker. Sends notifications to a Kafka topic with channel:recipient as the message key for partition ordering.
When to use: You're already using Kafka in your infrastructure, or you need high-throughput notification processing at scale.
What it does: Exposes all NotifyHub channels as MCP (Model Context Protocol) tools, allowing AI agents (Claude Desktop, Claude Code, Cursor) to send notifications through natural language commands. Runs as a headless Spring Boot app communicating via STDIO JSON-RPC. Provides 27 tools: send via any channel, batch send, audience management, DLQ monitoring, and delivery analytics.
When to use: You want AI agents to send notifications on your behalf. Configure the JAR path in your MCP client's config file and the agent will discover all available tools automatically.