@ateam-ai/mcp 0.4.31 → 0.4.33

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 +52 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.31",
3
+ "version": "0.4.33",
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
@@ -136,11 +136,13 @@ async function verifyWidgetHealth(solution_id, sid) {
136
136
  } catch (e) {
137
137
  return { ok: false, error: `widget health: could not read solution definition — ${e.message}` };
138
138
  }
139
- if (declared.length === 0) return null; // no widgets → nothing to verify
140
139
 
141
- // 2. Live catalog — what Core actually discovered/serves right now. Go through
142
- // the Builder proxy (reliable from any connection), NOT ADAS_CORE_URL directly
143
- // (unreachable from remote/desktop MCP the old "fetch failed" flakiness).
140
+ // 2. Live catalog — what Core actually discovered/serves right now. Includes
141
+ // CONNECTOR-BUNDLED widgets that render WITHOUT being declared in ui_plugins[],
142
+ // so we must consult it even when ui_plugins is empty (was the bug: verify
143
+ // reported "no widgets declared / checked 0" while 16 widgets were live).
144
+ // Go through the Builder proxy (reliable from any connection), NOT
145
+ // ADAS_CORE_URL directly (unreachable from remote/desktop MCP).
144
146
  let live = [];
145
147
  try {
146
148
  const data = await get(`/deploy/solutions/${solution_id}/ui-plugins`, sid);
@@ -150,6 +152,29 @@ async function verifyWidgetHealth(solution_id, sid) {
150
152
  }
151
153
  const liveById = new Map(live.map((p) => [p?.id, p]));
152
154
 
155
+ // Nothing declared AND nothing served → genuinely no widgets.
156
+ if (declared.length === 0 && live.length === 0) return null;
157
+
158
+ // Nothing declared but connectors SERVE widgets → verify the live
159
+ // (connector-bundled) set instead of falsely reporting "no widgets".
160
+ if (declared.length === 0) {
161
+ const plugins = live.map((p) => {
162
+ const render_ok = _widgetHasRender(p?.render);
163
+ return {
164
+ id: p?.id || "(missing)", discovered: true, render_ok, source: "connector-bundled",
165
+ problems: render_ok ? [] : ["no usable render block — need render.mode + iframeUrl (iframe) or reactNative.component (RN)"],
166
+ };
167
+ });
168
+ const unhealthy = plugins.filter((p) => p.problems.length);
169
+ return {
170
+ ok: unhealthy.length === 0,
171
+ checked: plugins.length,
172
+ note: `${plugins.length} connector-bundled widget(s) served by connectors (none declared in solution.ui_plugins[])`,
173
+ plugins,
174
+ issues: unhealthy.flatMap((p) => p.problems.map((pr) => `${p.id}: ${pr}`)),
175
+ };
176
+ }
177
+
153
178
  // 3. Cross-check each declared plugin against live discovery + render block
154
179
  const plugins = declared.map((d) => {
155
180
  const id = typeof d === "string" ? d : d?.id;
@@ -3478,12 +3503,18 @@ const handlers = {
3478
3503
  // the redeploy with ateam_redeploy(solution_id, skill_id).
3479
3504
  let redeployResult;
3480
3505
  try {
3481
- if (target === "skill" && skill_id) {
3482
- redeployResult = await post(`/deploy/solutions/${solution_id}/skills/${skill_id}/redeploy`, {}, sid, { timeoutMs: 180_000 });
3483
- } else {
3484
- redeployResult = await post(`/deploy/solutions/${solution_id}/redeploy`, {}, sid, { timeoutMs: 180_000 });
3485
- }
3486
- phases.push({ phase: "redeploy", status: "done" });
3506
+ const rdEndpoint = (target === "skill" && skill_id)
3507
+ ? `/deploy/solutions/${solution_id}/skills/${skill_id}/redeploy`
3508
+ : `/deploy/solutions/${solution_id}/redeploy`;
3509
+ // Async-first, same as ateam_redeploy: a bulk (solution) redeploy of a
3510
+ // many-skill solution takes >100s and 524s on the sync path — the patch
3511
+ // then LOOKED like it failed / never reached Core. Kick async + poll;
3512
+ // fall back to sync for older backends.
3513
+ const kicked = await post(rdEndpoint, { async: true }, sid, { timeoutMs: 30_000 });
3514
+ redeployResult = (kicked?.async && kicked.job_id)
3515
+ ? await pollDeployJob(kicked.job_id, sid, { label: skill_id ? `redeploy-skill ${skill_id}` : "redeploy-bulk", maxMs: 15 * 60_000, intervalMs: 2000 })
3516
+ : kicked;
3517
+ phases.push({ phase: "redeploy", status: redeployResult?.ok === false ? "error" : "done" });
3487
3518
  } catch (err) {
3488
3519
  // Partial success: patch is saved to GitHub, only redeploy failed.
3489
3520
  // Return ok:true so the agent doesn't think the patch was lost.
@@ -3985,8 +4016,17 @@ const handlers = {
3985
4016
  // Reaches the catalog through the Builder proxy (/deploy/.../ui-plugins) on
3986
4017
  // the normal base URL — reliable from any connection. (The old direct
3987
4018
  // ADAS_CORE_URL fetch "fetch failed" from remote/desktop MCP connections.)
3988
- if (!solution_id) throw new Error("solution_id required (used to route the catalog request through the Builder).");
3989
- const data = await get(`/deploy/solutions/${solution_id}/ui-plugins`, sid);
4019
+ // solution_id is optional (one tenant = one solution): auto-resolve the
4020
+ // tenant's solution when omitted, per the doc — don't hard-error.
4021
+ let sol = solution_id;
4022
+ if (!sol) {
4023
+ const list = await get(`/deploy/solutions`, sid).catch((e) => { throw new Error(`solution_id omitted and could not list the tenant's solutions to auto-resolve: ${e.message}`); });
4024
+ const sols = Array.isArray(list?.solutions) ? list.solutions : [];
4025
+ if (sols.length === 1) sol = sols[0]?.id || sols[0];
4026
+ else if (sols.length === 0) throw new Error("solution_id omitted and this tenant has no solutions yet.");
4027
+ else throw new Error(`solution_id omitted and this tenant has multiple solutions (${sols.map((s) => s?.id || s).join(", ")}) — pass solution_id explicitly.`);
4028
+ }
4029
+ const data = await get(`/deploy/solutions/${sol}/ui-plugins`, sid);
3990
4030
  if (data?.ok === false) {
3991
4031
  throw new Error(`widget catalog unavailable: ${data.error || "unknown"}`);
3992
4032
  }