@ductape/mcp 0.1.58 → 0.1.59

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
@@ -123,8 +123,9 @@ There are THREE categories of operations. Use the right tool for each:
123
123
  ductape_cli("resources storage list")
124
124
  ductape_cli("resources database create -f db-config.json")
125
125
  This applies to: products, apps, and resources (databases, storage, caches, etc.),
126
- cloud connections, and secrets. Environments, app actions, auths, features, quotas,
127
- fallbacks, jobs, and healthchecks are configured in the Workbench UI.
126
+ cloud connections, and secrets. Environments, app actions, auths, quotas, fallbacks,
127
+ jobs, and healthchecks are configured in the Workbench UI. Features have no CLI create
128
+ command because their definitions are code-first through features.define.
128
129
 
129
130
  ⚠ MULTI-ENV REQUIREMENT — applies to ALL product assets (storage, database, cache,
130
131
  messageBroker, graph, vector, and any other resource with an envs array):
@@ -786,7 +787,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
786
787
  // ctx.graph.execute({ graph, action, input })
787
788
  // ctx.notification.send/email/push/sms({ notification, event, ... })
788
789
  // ctx.storage.upload/download({ storage, event, input })
789
- // ctx.messaging.produce({ event: "broker:topic", message: {} })
790
+ // ctx.events.produce({ event: "broker:topic", message: {} })
790
791
  // ctx.quota.execute({ quota, input })
791
792
  // ctx.fallback.execute({ fallback, input })
792
793
  // ctx.healthcheck.getStatus(tag)
