@dypai-ai/mcp 1.7.1 → 1.7.2

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.7.1",
3
+ "version": "1.7.2",
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",
@@ -483,7 +483,8 @@ export const dypaiPushTool = {
483
483
  "After validation, regenerates `dypai/types/endpoints.gen.ts` from effective Flow/YAML contracts (check the `types` field in the response). " +
484
484
  "ALWAYS run dypai_diff first to preview what will be staged. " +
485
485
  "The public dypai_push wrapper also saves frontend source to Studio. " +
486
- "By default, endpoints in remote but missing locally are kept (safe). Pass delete_orphans: true to stage their deletion as a draft as well.",
486
+ "By default, endpoints in remote but missing locally are kept (safe). Pass delete_orphans: true to stage their deletion as a draft as well. " +
487
+ "PARTIAL PUSH: an endpoint whose flow has errors is SKIPPED (it keeps its live version) and the rest are pushed — one broken endpoint no longer blocks the whole push. Skipped ones are listed in `skipped_endpoints` (with their errors) and `partial_success` is set. A project-level error still blocks. Use skip_validation:true to push everything, errors included.",
487
488
  inputSchema: {
488
489
  type: "object",
489
490
  properties: {
@@ -513,7 +514,7 @@ export const dypaiPushTool = {
513
514
  },
514
515
  skip_validation: {
515
516
  type: "boolean",
516
- description: "Skip the dypai_validate pre-flight check. Use only when you know the validator is wrong. Default: false.",
517
+ description: "Skip the dypai_validate pre-flight check and push EVERY endpoint, including ones with errors (no per-endpoint skipping). By default the push already applies the valid endpoints and only skips the erroring ones — so use this only when you know the validator is wrong. Default: false.",
517
518
  default: false,
518
519
  },
519
520
  },
@@ -529,19 +530,31 @@ export const dypaiPushTool = {
529
530
  const configProjectId = config?.project_id || null
530
531
  const targetProjectId = project_id || configProjectId
531
532
 
532
- // Pre-flight validation (lint). Blocks the push unless skip_validation is set.
533
+ // Pre-flight validation (lint). Partial push: endpoints whose flow has an
534
+ // error are SKIPPED (they keep their live version) and the rest is pushed —
535
+ // one broken endpoint no longer tanks the whole push. A project-level error
536
+ // (no endpoint to isolate it to) still blocks, since it can't be scoped out.
537
+ // skip_validation bypasses all of this and pushes everything.
538
+ let erroringEndpoints = new Set()
539
+ let skippedDiagnostics = []
533
540
  if (!skip_validation && !dry_run) {
534
541
  try {
535
542
  const validation = await runValidation(rootDir, project_id || configProjectId)
536
543
  if (!validation.success) {
537
- return {
538
- success: false,
539
- applied: false,
540
- reason: "validation_failed",
541
- summary: validation.summary,
542
- diagnostics: validation.diagnostics.filter(d => d.severity === "error").slice(0, 20),
543
- hint: `${validation.summary.errors} error(s) would cause runtime failures. Fix them, or retry with skip_validation: true to override.`,
544
+ const errorDiags = (validation.diagnostics || []).filter(d => d.severity === "error")
545
+ const projectLevel = errorDiags.filter(d => !d.endpoint)
546
+ if (projectLevel.length) {
547
+ return {
548
+ success: false,
549
+ applied: false,
550
+ reason: "validation_failed",
551
+ summary: validation.summary,
552
+ diagnostics: projectLevel.slice(0, 20),
553
+ hint: `${projectLevel.length} project-level error(s) can't be isolated to a single endpoint. Fix them, or retry with skip_validation: true to override.`,
554
+ }
544
555
  }
556
+ skippedDiagnostics = errorDiags
557
+ erroringEndpoints = new Set(errorDiags.map(d => d.endpoint).filter(Boolean))
545
558
  }
546
559
  } catch (e) {
547
560
  // Don't block the push on a validator crash — just warn
@@ -640,6 +653,30 @@ export const dypaiPushTool = {
640
653
  stateSnapshot,
641
654
  liveRemote: remote,
642
655
  })
656
+
657
+ // Partial push: drop endpoints that failed validation from create/update so
658
+ // they aren't pushed (they keep their live version). Deletes stay — a broken
659
+ // local flow shouldn't block removing endpoints. skip_validation leaves
660
+ // erroringEndpoints empty, so nothing is dropped.
661
+ const skippedNames = []
662
+ if (erroringEndpoints.size) {
663
+ const drop = (arr) => (arr || []).filter((item) => {
664
+ if (erroringEndpoints.has(item.name)) { skippedNames.push(item.name); return false }
665
+ return true
666
+ })
667
+ plan.create = drop(plan.create)
668
+ plan.update = drop(plan.update)
669
+ }
670
+ const skipped_endpoints = skippedNames.length
671
+ ? [...new Set(skippedNames)].map((name) => ({
672
+ endpoint: name,
673
+ errors: skippedDiagnostics
674
+ .filter((d) => d.endpoint === name)
675
+ .slice(0, 5)
676
+ .map((d) => ({ rule: d.rule, message: d.message, file: d.file, loc: d.loc })),
677
+ }))
678
+ : undefined
679
+
643
680
  const groupChanges = (plan.groups?.create?.length || 0) + (plan.groups?.delete?.length || 0)
644
681
  const totalChanges = plan.create.length + plan.update.length + plan.delete.length + groupChanges
645
682
 
@@ -676,8 +713,10 @@ export const dypaiPushTool = {
676
713
  ? "source_checkpoint_failed"
677
714
  : automationSyncHasFailed
678
715
  ? "automation_sync_failed"
716
+ : skipped_endpoints && totalChanges === 0 ? "all_skipped"
679
717
  : totalChanges === 0 ? "no_changes" : "dry_run",
680
718
  summary: summaryFromPlan(plan),
719
+ skipped_endpoints,
681
720
  plan,
682
721
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
683
722
  types: typesGenerated,
@@ -847,7 +886,7 @@ export const dypaiPushTool = {
847
886
  return {
848
887
  success: errors.length === 0 && !sourceCheckpointFailed && !automationSyncHasFailed,
849
888
  applied: endpointTotal > 0 || (realtime && !realtime.skipped),
850
- partial_success: partialSuccess || sourceCheckpointFailed || automationSyncHasFailed,
889
+ partial_success: partialSuccess || sourceCheckpointFailed || automationSyncHasFailed || !!skipped_endpoints,
851
890
  reason: sourceCheckpointFailed
852
891
  ? "source_checkpoint_failed"
853
892
  : automationSyncHasFailed
@@ -878,6 +917,7 @@ export const dypaiPushTool = {
878
917
  },
879
918
  details: applied,
880
919
  endpoint_results,
920
+ skipped_endpoints,
881
921
  non_blocking_conflicts: conflictSplit.non_blocking.length ? conflictSplit.non_blocking : undefined,
882
922
  errors: errors.length ? errors : undefined,
883
923
  types: typesGenerated,
@@ -887,7 +927,9 @@ export const dypaiPushTool = {
887
927
  // Only one next_step — and only when it's non-obvious. Drafts win
888
928
  // over the test suggestion because tests against live won't see
889
929
  // the change until the drafts are promoted.
890
- next_step: errors.length
930
+ next_step: skipped_endpoints
931
+ ? `⚠️ ${skipped_endpoints.length} endpoint(s) SKIPPED (they keep their live version) because their flow has errors: ${skipped_endpoints.map(s => s.endpoint).slice(0, 5).join(", ")}${skipped_endpoints.length > 5 ? "…" : ""}. Everything else was pushed. Fix the skipped ones (see skipped_endpoints[].errors) and push again — or use skip_validation:true to push them anyway.`
932
+ : errors.length
891
933
  ? partialSuccess
892
934
  ? `${endpointTotal} endpoint(s) saved, ${failedTotal} failed. Fix failed endpoints and push again. Failed: ${errors.slice(0, 3).map((item) => item.endpoint || item.group || item.op).join(", ")}${errors.length > 3 ? "…" : ""}`
893
935
  : "Fix the offending YAMLs and push again."