@ateam-ai/mcp 0.4.76 → 0.4.77

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 +69 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.76",
3
+ "version": "0.4.77",
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
@@ -5347,10 +5347,78 @@ const handlers = {
5347
5347
  gaps.push(`solution health unavailable: ${e.message}`);
5348
5348
  }
5349
5349
 
5350
+ // 4. SMOKE CALL — actually invoke a tool the SOLUTION depends on.
5351
+ //
5352
+ // Everything above is tools/list-level: `connected`, `tools > 0`, "renders",
5353
+ // "deployed". All of it stayed green on a clinic connector that answered
5354
+ // tools/list correctly and returned 401 on EVERY storage call, because its
5355
+ // generated client put a PAT in the shared-secret header. The build shipped,
5356
+ // reported healthy, and failed the first time a user touched it. The only
5357
+ // check that could have caught it is calling something.
5358
+ //
5359
+ // Tool names come from the SKILLS, not the connector: the connector
5360
+ // endpoints expose a count and a description but no name (verified live —
5361
+ // /connectors/<id>/tools returns 7 objects that are all {description:""}),
5362
+ // and the tools a skill declares are the ones that actually have to work.
5363
+ // Testing those is a better question than testing an arbitrary one.
5364
+ out.smoke = [];
5365
+ try {
5366
+ const wanted = new Map(); // toolName -> connectorId (first skill that declares it)
5367
+ for (const sk of Array.isArray(out.skills) ? out.skills : []) {
5368
+ if (!sk?.id) continue;
5369
+ const def = await get(`/deploy/solutions/${solution_id}/skills/${sk.id}`, sid).catch(() => null);
5370
+ for (const t of (def?.skill?.tools || def?.tools || [])) {
5371
+ const name = typeof t === "string" ? t : t?.name;
5372
+ if (!name || wanted.has(name)) continue;
5373
+ const conn = (typeof t === "object" && (t?.source?.connector || t?.source?.id)) || null;
5374
+ wanted.set(name, conn);
5375
+ }
5376
+ }
5377
+
5378
+ // READ-SHAPED ONLY. A smoke test must never book an appointment or delete a
5379
+ // row to prove a connector is alive, so a write-shaped name is skipped and
5380
+ // SAID to be skipped rather than quietly passed over.
5381
+ const readish = [...wanted.keys()].filter((n) => /(^|[._])(list|get|today|available|health|status|ping|info|search)([._]|$)/i.test(n));
5382
+ const perConnector = new Map();
5383
+ for (const name of readish) {
5384
+ const conn = wanted.get(name) || (Array.isArray(out.connectors) && out.connectors[0]?.id) || null;
5385
+ if (!conn || perConnector.has(conn)) continue;
5386
+ perConnector.set(conn, name);
5387
+ }
5388
+
5389
+ for (const c of Array.isArray(out.connectors) ? out.connectors : []) {
5390
+ // DELIBERATELY NOT GATED ON c.connected. Connectors are LAZY — one idles
5391
+ // back to sleep between step 1 and here, and the /call endpoint wakes it
5392
+ // on demand. Skipping a sleeping connector would make this check silently
5393
+ // untestable exactly when it is most needed, and "asleep" is not an
5394
+ // answer to "do its calls work?". The call itself is the verdict.
5395
+ const pick = perConnector.get(c.id);
5396
+ if (!pick) {
5397
+ out.smoke.push({ connector: c.id, called: null, note: "no read-shaped tool declared by any skill — NOT smoke-tested" });
5398
+ gaps.push(`connector '${c.id}' was not smoke-tested (no read-shaped tool declared by a skill); tools/list working does NOT prove its calls succeed`);
5399
+ continue;
5400
+ }
5401
+ try {
5402
+ const r = await post(`/deploy/solutions/${solution_id}/connectors/${c.id}/call`, { tool: pick, args: {} }, sid);
5403
+ const failed = r?.ok === false;
5404
+ out.smoke.push({ connector: c.id, called: pick, ok: !failed, ...(failed && { error: String(r?.error || "").slice(0, 200) }) });
5405
+ if (failed) {
5406
+ gaps.push(`connector '${c.id}' lists ${c.tools} tool(s) but CALLING ${pick} failed: ${String(r?.error || "").slice(0, 160)} — tools/list works and real calls do not`);
5407
+ }
5408
+ } catch (e) {
5409
+ out.smoke.push({ connector: c.id, called: pick, ok: false, error: e.message.slice(0, 200) });
5410
+ gaps.push(`connector '${c.id}' smoke call ${pick} errored: ${e.message.slice(0, 160)}`);
5411
+ }
5412
+ }
5413
+ } catch (e) {
5414
+ out.smoke = { error: e.message };
5415
+ gaps.push(`smoke check could not run: ${e.message}`);
5416
+ }
5417
+
5350
5418
  out.gaps = gaps;
5351
5419
  out.ok = gaps.length === 0;
5352
5420
  out._status = out.ok
5353
- ? "✅ Verified live — connectors connected, widgets render, skills deployed."
5421
+ ? "✅ Verified live — connectors connected AND answering real calls, widgets render, skills deployed."
5354
5422
  : `⚠️ ${gaps.length} gap(s): ${gaps.slice(0, 5).join("; ")}${gaps.length > 5 ? " …" : ""}`;
5355
5423
  return out;
5356
5424
  },