@ateam-ai/mcp 0.2.9 → 0.3.1
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.
- package/package.json +1 -1
- package/src/api.js +65 -41
- package/src/tools.js +74 -4
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -353,50 +353,74 @@ function formatError(method, path, status, body) {
|
|
|
353
353
|
*/
|
|
354
354
|
async function request(method, path, body, sessionId, opts = {}) {
|
|
355
355
|
const timeoutMs = opts.timeoutMs || REQUEST_TIMEOUT_MS;
|
|
356
|
-
const
|
|
357
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
356
|
+
const maxRetries = opts.retries ?? 0;
|
|
358
357
|
const baseUrl = getBaseUrl(sessionId);
|
|
359
358
|
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
);
|
|
359
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
360
|
+
const controller = new AbortController();
|
|
361
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
const fetchOpts = {
|
|
365
|
+
method,
|
|
366
|
+
headers: headers(sessionId),
|
|
367
|
+
signal: controller.signal,
|
|
368
|
+
};
|
|
369
|
+
if (body !== undefined) {
|
|
370
|
+
fetchOpts.body = JSON.stringify(body);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const res = await fetch(`${baseUrl}${path}`, fetchOpts);
|
|
374
|
+
|
|
375
|
+
// Auto-retry on 502/504 (proxy timeout during long deploys)
|
|
376
|
+
if ((res.status === 502 || res.status === 504) && attempt < maxRetries) {
|
|
377
|
+
const wait = Math.min(5000 * (attempt + 1), 15000);
|
|
378
|
+
console.error(`[MCP] ${method} ${path} returned ${res.status}, retrying in ${wait / 1000}s (attempt ${attempt + 1}/${maxRetries})...`);
|
|
379
|
+
await new Promise(r => setTimeout(r, wait));
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (!res.ok) {
|
|
384
|
+
const text = await res.text().catch(() => "");
|
|
385
|
+
throw new Error(formatError(method, path, res.status, text));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return res.json();
|
|
389
|
+
} catch (err) {
|
|
390
|
+
if (err.name === "AbortError") {
|
|
391
|
+
if (attempt < maxRetries) {
|
|
392
|
+
const wait = Math.min(5000 * (attempt + 1), 15000);
|
|
393
|
+
console.error(`[MCP] ${method} ${path} timed out, retrying in ${wait / 1000}s (attempt ${attempt + 1}/${maxRetries})...`);
|
|
394
|
+
await new Promise(r => setTimeout(r, wait));
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
throw new Error(
|
|
398
|
+
`A-Team API timeout: ${method} ${path} did not respond within ${timeoutMs / 1000}s.\n` +
|
|
399
|
+
`Hint: The A-Team API at ${baseUrl} may be down. Check ${baseUrl}/health`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
if (err.cause?.code === "ECONNREFUSED") {
|
|
403
|
+
if (attempt < maxRetries) {
|
|
404
|
+
const wait = Math.min(5000 * (attempt + 1), 15000);
|
|
405
|
+
console.error(`[MCP] ${method} ${path} connection refused, retrying in ${wait / 1000}s (attempt ${attempt + 1}/${maxRetries})...`);
|
|
406
|
+
await new Promise(r => setTimeout(r, wait));
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
throw new Error(
|
|
410
|
+
`Cannot connect to A-Team API at ${baseUrl}.\n` +
|
|
411
|
+
`Hint: The service may be down. Check ${baseUrl}/health`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
if (err.cause?.code === "ENOTFOUND") {
|
|
415
|
+
throw new Error(
|
|
416
|
+
`Cannot resolve A-Team API host: ${baseUrl}.\n` +
|
|
417
|
+
`Hint: Check your internet connection and ADAS_API_URL setting.`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
throw err;
|
|
421
|
+
} finally {
|
|
422
|
+
clearTimeout(timeout);
|
|
390
423
|
}
|
|
391
|
-
if (err.cause?.code === "ENOTFOUND") {
|
|
392
|
-
throw new Error(
|
|
393
|
-
`Cannot resolve A-Team API host: ${baseUrl}.\n` +
|
|
394
|
-
`Hint: Check your internet connection and ADAS_API_URL setting.`
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
throw err;
|
|
398
|
-
} finally {
|
|
399
|
-
clearTimeout(timeout);
|
|
400
424
|
}
|
|
401
425
|
}
|
|
402
426
|
|
package/src/tools.js
CHANGED
|
@@ -832,7 +832,68 @@ export const tools = [
|
|
|
832
832
|
},
|
|
833
833
|
|
|
834
834
|
// ═══════════════════════════════════════════════════════════════════
|
|
835
|
-
//
|
|
835
|
+
// RELEASE MANAGEMENT — promote, rollback, version listing
|
|
836
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
837
|
+
|
|
838
|
+
{
|
|
839
|
+
name: "ateam_github_promote",
|
|
840
|
+
core: true,
|
|
841
|
+
description:
|
|
842
|
+
"Promote a dev version to main (production). By default promotes the latest dev tag. Optionally specify a specific dev tag to promote. Creates a prod-YYYY-MM-DD-NNN tag on main.",
|
|
843
|
+
inputSchema: {
|
|
844
|
+
type: "object",
|
|
845
|
+
properties: {
|
|
846
|
+
solution_id: {
|
|
847
|
+
type: "string",
|
|
848
|
+
description: "The solution ID",
|
|
849
|
+
},
|
|
850
|
+
tag: {
|
|
851
|
+
type: "string",
|
|
852
|
+
description: "Optional: specific dev tag to promote (e.g., 'dev-2026-03-11-005'). If omitted, promotes the latest dev tag.",
|
|
853
|
+
},
|
|
854
|
+
},
|
|
855
|
+
required: ["solution_id"],
|
|
856
|
+
},
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
name: "ateam_github_rollback",
|
|
860
|
+
core: true,
|
|
861
|
+
description:
|
|
862
|
+
"Rollback main (production) to a previous production tag. Resets main branch to the specified prod tag commit. ⚠️ DESTRUCTIVE — use with caution. Use ateam_github_list_versions to find available production tags first.",
|
|
863
|
+
inputSchema: {
|
|
864
|
+
type: "object",
|
|
865
|
+
properties: {
|
|
866
|
+
solution_id: {
|
|
867
|
+
type: "string",
|
|
868
|
+
description: "The solution ID",
|
|
869
|
+
},
|
|
870
|
+
tag: {
|
|
871
|
+
type: "string",
|
|
872
|
+
description: "Required: production tag to rollback to (e.g., 'prod-2026-03-10-001')",
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
required: ["solution_id", "tag"],
|
|
876
|
+
},
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
name: "ateam_github_list_versions",
|
|
880
|
+
core: true,
|
|
881
|
+
description:
|
|
882
|
+
"List all available dev version tags for a solution. Shows tag name, date, counter, and commit SHA. Use before promoting to see what's available.",
|
|
883
|
+
inputSchema: {
|
|
884
|
+
type: "object",
|
|
885
|
+
properties: {
|
|
886
|
+
solution_id: {
|
|
887
|
+
type: "string",
|
|
888
|
+
description: "The solution ID",
|
|
889
|
+
},
|
|
890
|
+
},
|
|
891
|
+
required: ["solution_id"],
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
|
|
895
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
896
|
+
// INFRASTRUCTURE — redeploy, master key bulk operations
|
|
836
897
|
// ═══════════════════════════════════════════════════════════════════
|
|
837
898
|
|
|
838
899
|
{
|
|
@@ -1207,7 +1268,7 @@ const handlers = {
|
|
|
1207
1268
|
// Phase 2: Deploy
|
|
1208
1269
|
let deploy;
|
|
1209
1270
|
try {
|
|
1210
|
-
deploy = await post("/deploy/solution", { solution, skills, connectors, mcp_store: effectiveMcpStore }, sid, { timeoutMs: 300_000 });
|
|
1271
|
+
deploy = await post("/deploy/solution", { solution, skills, connectors, mcp_store: effectiveMcpStore }, sid, { timeoutMs: 300_000, retries: 2 });
|
|
1211
1272
|
phases.push({ phase: "deploy", status: deploy.ok ? "done" : "failed" });
|
|
1212
1273
|
} catch (err) {
|
|
1213
1274
|
return {
|
|
@@ -1497,7 +1558,7 @@ const handlers = {
|
|
|
1497
1558
|
post(`/deploy/solutions/${solution_id}/github/push`, { message }, sid, { timeoutMs: 60_000 }),
|
|
1498
1559
|
|
|
1499
1560
|
ateam_github_pull: async ({ solution_id }, sid) =>
|
|
1500
|
-
post(`/deploy/solutions/${solution_id}/github/pull`, {}, sid, { timeoutMs: 300_000 }),
|
|
1561
|
+
post(`/deploy/solutions/${solution_id}/github/pull`, {}, sid, { timeoutMs: 300_000, retries: 2 }),
|
|
1501
1562
|
|
|
1502
1563
|
ateam_github_status: async ({ solution_id }, sid) =>
|
|
1503
1564
|
get(`/deploy/solutions/${solution_id}/github/status`, sid),
|
|
@@ -1513,6 +1574,15 @@ const handlers = {
|
|
|
1513
1574
|
return get(`/deploy/solutions/${solution_id}/github/log${qs}`, sid);
|
|
1514
1575
|
},
|
|
1515
1576
|
|
|
1577
|
+
ateam_github_promote: async ({ solution_id, tag }, sid) =>
|
|
1578
|
+
post(`/deploy/solutions/${solution_id}/promote`, tag ? { tag } : {}, sid),
|
|
1579
|
+
|
|
1580
|
+
ateam_github_rollback: async ({ solution_id, tag }, sid) =>
|
|
1581
|
+
post(`/deploy/solutions/${solution_id}/rollback`, { tag }, sid),
|
|
1582
|
+
|
|
1583
|
+
ateam_github_list_versions: async ({ solution_id }, sid) =>
|
|
1584
|
+
get(`/deploy/solutions/${solution_id}/versions/dev`, sid),
|
|
1585
|
+
|
|
1516
1586
|
ateam_delete_solution: async ({ solution_id }, sid) =>
|
|
1517
1587
|
del(`/deploy/solutions/${solution_id}`, sid),
|
|
1518
1588
|
|
|
@@ -1523,7 +1593,7 @@ const handlers = {
|
|
|
1523
1593
|
const endpoint = skill_id
|
|
1524
1594
|
? `/deploy/solutions/${solution_id}/skills/${skill_id}/redeploy`
|
|
1525
1595
|
: `/deploy/solutions/${solution_id}/redeploy`;
|
|
1526
|
-
const result = await post(endpoint, {}, sid, { timeoutMs: 300_000 });
|
|
1596
|
+
const result = await post(endpoint, {}, sid, { timeoutMs: 300_000, retries: 2 });
|
|
1527
1597
|
return {
|
|
1528
1598
|
ok: result.ok,
|
|
1529
1599
|
solution_id,
|