No description
  • TypeScript 99.1%
  • JavaScript 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
s.savinel de14c17390 test: end-to-end suite driving the real MCP tool surface
Opt-in (NOVU_MCP_INTEGRATION=1) suite that starts the built server over
stdio and exercises every fixed defect against a live environment:
v2 create shape, notification group listing, step identity across both
update paths, payloadSchema update without step loss, translation merge
vs explicit replace, a second locale pushed independently, and the
Liquid-tag URL guard. Acceptance case for the create path is covered:
shell plus in_app/delay/email steps with controlValues and two locales,
created and deleted through MCP only.

The suite creates and deletes its own zz-mcp-test-* workflow, never
touches an existing one, and never calls sync. Cleanup failure fails the
run rather than leaving throwaway workflows behind.

Bumps to 1.1.0 and documents the new tools and the merge/identity
semantics in the README.
2026-09-11 12:22:34 +02:00
src test: end-to-end suite driving the real MCP tool surface 2026-09-11 12:22:34 +02:00
tests test: end-to-end suite driving the real MCP tool surface 2026-09-11 12:22:34 +02:00
.gitignore chore: scaffold novu-mcp-server project 2026-03-30 13:51:57 +02:00
package-lock.json fix: translation upsert merges by default instead of wiping the locale 2026-09-11 12:07:11 +02:00
package.json test: end-to-end suite driving the real MCP tool surface 2026-09-11 12:22:34 +02:00
README.md test: end-to-end suite driving the real MCP tool surface 2026-09-11 12:22:34 +02:00
tsconfig.json chore: scaffold novu-mcp-server project 2026-03-30 13:51:57 +02:00
vitest.config.ts wip: expand tool coverage (layouts, env variables, notifications) and add vitest suite 2026-09-08 16:34:08 +02:00

Novu MCP Server

An MCP (Model Context Protocol) server that provides full coverage of the Novu notification infrastructure API. Enables LLMs to manage subscribers, trigger notifications, author workflows and email layouts, localize content, and more through 116 tools across 13 API domains.

Features

  • Full API coverage: 116 tools spanning Events, Subscribers, Topics, Workflows, Layouts, Notifications, Messages, Integrations, Environments, Environment Variables, Translations, Contexts, and Channels
  • Current v2 API: Workflows, Layouts, Translations, Subscribers, Contexts and Topics target Novu's v2 endpoints
  • Dual transport: stdio (for local use with Claude Code, OpenCode, etc.) and Streamable HTTP (for remote/multi-client use)
  • Pagination support: Offset-based (v1) and cursor-based (v2) pagination
  • Error handling: Actionable error messages with HTTP status-specific guidance
  • Response truncation: Automatic truncation of large responses with pagination hints

Prerequisites

Installation

git clone <this-repo>
cd novu-mcp-server
npm install
npm run build

Configuration

Environment Variable Required Default Description
NOVU_SECRET_KEY Yes - Your Novu API key from the dashboard
NOVU_API_URL No https://api.novu.co API base URL. Use https://eu.api.novu.co for EU region
TRANSPORT No stdio Transport mode: stdio or http
PORT No 3000 HTTP server port (only used when TRANSPORT=http)

Usage

With Claude Code / OpenCode (stdio)

Add to your MCP configuration:

{
  "mcpServers": {
    "novu": {
      "command": "node",
      "args": ["/path/to/novu-mcp-server/dist/index.js"],
      "env": {
        "NOVU_SECRET_KEY": "your-api-key-here"
      }
    }
  }
}

With HTTP transport

NOVU_SECRET_KEY=your-key TRANSPORT=http PORT=3000 node dist/index.js

Then connect your MCP client to http://localhost:3000/mcp.

Available Tools (110)

Events (4 tools)

Tool Description
novu_trigger_event Trigger a notification workflow for specific subscribers
novu_bulk_trigger_event Trigger multiple notification events in a single request (max 100)
novu_broadcast_event Broadcast a notification to all subscribers
novu_cancel_event Cancel a pending triggered event by transaction ID

Subscribers (29 tools)

Core (v2, except bulk create / online-status / credentials which remain v1):

Tool Description
novu_create_subscriber Create a new subscriber (optional fail_if_exists)
novu_get_subscriber Retrieve a subscriber by ID
novu_update_subscriber Update subscriber attributes
novu_delete_subscriber Delete a subscriber
novu_search_subscribers Search/list subscribers (cursor pagination, filters)
novu_bulk_create_subscribers Create multiple subscribers at once (max 500)
novu_get_subscriber_preferences Get notification preferences for a subscriber
novu_update_subscriber_preferences Update notification preferences
novu_bulk_update_subscriber_preferences Bulk update preferences (max 100)
novu_get_subscriber_subscriptions Get topic subscriptions for a subscriber
novu_update_subscriber_online_status Set subscriber online/offline status
novu_update_provider_credentials Replace push/chat provider credentials
novu_upsert_provider_credentials Append push/chat provider credentials
novu_delete_provider_credentials Delete provider credentials

