@ateam-ai/mcp 0.4.11 → 0.4.13

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 +61 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
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
@@ -435,8 +435,9 @@ export const tools = [
435
435
  core: true,
436
436
  description:
437
437
  "Send a chat message to a deployed solution. No skill_id needed — the system auto-routes to the right skill.\n\n" +
438
- "ALWAYS ASYNC: returns a chain id (job_id) immediately — the assistant's reply is NOT in this response (a conversation can run for minutes, so a synchronous wait would hit the 100s edge timeout → 524). Poll for the reply with ateam_get_chain(job_id) — it returns the chain tree + per-job status; the routed worker's terminal job carries the reply.\n\n" +
439
- "Multi-turn: pass the actor_id from a previous response back in to continue the same thread (e.g. reply to a confirmation prompt). Each call is a new job; the same actor_id maintains conversation context.",
438
+ "ALWAYS ASYNC: returns a chain_id immediately — the assistant's reply is NOT in this response (a conversation can run for minutes across handoffs + subcalls, so a synchronous wait would hit the 100s edge timeout → 524).\n\n" +
439
+ "POLL BY CHAIN, NEVER BY JOB: an individual job can terminate while the chain is still running, so poll ateam_chain_status(chain_id) on a loop (~2s) and stop when chain_done === true (or pending_question is set — the assistant is waiting on the user). That is the cheap chip-quick poll (Core's whole-chain computeChainStatus — the same thing the standard chat uses). Use ateam_get_chain(chain_id) only ONCE at the end if you want the full tree / per-job detail — it's too heavy to loop on.\n\n" +
440
+ "Multi-turn: pass the actor_id from a previous response back in to continue the same thread (e.g. reply to a confirmation prompt). Each call starts a new chain; the same actor_id maintains conversation context.",
440
441
  inputSchema: {
441
442
  type: "object",
442
443
  properties: {
@@ -1121,6 +1122,24 @@ export const tools = [
1121
1122
  required: ["job_id"],
1122
1123
  },
1123
1124
  },
1125
+ {
1126
+ name: "ateam_chain_status",
1127
+ core: true,
1128
+ description:
1129
+ "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" +
1130
+ "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" +
1131
+ "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.",
1132
+ inputSchema: {
1133
+ type: "object",
1134
+ properties: {
1135
+ chain_id: {
1136
+ type: "string",
1137
+ 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.",
1138
+ },
1139
+ },
1140
+ required: ["chain_id"],
1141
+ },
1142
+ },
1124
1143
  {
1125
1144
  name: "ateam_get_widget_catalog",
1126
1145
  core: true,
@@ -1722,6 +1741,7 @@ const TENANT_TOOLS = new Set([
1722
1741
  "ateam_test_status",
1723
1742
  "ateam_test_abort",
1724
1743
  "ateam_get_chain",
1744
+ "ateam_chain_status",
1725
1745
  "ateam_get_widget_catalog",
1726
1746
  "ateam_get_connector_source",
1727
1747
  "ateam_get_metrics",
@@ -3172,7 +3192,8 @@ const handlers = {
3172
3192
  _poll: chainId
3173
3193
  ? {
3174
3194
  _note: "Conversation started (async). The reply is NOT in this response — poll the CHAIN for it.",
3175
- slim: `ateam_get_chain(job_id: "${chainId}") → chain tree + per-job status; the routed worker's terminal job carries the reply`,
3195
+ 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.`,
3196
+ full: `ateam_get_chain(job_id: "${chainId}") → full tree + per-job detail (heavier; use once, not in a poll loop)`,
3176
3197
  continue: kickoff?.actor_id ? `ateam_conversation(actor_id: "${kickoff.actor_id}", ...) to continue the thread` : undefined,
3177
3198
  }
3178
3199
  : undefined,
@@ -3421,6 +3442,43 @@ const handlers = {
3421
3442
  return data;
3422
3443
  },
3423
3444
 
3445
+ // SLIM chain status — the chip-quick poll. Hits Core /api/job/:id/status
3446
+ // (slimJob), which returns the WHOLE-CHAIN aggregate `chainStatus`/`chainDone`
3447
+ // (computeChainStatus over chainId) alongside the single-job status. This is
3448
+ // the right thing to poll on a loop after ateam_conversation: a single job
3449
+ // can terminate while the chain is still active — chainDone only flips when
3450
+ // the CHAIN is done. Cheap enough for periodic polling (no full tree).
3451
+ ateam_chain_status: async ({ chain_id, job_id }, sid) => {
3452
+ const id = chain_id || job_id;
3453
+ if (!id) throw new Error("chain_id required");
3454
+ const creds = getCredentials(sid);
3455
+ const apiKey = creds?.apiKey;
3456
+ if (!apiKey) throw new Error("No api_key in session — call ateam_auth(api_key) first.");
3457
+ const coreUrl = process.env.ADAS_CORE_URL || "http://adas-backend:4000";
3458
+ const res = await fetch(`${coreUrl}/api/job/${encodeURIComponent(id)}/status`, {
3459
+ method: "GET",
3460
+ headers: { "x-api-key": apiKey, "X-ADAS-SERVICE": "ateam-mcp.chain_status" },
3461
+ signal: AbortSignal.timeout(15_000),
3462
+ });
3463
+ const text = await res.text();
3464
+ let data;
3465
+ try { data = JSON.parse(text); } catch { data = { ok: false, error: text.slice(0, 400) }; }
3466
+ if (!res.ok) {
3467
+ throw new Error(`Core /api/job/${id}/status returned ${res.status}: ${data.error || JSON.stringify(data).slice(0, 200)}`);
3468
+ }
3469
+ // Surface the chain-aggregate truth as the primary fields; keep the raw
3470
+ // slim job under `job` for callers that want per-job detail.
3471
+ return {
3472
+ chain_id: data.chainId || id,
3473
+ chain_status: data.chainStatus ?? data.status ?? null,
3474
+ chain_done: data.chainDone ?? data.done ?? null,
3475
+ pending_question: data.pendingQuestion || null,
3476
+ result: data.result ?? null,
3477
+ progress: data.progress || null,
3478
+ job: data,
3479
+ };
3480
+ },
3481
+
3424
3482
  ateam_get_widget_catalog: async ({ origin, format }, sid) => {
3425
3483
  // Wraps Core's existing GET /api/ui-plugins (merged tenant plugin list)
3426
3484
  // and enriches each entry with the documentation/how-to-use layer.