@ateam-ai/mcp 0.4.49 → 0.4.51
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/tools.js +57 -44
package/package.json
CHANGED
package/src/tools.js
CHANGED
|
@@ -1324,7 +1324,10 @@ export const tools = [
|
|
|
1324
1324
|
},
|
|
1325
1325
|
{
|
|
1326
1326
|
name: "ateam_get_execution_logs",
|
|
1327
|
-
core:
|
|
1327
|
+
// Advertised (was core:false): these are the RUNTIME DIAGNOSTICS a caller needs
|
|
1328
|
+
// mid-run, but a connector-wildcard grant expands over ADVERTISED tools only, so
|
|
1329
|
+
// hiding them made them ungrantable — invisible to every agent that needed them.
|
|
1330
|
+
core: true,
|
|
1328
1331
|
description:
|
|
1329
1332
|
"Get execution logs for a solution — recent jobs with step traces, tool calls, errors, and timing. Essential for debugging what actually happened during skill execution. (Advanced.)",
|
|
1330
1333
|
inputSchema: {
|
|
@@ -1540,7 +1543,10 @@ export const tools = [
|
|
|
1540
1543
|
},
|
|
1541
1544
|
{
|
|
1542
1545
|
name: "ateam_get_metrics",
|
|
1543
|
-
core:
|
|
1546
|
+
// Advertised (was core:false): these are the RUNTIME DIAGNOSTICS a caller needs
|
|
1547
|
+
// mid-run, but a connector-wildcard grant expands over ADVERTISED tools only, so
|
|
1548
|
+
// hiding them made them ungrantable — invisible to every agent that needed them.
|
|
1549
|
+
core: true,
|
|
1544
1550
|
description:
|
|
1545
1551
|
"Get execution metrics — timing, tool stats, bottlenecks, signals, and recommendations. (Advanced.)",
|
|
1546
1552
|
inputSchema: {
|
|
@@ -3091,8 +3097,23 @@ const handlers = {
|
|
|
3091
3097
|
// The pull-bundle endpoint returns mcp_store (files) and solution.platform_connectors
|
|
3092
3098
|
// (declarations) but not a top-level connectors[] array. The validator/deploy
|
|
3093
3099
|
// pipeline expects one, so build it from the mcp_store we just pulled.
|
|
3100
|
+
//
|
|
3101
|
+
// ROBUSTNESS: mcp_store is normally keyed by CONNECTOR ID, but a bad/older
|
|
3102
|
+
// pull-bundle can key it by the full `connectors/<id>/<file>` path — in
|
|
3103
|
+
// which case the old `map(id => ...)` registered ONE connector PER FILE with
|
|
3104
|
+
// the path as its id (observed 2026-08-15: db.connectors got
|
|
3105
|
+
// connectors/expense-tracker-mcp/server.js etc. as rows). Collapse either
|
|
3106
|
+
// shape to the connector id and dedupe, so a mis-keyed mcp_store can never
|
|
3107
|
+
// manufacture file-path connectors. (Core also rejects "/"-bearing ids at
|
|
3108
|
+
// its boundary as defense-in-depth.)
|
|
3094
3109
|
if (!connectors?.length && Object.keys(effectiveMcpStore).length > 0) {
|
|
3095
|
-
|
|
3110
|
+
const connIds = [...new Set(
|
|
3111
|
+
Object.keys(effectiveMcpStore).map((k) => {
|
|
3112
|
+
const m = String(k).match(/^connectors\/([^/]+)\//);
|
|
3113
|
+
return m ? m[1] : k;
|
|
3114
|
+
})
|
|
3115
|
+
)];
|
|
3116
|
+
connectors = connIds.map((id) => ({
|
|
3096
3117
|
id,
|
|
3097
3118
|
name: id,
|
|
3098
3119
|
transport: "stdio",
|
|
@@ -4163,12 +4184,9 @@ const handlers = {
|
|
|
4163
4184
|
while (Date.now() - startedAt < totalTimeoutMs) {
|
|
4164
4185
|
const qs = new URLSearchParams();
|
|
4165
4186
|
qs.set("skillSlug", skill_id);
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
signal: AbortSignal.timeout(15_000),
|
|
4170
|
-
}).catch(err => ({ ok: false, _err: err.message }));
|
|
4171
|
-
const data = res.ok === false && res._err ? { ok: false, error: res._err } : await res.json().catch(() => ({ ok: false, error: "non-json chain response" }));
|
|
4187
|
+
// Builder proxy, not ADAS_CORE_URL (docker-internal; see ateam_chain_status).
|
|
4188
|
+
const data = await get(`/deploy/jobs/${encodeURIComponent(rootJobId)}/chain?${qs}`, sid)
|
|
4189
|
+
.catch(err => ({ ok: false, error: err.message }));
|
|
4172
4190
|
lastChain = data;
|
|
4173
4191
|
const jobs = Array.isArray(data?.chainJobsList) ? data.chainJobsList : Array.isArray(data?.chainJobs) ? data.chainJobs : null;
|
|
4174
4192
|
if (jobs && jobs.length > 0 && jobs.every(j => isTerminal(j.status))) {
|
|
@@ -4322,15 +4340,11 @@ const handlers = {
|
|
|
4322
4340
|
const creds = getCredentials(sid);
|
|
4323
4341
|
const apiKey = creds?.apiKey;
|
|
4324
4342
|
if (!apiKey) return { ...single, chain: { ok: false, error: "include_chain requires api-key auth (call ateam_auth)" } };
|
|
4325
|
-
const coreUrl = process.env.ADAS_CORE_URL || "http://adas-backend:4000";
|
|
4326
4343
|
const qs = new URLSearchParams();
|
|
4327
4344
|
if (skill_id) qs.set("skillSlug", skill_id);
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
signal: AbortSignal.timeout(15_000),
|
|
4332
|
-
}).catch(err => ({ ok: false, _err: err.message }));
|
|
4333
|
-
const chain = res.ok === false && res._err ? { ok: false, error: res._err } : await res.json().catch(() => ({ ok: false, error: "non-json chain response" }));
|
|
4345
|
+
// Builder proxy, not ADAS_CORE_URL (docker-internal; see ateam_chain_status).
|
|
4346
|
+
const chain = await get(`/deploy/jobs/${encodeURIComponent(job_id)}/chain?${qs}`, sid)
|
|
4347
|
+
.catch(err => ({ ok: false, error: err.message }));
|
|
4334
4348
|
return { ...single, chain };
|
|
4335
4349
|
},
|
|
4336
4350
|
|
|
@@ -4339,21 +4353,12 @@ const handlers = {
|
|
|
4339
4353
|
const creds = getCredentials(sid);
|
|
4340
4354
|
const apiKey = creds?.apiKey;
|
|
4341
4355
|
if (!apiKey) throw new Error("No api_key in session — call ateam_auth(api_key) first.");
|
|
4342
|
-
|
|
4356
|
+
// Via the Builder proxy (see ateam_chain_status) — Core's hostname is
|
|
4357
|
+
// docker-internal and unreachable from a desktop/laptop MCP process.
|
|
4343
4358
|
const qs = new URLSearchParams();
|
|
4344
4359
|
if (skill_slug) qs.set("skillSlug", skill_slug);
|
|
4345
|
-
const
|
|
4346
|
-
|
|
4347
|
-
headers: { "x-api-key": apiKey, "X-ADAS-SERVICE": "ateam-mcp.get_chain" },
|
|
4348
|
-
signal: AbortSignal.timeout(15_000),
|
|
4349
|
-
});
|
|
4350
|
-
const text = await res.text();
|
|
4351
|
-
let data;
|
|
4352
|
-
try { data = JSON.parse(text); } catch { data = { ok: false, error: text.slice(0, 400) }; }
|
|
4353
|
-
if (!res.ok) {
|
|
4354
|
-
throw new Error(`Core /api/job/${job_id}/chain returned ${res.status}: ${data.error || JSON.stringify(data).slice(0, 200)}`);
|
|
4355
|
-
}
|
|
4356
|
-
return data;
|
|
4360
|
+
const suffix = qs.toString() ? `?${qs}` : "";
|
|
4361
|
+
return await get(`/deploy/jobs/${encodeURIComponent(job_id)}/chain${suffix}`, sid);
|
|
4357
4362
|
},
|
|
4358
4363
|
|
|
4359
4364
|
// SLIM chain status — the chip-quick poll. Hits Core /api/job/:id/status
|
|
@@ -4365,21 +4370,26 @@ const handlers = {
|
|
|
4365
4370
|
ateam_chain_status: async ({ chain_id, job_id }, sid) => {
|
|
4366
4371
|
const id = chain_id || job_id;
|
|
4367
4372
|
if (!id) throw new Error("chain_id required");
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4373
|
+
// Routed through the BUILDER proxy (/deploy/jobs/:id/status), not
|
|
4374
|
+
// ADAS_CORE_URL directly. Core is the only holder of job state, but its
|
|
4375
|
+
// hostname is docker-internal — every laptop MCP session got a bare "fetch
|
|
4376
|
+
// failed" that read as "job not found" (2026-08-15: a full day spent reading
|
|
4377
|
+
// Mongo by hand to answer "is this run alive?"). Same reason ateam_verify
|
|
4378
|
+
// proxies. `get()` also carries the session's auth/tenant headers.
|
|
4379
|
+
const data = await get(`/deploy/jobs/${encodeURIComponent(id)}/status`, sid);
|
|
4380
|
+
// LAST ACTIVITY — the running-vs-corpse discriminator. `status:"running"` is
|
|
4381
|
+
// true for a healthy build AND a dead one; the only way to tell them apart
|
|
4382
|
+
// was querying llm_traces for the newest timestamp. Core bumps job.lastUpdate
|
|
4383
|
+
// in the same setStatus() call that writes job.subStatus, so the timestamp
|
|
4384
|
+
// and "what it was doing" move together — one cheap read, no tree walk, so
|
|
4385
|
+
// this stays safe to poll. idle_seconds alone needs interpreting (a live
|
|
4386
|
+
// build can sit minutes inside one provider call), which is why
|
|
4387
|
+
// activity_source ships with it: "idle 180s — in provider call" is a state
|
|
4388
|
+
// you can act on; "idle 180s" is a number you have to guess about.
|
|
4389
|
+
const lastActivityAt = data.lastUpdate ?? data.last_update ?? null;
|
|
4390
|
+
const idleSeconds = lastActivityAt
|
|
4391
|
+
? Math.max(0, Math.round((Date.now() - new Date(lastActivityAt).getTime()) / 1000))
|
|
4392
|
+
: null;
|
|
4383
4393
|
// Surface the chain-aggregate truth as the primary fields; keep the raw
|
|
4384
4394
|
// slim job under `job` for callers that want per-job detail.
|
|
4385
4395
|
return {
|
|
@@ -4389,6 +4399,9 @@ const handlers = {
|
|
|
4389
4399
|
pending_question: data.pendingQuestion || null,
|
|
4390
4400
|
result: data.result ?? null,
|
|
4391
4401
|
progress: data.progress || null,
|
|
4402
|
+
last_activity_at: lastActivityAt,
|
|
4403
|
+
idle_seconds: idleSeconds,
|
|
4404
|
+
activity_source: data.subStatus || null,
|
|
4392
4405
|
job: data,
|
|
4393
4406
|
};
|
|
4394
4407
|
},
|