@dypai-ai/mcp 1.4.0 → 1.4.1

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.4.0",
3
+ "version": "1.4.1",
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",
@@ -74,14 +74,17 @@ export const NODE_FIELD_TRANSFORMS = [
74
74
  name: "sql_extraction",
75
75
  appliesWhen: (nodeType) => nodeType === "dypai_database",
76
76
  pull(params, ctx) {
77
- if (params.query && !shouldInlineSql(params.query)) {
78
- // Flat layout: sql/<endpoint>.sql if only one SQL node, else sql/<endpoint>.<node>.sql
79
- const suffix = ctx.sqlNodeCount > 1 ? `.${ctx.nodeId}` : ""
80
- const path = `sql/${ctx.endpointName}${suffix}.sql`
81
- ctx.emitFile(path, params.query.trim() + "\n")
82
- return { query_file: path }
77
+ if (!params.query) return {}
78
+ if (shouldInlineSql(params.query)) {
79
+ // Short SQL stays inline. Must be re-emitted here because
80
+ // `pullConsumes: ["query"]` deletes it from the base object.
81
+ return { query: params.query }
83
82
  }
84
- return {}
83
+ // Flat layout: sql/<endpoint>.sql if only one SQL node, else sql/<endpoint>.<node>.sql
84
+ const suffix = ctx.sqlNodeCount > 1 ? `.${ctx.nodeId}` : ""
85
+ const path = `sql/${ctx.endpointName}${suffix}.sql`
86
+ ctx.emitFile(path, params.query.trim() + "\n")
87
+ return { query_file: path }
85
88
  },
86
89
  push(params, ctx) {
87
90
  if (params.query_file) {
@@ -97,13 +100,16 @@ export const NODE_FIELD_TRANSFORMS = [
97
100
  name: "prompt_extraction",
98
101
  appliesWhen: (nodeType) => nodeType === "agent",
99
102
  pull(params, ctx) {
100
- if (params.system_prompt && params.system_prompt.length > PROMPT_INLINE_MAX_CHARS) {
101
- const suffix = ctx.promptNodeCount > 1 ? `.${ctx.nodeId}` : ""
102
- const path = `prompts/${ctx.endpointName}${suffix}.md`
103
- ctx.emitFile(path, params.system_prompt.trim() + "\n")
104
- return { system_prompt_file: path }
103
+ if (!params.system_prompt) return {}
104
+ if (params.system_prompt.length <= PROMPT_INLINE_MAX_CHARS) {
105
+ // Short prompt stays inline. Must be re-emitted here because
106
+ // `pullConsumes: ["system_prompt"]` deletes it from the base object.
107
+ return { system_prompt: params.system_prompt }
105
108
  }
106
- return {}
109
+ const suffix = ctx.promptNodeCount > 1 ? `.${ctx.nodeId}` : ""
110
+ const path = `prompts/${ctx.endpointName}${suffix}.md`
111
+ ctx.emitFile(path, params.system_prompt.trim() + "\n")
112
+ return { system_prompt_file: path }
107
113
  },
108
114
  push(params, ctx) {
109
115
  if (params.system_prompt_file) {
@@ -119,14 +125,20 @@ export const NODE_FIELD_TRANSFORMS = [
119
125
  name: "code_extraction",
120
126
  appliesWhen: (nodeType) => nodeType === "javascript_code" || nodeType === "python_code",
121
127
  pull(params, ctx) {
122
- if (params.code && params.code.length > SQL_INLINE_MAX_CHARS) {
123
- const ext = ctx.nodeType === "python_code" ? "py" : "js"
124
- const suffix = ctx.codeNodeCount > 1 ? `.${ctx.nodeId}` : ""
125
- const path = `code/${ctx.endpointName}${suffix}.${ext}`
126
- ctx.emitFile(path, params.code.trim() + "\n")
127
- return { code_file: path }
128
+ if (!params.code) return {}
129
+ if (params.code.length <= SQL_INLINE_MAX_CHARS) {
130
+ // Short code stays inline. Must be re-emitted here because
131
+ // `pullConsumes: ["code"]` deletes it from the base object.
132
+ // Before this fix, short code was silently dropped from the YAML
133
+ // (neither extracted to a file nor kept inline) — endpoints pulled
134
+ // from the engine ended up with just `timeout_ms` and no handler.
135
+ return { code: params.code }
128
136
  }
129
- return {}
137
+ const ext = ctx.nodeType === "python_code" ? "py" : "js"
138
+ const suffix = ctx.codeNodeCount > 1 ? `.${ctx.nodeId}` : ""
139
+ const path = `code/${ctx.endpointName}${suffix}.${ext}`
140
+ ctx.emitFile(path, params.code.trim() + "\n")
141
+ return { code_file: path }
130
142
  },
131
143
  push(params, ctx) {
132
144
  if (params.code_file) {
@@ -580,7 +580,12 @@ function validateEndpoint(entry, ctx) {
580
580
  // Enum / range checks for primitive values
581
581
  const prop = properties[key]
582
582
  const v = node[key]
583
- if (prop.enum && typeof v === "string" && !prop.enum.includes(v)) {
583
+ // Skip enum validation if the value contains a ${...} placeholder —
584
+ // the actual value is resolved at runtime, so the engine enforces
585
+ // the enum then. Common case: operation: ${input.operation} in
586
+ // dypai_storage / dypai_database nodes.
587
+ const hasPlaceholder = typeof v === "string" && v.includes("${")
588
+ if (prop.enum && typeof v === "string" && !hasPlaceholder && !prop.enum.includes(v)) {
584
589
  diagnostics.push({
585
590
  severity: "error",
586
591
  rule: "param_enum_violation",