@@ -1231,7 +1232,9 @@ function runCli(command) {
1231
1232
  try {
1232
1233
  const output = execSync(`ductape ${finalCommand}`, {
1233
1234
  encoding: 'utf8',
1234
- timeout: 30000,
1235
+ // Must exceed the proxy's operation timeout so stderr can preserve the structured timeout
1236
+ // instead of this wrapper killing the CLI first and reducing it to "(no data)".
1237
+ timeout: 90000,
1235
1238
  stdio: ['pipe', 'pipe', 'pipe'],
1236
1239
  });
1237
1240
  return { success: true, output: output.trim() };
@@ -2650,9 +2653,11 @@ STEP 4 — PRESENT the plan and get approval BEFORE writing any code or creating
2650
2653
  STEP 5 — CREATE missing components (only with user approval)
2651
2654
  Administrative assets must never be created through ductape_execute. Use ductape_cli for products,
2652
2655
  apps, supported resources, broker topics, cloud connections, secrets, and declarative apply flows.
2653
- App actions, auths, Features, quotas, fallbacks, health checks, and other assets for which the CLI
2654
- has no command must be configured in Workbench. Do not generate an impossible publishable-key
2655
- create/update call. For a missing database action, configure it in Workbench, then verify it exists.
2656
+ App actions, auths, quotas, fallbacks, health checks, and other administrative assets for which
2657
+ the CLI has no command must be configured in Workbench. Feature definitions are the exception:
2658
+ they are code-first via features.define, are registered by application boot/runtime initialization,
2659
+ and cannot be created with the CLI. Do not generate a Workbench-only or publishable-key
2660
+ create/update call for a Feature. For a missing database action, configure it in Workbench, then verify it exists.
2656
2661
  For a missing child feature, recursively apply this same workflow.
2657
2662
  Tell the user what you are about to create before each tool call.
2658
2663
 
@@ -2761,7 +2766,9 @@ When you call features.define({ handler }), the handler runs TWICE:
2761
2766
  Features do NOT execute arbitrary NestJS or server code directly. A feature handler can only
2762
2767
  call Ductape component primitives (ctx.api, ctx.database, ctx.notification, etc.) as steps.
2763
2768
  To invoke internal application business logic, produce a broker event from a feature step
2764
- (ctx.messaging.produce) and consume it in your NestJS service — that is the correct pattern.
2769
+ (ctx.events.produce in the currently published SDK) and consume it in your NestJS service.
2770
+ ctx.publish is deprecated; do not use it. Do not assume a ctx.messaging alias exists unless the
2771
+ installed SDK types explicitly expose it.
2765
2772
 
2766
2773
  ━━━ ORCHESTRATION DECISION RULE ━━━
2767
2774
 
@@ -2775,7 +2782,7 @@ When you call features.define({ handler }), the handler runs TWICE:
2775
2782
  → define a Feature, then features.dispatch to schedule it
2776
2783
 
2777
2784
  Invoke internal application business logic (your own NestJS/backend service code):
2778
- → produce a broker event (ctx.messaging.produce or ductape.events.produce)
2785
+ → produce a broker event (ctx.events.produce inside a Feature, or ductape.events.produce outside it)
2779
2786
  → follow ductape_docs({ topic: "events" }) and use the canonical NestJS decorator:
2780
2787
  @Events.Consumer({ event: "broker-tag:topic-tag" })
2781
2788
  async handle(message: MessageShape) { /* injected-service business logic; throw to nack */ }
@@ -3710,8 +3717,9 @@ const cliInputSchema = z.object({
3710
3717
  'Use this tool for administrative operations: creating or updating products, apps, ' +
3711
3718
  'resources (databases, storage, caches…), event broker topics, cloud connections, secrets, ' +
3712
3719
  'and for apply/migrate workflows.\n\n' +
3713
- 'Note: environments, app actions, features, quotas, fallbacks, and jobs are configured ' +
3714
- 'in the Workbench UI there are no CLI commands for them.\n\n' +
3720
+ 'Note: environments, app actions, quotas, fallbacks, and jobs are configured in the ' +
3721
+ 'Workbench UI. Features also have no CLI creation command: define them in application code ' +
3722
+ 'with features.define so application boot/runtime registration makes them available.\n\n' +
3715
3723
  'The CLI uses the user\'s local logged-in session (ductape login) — no key is required.'),
3716
3724
  });
3717
3725
  async function loadMcpSdk() {
@@ -4111,8 +4119,9 @@ async function main() {
4111
4119
  ' - Linking a project folder: "link --product <tag> --env <slug>"\n' +
4112
4120
  ' - Syncing sessions/notifications/events: "apply" or "apply sessions" etc.\n' +
4113
4121
  ' - Running database migrations: "db migrate", "db schema generate"\n\n' +
4114
- 'NOTE: Environments, app actions, auths, features, quotas, fallbacks, and jobs are ' +
4115
- 'configured in the Workbench UI the CLI does not have commands for them.\n\n' +
4122
+ 'NOTE: Environments, app actions, auths, quotas, fallbacks, and jobs are configured ' +
4123
+ 'in the Workbench UI. Features have no CLI creation command because definitions are ' +
4124
+ 'code-first through features.define and registered by the application runtime.\n\n' +
4116
4125
  'DO NOT use ductape_execute for admin operations — it uses a publishable key which only ' +
4117
4126
  'covers runtime operations. Administrative operations will fail with "Authentication failed".\n\n' +
4118
4127
  'The CLI uses the user\'s local logged-in session (ductape login). ' +
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-client.d.ts","sourceRoot":"","sources":["../src/proxy-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,YAAY,4BAA4B,CAAC;AAEtD,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,KAAK,GACL,WAAW,GACX,OAAO,GACP,UAAU,GACV,eAAe,GACf,gBAAgB,GAChB,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,SAAS,GACT,UAAU,GACV,MAAM,GACN,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,SAAS,CAAC;AAUd;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/C,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED,MAAM,WAAW,iCAAiC;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,kCAAkC;IACjD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AASD,wBAAsB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AA4BD,wBAAsB,yBAAyB,CAAC,CAAC,GAAG,kCAAkC,EACpF,OAAO,EAAE,iCAAiC,GACzC,OAAO,CAAC,CAAC,CAAC,CAwBZ"}
1
+ {"version":3,"file":"proxy-client.d.ts","sourceRoot":"","sources":["../src/proxy-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,YAAY,4BAA4B,CAAC;AAEtD,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,KAAK,GACL,WAAW,GACX,OAAO,GACP,UAAU,GACV,eAAe,GACf,gBAAgB,GAChB,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,SAAS,GACT,UAAU,GACV,MAAM,GACN,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,SAAS,CAAC;AAUd;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,GAAG,OAAO,EAC/C,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED,MAAM,WAAW,iCAAiC;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,kCAAkC;IACjD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AASD,wBAAsB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYvE;AA4BD,wBAAsB,yBAAyB,CAAC,CAAC,GAAG,kCAAkC,EACpF,OAAO,EAAE,iCAAiC,GACzC,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
@@ -67,9 +67,15 @@ function normalizeTargets(targets) {
67
67
  return result;
68
68
  }
69
69
  export async function generateExecutablePayload(request) {
70
+ // execution_context is MCP guidance metadata, not part of the integrations
71
+ // payload-generator API contract. Keep it for local session-awareness output
72
+ // but never forward it to the backend validator.
73
+ const { execution_context: _executionContext, ...backendRequest } = request;
70
74
  const normalizedRequest = {
71
- ...request,
72
- targets: request.targets ? normalizeTargets(request.targets) : request.targets,
75
+ ...backendRequest,
76
+ targets: backendRequest.targets
77
+ ? normalizeTargets(backendRequest.targets)
78
+ : backendRequest.targets,
73
79
  };
74
80
  const url = `${API_BASE_URL.replace(/\/$/, '')}/integrations/v1/payloads/generate`;
75
81
  const res = await fetch(url, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.1.58",
3
+ "version": "0.1.59",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,6 +56,8 @@ const safetyChecks = [
56
56
  ['notification declarations require array shape', /file MUST be a top-level JSON array/],
57
57
  ['external CLI login is re-read', /authState === 'unknown' \|\| authState === 'none'/],
58
58
  ['compact product inventory documented', /products components list --tag <tag> --json/],
59
+ ['features use installed events context', /ctx\.events\.produce inside a Feature/],
60
+ ['features are code-first rather than Workbench-created', /Features have no CLI (?:create|creation)\s+command because (?:their )?definitions are code-first/],
59
61
  ['Firebase GCP cloud connection documented', /FIREBASE THROUGH A GCP CLOUD CONNECTION[\s\S]*authMode.*cloud_connection/],
60
62
  ['Slack and Discord sends documented', /notifications\.slack\.send[\s\S]*notifications\.discord\.send/],
61
63
  ];
@@ -77,4 +79,10 @@ assert.doesNotMatch(
77
79
  'Browser Events guidance must not import the server SDK',
78
80
  );
79
81
 
82
+ assert.doesNotMatch(
83
+ source,
84
+ /ctx\.messaging\.produce/,
85
+ 'Feature guidance must use the installed ctx.events API, not a nonexistent ctx.messaging alias',
86
+ );
87
+
80
88
  console.log(`MCP guidance: ${checks.length + 1 + safetyChecks.length} acceptance checks passed`);
package/src/index.ts CHANGED
@@ -134,8 +134,9 @@ There are THREE categories of operations. Use the right tool for each:
134
134
  ductape_cli("resources storage list")
135
135
  ductape_cli("resources database create -f db-config.json")
136
136
  This applies to: products, apps, and resources (databases, storage, caches, etc.),
137
- cloud connections, and secrets. Environments, app actions, auths, features, quotas,
138
- fallbacks, jobs, and healthchecks are configured in the Workbench UI.
137
+ cloud connections, and secrets. Environments, app actions, auths, quotas, fallbacks,
138
+ jobs, and healthchecks are configured in the Workbench UI. Features have no CLI create
139
+ command because their definitions are code-first through features.define.
139
140
 
140
141
  ⚠ MULTI-ENV REQUIREMENT — applies to ALL product assets (storage, database, cache,
141
142
  messageBroker, graph, vector, and any other resource with an envs array):
@@ -797,7 +798,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
797
798
  // ctx.graph.execute({ graph, action, input })
798
799
  // ctx.notification.send/email/push/sms({ notification, event, ... })
799
800
  // ctx.storage.upload/download({ storage, event, input })
800
- // ctx.messaging.produce({ event: "broker:topic", message: {} })
801
+ // ctx.events.produce({ event: "broker:topic", message: {} })
801
802
  // ctx.quota.execute({ quota, input })
802
803
  // ctx.fallback.execute({ fallback, input })
803
804
  // ctx.healthcheck.getStatus(tag)
@@ -1292,7 +1293,9 @@ function runCli(command: string): { success: boolean; output: string } {
1292
1293
  try {
1293
1294
  const output = execSync(`ductape ${finalCommand}`, {
1294
1295
  encoding: 'utf8',
1295
- timeout: 30000,
1296
+ // Must exceed the proxy's operation timeout so stderr can preserve the structured timeout
1297
+ // instead of this wrapper killing the CLI first and reducing it to "(no data)".
1298
+ timeout: 90000,
1296
1299
  stdio: ['pipe', 'pipe', 'pipe'],
1297
1300
  });
1298
1301
  return { success: true, output: output.trim() };
@@ -2736,9 +2739,11 @@ STEP 4 — PRESENT the plan and get approval BEFORE writing any code or creating
2736
2739
  STEP 5 — CREATE missing components (only with user approval)
2737
2740
  Administrative assets must never be created through ductape_execute. Use ductape_cli for products,
2738
2741
  apps, supported resources, broker topics, cloud connections, secrets, and declarative apply flows.
2739
- App actions, auths, Features, quotas, fallbacks, health checks, and other assets for which the CLI
2740
- has no command must be configured in Workbench. Do not generate an impossible publishable-key
2741
- create/update call. For a missing database action, configure it in Workbench, then verify it exists.
2742
+ App actions, auths, quotas, fallbacks, health checks, and other administrative assets for which
2743
+ the CLI has no command must be configured in Workbench. Feature definitions are the exception:
2744
+ they are code-first via features.define, are registered by application boot/runtime initialization,
2745
+ and cannot be created with the CLI. Do not generate a Workbench-only or publishable-key
2746
+ create/update call for a Feature. For a missing database action, configure it in Workbench, then verify it exists.
2742
2747
  For a missing child feature, recursively apply this same workflow.
2743
2748
  Tell the user what you are about to create before each tool call.
2744
2749
 
@@ -2847,7 +2852,9 @@ When you call features.define({ handler }), the handler runs TWICE:
2847
2852
  Features do NOT execute arbitrary NestJS or server code directly. A feature handler can only
2848
2853
  call Ductape component primitives (ctx.api, ctx.database, ctx.notification, etc.) as steps.
2849
2854
  To invoke internal application business logic, produce a broker event from a feature step
2850
- (ctx.messaging.produce) and consume it in your NestJS service — that is the correct pattern.
2855
+ (ctx.events.produce in the currently published SDK) and consume it in your NestJS service.
2856
+ ctx.publish is deprecated; do not use it. Do not assume a ctx.messaging alias exists unless the
2857
+ installed SDK types explicitly expose it.
2851
2858
 
2852
2859
  ━━━ ORCHESTRATION DECISION RULE ━━━
2853
2860
 
@@ -2861,7 +2868,7 @@ When you call features.define({ handler }), the handler runs TWICE:
2861
2868
  → define a Feature, then features.dispatch to schedule it
2862
2869
 
2863
2870
  Invoke internal application business logic (your own NestJS/backend service code):
2864
- → produce a broker event (ctx.messaging.produce or ductape.events.produce)
2871
+ → produce a broker event (ctx.events.produce inside a Feature, or ductape.events.produce outside it)
2865
2872
  → follow ductape_docs({ topic: "events" }) and use the canonical NestJS decorator:
2866
2873
  @Events.Consumer({ event: "broker-tag:topic-tag" })
2867
2874
  async handle(message: MessageShape) { /* injected-service business logic; throw to nack */ }
@@ -3804,8 +3811,9 @@ const cliInputSchema = z.object({
3804
3811
  'Use this tool for administrative operations: creating or updating products, apps, ' +
3805
3812
  'resources (databases, storage, caches…), event broker topics, cloud connections, secrets, ' +
3806
3813
  'and for apply/migrate workflows.\n\n' +
3807
- 'Note: environments, app actions, features, quotas, fallbacks, and jobs are configured ' +
3808
- 'in the Workbench UI there are no CLI commands for them.\n\n' +
3814
+ 'Note: environments, app actions, quotas, fallbacks, and jobs are configured in the ' +
3815
+ 'Workbench UI. Features also have no CLI creation command: define them in application code ' +
3816
+ 'with features.define so application boot/runtime registration makes them available.\n\n' +
3809
3817
  'The CLI uses the user\'s local logged-in session (ductape login) — no key is required.',
3810
3818
  ),
3811
3819
  });
@@ -4272,8 +4280,9 @@ async function main() {
4272
4280
  ' - Linking a project folder: "link --product <tag> --env <slug>"\n' +
4273
4281
  ' - Syncing sessions/notifications/events: "apply" or "apply sessions" etc.\n' +
4274
4282
  ' - Running database migrations: "db migrate", "db schema generate"\n\n' +
4275
- 'NOTE: Environments, app actions, auths, features, quotas, fallbacks, and jobs are ' +
4276
- 'configured in the Workbench UI the CLI does not have commands for them.\n\n' +
4283
+ 'NOTE: Environments, app actions, auths, quotas, fallbacks, and jobs are configured ' +
4284
+ 'in the Workbench UI. Features have no CLI creation command because definitions are ' +
4285
+ 'code-first through features.define and registered by the application runtime.\n\n' +
4277
4286
  'DO NOT use ductape_execute for admin operations — it uses a publishable key which only ' +
4278
4287
  'covers runtime operations. Administrative operations will fail with "Authentication failed".\n\n' +
4279
4288
  'The CLI uses the user\'s local logged-in session (ductape login). ' +
@@ -137,9 +137,15 @@ function normalizeTargets(targets: Record<string, unknown>): Record<string, unkn
137
137
  export async function generateExecutablePayload<T = IGenerateExecutablePayloadResponse>(
138
138
  request: IGenerateExecutablePayloadRequest,
139
139
  ): Promise<T> {
140
+ // execution_context is MCP guidance metadata, not part of the integrations
141
+ // payload-generator API contract. Keep it for local session-awareness output
142
+ // but never forward it to the backend validator.
143
+ const { execution_context: _executionContext, ...backendRequest } = request;
140
144
  const normalizedRequest = {
141
- ...request,
142
- targets: request.targets ? normalizeTargets(request.targets as Record<string, unknown>) : request.targets,
145
+ ...backendRequest,
146
+ targets: backendRequest.targets
147
+ ? normalizeTargets(backendRequest.targets as Record<string, unknown>)
148
+ : backendRequest.targets,
143
149
  };
144
150
  const url = `${API_BASE_URL.replace(/\/$/, '')}/integrations/v1/payloads/generate`;
145
151
  const res = await fetch(url, {