@ateam-ai/mcp 0.4.93 → 0.4.94

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +89 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.93",
3
+ "version": "0.4.94",
4
4
  "mcpName": "io.github.ariekogan/ateam-mcp",
5
5
  "description": "A-Team MCP Server — build, validate, and deploy multi-agent solutions from any AI environment",
6
6
  "type": "module",
package/src/tools.js CHANGED
@@ -1051,9 +1051,14 @@ export const tools = [
1051
1051
  name: "ateam_delete_solution",
1052
1052
  core: true,
1053
1053
  description:
1054
- "⚠️ IRREVERSIBLE — kills Mongo state, running MCP processes, and Builder FS for the whole solution and every skill. " +
1054
+ "⚠️ IRREVERSIBLE — THIS CLEARS THE WHOLE TENANT, not just the named solution. " +
1055
+ "TENANT === SOLUTION, so it wipes EVERY skill and connector in the tenant's Core registry, the solution record, " +
1056
+ "and Builder FS — INCLUDING any orphaned skill that no longer belongs to a solution. The name says 'solution'; the " +
1057
+ "blast radius is the tenant. Read the tenant's skill list first (ateam_get_solution view:'skills' or Core's registry) " +
1058
+ "and know what you are destroying — an orphan from an earlier solution is still in there and still goes. " +
1055
1059
  "REQUIRES `confirm:true` AND `confirm_solution_id` echoing the solution id you're destroying (defeats typos and hallucinated ids). " +
1056
- "RECOVERY: the GitHub repo is untouched; `ateam_github_pull` rebuilds the solution from `main`. Prefer that over re-deploying from memory.",
1060
+ "RECOVERY: only what GitHub holds. `ateam_github_pull` rebuilds from `main` anything never pushed there is GONE. " +
1061
+ "A skill authored FS-only, or orphaned before its solution was pushed, has no copy anywhere.",
1057
1062
  inputSchema: {
1058
1063
  type: "object",
1059
1064
  properties: {
@@ -1067,10 +1072,17 @@ export const tools = [
1067
1072
  },
1068
1073
  confirm_solution_id: {
1069
1074
  type: "string",
1070
- description: "REQUIRED. Must exactly equal `solution_id`. This defeats typos and hallucinated ids — you can't wipe a solution you couldn't spell.",
1075
+ description: "Required with force:true. Must exactly equal `solution_id`. This defeats typos and hallucinated ids — you can't wipe a solution you couldn't spell.",
1076
+ },
1077
+ force: {
1078
+ type: "boolean",
1079
+ description:
1080
+ "Omit (DEFAULT) to PREVIEW: returns will_clear — every skill and connector that would be destroyed, with " +
1081
+ "orphan_skills called out separately — and clears NOTHING. Pass true only after reading that list. The " +
1082
+ "preview exists because a description cannot name the orphan you did not know was in the registry.",
1071
1083
  },
1072
1084
  },
1073
- required: ["solution_id", "confirm", "confirm_solution_id"],
1085
+ required: ["solution_id"],
1074
1086
  },
1075
1087
  },