Inbox notification actions (v2):

Tool Description
novu_get_subscriber_notifications List inbox notifications, with filters and pagination
novu_get_subscriber_notifications_count Count inbox notifications matching filters
novu_mark_notification_as_read Mark one notification as read
novu_mark_notification_as_unread Mark one notification as unread
novu_mark_all_notifications_as_read Mark all matching notifications as read
novu_mark_notifications_as_seen Mark notifications as seen
novu_snooze_notification Snooze a notification until a time
novu_unsnooze_notification Cancel a snooze
novu_archive_notification Archive a notification
novu_unarchive_notification Unarchive a notification
novu_archive_all_notifications Archive all matching notifications
novu_archive_all_read_notifications Archive all read notifications
novu_delete_notification Delete a notification
novu_delete_all_notifications Delete all matching notifications
novu_complete_notification_action Mark a primary/secondary action complete
novu_revert_notification_action Revert a primary/secondary action

Topics (11 tools)

Tool Description
novu_create_topic Create a new topic
novu_get_topic Retrieve a topic by key
novu_update_topic Update a topic's name
novu_delete_topic Delete a topic
novu_list_topics List all topics (cursor-based pagination)
novu_create_topic_subscriptions Subscribe subscribers to a topic
novu_delete_topic_subscriptions Unsubscribe subscribers from a topic
novu_update_topic_subscription Update a topic subscription
novu_list_topic_subscriptions List subscribers of a topic
novu_check_topic_subscriber Check if a subscriber belongs to a topic
novu_get_topic_subscription Get subscription details

Workflows (11 tools, v2)

Tool Description
novu_create_workflow Create a workflow with typed steps + control values (v2: origin: novu-cloud)
novu_get_workflow Retrieve a workflow by ID
novu_update_workflow Update a workflow (fetch-merge-PUT, step identity preserved)
novu_update_workflow_payload_schema Replace a workflow's payloadSchema without touching steps
novu_update_workflow_step Merge control values into one step, preserving its identity
novu_delete_workflow Delete a workflow
novu_list_workflows List workflows (filter by tag/status, sort)
novu_list_notification_groups List notification groups and their IDs (legacy v1 endpoints only)
novu_sync_workflow Sync a workflow to a target environment
novu_get_workflow_step Get details of a specific workflow step
novu_generate_workflow_step_preview Render a step preview from control values + payload

Layouts (8 tools, v2)

Reusable email wrappers ("templates") that email steps render inside.

Tool Description
novu_list_layouts List email layouts
novu_get_layout Retrieve a layout by ID
novu_create_layout Create an email layout
novu_update_layout Update a layout's name / email body / editor type
novu_delete_layout Delete a layout
novu_duplicate_layout Duplicate an existing layout
novu_generate_layout_preview Render a layout preview
novu_get_layout_usage List workflows that use a layout

Step identity. The v2 workflow PUT is a full replace of the step list, and Novu matches an incoming step to an existing one by _id. A step sent without _id is deleted and recreated with a fresh _id, stepId and slug, which silently breaks trigger-time overrides.steps['<stepId>']. These tools always echo identity back, and novu_update_workflow_step fails loudly if the step is recreated anyway.

Payload schemas. When a template starts referencing new payload fields, move the schema with it via novu_update_workflow_payload_schema. With validatePayload enabled, a template and schema that disagree fail the trigger with 400 PAYLOAD_VALIDATION_ERROR in both directions.

Notifications (2 tools)

Tool Description
novu_list_notification_events List notification events with filters
novu_get_notification_event Get detailed notification event with execution logs

Messages (3 tools)

Tool Description
novu_list_messages List messages with filters
novu_delete_message Delete a specific message
novu_delete_messages_by_transaction Delete all messages for a transaction

Integrations (8 tools)

Tool Description
novu_list_integrations List all integrations
novu_list_active_integrations List only active integrations
novu_create_integration Create a new provider integration
novu_update_integration Update an integration
novu_delete_integration Delete an integration
novu_set_primary_integration Set an integration as primary for its channel
novu_generate_chat_oauth_url Generate OAuth URL for chat integrations (deprecated)
novu_auto_configure_integration Auto-configure a provider for inbound webhooks

Environments (7 tools)

Tool Description
novu_list_environments List all environments
novu_create_environment Create a new environment
novu_update_environment Update an environment
novu_delete_environment Delete an environment
novu_list_environment_tags List tags across environments
novu_compare_environment_resources Diff resources between two environments
novu_publish_environment_resources Publish resources to a target environment

Environment Variables (6 tools)

Tool Description
novu_list_environment_variables List environment variables (secrets masked)
novu_create_environment_variable Create a {{env.KEY}} variable
novu_get_environment_variable Retrieve a variable by key
novu_update_environment_variable Update a variable
novu_delete_environment_variable Delete a variable
novu_get_environment_variable_usage List workflows referencing a variable

