@dypai-ai/mcp 1.5.23 → 1.5.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dypai-ai/mcp",
3
- "version": "1.5.23",
3
+ "version": "1.5.24",
4
4
  "description": "DYPAI MCP Server — AI agent toolkit for building and deploying full-stack apps",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -1078,10 +1078,11 @@ Mental translations: "edge function" → workflow with one code node; "cron" →
1078
1078
  3. **Treating \`dypai_push\` as a deploy** — it's "save as draft", not publish. Live traffic is untouched until \`manage_drafts(publish, confirm:true)\`. Push freely, only ask the user before publish.
1079
1079
  4. **\`public\` auth_mode with \`\${current_user_id}\`** — no JWT → placeholder empty → SQL fails or returns wrong data. Use \`jwt\` if you need the user.
1080
1080
  5. **Missing \`return: true\`** — endpoint returns \`null\`. Every path that should produce an HTTP response needs one node with \`return: true\`.
1081
- 6. **SQL return + \`output.type: object\` without \`response_cardinality\` or \`set_fields\`** — runtime body is \`[{...}]\` but the frontend expects \`{...}\`. Add top-level \`response_cardinality: single\` for direct SQL returns, or compose the public object with \`set_fields\`. \`dypai_validate\` errors with \`response_cardinality_required\`. Do not unwrap arrays in frontend code.
1082
- 7. **\`tool_ids\` in YAML instead of \`tools\`** write \`tools: [name1, name2]\`. \`tool_ids\` bypasses the codec and fails silently in prod.
1083
- 8. **Putting workflow placeholders inside \`javascript_code.code\`** — code is raw JavaScript, so JS template literals like \`\${where.join(" AND ")}\` are safe and not rendered by DYPAI. Pass workflow values via \`input_data\`, \`ctx.nodes\`, \`ctx.user\`, or \`ctx.env\`; do not write \`\${input.email}\` inside code or set \`code\` from another node output.
1084
- 9. **Human endpoint names** \`name: Listar videos\` in \`list-videos.yaml\` creates a draft the frontend cannot call as \`list-videos\`. \`dypai_validate\` and \`dypai_push\` reject this; fix the slug instead of testing around it.
1081
+ 6. **SQL return + \`output.type: object\` without \`response_cardinality\` or \`set_fields\`** — runtime body is \`[{...}]\` but the frontend expects \`{...}\`. Add top-level \`response_cardinality: single\` for direct SQL returns, or compose the public object with \`set_fields operation: compose\`. \`dypai_validate\` errors with \`response_cardinality_required\`. Do not unwrap arrays in frontend code.
1082
+ 7. **\`set_fields\` without \`operation\`** runtime throws \`Unknown Set Fields operation: undefined\`. Wrapper responses need \`operation: compose\`; adding fields to upstream data uses \`operation: set\`. \`dypai_validate\` / \`backend_validate\` error with \`set_fields_operation_missing\`.
1083
+ 8. **\`tool_ids\` in YAML instead of \`tools\`** — write \`tools: [name1, name2]\`. \`tool_ids\` bypasses the codec and fails silently in prod.
1084
+ 9. **Putting workflow placeholders inside \`javascript_code.code\`** code is raw JavaScript, so JS template literals like \`\${where.join(" AND ")}\` are safe and not rendered by DYPAI. Pass workflow values via \`input_data\`, \`ctx.nodes\`, \`ctx.user\`, or \`ctx.env\`; do not write \`\${input.email}\` inside code or set \`code\` from another node output.
1085
+ 10. **Human endpoint names** — \`name: Listar videos\` in \`list-videos.yaml\` creates a draft the frontend cannot call as \`list-videos\`. \`dypai_validate\` and \`dypai_push\` reject this; fix the slug instead of testing around it.
1085
1086
 
1086
1087
  → Longer list of common pitfalls + fixes: \`search_docs("troubleshooting")\`.
1087
1088
 
@@ -1102,7 +1103,7 @@ Mental translations: "edge function" → workflow with one code node; "cron" →
1102
1103
 
1103
1104
  SDK is pre-configured at \`src/lib/dypai.ts\` (or \`src/dypai.ts\`). Import \`dypai\` from there. Every method returns \`{ data, error }\` — never throws.
1104
1105
 
1105
- - **API**: \`dypai.api.get(name)\`, \`.post(name, body)\`, \`.put()\`, \`.delete()\`, \`.upload(name, file)\`, \`.stream(name, body)\`. \`response.data\` matches the endpoint \`output\` schema — if SQL returns row arrays, declare \`response_cardinality: single\` or use \`set_fields\`; never unwrap in the UI.
1106
+ - **API**: \`dypai.api.get(name)\`, \`.post(name, body)\`, \`.put()\`, \`.delete()\`, \`.upload(name, file)\`, \`.stream(name, body)\`. \`response.data\` matches the endpoint \`output\` schema — if SQL returns row arrays, declare \`response_cardinality: single\` or use \`set_fields operation: compose\`; never unwrap in the UI.
1106
1107
  - **Auth**: \`dypai.auth.signInWithPassword()\`, \`.signUp()\`, \`.signOut()\`, \`.getSession()\`. **Never** create login/signup workflows — auth is built-in.
1107
1108
  - **Hooks**: \`useAuth\`, \`useEndpoint\`, \`useAction\`, \`useUpload\`, \`useRealtime\`, \`<ProtectedRoute>\`.
1108
1109
  - **Rule**: NEVER \`fetch()\` directly — always through the SDK.
@@ -1143,7 +1144,7 @@ async function handleRequest(msg) {
1143
1144
  return makeResponse(id, {
1144
1145
  protocolVersion: "2024-11-05",
1145
1146
  capabilities: { tools: {} },
1146
- serverInfo: { name: "dypai", version: "1.5.23" },
1147
+ serverInfo: { name: "dypai", version: "1.5.24" },
1147
1148
  instructions: SERVER_INSTRUCTIONS,
1148
1149
  })
1149
1150
  }
@@ -287,6 +287,7 @@ workflow:
287
287
  # \`return: true\` — it marks that node's output as the HTTP body.
288
288
  - id: build_response
289
289
  type: set_fields
290
+ operation: compose
290
291
  return: true
291
292
  fields:
292
293
  order_id: \${nodes.insert_order.id}
@@ -297,6 +298,7 @@ workflow:
297
298
  # Multiple return nodes are fine as long as only one runs per execution.
298
299
  - id: out_of_stock
299
300
  type: set_fields
301
+ operation: compose
300
302
  return: true
301
303
  fields:
302
304
  error: out_of_stock
@@ -30,6 +30,7 @@ import {
30
30
  * Outside the window, sql_table_not_found triggers a remote verification. */
31
31
  const SCHEMA_FRESHNESS_MS = 5 * 60 * 1000 // 5 minutes
32
32
  const VALID_RESPONSE_CARDINALITIES = new Set(["single", "many", "zero_or_one"])
33
+ const VALID_SET_FIELDS_OPERATIONS = new Set(["set", "compose", "rename", "remove", "keep", "merge"])
33
34
  const DATABASE_ROW_ARRAY_OPS = new Set([
34
35
  "query",
35
36
  "custom_query",
@@ -804,7 +805,8 @@ function buildNodeOutputContracts(nodes, fileMap, ctx) {
804
805
  const params = nodeParams(node)
805
806
 
806
807
  if (nodeType === "set_fields") {
807
- const op = nodeField(node, params, "operation") || "set"
808
+ const op = nodeField(node, params, "operation")
809
+ if (!op) continue
808
810
  const fields = nodeField(node, params, "fields")
809
811
  if (fields && typeof fields === "object" && !Array.isArray(fields)) {
810
812
  contracts.set(node.id, {
@@ -1437,6 +1439,28 @@ function validateEndpoint(entry, ctx) {
1437
1439
  }
1438
1440
  }
1439
1441
  }
1442
+
1443
+ if (nodeType === "set_fields") {
1444
+ const params = nodeParams(node)
1445
+ const op = nodeField(node, params, "operation")
1446
+ if (!op) {
1447
+ diagnostics.push({
1448
+ severity: "error",
1449
+ rule: "set_fields_operation_missing",
1450
+ endpoint: name, file, loc: `workflow.nodes[${node.id || "?"}]`,
1451
+ message: `set_fields node '${node.id || "(no id)"}' is missing operation.`,
1452
+ fix_hint: "Add operation: compose when building a fresh response object, or operation: set when adding fields to upstream input.",
1453
+ })
1454
+ } else if (!VALID_SET_FIELDS_OPERATIONS.has(op)) {
1455
+ diagnostics.push({
1456
+ severity: "error",
1457
+ rule: "set_fields_operation_invalid",
1458
+ endpoint: name, file, loc: `workflow.nodes[${node.id || "?"}].operation`,
1459
+ message: `set_fields node '${node.id || "(no id)"}' has unsupported operation '${op}'.`,
1460
+ fix_hint: `Use one of: ${[...VALID_SET_FIELDS_OPERATIONS].join(", ")}.`,
1461
+ })
1462
+ }
1463
+ }
1440
1464
  if (node.tool_ids !== undefined && node.tools === undefined) {
1441
1465
  const toolIds = Array.isArray(node.tool_ids) ? node.tool_ids : []
1442
1466
  const legacyUuidToolIds = toolIds.length === 0 || toolIds.every(isUuidString)