@ateam-ai/mcp 0.4.10 → 0.4.12

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 +65 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
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
@@ -1121,6 +1121,24 @@ export const tools = [
1121
1121
  required: ["job_id"],
1122
1122
  },
1123
1123
  },
1124
+ {
1125
+ name: "ateam_chain_status",
1126
+ core: true,
1127
+ description:
1128
+ "SLIM chain status — the chip-quick poll. Given a chain_id (from ateam_conversation), returns the WHOLE-CHAIN aggregate status cheaply: chain_status + chain_done (true only when the ENTIRE chain — root job + every handoff + askAnySkill subcall — is terminal), plus pending_question, result, and a short progress line.\n\n" +
1129
+ "This is what you poll on a loop after ateam_conversation — NOT ateam_get_chain (that returns the full tree; too heavy for periodic polling). A single job can finish while the chain is still running, so poll chain_done, not a job's status.\n\n" +
1130
+ "Loop: call every ~2s until chain_done === true (or pending_question is set — the assistant is waiting on the user). Then read `result` / fetch the full tree once via ateam_get_chain if you need per-job detail.",
1131
+ inputSchema: {
1132
+ type: "object",
1133
+ properties: {
1134
+ chain_id: {
1135
+ type: "string",
1136
+ description: "The chain id returned by ateam_conversation (the conversation's identity). Any job id in the chain also works — Core resolves the chain aggregate.",
1137
+ },
1138
+ },
1139
+ required: ["chain_id"],
1140
+ },
1141
+ },
1124
1142
  {
1125
1143
  name: "ateam_get_widget_catalog",
1126
1144
  core: true,
@@ -1722,6 +1740,7 @@ const TENANT_TOOLS = new Set([
1722
1740
  "ateam_test_status",
1723
1741
  "ateam_test_abort",
1724
1742
  "ateam_get_chain",
1743
+ "ateam_chain_status",
1725
1744
  "ateam_get_widget_catalog",
1726
1745
  "ateam_get_connector_source",
1727
1746
  "ateam_get_metrics",
@@ -3162,15 +3181,18 @@ const handlers = {
3162
3181
  // accepted for back-compat but no longer hold the HTTP request open.
3163
3182
  const body = { message, async: true, ...(actor_id ? { actor_id } : {}) };
3164
3183
  const kickoff = await post(`/deploy/solutions/${solution_id}/test`, body, sid, { timeoutMs: 15_000 });
3165
- const jobId = kickoff?.job_id || kickoff?.jobId || null;
3184
+ // The CHAIN id not a single job id — is the conversation's identity and
3185
+ // what you poll. The Builder returns it as chain_id (falls back to the
3186
+ // root job id only if an older Builder didn't send one).
3187
+ const chainId = kickoff?.chain_id || kickoff?.chainId || kickoff?.job_id || kickoff?.jobId || null;
3166
3188
  return {
3167
3189
  ...kickoff,
3168
- job_id: jobId,
3169
- chain_id: jobId,
3170
- _poll: jobId
3190
+ chain_id: chainId,
3191
+ _poll: chainId
3171
3192
  ? {
3172
- _note: "Conversation started (async). Poll for the reply do NOT expect it in this response.",
3173
- slim: `ateam_get_chain(job_id: "${jobId}") → chain tree + per-job status`,
3193
+ _note: "Conversation started (async). The reply is NOT in this response poll the CHAIN for it.",
3194
+ slim: `ateam_chain_status(chain_id: "${chainId}") → cheap chip-quick poll; loop ~2s until chain_done===true (whole chain terminal, not just one job). Then read result.`,
3195
+ full: `ateam_get_chain(job_id: "${chainId}") → full tree + per-job detail (heavier; use once, not in a poll loop)`,
3174
3196
  continue: kickoff?.actor_id ? `ateam_conversation(actor_id: "${kickoff.actor_id}", ...) to continue the thread` : undefined,
3175
3197
  }
3176
3198
  : undefined,
@@ -3419,6 +3441,43 @@ const handlers = {
3419
3441
  return data;
3420
3442
  },
3421
3443
 
3444
+ // SLIM chain status — the chip-quick poll. Hits Core /api/job/:id/status
3445
+ // (slimJob), which returns the WHOLE-CHAIN aggregate `chainStatus`/`chainDone`
3446
+ // (computeChainStatus over chainId) alongside the single-job status. This is
3447
+ // the right thing to poll on a loop after ateam_conversation: a single job
3448
+ // can terminate while the chain is still active — chainDone only flips when
3449
+ // the CHAIN is done. Cheap enough for periodic polling (no full tree).
3450
+ ateam_chain_status: async ({ chain_id, job_id }, sid) => {
3451
+ const id = chain_id || job_id;
3452
+ if (!id) throw new Error("chain_id required");
3453
+ const creds = getCredentials(sid);
3454
+ const apiKey = creds?.apiKey;
3455
+ if (!apiKey) throw new Error("No api_key in session — call ateam_auth(api_key) first.");
3456
+ const coreUrl = process.env.ADAS_CORE_URL || "http://adas-backend:4000";
3457
+ const res = await fetch(`${coreUrl}/api/job/${encodeURIComponent(id)}/status`, {
3458
+ method: "GET",
3459
+ headers: { "x-api-key": apiKey, "X-ADAS-SERVICE": "ateam-mcp.chain_status" },
3460
+ signal: AbortSignal.timeout(15_000),
3461
+ });
3462
+ const text = await res.text();
3463
+ let data;
3464
+ try { data = JSON.parse(text); } catch { data = { ok: false, error: text.slice(0, 400) }; }
3465
+ if (!res.ok) {
3466
+ throw new Error(`Core /api/job/${id}/status returned ${res.status}: ${data.error || JSON.stringify(data).slice(0, 200)}`);
3467
+ }
3468
+ // Surface the chain-aggregate truth as the primary fields; keep the raw
3469
+ // slim job under `job` for callers that want per-job detail.
3470
+ return {
3471
+ chain_id: data.chainId || id,
3472
+ chain_status: data.chainStatus ?? data.status ?? null,
3473
+ chain_done: data.chainDone ?? data.done ?? null,
3474
+ pending_question: data.pendingQuestion || null,
3475
+ result: data.result ?? null,
3476
+ progress: data.progress || null,
3477
+ job: data,
3478
+ };
3479
+ },
3480
+
3422
3481
  ateam_get_widget_catalog: async ({ origin, format }, sid) => {
3423
3482
  // Wraps Core's existing GET /api/ui-plugins (merged tenant plugin list)
3424
3483
  // and enriches each entry with the documentation/how-to-use layer.