@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 +51 -3
- package/package.json +1 -1
- package/scripts/check-frontend-analytics-guidance.mjs +4 -0
- package/src/index.ts +51 -3
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
|
-
|
|
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
|
-
|
|
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
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|