feat: add all tool domain files (events, subscribers, topics, workflows, notifications, messages, integrations, environments, translations, contexts, channels)
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import { novuRequest, toolResult, toolError } from "../services/api-client.js";
|
||||
import { PaginationV1Schema } from "../schemas/common.js";
|
||||
|
||||
export function registerWorkflowsTools(server: McpServer): void {
|
||||
// ── List Workflows ──────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_list_workflows",
|
||||
{
|
||||
title: "List Novu Workflows",
|
||||
description:
|
||||
"List all notification workflows in the current Novu environment. " +
|
||||
"Returns workflow names, IDs, statuses, and step summaries. " +
|
||||
"Supports offset-based pagination.",
|
||||
inputSchema: {
|
||||
...PaginationV1Schema,
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await novuRequest("/v1/workflows", "GET", undefined, {
|
||||
limit: params.limit,
|
||||
offset: params.offset,
|
||||
});
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Get Workflow ────────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_get_workflow",
|
||||
{
|
||||
title: "Get Novu Workflow",
|
||||
description:
|
||||
"Retrieve a single workflow by its ID. " +
|
||||
"Returns the full workflow definition including steps, triggers, tags, and status.",
|
||||
inputSchema: {
|
||||
workflow_id: z.string().describe("The unique ID of the workflow to retrieve"),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await novuRequest(
|
||||
`/v1/workflows/${params.workflow_id}`,
|
||||
"GET"
|
||||
);
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Create Workflow ─────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_create_workflow",
|
||||
{
|
||||
title: "Create Novu Workflow",
|
||||
description:
|
||||
"Create a new notification workflow. " +
|
||||
"At minimum, provide a name. Optionally configure description, tags, " +
|
||||
"active status, steps, notification group, and critical flag. " +
|
||||
"Steps and triggers are complex nested objects; pass them as arrays of objects.",
|
||||
inputSchema: {
|
||||
name: z.string().describe("Name of the workflow"),
|
||||
description: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Description of the workflow"),
|
||||
tags: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.describe("Tags to categorize the workflow"),
|
||||
active: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Whether the workflow is active (default: true)"),
|
||||
steps: z
|
||||
.array(z.record(z.unknown()))
|
||||
.optional()
|
||||
.describe(
|
||||
"Array of step definition objects. Each step typically includes " +
|
||||
"a template (with type, content, subject, etc.) and optional filters."
|
||||
),
|
||||
notificationGroupId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("ID of the notification group this workflow belongs to"),
|
||||
critical: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe(
|
||||
"Whether this workflow is critical. Critical workflows are always sent, " +
|
||||
"even if the subscriber has disabled notifications."
|
||||
),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: false,
|
||||
destructiveHint: false,
|
||||
idempotentHint: false,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const body: Record<string, unknown> = { name: params.name };
|
||||
if (params.description !== undefined)
|
||||
body.description = params.description;
|
||||
if (params.tags !== undefined) body.tags = params.tags;
|
||||
if (params.active !== undefined) body.active = params.active;
|
||||
if (params.steps !== undefined) body.steps = params.steps;
|
||||
if (params.notificationGroupId !== undefined)
|
||||
body.notificationGroupId = params.notificationGroupId;
|
||||
if (params.critical !== undefined) body.critical = params.critical;
|
||||
|
||||
const result = await novuRequest("/v1/workflows", "POST", body);
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Update Workflow ─────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_update_workflow",
|
||||
{
|
||||
title: "Update Novu Workflow",
|
||||
description:
|
||||
"Update an existing workflow by its ID. " +
|
||||
"Provide only the fields you want to change. " +
|
||||
"Steps and triggers are complex nested objects; pass them as arrays of objects.",
|
||||
inputSchema: {
|
||||
workflow_id: z.string().describe("The unique ID of the workflow to update"),
|
||||
name: z.string().optional().describe("Updated name of the workflow"),
|
||||
description: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Updated description of the workflow"),
|
||||
tags: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.describe("Updated tags to categorize the workflow"),
|
||||
active: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Whether the workflow is active"),
|
||||
steps: z
|
||||
.array(z.record(z.unknown()))
|
||||
.optional()
|
||||
.describe(
|
||||
"Updated array of step definition objects. Each step typically includes " +
|
||||
"a template (with type, content, subject, etc.) and optional filters."
|
||||
),
|
||||
notificationGroupId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("ID of the notification group this workflow belongs to"),
|
||||
critical: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe(
|
||||
"Whether this workflow is critical. Critical workflows are always sent, " +
|
||||
"even if the subscriber has disabled notifications."
|
||||
),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: false,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const body: Record<string, unknown> = {};
|
||||
if (params.name !== undefined) body.name = params.name;
|
||||
if (params.description !== undefined)
|
||||
body.description = params.description;
|
||||
if (params.tags !== undefined) body.tags = params.tags;
|
||||
if (params.active !== undefined) body.active = params.active;
|
||||
if (params.steps !== undefined) body.steps = params.steps;
|
||||
if (params.notificationGroupId !== undefined)
|
||||
body.notificationGroupId = params.notificationGroupId;
|
||||
if (params.critical !== undefined) body.critical = params.critical;
|
||||
|
||||
const result = await novuRequest(
|
||||
`/v1/workflows/${params.workflow_id}`,
|
||||
"PUT",
|
||||
body
|
||||
);
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Delete Workflow ─────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_delete_workflow",
|
||||
{
|
||||
title: "Delete Novu Workflow",
|
||||
description:
|
||||
"Permanently delete a workflow by its ID. " +
|
||||
"This action cannot be undone. All associated triggers will stop working.",
|
||||
inputSchema: {
|
||||
workflow_id: z.string().describe("The unique ID of the workflow to delete"),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: false,
|
||||
destructiveHint: true,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await novuRequest(
|
||||
`/v1/workflows/${params.workflow_id}`,
|
||||
"DELETE"
|
||||
);
|
||||
return toolResult(
|
||||
JSON.stringify(
|
||||
result ?? { success: true, message: "Workflow deleted successfully" },
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Sync Workflow ───────────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_sync_workflow",
|
||||
{
|
||||
title: "Sync Novu Workflow",
|
||||
description:
|
||||
"Sync a workflow to the target environment. " +
|
||||
"Use this to promote workflow changes between environments (e.g., dev to production).",
|
||||
inputSchema: {
|
||||
workflow_id: z.string().describe("The unique ID of the workflow to sync"),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: false,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await novuRequest(
|
||||
`/v1/workflows/${params.workflow_id}/sync`,
|
||||
"PUT"
|
||||
);
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── Get Workflow Step ───────────────────────────────────────────────
|
||||
server.registerTool(
|
||||
"novu_get_workflow_step",
|
||||
{
|
||||
title: "Get Novu Workflow Step",
|
||||
description:
|
||||
"Retrieve a specific step from a workflow. " +
|
||||
"Returns the full step definition including its template, filters, and metadata.",
|
||||
inputSchema: {
|
||||
workflow_id: z.string().describe("The unique ID of the workflow"),
|
||||
step_id: z.string().describe("The unique ID of the step within the workflow"),
|
||||
},
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
destructiveHint: false,
|
||||
idempotentHint: true,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await novuRequest(
|
||||
`/v1/workflows/${params.workflow_id}/steps/${params.step_id}`,
|
||||
"GET"
|
||||
);
|
||||
return toolResult(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
return toolError(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user