Translations (11 tools, v2)

Localize workflow/layout content per subscriber locale (beta; Team/Enterprise plan). Keyed by resource_type + resource_id + locale.

Tool Description
novu_create_translation Create/update a translation for a resource + locale
novu_get_translation Retrieve a translation
novu_delete_translation Delete a translation (one locale)
novu_get_translation_group Get a resource's translation group (all locales)
novu_delete_translation_group Delete a resource's entire translation group
novu_import_master_translations Import master JSON for a locale
novu_get_master_translations Export master JSON for a locale
novu_upload_translation_files Upload locale JSON files for a resource
novu_upload_master_translations_file Upload a master JSON file (locale from filename)
novu_upsert_workflow_translation Write keys for one locale of a workflow (merges by default)
novu_upsert_layout_translation Write keys for one locale of a layout (merges by default)

Translation writes merge by default. POST /v2/translations is a full replace: a call carrying a subset of keys wipes every other key for that locale. The two upsert_*_translation tools therefore read the locale first and deep-merge the supplied keys on top. Pass mode: "replace" to get the raw overwrite. Both modes return keysBefore / keysAfter / keysAdded / keysRemoved, plus a warning when anything was removed, so unintended loss is visible in the tool result. novu_create_translation is the unguarded passthrough and still replaces the whole locale.

Contexts (5 tools, v2)

Keyed by type + id.

Tool Description
novu_list_contexts List all contexts
novu_create_context Create a new context (type + id + data)
novu_get_context Retrieve a context by type + id
novu_update_context Update a context's data
novu_delete_context Delete a context

Channels (10 tools)

Tool Description
novu_list_channel_connections List channel connections
novu_create_channel_connection Create a channel connection
novu_get_channel_connection Get a channel connection
novu_update_channel_connection Update a channel connection
novu_delete_channel_connection Delete a channel connection
novu_list_channel_endpoints List channel endpoints
novu_create_channel_endpoint Create a channel endpoint
novu_get_channel_endpoint Get a channel endpoint
novu_update_channel_endpoint Update a channel endpoint
novu_delete_channel_endpoint Delete a channel endpoint

Usage notes & gotchas

Learned authoring the Monizze card-workflow communications end to end. These are API behaviours, not bugs in the server — worth knowing before you script against it.

Workflows (v2)

  • The workflow_id you pass becomes the trigger identifier verbatim (e.g. payment-received). Choose it deliberately; the backend triggers on it.
  • Steps are { name, type, control_values }. Control shapes by type:
    • email: { subject, body, editorType: "html" | "block", layoutId, replyTo, from, preheader }. Pass editorType: "html" to store raw HTML in body; otherwise it's a Maily block doc. layoutId is the layout slug (e.g. technical-generic), not the _id.
    • delay: { type: "regular", amount, unit, extendToSchedule }.
    • in_app: { subject, body, avatar, primaryAction: { label, redirect: { url } } }. A primaryAction requires a label — you can't attach a redirect URL without one.
    • push: { subject, body }.
  • is_translation_enabled: true must be set for {{t.*}} to resolve per locale.
  • Update is a full replace (PUT): fetch, modify, send the whole definition.

Layouts (v2)

  • POST /v2/layouts ignores controlValues — a created layout gets a default empty block-editor body. To store an HTML layout body you must PUT after create with { controlValues: { email: { body, editorType: "html" } } }. Create the shell, then PUT the body.
  • layoutId (slug) is what workflow email steps reference; GET /v2/layouts lists both slug and _id.
  • Layout bodies must contain the {{content}} variable where the workflow content injects.

Translations (v2)

  • Keyed by (resourceType: workflow | layout, resourceId: slug, locale) — there is no standalone "translation group" to create; the resource is the group.
  • The target workflow/layout must exist first (resolve workflow … cannot be found otherwise).
  • Beta feature — requires the Team/Enterprise plan. On other plans the endpoints 404.
  • create_translation is upsert (create or replace) per locale; import_master_translations loads many resources at once from master JSON.

Auth / region

  • Auth header is Authorization: ApiKey <NOVU_SECRET_KEY>.
  • Monizze is on the EU region → set NOVU_API_URL=https://eu.api.novu.co.

Development

# Watch mode with auto-reload
npm run dev

# Build
npm run build

# Run the test suite (vitest; no live API calls)
npm test

# End-to-end tests against a real environment.
# Use a NON-PRODUCTION key. The suite creates and deletes its own
# `zz-mcp-test-*` workflow and never touches an existing one.
# Skipped automatically unless NOVU_MCP_INTEGRATION=1 is set.
NOVU_API_URL=https://eu.api.novu.co NOVU_SECRET_KEY=your-dev-key npm run test:integration

# Test with MCP Inspector
NOVU_SECRET_KEY=your-key npx @modelcontextprotocol/inspector node dist/index.js

License

MIT