@ateam-ai/mcp 0.4.45 → 0.4.47

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 (3) hide show
  1. package/package.json +1 -1
  2. package/src/api.js +14 -8
  3. package/src/tools.js +16 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.45",
3
+ "version": "0.4.47",
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/api.js CHANGED
@@ -467,14 +467,14 @@ function formatError(method, path, status, body, baseUrl) {
467
467
  // the caller as a bare "returned 422", throwing away the very thing it was
468
468
  // asked to produce. Serialize objects too, capped the same way.
469
469
  let detail = "";
470
- if (typeof body === "string") {
471
- if (body.length > 0 && body.length < 2000) detail = body;
472
- } else if (body && typeof body === "object") {
473
- try {
474
- const s = JSON.stringify(body);
475
- if (s.length < 2000) detail = s;
476
- else detail = s.slice(0, 2000) + "… (truncated)";
477
- } catch { /* non-serializable leave detail empty */ }
470
+ const asText = typeof body === "string"
471
+ ? body
472
+ : (body && typeof body === "object" ? (() => { try { return JSON.stringify(body); } catch { return ""; } })() : "");
473
+ if (asText.length > 0) {
474
+ // Previously a body of 2000+ chars was dropped ENTIRELY, so the richer the
475
+ // error the less the caller was told — a 422 carrying the full diagnosis
476
+ // arrived as a bare status code. Truncate instead of discarding.
477
+ detail = asText.length < 2000 ? asText : asText.slice(0, 2000) + "… (truncated)";
478
478
  }
479
479
 
480
480
  // Always show the FULL URL actually hit — ateam-mcp is a PUBLIC MCP with a
@@ -539,6 +539,12 @@ async function request(method, path, body, sessionId, opts = {}) {
539
539
  // on this to NOT scaffold-clobber an existing skill on a read error.
540
540
  const e = new Error(formatError(method, path, res.status, text, baseUrl));
541
541
  e.status = res.status;
542
+ // Keep the RAW body on the error. formatError truncates for humans, and
543
+ // an endpoint that answers 4xx WITH the diagnosis (ui.surfaceProbe's 422
544
+ // carries the failures explaining why a surface is broken) is exactly the
545
+ // case where the body matters more than the status. A caller that knows
546
+ // how to read its own error shape should not have to scrape a message.
547
+ e.body = text;
542
548
  throw e;
543
549
  }
544
550
 
package/src/tools.js CHANGED
@@ -2168,6 +2168,20 @@ function _scaffoldConnectorFiles({ connectorId, displayName, uiCapable }) {
2168
2168
  //
2169
2169
  // Fill in your real tools below (see TOOLS + the tools/call dispatch). The
2170
2170
  // JSON-RPC framing, actor isolation, stdio loop${uiCapable ? ", and ui-dist plugin discovery" : ""} are template-provided.
2171
+ //
2172
+ // ⚠️ NEVER SWALLOW A FAILURE. If something this tool depends on fails — a fetch,
2173
+ // a platform call, a store read — RETURN THE ERROR. Do not catch it and answer
2174
+ // with empty data:
2175
+ //
2176
+ // BAD: try { rows = await load(); } catch { rows = []; } // renders 0.00 forever
2177
+ // GOOD: try { rows = await load(); }
2178
+ // catch (e) { return toText({ ok: false, error: String(e.message || e) }); }
2179
+ //
2180
+ // A tool that returns ok:true with an empty result when its dependency is broken
2181
+ // is INDISTINGUISHABLE from one that genuinely has no data — to the widget, to
2182
+ // the person reading the screen, and to the agent trying to fix it. That exact
2183
+ // shape cost a full day: a connector caught a 401, returned an empty ledger, and
2184
+ // the dashboard showed 0.00 while every check reported success.
2171
2185
  ${uiCapable ? `
2172
2186
  import { readdirSync, readFileSync, existsSync } from "node:fs";
2173
2187
  import { fileURLToPath } from "node:url";
@@ -4047,10 +4061,9 @@ const handlers = {
4047
4061
  // generic error path turned into "returned 422" — hiding the failures that
4048
4062
  // say WHY the screen is broken, and leaving the caller as blind as before
4049
4063
  // it ran the probe. Hand the verdict back as a result instead of throwing.
4050
- const m = /returned (4\d\d|503)\b[\s\S]*?— (\{[\s\S]*)$/.exec(err?.message || "");
4051
- if (m) {
4064
+ if (typeof err?.body === "string" && err.body) {
4052
4065
  try {
4053
- const parsed = JSON.parse(m[2].replace(/\n?Hint: [\s\S]*$/, "").trim());
4066
+ const parsed = JSON.parse(err.body);
4054
4067
  if (parsed && (parsed.verdict || Array.isArray(parsed.failures))) return parsed;
4055
4068
  } catch { /* not the probe's body — fall through */ }
4056
4069
  }