1076
1088
  {
@@ -4693,8 +4705,36 @@ export const handlers = {
4693
4705
  ? ` ⚠️ Skill "${skill_id}" is INVALID (${validation.error_count ?? "?"} error(s)) — see validation (non-blocking; build_and_run will refuse until fixed).`
4694
4706
  : "";
4695
4707
 
4708
+ // A PATCH THAT DID NOT REBUILD IS NOT A SUCCESSFUL PATCH.
4709
+ //
4710
+ // This returned ok:true whenever the write landed, even if the redeploy
4711
+ // failed or timed out, on the reasoning that the edit "is not lost". The
4712
+ // edit genuinely is not lost — but ok:true is not where that belongs.
4713
+ //
4714
+ // Changing skill.connectors[] makes the connector-derived half of tools[]
4715
+ // STALE, and only the redeploy rebuilds it. So a green patch with a failed
4716
+ // redeploy hands back exactly the state this whole fix exists to prevent: a
4717
+ // skill whose declarations say one thing and whose generated tools still
4718
+ // say another, reported as done. The caller stops, because it was told it
4719
+ // succeeded.
4720
+ //
4721
+ // ok now reflects the LIFECYCLE — update, rebuild, validate, redeploy —
4722
+ // and `patch_persisted` carries the "nothing was lost" fact as a field,
4723
+ // where a caller can act on it, instead of as a lie in the status.
4724
+ const lifecycleOk = redeployResult === undefined ? true : redeployOk;
4725
+
4696
4726
  return {
4697
- ok: true,
4727
+ ok: lifecycleOk,
4728
+ ...(!lifecycleOk && {
4729
+ patch_persisted: true,
4730
+ phase: "redeploy",
4731
+ error:
4732
+ `The edit was saved to ${store} but the redeploy did not complete, so the skill's ` +
4733
+ `connector-derived tools were NOT rebuilt. Nothing is lost and nothing needs re-patching — ` +
4734
+ `the definition is stored. Finish it with ateam_redeploy(solution_id` +
4735
+ (skill_id ? `, skill_id: "${skill_id}"` : "") + `). Until then Builder and Core disagree ` +
4736
+ `about this skill's tools.`,
4737
+ }),
4698
4738
  solution_id,
4699
4739
  source: isLocal ? "local" : "github",
4700
4740
  ...(degradedToLocal && {
@@ -4729,7 +4769,7 @@ export const handlers = {
4729
4769
  ? (widget_health && !widget_health.ok
4730
4770
  ? `✅ Patched on ${store} + redeployed. ⚠️ ${widget_health.issues?.length || 0} widget(s) not rendering — see widget_health.`
4731
4771
  : `✅ Patched on ${store} + redeployed.`)
4732
- : `⚠️ Patched on ${store} ✅ but redeploy timed out. Run: ateam_redeploy(solution_id` + (skill_id ? `, skill_id: "${skill_id}"` : '') + ')') + validationStatus,
4772
+ : `⚠️ Patched on ${store} ✅ but the redeploy did NOT complete, so connector-derived tools were not rebuilt — Builder and Core disagree until you run: ateam_redeploy(solution_id` + (skill_id ? `, skill_id: "${skill_id}"` : '') + ')') + validationStatus,
4733
4773
  _next: isLocal
4734
4774
  ? 'Local edit saved + redeployed. When the tenant connects a GitHub repo, the local state is pushed → GitHub (which then becomes master).'
4735
4775
  : 'Create a checkpoint before making more changes: ateam_github_promote(solution_id)',
@@ -5889,23 +5929,61 @@ export const handlers = {
5889
5929
  ateam_github_list_versions: async ({ solution_id }, sid) =>
5890
5930
  get(`/deploy/solutions/${solution_id}/versions/dev`, sid),
5891
5931
 
5892
- ateam_delete_solution: async ({ solution_id, confirm, confirm_solution_id }, sid) => {
5932
+ // SHOW BEFORE YOU DESTROY.
5933
+ //
5934
+ // Without force:true this RETURNS THE INVENTORY — every skill and connector
5935
+ // the clear would take — and touches nothing. Only force:true clears.
5936
+ //
5937
+ // A warning in a description is a claim the caller must take on trust, and it
5938
+ // cannot mention the ORPHAN nobody knew was in the registry. The inventory is
5939
+ // evidence: the caller reads the actual names first. On 2026-09-11 the absence
5940
+ // of that step cost `walk-guide` — destroyed while clearing an unrelated test
5941
+ // fixture, present in no GitHub branch, unrecoverable.
5942
+ //
5943
+ // confirm/confirm_solution_id still guard typos and hallucinated ids. They
5944
+ // answer "did you mean THIS tenant"; force answers "have you read what is in
5945
+ // it". Both are needed, and neither substitutes for the other.
5946
+ ateam_delete_solution: async ({ solution_id, confirm, confirm_solution_id, force }, sid) => {
5947
+ if (confirm_solution_id !== undefined && confirm_solution_id !== solution_id) {
5948
+ return {
5949
+ ok: false,
5950
+ error: `⚠️ REFUSED: confirm_solution_id must exactly equal solution_id. Got confirm_solution_id="${confirm_solution_id}" but solution_id="${solution_id}". This check defeats typos and hallucinated ids — you should not be able to wipe a solution whose id you can't spell correctly.`,
5951
+ expected: solution_id,
5952
+ received: confirm_solution_id,
5953
+ };
5954
+ }
5955
+
5956
+ // Preview: no confirm needed to LOOK, and looking is the default.
5957
+ if (force !== true) {
5958
+ const preview = await del(`/deploy/solutions/${solution_id}`, sid);
5959
+ return {
5960
+ ...preview,
5961
+ _next:
5962
+ "Nothing was cleared. Read will_clear above — especially orphan_skills, which belong to no solution and " +
5963
+ "are the ones most likely to be unrecoverable. To proceed: ateam_delete_solution(solution_id, " +
5964
+ `confirm:true, confirm_solution_id:"${solution_id}", force:true)`,
5965
+ };
5966
+ }
5967
+
5893
5968
  if (confirm !== true) {
5894
5969
  return {
5895
5970
  ok: false,
5896
- error: "⚠️ REFUSED: ateam_delete_solution requires confirm:true. This is irreversible in Core + Builder FS. GitHub source is preserved — ateam_github_pull rebuilds from `main` if you already deleted by mistake.",
5897
- recovery: "ateam_github_pull(solution_id, ref:'main')",
5971
+ error:
5972
+ "⚠️ REFUSED: force:true also requires confirm:true. THIS CLEARS THE WHOLE TENANT — TENANT === SOLUTION, so " +
5973
+ "every skill and connector in the tenant's Core registry goes, including any ORPHAN that no longer belongs " +
5974
+ "to a solution. Recovery reaches only as far as GitHub: anything never pushed is unrecoverable.",
5975
+ recovery: "ateam_github_pull(solution_id, ref:'main') — restores ONLY what `main` holds",
5898
5976
  };
5899
5977
  }
5900
5978
  if (confirm_solution_id !== solution_id) {
5901
5979
  return {
5902
5980
  ok: false,
5903
- error: `⚠️ REFUSED: confirm_solution_id must exactly equal solution_id. Got confirm_solution_id="${confirm_solution_id}" but solution_id="${solution_id}". This check defeats typos and hallucinated ids — you should not be able to wipe a solution whose id you can't spell correctly.`,
5981
+ error: `⚠️ REFUSED: force:true requires confirm_solution_id to exactly equal solution_id.`,
5904
5982
  expected: solution_id,
5905
5983
  received: confirm_solution_id,
5906
5984
  };
5907
5985
  }
5908
- return del(`/deploy/solutions/${solution_id}`, sid);
5986
+ return del(`/deploy/solutions/${solution_id}?force=true`, sid);
5909
5987
  },
5910
5988
 
5911
5989
  ateam_delete_skill: async ({ solution_id, skill_id, confirm }, sid) => {