@kadoa/mcp 0.3.4-rc.0 → 0.3.4-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +202 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -49115,11 +49115,15 @@ function isJwtExpired(jwt2) {
49115
49115
  }
49116
49116
  }
49117
49117
  async function refreshSupabaseJwt(ctx) {
49118
- if (!ctx.supabaseRefreshToken)
49118
+ if (!ctx.supabaseRefreshToken) {
49119
+ console.error("[JWT Refresh] No refresh token available, cannot refresh");
49119
49120
  return;
49121
+ }
49120
49122
  const supabaseUrl = process.env.SUPABASE_URL;
49121
- if (!supabaseUrl)
49123
+ if (!supabaseUrl) {
49124
+ console.error("[JWT Refresh] SUPABASE_URL not set, cannot refresh");
49122
49125
  return;
49126
+ }
49123
49127
  try {
49124
49128
  const res = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=refresh_token`, {
49125
49129
  method: "POST",
@@ -49129,14 +49133,19 @@ async function refreshSupabaseJwt(ctx) {
49129
49133
  },
49130
49134
  body: JSON.stringify({ refresh_token: ctx.supabaseRefreshToken })
49131
49135
  });
49132
- if (!res.ok)
49136
+ if (!res.ok) {
49137
+ const body = await res.text().catch(() => "");
49138
+ console.error(`[JWT Refresh] Supabase returned ${res.status}: ${body}`);
49133
49139
  return;
49140
+ }
49134
49141
  const data = await res.json();
49135
49142
  ctx.supabaseJwt = data.access_token;
49136
49143
  ctx.supabaseRefreshToken = data.refresh_token;
49137
49144
  ctx.client.setBearerToken(data.access_token);
49145
+ console.error("[JWT Refresh] Token refreshed successfully");
49138
49146
  return data.access_token;
49139
- } catch {
49147
+ } catch (error48) {
49148
+ console.error("[JWT Refresh] Failed:", error48);
49140
49149
  return;
49141
49150
  }
49142
49151
  }
@@ -49231,18 +49240,19 @@ function classifyError(error48) {
49231
49240
  }
49232
49241
  return "Unknown error";
49233
49242
  }
49234
- function withErrorHandling(name, handler) {
49235
- return async (...args) => {
49236
- try {
49237
- return await handler(...args);
49238
- } catch (error48) {
49239
- const message = classifyError(error48);
49240
- console.error(`[Tool Error] ${name}:`, error48);
49241
- return errorResult(message);
49242
- }
49243
- };
49244
- }
49245
49243
  function registerTools(server, ctx) {
49244
+ function withErrorHandling(name, handler) {
49245
+ return async (...args) => {
49246
+ try {
49247
+ await getValidJwt(ctx);
49248
+ return await handler(...args);
49249
+ } catch (error48) {
49250
+ const message = classifyError(error48);
49251
+ console.error(`[Tool Error] ${name}:`, error48);
49252
+ return errorResult(message);
49253
+ }
49254
+ };
49255
+ }
49246
49256
  server.registerTool("whoami", {
49247
49257
  description: "Show current user details: email, authentication method, and team memberships",
49248
49258
  inputSchema: {},
@@ -49540,6 +49550,183 @@ function registerTools(server, ctx) {
49540
49550
  workflow: result
49541
49551
  });
49542
49552
  }));
49553
+ server.registerTool("list_notification_channels", {
49554
+ description: "List notification channels configured for a workflow or across the workspace. Channels are destinations (email, Slack, webhook, websocket) where notifications are sent.",
49555
+ inputSchema: {
49556
+ workflowId: exports_external.string().optional().describe("Filter channels linked to a specific workflow. Omit to list all workspace channels.")
49557
+ },
49558
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
49559
+ }, withErrorHandling("list_notification_channels", async (args) => {
49560
+ const channels = args.workflowId ? await ctx.client.notification.channels.listAllChannels(args.workflowId) : await ctx.client.notification.channels.listAllChannels();
49561
+ return jsonResult({
49562
+ channels: channels.map((ch) => ({
49563
+ id: ch.id,
49564
+ name: ch.name,
49565
+ channelType: ch.channelType,
49566
+ config: ch.config,
49567
+ linkedConfigurations: ch.linkedConfigurations,
49568
+ createdAt: ch.createdAt
49569
+ })),
49570
+ total: channels.length
49571
+ });
49572
+ }));
49573
+ server.registerTool("create_notification_channel", {
49574
+ description: "Create a notification channel (email, webhook, or slack). The channel can then be linked to notification settings for specific events.",
49575
+ inputSchema: {
49576
+ channelType: exports_external.enum(["EMAIL", "WEBHOOK", "SLACK"]).describe("Type of notification channel"),
49577
+ name: exports_external.string().optional().describe("Name for the channel (defaults to 'default')"),
49578
+ config: exports_external.object({
49579
+ recipients: exports_external.array(exports_external.string()).optional().describe("Email recipients (required for EMAIL channels)"),
49580
+ webhookUrl: exports_external.string().optional().describe("Webhook/Slack endpoint URL (required for WEBHOOK and SLACK channels)"),
49581
+ httpMethod: exports_external.enum(["POST", "GET", "PUT", "PATCH"]).optional().describe("HTTP method for WEBHOOK channels (defaults to POST)")
49582
+ }).optional().describe("Channel-specific configuration. For EMAIL: provide recipients. For WEBHOOK: provide webhookUrl. For SLACK: provide webhookUrl.")
49583
+ },
49584
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
49585
+ }, withErrorHandling("create_notification_channel", async (args) => {
49586
+ const channel = await ctx.client.notification.channels.createChannel(args.channelType, {
49587
+ name: args.name || "default",
49588
+ config: args.config
49589
+ });
49590
+ return jsonResult({
49591
+ success: true,
49592
+ channel: {
49593
+ id: channel.id,
49594
+ name: channel.name,
49595
+ channelType: channel.channelType,
49596
+ config: channel.config
49597
+ },
49598
+ message: `${args.channelType} notification channel created successfully.`
49599
+ });
49600
+ }));
49601
+ server.registerTool("delete_notification_channel", {
49602
+ description: "Delete a notification channel by ID",
49603
+ inputSchema: {
49604
+ channelId: exports_external.string().describe("The channel ID to delete")
49605
+ },
49606
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true }
49607
+ }, withErrorHandling("delete_notification_channel", async (args) => {
49608
+ await ctx.client.notification.channels.deleteChannel(args.channelId);
49609
+ return jsonResult({
49610
+ success: true,
49611
+ message: "Notification channel deleted successfully."
49612
+ });
49613
+ }));
49614
+ server.registerTool("list_notification_settings", {
49615
+ description: "List notification settings (event-to-channel mappings) for a workflow or workspace. Shows which events trigger notifications and through which channels.",
49616
+ inputSchema: {
49617
+ workflowId: exports_external.string().optional().describe("Filter settings for a specific workflow. Omit to list workspace-level settings."),
49618
+ eventType: exports_external.enum([
49619
+ "workflow_started",
49620
+ "workflow_finished",
49621
+ "workflow_failed",
49622
+ "workflow_sample_finished",
49623
+ "workflow_data_change",
49624
+ "system_maintenance",
49625
+ "service_degradation",
49626
+ "credits_low",
49627
+ "free_trial_ending"
49628
+ ]).optional().describe("Filter by event type")
49629
+ },
49630
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
49631
+ }, withErrorHandling("list_notification_settings", async (args) => {
49632
+ const filters = {};
49633
+ if (args.workflowId)
49634
+ filters.workflowId = args.workflowId;
49635
+ if (args.eventType)
49636
+ filters.eventType = args.eventType;
49637
+ const settings = await ctx.client.notification.settings.listSettings(filters);
49638
+ return jsonResult({
49639
+ settings: settings.map((s) => ({
49640
+ id: s.id,
49641
+ workflowId: s.workflowId,
49642
+ eventType: s.eventType,
49643
+ enabled: s.enabled,
49644
+ channels: s.channels,
49645
+ createdAt: s.createdAt
49646
+ })),
49647
+ total: settings.length
49648
+ });
49649
+ }));
49650
+ server.registerTool("configure_notifications", {
49651
+ description: "Set up notifications for a workflow or workspace. Creates channels and settings in one step. " + "Specify which events to listen for and which channels to deliver to (email, webhook, slack, websocket).",
49652
+ inputSchema: {
49653
+ workflowId: exports_external.string().optional().describe("Workflow ID to configure notifications for. Omit for workspace-level notifications."),
49654
+ events: exports_external.array(exports_external.string()).describe('Event types to notify on. Pass ["all"] for all events, or pick from: ' + "workflow_started, workflow_finished, workflow_failed, workflow_sample_finished, " + "workflow_data_change, system_maintenance, service_degradation, credits_low, free_trial_ending"),
49655
+ channels: exports_external.object({
49656
+ email: exports_external.object({
49657
+ recipients: exports_external.array(exports_external.string().email()).optional().describe("Email addresses to notify. Omit to use the account default email.")
49658
+ }).optional().describe("Send email notifications. Pass {} for default email or {recipients: [...]} for custom addresses."),
49659
+ webhook: exports_external.object({
49660
+ url: exports_external.string().url().describe("Webhook endpoint URL"),
49661
+ httpMethod: exports_external.enum(["POST", "GET", "PUT", "PATCH"]).optional().describe("HTTP method (defaults to POST)")
49662
+ }).optional().describe("Send via HTTP webhook"),
49663
+ slack: exports_external.object({
49664
+ webhookUrl: exports_external.string().url().describe("Slack incoming webhook URL")
49665
+ }).optional().describe("Send to Slack channel"),
49666
+ websocket: exports_external.boolean().optional().describe("Enable WebSocket notifications")
49667
+ }).describe("At least one channel must be specified")
49668
+ },
49669
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
49670
+ }, withErrorHandling("configure_notifications", async (args) => {
49671
+ const events = args.events.length === 1 && args.events[0] === "all" ? "all" : args.events;
49672
+ const channelSetup = {};
49673
+ const ch = args.channels;
49674
+ if (ch.email) {
49675
+ if (ch.email.recipients?.length) {
49676
+ channelSetup.EMAIL = { name: "mcp-email", recipients: ch.email.recipients };
49677
+ } else {
49678
+ channelSetup.EMAIL = true;
49679
+ }
49680
+ }
49681
+ if (ch.websocket)
49682
+ channelSetup.WEBSOCKET = true;
49683
+ if (ch.webhook) {
49684
+ channelSetup.WEBHOOK = {
49685
+ name: "mcp-webhook",
49686
+ webhookUrl: ch.webhook.url,
49687
+ httpMethod: ch.webhook.httpMethod || "POST"
49688
+ };
49689
+ }
49690
+ if (ch.slack) {
49691
+ channelSetup.SLACK = {
49692
+ name: "mcp-slack",
49693
+ webhookUrl: ch.slack.webhookUrl
49694
+ };
49695
+ }
49696
+ if (Object.keys(channelSetup).length === 0) {
49697
+ return errorResult("At least one notification channel must be specified (email, webhook, slack, or websocket).");
49698
+ }
49699
+ const settings = await ctx.client.notification.configure({
49700
+ workflowId: args.workflowId,
49701
+ events,
49702
+ channels: channelSetup
49703
+ });
49704
+ const enabledChannels = Object.keys(channelSetup).map((k) => k.toLowerCase());
49705
+ const scope = args.workflowId ? `workflow ${args.workflowId}` : "workspace";
49706
+ return jsonResult({
49707
+ success: true,
49708
+ message: `Notifications configured for ${scope}. Events: ${events === "all" ? "all" : events.join(", ")}. Channels: ${enabledChannels.join(", ")}.`,
49709
+ settings: settings.map((s) => ({
49710
+ id: s.id,
49711
+ eventType: s.eventType,
49712
+ enabled: s.enabled,
49713
+ channels: s.channels
49714
+ }))
49715
+ });
49716
+ }));
49717
+ server.registerTool("delete_notification_setting", {
49718
+ description: "Delete a notification setting by ID. This removes the event-to-channel mapping but does not delete the channels themselves.",
49719
+ inputSchema: {
49720
+ settingsId: exports_external.string().describe("The notification settings ID to delete")
49721
+ },
49722
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true }
49723
+ }, withErrorHandling("delete_notification_setting", async (args) => {
49724
+ await ctx.client.notification.settings.deleteSettings(args.settingsId);
49725
+ return jsonResult({
49726
+ success: true,
49727
+ message: "Notification setting deleted successfully."
49728
+ });
49729
+ }));
49543
49730
  server.registerTool("team_list", {
49544
49731
  description: "List all teams the current user belongs to, showing which team is currently active",
49545
49732
  inputSchema: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kadoa/mcp",
3
- "version": "0.3.4-rc.0",
3
+ "version": "0.3.4-rc.2",
4
4
  "description": "Kadoa MCP Server — manage workflows from Claude Desktop, Cursor, and other MCP clients",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",