@ateam-ai/mcp 0.3.0 → 0.3.2
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 +52 -3
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
|
@@ -367,6 +367,46 @@ export const tools = [
|
|
|
367
367
|
},
|
|
368
368
|
},
|
|
369
369
|
|
|
370
|
+
{
|
|
371
|
+
name: "ateam_upload_connector",
|
|
372
|
+
core: true,
|
|
373
|
+
description:
|
|
374
|
+
"Upload connector code to Core and restart — WITHOUT redeploying skills. " +
|
|
375
|
+
"Use this to update connector source code (server.js, UI assets, plugins) quickly. " +
|
|
376
|
+
"Set github=true to pull files from the solution's GitHub repo, or pass files directly. " +
|
|
377
|
+
"Much faster than ateam_build_and_run for connector-only changes.",
|
|
378
|
+
inputSchema: {
|
|
379
|
+
type: "object",
|
|
380
|
+
properties: {
|
|
381
|
+
solution_id: {
|
|
382
|
+
type: "string",
|
|
383
|
+
description: "The solution ID",
|
|
384
|
+
},
|
|
385
|
+
connector_id: {
|
|
386
|
+
type: "string",
|
|
387
|
+
description: "The connector ID to upload (e.g. 'personal-assistant-ui-mcp')",
|
|
388
|
+
},
|
|
389
|
+
github: {
|
|
390
|
+
type: "boolean",
|
|
391
|
+
description: "If true, pull connector files from GitHub repo. Default: false.",
|
|
392
|
+
},
|
|
393
|
+
files: {
|
|
394
|
+
type: "array",
|
|
395
|
+
items: {
|
|
396
|
+
type: "object",
|
|
397
|
+
properties: {
|
|
398
|
+
path: { type: "string", description: "Relative file path (e.g. 'server.js', 'ui-dist/panel/1.0.0/index.html')" },
|
|
399
|
+
content: { type: "string", description: "File content" },
|
|
400
|
+
},
|
|
401
|
+
required: ["path", "content"],
|
|
402
|
+
},
|
|
403
|
+
description: "Files to upload. Alternative to github=true.",
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
required: ["solution_id", "connector_id"],
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
|
|
370
410
|
// ═══════════════════════════════════════════════════════════════════
|
|
371
411
|
// ADVANCED TOOLS — hidden from tools/list, still callable by name
|
|
372
412
|
// Use these for manual lifecycle control, debugging, and diagnostics
|
|
@@ -987,6 +1027,7 @@ const TENANT_TOOLS = new Set([
|
|
|
987
1027
|
"ateam_redeploy",
|
|
988
1028
|
"ateam_delete_solution",
|
|
989
1029
|
"ateam_delete_connector",
|
|
1030
|
+
"ateam_upload_connector",
|
|
990
1031
|
"ateam_solution_chat",
|
|
991
1032
|
// Read operations (tenant-specific data)
|
|
992
1033
|
"ateam_list_solutions",
|
|
@@ -1268,7 +1309,7 @@ const handlers = {
|
|
|
1268
1309
|
// Phase 2: Deploy
|
|
1269
1310
|
let deploy;
|
|
1270
1311
|
try {
|
|
1271
|
-
deploy = await post("/deploy/solution", { solution, skills, connectors, mcp_store: effectiveMcpStore }, sid, { timeoutMs: 300_000 });
|
|
1312
|
+
deploy = await post("/deploy/solution", { solution, skills, connectors, mcp_store: effectiveMcpStore }, sid, { timeoutMs: 300_000, retries: 2 });
|
|
1272
1313
|
phases.push({ phase: "deploy", status: deploy.ok ? "done" : "failed" });
|
|
1273
1314
|
} catch (err) {
|
|
1274
1315
|
return {
|
|
@@ -1558,7 +1599,7 @@ const handlers = {
|
|
|
1558
1599
|
post(`/deploy/solutions/${solution_id}/github/push`, { message }, sid, { timeoutMs: 60_000 }),
|
|
1559
1600
|
|
|
1560
1601
|
ateam_github_pull: async ({ solution_id }, sid) =>
|
|
1561
|
-
post(`/deploy/solutions/${solution_id}/github/pull`, {}, sid, { timeoutMs: 300_000 }),
|
|
1602
|
+
post(`/deploy/solutions/${solution_id}/github/pull`, {}, sid, { timeoutMs: 300_000, retries: 2 }),
|
|
1562
1603
|
|
|
1563
1604
|
ateam_github_status: async ({ solution_id }, sid) =>
|
|
1564
1605
|
get(`/deploy/solutions/${solution_id}/github/status`, sid),
|
|
@@ -1589,11 +1630,19 @@ const handlers = {
|
|
|
1589
1630
|
ateam_delete_connector: async ({ solution_id, connector_id }, sid) =>
|
|
1590
1631
|
del(`/deploy/solutions/${solution_id}/connectors/${connector_id}`, sid),
|
|
1591
1632
|
|
|
1633
|
+
ateam_upload_connector: async ({ solution_id, connector_id, github, files }, sid) =>
|
|
1634
|
+
post(
|
|
1635
|
+
`/deploy/solutions/${solution_id}/connectors/${connector_id}/upload`,
|
|
1636
|
+
{ github, files },
|
|
1637
|
+
sid,
|
|
1638
|
+
{ timeoutMs: 300_000, retries: 1 },
|
|
1639
|
+
),
|
|
1640
|
+
|
|
1592
1641
|
ateam_redeploy: async ({ solution_id, skill_id }, sid) => {
|
|
1593
1642
|
const endpoint = skill_id
|
|
1594
1643
|
? `/deploy/solutions/${solution_id}/skills/${skill_id}/redeploy`
|
|
1595
1644
|
: `/deploy/solutions/${solution_id}/redeploy`;
|
|
1596
|
-
const result = await post(endpoint, {}, sid, { timeoutMs: 300_000 });
|
|
1645
|
+
const result = await post(endpoint, {}, sid, { timeoutMs: 300_000, retries: 2 });
|
|
1597
1646
|
return {
|
|
1598
1647
|
ok: result.ok,
|
|
1599
1648
|
solution_id,
|