@ateam-ai/mcp 0.4.78 → 0.4.80
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 +2 -2
- package/src/api.js +30 -0
- package/src/tools.js +19 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ateam-ai/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.80",
|
|
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",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"start:http": "node src/index.js --http",
|
|
14
14
|
"dev": "node --watch src/index.js",
|
|
15
15
|
"dev:http": "node --watch src/index.js --http",
|
|
16
|
-
"test": "node test/session-isolation.test.mjs && node test/widget-protocol.test.mjs"
|
|
16
|
+
"test": "node test/session-isolation.test.mjs && node test/widget-protocol.test.mjs && node test/actor-binding.test.mjs"
|
|
17
17
|
},
|
|
18
18
|
"keywords": [
|
|
19
19
|
"mcp",
|
package/src/api.js
CHANGED
|
@@ -173,6 +173,27 @@ export function isExplicitlyAuthenticated(sessionId) {
|
|
|
173
173
|
* Record activity on a session — called on every tool call.
|
|
174
174
|
* Keeps the session alive and updates context for smarter UX.
|
|
175
175
|
*/
|
|
176
|
+
/**
|
|
177
|
+
* Forget the session's bound actor.
|
|
178
|
+
*
|
|
179
|
+
* A session binds an actor from args or from a run-starting tool's result, and
|
|
180
|
+
* NOTHING ever unbound it — so a session that bound a bad value ("dev", a
|
|
181
|
+
* branch name a caller mistook for an actor) sent it on every later request
|
|
182
|
+
* forever, each one 401-ing with `Actor "dev" not found`. Restricting where a
|
|
183
|
+
* bind may come from narrows the entrance; it does not open an exit.
|
|
184
|
+
*
|
|
185
|
+
* Called when Core tells us the actor does not exist. Self-healing beats a
|
|
186
|
+
* hint telling a human to re-authenticate a key that was never the problem.
|
|
187
|
+
*/
|
|
188
|
+
export function clearSessionActor(sessionId, reason = "") {
|
|
189
|
+
const session = sessionId ? sessions.get(sessionId) : null;
|
|
190
|
+
if (!session?.context?.actorId) return false;
|
|
191
|
+
const had = session.context.actorId;
|
|
192
|
+
delete session.context.actorId;
|
|
193
|
+
console.warn(`[Auth] Unbound session actor "${had}"${reason ? ` — ${reason}` : ""}. Later calls act as the tenant until an actor is passed again.`);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
176
197
|
export function touchSession(sessionId, { toolName, solutionId, skillId, actorId } = {}) {
|
|
177
198
|
const session = sessions.get(sessionId);
|
|
178
199
|
if (!session) return;
|
|
@@ -641,6 +662,15 @@ async function request(method, path, body, sessionId, opts = {}) {
|
|
|
641
662
|
|
|
642
663
|
if (!res.ok) {
|
|
643
664
|
const text = await res.text().catch(() => "");
|
|
665
|
+
// SELF-HEAL A BAD ACTOR BINDING. Core saying `Actor "X" not found` is
|
|
666
|
+
// proof the session is carrying an actor that does not exist, and every
|
|
667
|
+
// subsequent request would send it again. Restricting where a bind may
|
|
668
|
+
// come from narrows the entrance; this is the exit. Unbinding costs
|
|
669
|
+
// nothing when the actor was genuinely wrong, and the next call simply
|
|
670
|
+
// acts as the tenant until a real actor is passed.
|
|
671
|
+
if (res.status === 401 && /Actor\s+\\?"?[^"\\,}]+\\?"?\s+not found|unknown actor/i.test(text)) {
|
|
672
|
+
clearSessionActor(sessionId, `Core rejected it on ${method} ${path}`);
|
|
673
|
+
}
|
|
644
674
|
// Attach the HTTP status so callers can distinguish a genuine 404
|
|
645
675
|
// (resource absent) from a transient/5xx failure. ateam_patch relies
|
|
646
676
|
// on this to NOT scaffold-clobber an existing skill on a read error.
|
package/src/tools.js
CHANGED
|
@@ -4966,7 +4966,25 @@ const handlers = {
|
|
|
4966
4966
|
throw new Error("Pass chain_id (the whole run — recommended) or job_id. ateam_conversation returns chain_id.");
|
|
4967
4967
|
}
|
|
4968
4968
|
if (!skill_id) {
|
|
4969
|
-
|
|
4969
|
+
// ASK FOR NOTHING THE TOOL CAN WORK OUT ITSELF. This used to throw
|
|
4970
|
+
// "job_id needs skill_id too — pass chain_id instead". The message was
|
|
4971
|
+
// accurate and well-written, and it was reached by FAILING FIRST, every
|
|
4972
|
+
// time: 4 occurrences on 4 different job ids in a single clean e2e, each
|
|
4973
|
+
// one a wasted turn. A good error still costs a round trip.
|
|
4974
|
+
//
|
|
4975
|
+
// /deploy/jobs/:id/status resolves ANY job id — it is the same endpoint
|
|
4976
|
+
// the chain path above already uses — so a job id without a skill needs no
|
|
4977
|
+
// skill at all. `scope` says which question was answered, because "this
|
|
4978
|
+
// job" and "the whole run" genuinely differ: a root job can read completed
|
|
4979
|
+
// while a handoff is still running.
|
|
4980
|
+
const data = await get(`/deploy/jobs/${encodeURIComponent(job_id)}/status`, sid);
|
|
4981
|
+
return {
|
|
4982
|
+
ok: true,
|
|
4983
|
+
scope: "job",
|
|
4984
|
+
job_id,
|
|
4985
|
+
...data,
|
|
4986
|
+
_note: `Answered for THIS JOB. For the whole run — including handoffs a root job does not cover — pass chain_id instead${data?.chainId ? ` (this job's chain is "${data.chainId}")` : ""}.`,
|
|
4987
|
+
};
|
|
4970
4988
|
}
|
|
4971
4989
|
// Existing single-job snapshot via Builder (unchanged shape for back-compat).
|
|
4972
4990
|
const single = await get(`/deploy/solutions/${solution_id}/skills/${skill_id}/test/${job_id}`, sid);
|