@ductape/mcp 0.1.57 → 0.1.58
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 +56 -11
- package/package.json +1 -1
- package/scripts/check-frontend-analytics-guidance.mjs +5 -0
- package/src/index.ts +56 -11
package/dist/index.js
CHANGED
|
@@ -323,6 +323,9 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
|
|
|
323
323
|
IMPORTANT: ALL product.* methods require the access key and will return 403 with a publishable key.
|
|
324
324
|
Use ductape_cli for ALL product operations — never ductape_execute:
|
|
325
325
|
ductape_cli("products get --tag <tag> --json") ← fetch product + full inventory
|
|
326
|
+
ductape_cli("products components list --tag <tag> --json") ← compact non-secret inventory
|
|
327
|
+
ductape_cli("products components get --tag <tag> --type notifications --json")
|
|
328
|
+
ductape_cli("products components get --tag <tag> --type events --json")
|
|
326
329
|
ductape_cli("products create --name <name> --tag <tag>")
|
|
327
330
|
ductape_cli("products environments list <tag> --json")
|
|
328
331
|
ductape_cli("products environments get <tag> <slug> --json")
|
|
@@ -490,8 +493,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
|
|
|
490
493
|
notifications.fetch [product_tag, notif_tag]
|
|
491
494
|
notifications.list [product_tag]
|
|
492
495
|
notifications.delete [product_tag, notif_tag]
|
|
493
|
-
notifications.messages.create [product_tag, data: { tag: string,
|
|
494
|
-
notifications.messages.update [product_tag, msg_tag, data: {
|
|
496
|
+
notifications.messages.create [product_tag, data: { tag: string, name: string, description?: string, push_notification?: { title: string, body: string, data?: object }, email?: { subject: string, template: string }, callback?: object, sms?: string }]
|
|
497
|
+
notifications.messages.update [product_tag, msg_tag, data: { name?: string, description?: string, push_notification?: { title: string, body: string, data?: object }, email?: { subject: string, template: string }, callback?: object, sms?: string }]
|
|
495
498
|
notifications.messages.fetch [product_tag, msg_tag]
|
|
496
499
|
notifications.messages.list [product_tag, notification_tag]
|
|
497
500
|
notifications.send [{ product, env, event, input: { ... } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="send", targets={notification})
|
|
@@ -1163,6 +1166,7 @@ const ADMIN_SUBCOMMANDS = [
|
|
|
1163
1166
|
'link', 'unlink', 'init',
|
|
1164
1167
|
'products', 'apps',
|
|
1165
1168
|
'resources',
|
|
1169
|
+
'notifications',
|
|
1166
1170
|
'events',
|
|
1167
1171
|
'cloud',
|
|
1168
1172
|
'secrets',
|
|
@@ -2181,22 +2185,54 @@ ADMINISTRATION — CLI (never ductape_execute)
|
|
|
2181
2185
|
ductape_cli("notifications messages get --tag <notification:message> --json")
|
|
2182
2186
|
ductape_cli("notifications messages update --tag <notification:message> -f patch.json")
|
|
2183
2187
|
Declarative alternative: ductape/notifications.json then ductape_cli("apply notifications").
|
|
2188
|
+
The file MUST be a top-level JSON array. Each item is a notification definition and may contain
|
|
2189
|
+
a nested "messages" array. {"notifications":[],"messages":[]} is not a valid envelope.
|
|
2184
2190
|
|
|
2185
2191
|
Notification definition:
|
|
2186
2192
|
{
|
|
2187
|
-
tag: "welcome-email",
|
|
2193
|
+
tag: "welcome-email", // component tags cannot contain ":"
|
|
2188
2194
|
name: "Welcome Email",
|
|
2189
|
-
|
|
2195
|
+
description: "Transactional welcome messages",
|
|
2196
|
+
envs: [{
|
|
2197
|
+
slug: "prd",
|
|
2198
|
+
emails: {
|
|
2199
|
+
provider: "smtp",
|
|
2200
|
+
smtp: {
|
|
2201
|
+
host: "smtp.example.com",
|
|
2202
|
+
port: "$Secret{smtp-port}",
|
|
2203
|
+
sender_email: "hello@example.com",
|
|
2204
|
+
auth: { user: "$Secret{smtp-user}", pass: "$Secret{smtp-password}" },
|
|
2205
|
+
secure: true
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}],
|
|
2209
|
+
messages: []
|
|
2190
2210
|
}
|
|
2191
2211
|
|
|
2192
2212
|
Create a message template through declarative apply or Workbench:
|
|
2193
2213
|
{
|
|
2194
|
-
tag: "welcome-email:default",
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2214
|
+
tag: "welcome-email:default", // message tags use component-tag:message-tag
|
|
2215
|
+
name: "Default welcome",
|
|
2216
|
+
description: "Sent after account creation",
|
|
2217
|
+
push_notification: {
|
|
2218
|
+
title: "Welcome, {{name}}!",
|
|
2219
|
+
body: "Thanks for signing up.",
|
|
2220
|
+
data: {}
|
|
2221
|
+
},
|
|
2222
|
+
email: {
|
|
2223
|
+
subject: "Welcome, {{name}}!",
|
|
2224
|
+
template: "Hi {{name}}, thanks for signing up."
|
|
2225
|
+
}
|
|
2198
2226
|
}
|
|
2199
2227
|
|
|
2228
|
+
TAG AND SMTP RULES
|
|
2229
|
+
Component tag: "game-alerts-critical" (no colon).
|
|
2230
|
+
Message tag: "game-alerts-critical:match-launch" (one colon separator).
|
|
2231
|
+
Do not add "notification", "subject", or "body" at message root.
|
|
2232
|
+
SMTP requires emails.smtp.sender_email.
|
|
2233
|
+
emails.smtp.secure is a boolean and cannot be a $Secret{...} string.
|
|
2234
|
+
Credential strings such as auth.user and auth.pass may use $Secret{...}.
|
|
2235
|
+
|
|
2200
2236
|
Send at runtime (one channel at a time):
|
|
2201
2237
|
→ CALL ductape_generate_payload FIRST (operation_family="notification", method="email.send")
|
|
2202
2238
|
notifications.email.send [{ product, env, notification, input: { recipients, subject?, template? } }]
|
|
@@ -2244,6 +2280,10 @@ FIREBASE THROUGH A GCP CLOUD CONNECTION
|
|
|
2244
2280
|
}
|
|
2245
2281
|
The SDK requests current GCP credentials from the cloud connection at send time. Never put the
|
|
2246
2282
|
service-account private key in the notification file. Expo does not use a GCP cloud connection.
|
|
2283
|
+
The recommended cloud connection scope is "notifications". It expresses Ductape capability/UI
|
|
2284
|
+
intent; creating a notification does not prove Google-side FCM permission. Runtime delivery
|
|
2285
|
+
requires fcm.googleapis.com and roles/firebasecloudmessaging.admin, so validate the connection
|
|
2286
|
+
and perform a delivery test.
|
|
2247
2287
|
Notification tag and message tag are ALWAYS passed together as "notification_tag:message_tag".
|
|
2248
2288
|
`.trim(),
|
|
2249
2289
|
resilience: `
|
|
@@ -3753,8 +3793,10 @@ async function main() {
|
|
|
3753
3793
|
const firstWord = args.command.trim().split(/\s+/)[0];
|
|
3754
3794
|
const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
|
|
3755
3795
|
if (!isAuthCommand) {
|
|
3756
|
-
//
|
|
3757
|
-
|
|
3796
|
+
// Cache successful authentication, but re-check a missing/expired session on every call.
|
|
3797
|
+
// The user may complete `ductape login` in another terminal while this MCP process remains
|
|
3798
|
+
// alive; caching "none" would otherwise make the MCP blind to the newly written session.
|
|
3799
|
+
if (authState === 'unknown' || authState === 'none') {
|
|
3758
3800
|
checkLoginState();
|
|
3759
3801
|
}
|
|
3760
3802
|
if (authState === 'none') {
|
|
@@ -4062,7 +4104,10 @@ async function main() {
|
|
|
4062
4104
|
' Message brokers are import-only (no provision-persist). Import flow is the same as storage.\n' +
|
|
4063
4105
|
' type field = "messageBrokers" (not "messagebrokers" or "events").\n' +
|
|
4064
4106
|
' After importing, create topics first with ductape_cli("events topics create -f topic.json") — SQS requires explicit topic creation with queueUrls. For other providers, topics auto-register on first produce but should still be created explicitly before any consumer subscribes.\n' +
|
|
4065
|
-
' - Listing workspaces, products, secrets\n' +
|
|
4107
|
+
' - Listing workspaces, products, focused product components, secrets\n' +
|
|
4108
|
+
' Prefer "products components list --tag <tag> --json" for compact inventory; use\n' +
|
|
4109
|
+
' "products components get --tag <tag> --type notifications|events --json" for focused detail.\n' +
|
|
4110
|
+
' - Managing notification components and message templates through "resources notifications" and "notifications messages"\n' +
|
|
4066
4111
|
' - Linking a project folder: "link --product <tag> --env <slug>"\n' +
|
|
4067
4112
|
' - Syncing sessions/notifications/events: "apply" or "apply sessions" etc.\n' +
|
|
4068
4113
|
' - Running database migrations: "db migrate", "db schema generate"\n\n' +
|
package/package.json
CHANGED
|
@@ -51,6 +51,11 @@ const safetyChecks = [
|
|
|
51
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/],
|
|
52
52
|
['CLI auth guidance does not request secrets', /Never ask the user to paste their password/],
|
|
53
53
|
['notification CLI administration documented', /resources notifications create[\s\S]*notifications messages create/],
|
|
54
|
+
['notification command allowed by MCP', /ADMIN_SUBCOMMANDS[\s\S]*'notifications'/],
|
|
55
|
+
['notification template uses SDK shape', /push_notification\?: \{ title: string, body: string[\s\S]*email\?: \{ subject: string, template: string/],
|
|
56
|
+
['notification declarations require array shape', /file MUST be a top-level JSON array/],
|
|
57
|
+
['external CLI login is re-read', /authState === 'unknown' \|\| authState === 'none'/],
|
|
58
|
+
['compact product inventory documented', /products components list --tag <tag> --json/],
|
|
54
59
|
['Firebase GCP cloud connection documented', /FIREBASE THROUGH A GCP CLOUD CONNECTION[\s\S]*authMode.*cloud_connection/],
|
|
55
60
|
['Slack and Discord sends documented', /notifications\.slack\.send[\s\S]*notifications\.discord\.send/],
|
|
56
61
|
];
|
package/src/index.ts
CHANGED
|
@@ -334,6 +334,9 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
|
|
|
334
334
|
IMPORTANT: ALL product.* methods require the access key and will return 403 with a publishable key.
|
|
335
335
|
Use ductape_cli for ALL product operations — never ductape_execute:
|
|
336
336
|
ductape_cli("products get --tag <tag> --json") ← fetch product + full inventory
|
|
337
|
+
ductape_cli("products components list --tag <tag> --json") ← compact non-secret inventory
|
|
338
|
+
ductape_cli("products components get --tag <tag> --type notifications --json")
|
|
339
|
+
ductape_cli("products components get --tag <tag> --type events --json")
|
|
337
340
|
ductape_cli("products create --name <name> --tag <tag>")
|
|
338
341
|
ductape_cli("products environments list <tag> --json")
|
|
339
342
|
ductape_cli("products environments get <tag> <slug> --json")
|
|
@@ -501,8 +504,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
|
|
|
501
504
|
notifications.fetch [product_tag, notif_tag]
|
|
502
505
|
notifications.list [product_tag]
|
|
503
506
|
notifications.delete [product_tag, notif_tag]
|
|
504
|
-
notifications.messages.create [product_tag, data: { tag: string,
|
|
505
|
-
notifications.messages.update [product_tag, msg_tag, data: {
|
|
507
|
+
notifications.messages.create [product_tag, data: { tag: string, name: string, description?: string, push_notification?: { title: string, body: string, data?: object }, email?: { subject: string, template: string }, callback?: object, sms?: string }]
|
|
508
|
+
notifications.messages.update [product_tag, msg_tag, data: { name?: string, description?: string, push_notification?: { title: string, body: string, data?: object }, email?: { subject: string, template: string }, callback?: object, sms?: string }]
|
|
506
509
|
notifications.messages.fetch [product_tag, msg_tag]
|
|
507
510
|
notifications.messages.list [product_tag, notification_tag]
|
|
508
511
|
notifications.send [{ product, env, event, input: { ... } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="send", targets={notification})
|
|
@@ -1224,6 +1227,7 @@ const ADMIN_SUBCOMMANDS = [
|
|
|
1224
1227
|
'link', 'unlink', 'init',
|
|
1225
1228
|
'products', 'apps',
|
|
1226
1229
|
'resources',
|
|
1230
|
+
'notifications',
|
|
1227
1231
|
'events',
|
|
1228
1232
|
'cloud',
|
|
1229
1233
|
'secrets',
|
|
@@ -2264,22 +2268,54 @@ ADMINISTRATION — CLI (never ductape_execute)
|
|
|
2264
2268
|
ductape_cli("notifications messages get --tag <notification:message> --json")
|
|
2265
2269
|
ductape_cli("notifications messages update --tag <notification:message> -f patch.json")
|
|
2266
2270
|
Declarative alternative: ductape/notifications.json then ductape_cli("apply notifications").
|
|
2271
|
+
The file MUST be a top-level JSON array. Each item is a notification definition and may contain
|
|
2272
|
+
a nested "messages" array. {"notifications":[],"messages":[]} is not a valid envelope.
|
|
2267
2273
|
|
|
2268
2274
|
Notification definition:
|
|
2269
2275
|
{
|
|
2270
|
-
tag: "welcome-email",
|
|
2276
|
+
tag: "welcome-email", // component tags cannot contain ":"
|
|
2271
2277
|
name: "Welcome Email",
|
|
2272
|
-
|
|
2278
|
+
description: "Transactional welcome messages",
|
|
2279
|
+
envs: [{
|
|
2280
|
+
slug: "prd",
|
|
2281
|
+
emails: {
|
|
2282
|
+
provider: "smtp",
|
|
2283
|
+
smtp: {
|
|
2284
|
+
host: "smtp.example.com",
|
|
2285
|
+
port: "$Secret{smtp-port}",
|
|
2286
|
+
sender_email: "hello@example.com",
|
|
2287
|
+
auth: { user: "$Secret{smtp-user}", pass: "$Secret{smtp-password}" },
|
|
2288
|
+
secure: true
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}],
|
|
2292
|
+
messages: []
|
|
2273
2293
|
}
|
|
2274
2294
|
|
|
2275
2295
|
Create a message template through declarative apply or Workbench:
|
|
2276
2296
|
{
|
|
2277
|
-
tag: "welcome-email:default",
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2297
|
+
tag: "welcome-email:default", // message tags use component-tag:message-tag
|
|
2298
|
+
name: "Default welcome",
|
|
2299
|
+
description: "Sent after account creation",
|
|
2300
|
+
push_notification: {
|
|
2301
|
+
title: "Welcome, {{name}}!",
|
|
2302
|
+
body: "Thanks for signing up.",
|
|
2303
|
+
data: {}
|
|
2304
|
+
},
|
|
2305
|
+
email: {
|
|
2306
|
+
subject: "Welcome, {{name}}!",
|
|
2307
|
+
template: "Hi {{name}}, thanks for signing up."
|
|
2308
|
+
}
|
|
2281
2309
|
}
|
|
2282
2310
|
|
|
2311
|
+
TAG AND SMTP RULES
|
|
2312
|
+
Component tag: "game-alerts-critical" (no colon).
|
|
2313
|
+
Message tag: "game-alerts-critical:match-launch" (one colon separator).
|
|
2314
|
+
Do not add "notification", "subject", or "body" at message root.
|
|
2315
|
+
SMTP requires emails.smtp.sender_email.
|
|
2316
|
+
emails.smtp.secure is a boolean and cannot be a $Secret{...} string.
|
|
2317
|
+
Credential strings such as auth.user and auth.pass may use $Secret{...}.
|
|
2318
|
+
|
|
2283
2319
|
Send at runtime (one channel at a time):
|
|
2284
2320
|
→ CALL ductape_generate_payload FIRST (operation_family="notification", method="email.send")
|
|
2285
2321
|
notifications.email.send [{ product, env, notification, input: { recipients, subject?, template? } }]
|
|
@@ -2327,6 +2363,10 @@ FIREBASE THROUGH A GCP CLOUD CONNECTION
|
|
|
2327
2363
|
}
|
|
2328
2364
|
The SDK requests current GCP credentials from the cloud connection at send time. Never put the
|
|
2329
2365
|
service-account private key in the notification file. Expo does not use a GCP cloud connection.
|
|
2366
|
+
The recommended cloud connection scope is "notifications". It expresses Ductape capability/UI
|
|
2367
|
+
intent; creating a notification does not prove Google-side FCM permission. Runtime delivery
|
|
2368
|
+
requires fcm.googleapis.com and roles/firebasecloudmessaging.admin, so validate the connection
|
|
2369
|
+
and perform a delivery test.
|
|
2330
2370
|
Notification tag and message tag are ALWAYS passed together as "notification_tag:message_tag".
|
|
2331
2371
|
`.trim(),
|
|
2332
2372
|
|
|
@@ -3861,8 +3901,10 @@ async function main() {
|
|
|
3861
3901
|
const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
|
|
3862
3902
|
|
|
3863
3903
|
if (!isAuthCommand) {
|
|
3864
|
-
//
|
|
3865
|
-
|
|
3904
|
+
// Cache successful authentication, but re-check a missing/expired session on every call.
|
|
3905
|
+
// The user may complete `ductape login` in another terminal while this MCP process remains
|
|
3906
|
+
// alive; caching "none" would otherwise make the MCP blind to the newly written session.
|
|
3907
|
+
if (authState === 'unknown' || authState === 'none') {
|
|
3866
3908
|
checkLoginState();
|
|
3867
3909
|
}
|
|
3868
3910
|
if (authState === 'none') {
|
|
@@ -4223,7 +4265,10 @@ async function main() {
|
|
|
4223
4265
|
' Message brokers are import-only (no provision-persist). Import flow is the same as storage.\n' +
|
|
4224
4266
|
' type field = "messageBrokers" (not "messagebrokers" or "events").\n' +
|
|
4225
4267
|
' After importing, create topics first with ductape_cli("events topics create -f topic.json") — SQS requires explicit topic creation with queueUrls. For other providers, topics auto-register on first produce but should still be created explicitly before any consumer subscribes.\n' +
|
|
4226
|
-
' - Listing workspaces, products, secrets\n' +
|
|
4268
|
+
' - Listing workspaces, products, focused product components, secrets\n' +
|
|
4269
|
+
' Prefer "products components list --tag <tag> --json" for compact inventory; use\n' +
|
|
4270
|
+
' "products components get --tag <tag> --type notifications|events --json" for focused detail.\n' +
|
|
4271
|
+
' - Managing notification components and message templates through "resources notifications" and "notifications messages"\n' +
|
|
4227
4272
|
' - Linking a project folder: "link --product <tag> --env <slug>"\n' +
|
|
4228
4273
|
' - Syncing sessions/notifications/events: "apply" or "apply sessions" etc.\n' +
|
|
4229
4274
|
' - Running database migrations: "db migrate", "db schema generate"\n\n' +
|