@ductape/mcp 0.1.55 → 0.1.57

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.
package/dist/index.js CHANGED
@@ -499,6 +499,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
499
499
  notifications.push.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="push.send")
500
500
  notifications.sms.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="sms.send")
501
501
  notifications.callback.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="callback.send")
502
+ notifications.slack.send [{ product, env, notification, input: { text?, blocks?, channel? }, session?, cache? }]
503
+ notifications.discord.send [{ product, env, notification, input: { content?, embeds? }, session?, cache? }]
502
504
  notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch") — requires redisUrl in ductape initialization
503
505
  notifications.getMessages [{ product_tag?, env?, notification_tag?, status?, type?, start_date?, end_date?, page?, limit? }]
504
506
 
@@ -998,7 +1000,7 @@ const ALLOWED_SNIPPET_METHODS = {
998
1000
  graph: ['dispatch', 'find', 'insert', 'update', 'delete', 'query', 'execute'],
999
1001
  vector: ['query', 'find', 'findSimilar', 'upsert', 'insert', 'delete', 'dispatch'],
1000
1002
  storage: ['dispatch', 'upload', 'download', 'remove', 'listFiles', 'getSignedUrl', 'stats'],
1001
- notification: ['dispatch', 'send', 'email.send', 'push.send', 'sms.send', 'callback.send'],
1003
+ notification: ['dispatch', 'send', 'email.send', 'push.send', 'sms.send', 'callback.send', 'slack.send', 'discord.send'],
1002
1004
  messaging: ['dispatch', 'send', 'publish', 'produce', 'consume'],
1003
1005
  broker: ['dispatch', 'send', 'publish', 'produce', 'consume'],
1004
1006
  quota: ['run', 'dispatch', 'check', 'consume'],
@@ -1233,6 +1235,21 @@ function runCli(command) {
1233
1235
  catch (err) {
1234
1236
  const msg = (err.stderr || err.stdout || err.message || String(err)).trim();
1235
1237
  if (/\bHTTP 401\b|unauthori[sz]ed|invalid token|token expired/i.test(msg)) {
1238
+ // Distinguish a genuinely expired login from a command-specific endpoint/auth bug.
1239
+ // A valid workspace read proves the CLI session and selected workspace are authenticated.
1240
+ if (checkLoginState() === 'ok') {
1241
+ return {
1242
+ success: false,
1243
+ output: [
1244
+ 'The Ductape CLI session and active workspace are authenticated, but this command endpoint returned HTTP 401.',
1245
+ 'Do not ask the user to log in again and do not retry through ductape_execute.',
1246
+ 'This indicates a CLI command routing or endpoint authorization problem.',
1247
+ '',
1248
+ 'Update the Ductape CLI to the latest version and retry the same ductape_cli command.',
1249
+ `Original command: ductape ${command}`,
1250
+ ].join('\n'),
1251
+ };
1252
+ }
1236
1253
  authState = 'none';
1237
1254
  workspaceSynced = false;
1238
1255
  return {
@@ -2153,7 +2170,19 @@ DUCTAPE NOTIFICATIONS
2153
2170
 
2154
2171
  Notifications send messages across multiple channels: email, SMS, push, or HTTP callback.
2155
2172
 
2156
- Create a notification through declarative apply or Workbench (administrative), using:
2173
+ ADMINISTRATION CLI (never ductape_execute)
2174
+ ductape_cli("resources notifications create -f notification.json")
2175
+ ductape_cli("resources notifications get --tag <notification-tag> --json")
2176
+ ductape_cli("resources notifications list --json")
2177
+ ductape_cli("resources notifications update --tag <notification-tag> -f patch.json")
2178
+ ductape_cli("resources notifications delete --tag <notification-tag>")
2179
+ ductape_cli("notifications messages create -f message.json")
2180
+ ductape_cli("notifications messages list --notification <notification-tag> --json")
2181
+ ductape_cli("notifications messages get --tag <notification:message> --json")
2182
+ ductape_cli("notifications messages update --tag <notification:message> -f patch.json")
2183
+ Declarative alternative: ductape/notifications.json then ductape_cli("apply notifications").
2184
+
2185
+ Notification definition:
2157
2186
  {
2158
2187
  tag: "welcome-email",
2159
2188
  name: "Welcome Email",
@@ -2174,6 +2203,8 @@ Send at runtime (one channel at a time):
2174
2203
  notifications.push.send [{ product, env, notification, input: { device_tokens, title?, body?, data? } }]
2175
2204
  notifications.sms.send [{ product, env, notification, input: { recipients, body? } }]
2176
2205
  notifications.callback.send [{ product, env, notification, input: { query?, headers?, params?, body? } }]
2206
+ notifications.slack.send [{ product, env, notification, input: { text?, blocks?, channel? } }]
2207
+ notifications.discord.send [{ product, env, notification, input: { content?, embeds? } }]
2177
2208
 
2178
2209
  Multi-channel send (all channels in parallel):
2179
2210
  notifications.send [{ product, env, event: "notif_tag:message_tag", input: { ... } }]
@@ -2195,7 +2226,24 @@ Supported providers:
2195
2226
  Push: firebase | expo
2196
2227
  Callback: any HTTP endpoint
2197
2228
 
2198
- Channel configuration (envs per notification) is done in the Workbench UI, not via CLI.
2229
+ Each notification env may configure push_notifications, emails, sms, callbacks, slack, and discord.
2230
+ Email providers: smtp, sendgrid, mailgun, postmark, brevo.
2231
+ SMS providers: twilio, nexmo/vonage, plivo.
2232
+
2233
+ FIREBASE THROUGH A GCP CLOUD CONNECTION
2234
+ Complete and validate a GCP cloud connection with a service account authorized for Firebase
2235
+ Cloud Messaging. Then configure the notification env without copying service-account JSON:
2236
+ {
2237
+ "slug": "snd",
2238
+ "push_notifications": {
2239
+ "type": "firebase",
2240
+ "cloud": "gcp-connection-tag",
2241
+ "authMode": "cloud_connection",
2242
+ "databaseUrl": "https://<project>.firebaseio.com"
2243
+ }
2244
+ }
2245
+ The SDK requests current GCP credentials from the cloud connection at send time. Never put the
2246
+ service-account private key in the notification file. Expo does not use a GCP cloud connection.
2199
2247
  Notification tag and message tag are ALWAYS passed together as "notification_tag:message_tag".
2200
2248
  `.trim(),
2201
2249
  resilience: `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -48,7 +48,11 @@ const safetyChecks = [
48
48
  ['execute blocks administrative mutations', /Administrative operation.*is blocked in ductape_execute/],
49
49
  ['CLI auth is remotely validated', /ductape workspaces list --json/],
50
50
  ['CLI 401 triggers login-required state', /authentication expired or was revoked \(HTTP 401\)[\s\S]*ductape login/],
51
+ ['CLI distinguishes endpoint 401 from expired login', /session and active workspace are authenticated[\s\S]*Do not ask the user to log in again/],
51
52
  ['CLI auth guidance does not request secrets', /Never ask the user to paste their password/],
53
+ ['notification CLI administration documented', /resources notifications create[\s\S]*notifications messages create/],
54
+ ['Firebase GCP cloud connection documented', /FIREBASE THROUGH A GCP CLOUD CONNECTION[\s\S]*authMode.*cloud_connection/],
55
+ ['Slack and Discord sends documented', /notifications\.slack\.send[\s\S]*notifications\.discord\.send/],
52
56
  ];
53
57
 
54
58
  for (const [name, pattern] of safetyChecks) {
package/src/index.ts CHANGED
@@ -510,6 +510,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
510
510
  notifications.push.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="push.send")
511
511
  notifications.sms.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="sms.send")
512
512
  notifications.callback.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="callback.send")
513
+ notifications.slack.send [{ product, env, notification, input: { text?, blocks?, channel? }, session?, cache? }]
514
+ notifications.discord.send [{ product, env, notification, input: { content?, embeds? }, session?, cache? }]
513
515
  notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch") — requires redisUrl in ductape initialization
514
516
  notifications.getMessages [{ product_tag?, env?, notification_tag?, status?, type?, start_date?, end_date?, page?, limit? }]
515
517
 
@@ -1037,7 +1039,7 @@ const ALLOWED_SNIPPET_METHODS: Record<string, string[]> = {
1037
1039
  graph: ['dispatch', 'find', 'insert', 'update', 'delete', 'query', 'execute'],
1038
1040
  vector: ['query', 'find', 'findSimilar', 'upsert', 'insert', 'delete', 'dispatch'],
1039
1041
  storage: ['dispatch', 'upload', 'download', 'remove', 'listFiles', 'getSignedUrl', 'stats'],
1040
- notification: ['dispatch', 'send', 'email.send', 'push.send', 'sms.send', 'callback.send'],
1042
+ notification: ['dispatch', 'send', 'email.send', 'push.send', 'sms.send', 'callback.send', 'slack.send', 'discord.send'],
1041
1043
  messaging: ['dispatch', 'send', 'publish', 'produce', 'consume'],
1042
1044
  broker: ['dispatch', 'send', 'publish', 'produce', 'consume'],
1043
1045
  quota: ['run', 'dispatch', 'check', 'consume'],
@@ -1293,6 +1295,21 @@ function runCli(command: string): { success: boolean; output: string } {
1293
1295
  } catch (err: any) {
1294
1296
  const msg = (err.stderr || err.stdout || err.message || String(err)).trim();
1295
1297
  if (/\bHTTP 401\b|unauthori[sz]ed|invalid token|token expired/i.test(msg)) {
1298
+ // Distinguish a genuinely expired login from a command-specific endpoint/auth bug.
1299
+ // A valid workspace read proves the CLI session and selected workspace are authenticated.
1300
+ if (checkLoginState() === 'ok') {
1301
+ return {
1302
+ success: false,
1303
+ output: [
1304
+ 'The Ductape CLI session and active workspace are authenticated, but this command endpoint returned HTTP 401.',
1305
+ 'Do not ask the user to log in again and do not retry through ductape_execute.',
1306
+ 'This indicates a CLI command routing or endpoint authorization problem.',
1307
+ '',
1308
+ 'Update the Ductape CLI to the latest version and retry the same ductape_cli command.',
1309
+ `Original command: ductape ${command}`,
1310
+ ].join('\n'),
1311
+ };
1312
+ }
1296
1313
  authState = 'none';
1297
1314
  workspaceSynced = false;
1298
1315
  return {
@@ -2236,7 +2253,19 @@ DUCTAPE NOTIFICATIONS
2236
2253
 
2237
2254
  Notifications send messages across multiple channels: email, SMS, push, or HTTP callback.
2238
2255
 
2239
- Create a notification through declarative apply or Workbench (administrative), using:
2256
+ ADMINISTRATION CLI (never ductape_execute)
2257
+ ductape_cli("resources notifications create -f notification.json")
2258
+ ductape_cli("resources notifications get --tag <notification-tag> --json")
2259
+ ductape_cli("resources notifications list --json")
2260
+ ductape_cli("resources notifications update --tag <notification-tag> -f patch.json")
2261
+ ductape_cli("resources notifications delete --tag <notification-tag>")
2262
+ ductape_cli("notifications messages create -f message.json")
2263
+ ductape_cli("notifications messages list --notification <notification-tag> --json")
2264
+ ductape_cli("notifications messages get --tag <notification:message> --json")
2265
+ ductape_cli("notifications messages update --tag <notification:message> -f patch.json")
2266
+ Declarative alternative: ductape/notifications.json then ductape_cli("apply notifications").
2267
+
2268
+ Notification definition:
2240
2269
  {
2241
2270
  tag: "welcome-email",
2242
2271
  name: "Welcome Email",
@@ -2257,6 +2286,8 @@ Send at runtime (one channel at a time):
2257
2286
  notifications.push.send [{ product, env, notification, input: { device_tokens, title?, body?, data? } }]
2258
2287
  notifications.sms.send [{ product, env, notification, input: { recipients, body? } }]
2259
2288
  notifications.callback.send [{ product, env, notification, input: { query?, headers?, params?, body? } }]
2289
+ notifications.slack.send [{ product, env, notification, input: { text?, blocks?, channel? } }]
2290
+ notifications.discord.send [{ product, env, notification, input: { content?, embeds? } }]
2260
2291
 
2261
2292
  Multi-channel send (all channels in parallel):
2262
2293
  notifications.send [{ product, env, event: "notif_tag:message_tag", input: { ... } }]
@@ -2278,7 +2309,24 @@ Supported providers:
2278
2309
  Push: firebase | expo
2279
2310
  Callback: any HTTP endpoint
2280
2311
 
2281
- Channel configuration (envs per notification) is done in the Workbench UI, not via CLI.
2312
+ Each notification env may configure push_notifications, emails, sms, callbacks, slack, and discord.
2313
+ Email providers: smtp, sendgrid, mailgun, postmark, brevo.
2314
+ SMS providers: twilio, nexmo/vonage, plivo.
2315
+
2316
+ FIREBASE THROUGH A GCP CLOUD CONNECTION
2317
+ Complete and validate a GCP cloud connection with a service account authorized for Firebase
2318
+ Cloud Messaging. Then configure the notification env without copying service-account JSON:
2319
+ {
2320
+ "slug": "snd",
2321
+ "push_notifications": {
2322
+ "type": "firebase",
2323
+ "cloud": "gcp-connection-tag",
2324
+ "authMode": "cloud_connection",
2325
+ "databaseUrl": "https://<project>.firebaseio.com"
2326
+ }
2327
+ }
2328
+ The SDK requests current GCP credentials from the cloud connection at send time. Never put the
2329
+ service-account private key in the notification file. Expo does not use a GCP cloud connection.
2282
2330
  Notification tag and message tag are ALWAYS passed together as "notification_tag:message_tag".
2283
2331
  `.trim(),
2284
2332