@ateam-ai/mcp 0.4.58 → 0.4.60
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 +24 -3
- package/src/tools.js +27 -5
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -317,8 +317,20 @@ function apiToAppUrl(baseUrl) {
|
|
|
317
317
|
export function getWhere(sessionId) {
|
|
318
318
|
let tenant = null;
|
|
319
319
|
try { tenant = getCredentials(sessionId)?.tenant || null; } catch { /* unauthed */ }
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
// PLATFORM INTERNALS NEVER REACH THE AGENT. This used to return
|
|
321
|
+
// `app_url` plus a `_note` telling the agent to "view it at
|
|
322
|
+
// http://skill-builder-backend" — an internal compose service name. The
|
|
323
|
+
// agent cannot reach it, cannot act on it, and cannot show it to a user;
|
|
324
|
+
// it resolves nowhere outside Docker. Worse than useless: an
|
|
325
|
+
// actionable-looking instruction that leads nowhere.
|
|
326
|
+
//
|
|
327
|
+
// Only a PUBLIC url is worth returning, so we return one only when the
|
|
328
|
+
// resolved host actually looks public. Otherwise `_where` is just the
|
|
329
|
+
// tenant, which is the part that is solution-scoped and that the agent
|
|
330
|
+
// genuinely needs. (Arie, 2026-08-21, reading a raw error panel.)
|
|
331
|
+
const appUrl = apiToAppUrl(getBaseUrl(sessionId));
|
|
332
|
+
const isPublic = /^https?:\/\/[^/]*\./.test(appUrl || "") && !/^https?:\/\/(localhost|127\.|\[?::1)/i.test(appUrl || "");
|
|
333
|
+
if (!isPublic) return tenant ? { tenant } : {};
|
|
322
334
|
return {
|
|
323
335
|
tenant,
|
|
324
336
|
app_url: appUrl,
|
|
@@ -460,7 +472,16 @@ function formatError(method, path, status, body, baseUrl) {
|
|
|
460
472
|
].join("\n");
|
|
461
473
|
}
|
|
462
474
|
|
|
463
|
-
|
|
475
|
+
// A GENERIC HINT MUST NOT CONTRADICT A SPECIFIC ONE. When the body already
|
|
476
|
+
// carries its own `code` + `hint`, the endpoint has diagnosed the failure
|
|
477
|
+
// precisely — appending the status-level guess produces two hints pointing
|
|
478
|
+
// opposite ways, and the reader follows the wrong one. Observed 2026-08-21
|
|
479
|
+
// (job_aehopl8z): a patch whose search string did not match came back with
|
|
480
|
+
// the endpoint's correct "re-read the file and copy the exact bytes"
|
|
481
|
+
// followed by "Check the solution_id … use ateam_list_solutions", and the
|
|
482
|
+
// agent went hunting for a missing solution three times.
|
|
483
|
+
const hasSpecificHint = /"code"\s*:/.test(bodyStr) && /"hint"\s*:/.test(bodyStr);
|
|
484
|
+
const hint = hasSpecificHint ? "" : (hints[status] || "");
|
|
464
485
|
// A JSON error body used to be dropped entirely — only a string body became
|
|
465
486
|
// `detail`. So an endpoint that answers 4xx WITH the diagnosis (ui.surfaceProbe
|
|
466
487
|
// returns 422 + the failures that explain why the surface is broken) reached
|
package/src/tools.js
CHANGED
|
@@ -1785,6 +1785,7 @@ export const tools = [
|
|
|
1785
1785
|
inputSchema: {
|
|
1786
1786
|
type: "object",
|
|
1787
1787
|
properties: {
|
|
1788
|
+
branch: { type: "string", description: "Branch to read/write (alias for `ref`). Declared so MCP does not strip it — an undeclared argument is dropped silently, which made a branch:\"dev\" read return `main` with no error." },
|
|
1788
1789
|
solution_id: {
|
|
1789
1790
|
type: "string",
|
|
1790
1791
|
description: "The solution ID",
|
|
@@ -1814,6 +1815,7 @@ export const tools = [
|
|
|
1814
1815
|
inputSchema: {
|
|
1815
1816
|
type: "object",
|
|
1816
1817
|
properties: {
|
|
1818
|
+
branch: { type: "string", description: "Branch to read/write (alias for `ref`). Declared so MCP does not strip it — an undeclared argument is dropped silently, which made a branch:\"dev\" read return `main` with no error." },
|
|
1817
1819
|
solution_id: {
|
|
1818
1820
|
type: "string",
|
|
1819
1821
|
description: "The solution ID",
|
|
@@ -3382,11 +3384,23 @@ const handlers = {
|
|
|
3382
3384
|
validation = await post("/validate/solution", { solution, skills: effectiveSkills, connectors, mcp_store: effectiveMcpStore }, sid, { timeoutMs: 120_000 });
|
|
3383
3385
|
phases.push({ phase: "validate", status: "done" });
|
|
3384
3386
|
} catch (err) {
|
|
3387
|
+
// A DEAD SOCKET IS NOT A FORMAT ERROR. "fetch failed" / ECONNREFUSED /
|
|
3388
|
+
// ETIMEDOUT / socket hang up mean the deploy service was unreachable —
|
|
3389
|
+
// telling the agent to go re-read the solution spec sends it to fix
|
|
3390
|
+
// something that is not broken, at the cost of several turns. Observed
|
|
3391
|
+
// 2026-08-21 (job_aehopl8z): the backend had been restarted mid-run and
|
|
3392
|
+
// the agent burned turns on get_spec and spec_search chasing a phantom
|
|
3393
|
+
// format problem. The two diagnoses are opposites; pick by the cause.
|
|
3394
|
+
const transport = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|EAI_AGAIN|network|aborted/i
|
|
3395
|
+
.test(err.message || "");
|
|
3385
3396
|
return {
|
|
3386
3397
|
ok: false,
|
|
3387
3398
|
phase: "validation",
|
|
3388
3399
|
error: err.message,
|
|
3389
|
-
|
|
3400
|
+
retryable: transport,
|
|
3401
|
+
message: transport
|
|
3402
|
+
? "The deploy service was UNREACHABLE — this is a transport failure, not a problem with your solution. Do NOT re-read the spec or change your definition. Wait a few seconds and RETRY the same call; if it keeps failing, the backend is down or was restarted mid-run."
|
|
3403
|
+
: "Validation call failed. Check your solution/skill format against the spec (ateam_get_spec topic='solution').",
|
|
3390
3404
|
};
|
|
3391
3405
|
}
|
|
3392
3406
|
|
|
@@ -4902,9 +4916,16 @@ const handlers = {
|
|
|
4902
4916
|
ateam_github_status: async ({ solution_id }, sid) =>
|
|
4903
4917
|
get(`/deploy/solutions/${solution_id}/github/status`, sid),
|
|
4904
4918
|
|
|
4905
|
-
ateam_github_read: async ({ solution_id, path: filePath, ref }, sid) => {
|
|
4919
|
+
ateam_github_read: async ({ solution_id, path: filePath, ref, branch }, sid) => {
|
|
4920
|
+
// `branch` is an ALIAS for `ref`. The underlying API param is literally
|
|
4921
|
+
// called `branch`, so an agent passing branch:"dev" is being reasonable —
|
|
4922
|
+
// and because the schema did not declare it, MCP STRIPPED it and the read
|
|
4923
|
+
// silently returned `main`. On a tenant whose main and dev had diverged by
|
|
4924
|
+
// 67 commits, that answered a different question than the one asked, with
|
|
4925
|
+
// no error. (2026-08-21, job_aehopl8z.)
|
|
4926
|
+
const wanted = ref || branch;
|
|
4906
4927
|
const qs = new URLSearchParams({ path: filePath });
|
|
4907
|
-
if (
|
|
4928
|
+
if (wanted) qs.set('branch', wanted);
|
|
4908
4929
|
const result = await get(`/deploy/solutions/${solution_id}/github/read?${qs.toString()}`, sid);
|
|
4909
4930
|
// Additive only — never reshape `result`, callers depend on the raw payload.
|
|
4910
4931
|
const rep = _representationFor(filePath, result?.content, solution_id);
|
|
@@ -4913,8 +4934,9 @@ const handlers = {
|
|
|
4913
4934
|
: result;
|
|
4914
4935
|
},
|
|
4915
4936
|
|
|
4916
|
-
ateam_github_patch: async ({ solution_id, path: filePath, content, search, replace, message, ref }, sid) =>
|
|
4917
|
-
|
|
4937
|
+
ateam_github_patch: async ({ solution_id, path: filePath, content, search, replace, message, ref, branch }, sid) =>
|
|
4938
|
+
// `branch` is an alias for `ref` — see ateam_github_read.
|
|
4939
|
+
post(`/deploy/solutions/${solution_id}/github/patch`, { path: filePath, content, search, replace, message, ref: ref || branch }, sid),
|
|
4918
4940
|
|
|
4919
4941
|
ateam_github_write: async ({ solution_id, path: filePath, content, message, ref }, sid) =>
|
|
4920
4942
|
post(`/deploy/solutions/${solution_id}/github/patch`, { path: filePath, content, message, ref }, sid),
|