@ateam-ai/mcp 0.4.53 → 0.4.57

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +120 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.53",
3
+ "version": "0.4.57",
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",
package/src/tools.js CHANGED
@@ -1017,6 +1017,59 @@ export const tools = [
1017
1017
  },
1018
1018
  },
1019
1019
 
1020
+ {
1021
+ name: "ateam_log_lesson",
1022
+ core: true,
1023
+ description:
1024
+ "Record ONE lesson this run learned, so the NEXT run does not relearn it. " +
1025
+ "A building agent starts every run empty — it does not know which tool " +
1026
+ "misled the last run or the workaround that got past it. Log a lesson the " +
1027
+ "moment a tool misleads you AND you find a way through.\n\n" +
1028
+ "APPEND-ONLY. You cannot edit or delete earlier lessons, and you do not " +
1029
+ "supply the timestamp, job or actor — the server stamps those.\n\n" +
1030
+ "LOG ONLY WHAT YOU OBSERVED. Quote the error VERBATIM; never paraphrase it " +
1031
+ "and never write a theory about platform internals. A wrong lesson is worse " +
1032
+ "than no lesson, because the next run cannot check it and will act on it.\n\n" +
1033
+ "Use kind='misleading_success' when a call REPORTED success while the thing " +
1034
+ "you wanted did not happen — that class is the most expensive to rediscover " +
1035
+ "and it is invisible to a failures-only log.",
1036
+ inputSchema: {
1037
+ type: "object",
1038
+ properties: {
1039
+ solution_id: { type: "string", description: "The solution this lesson belongs to" },
1040
+ tool: { type: "string", description: "The tool that misled you, e.g. \"ateam_build_and_run\"" },
1041
+ error: { type: "string", description: "The VERBATIM error or failed_steps fragment. Not a paraphrase." },
1042
+ workaround: { type: "string", description: "What you did instead (optional)" },
1043
+ worked: { type: "boolean", description: "Did the workaround work? Omit if you never found out — 'unknown' is a real answer" },
1044
+ kind: {
1045
+ type: "string",
1046
+ enum: ["failure", "surprise", "misleading_success"],
1047
+ description: "failure = it errored; surprise = it worked but not as documented; misleading_success = it REPORTED success while the intended effect did not happen",
1048
+ },
1049
+ },
1050
+ required: ["solution_id", "tool", "error"],
1051
+ },
1052
+ },
1053
+
1054
+ {
1055
+ name: "ateam_get_lessons",
1056
+ core: true,
1057
+ description:
1058
+ "Read what EARLIER runs on this solution learned — newest first, bounded. " +
1059
+ "Call this during orientation, BEFORE planning: it is the only thing that " +
1060
+ "carries context across runs, and it is cheap. Each entry says which tool " +
1061
+ "misled a previous run, the verbatim error, what was tried instead, and " +
1062
+ "whether that worked. An empty list is a real answer (nothing learned yet).",
1063
+ inputSchema: {
1064
+ type: "object",
1065
+ properties: {
1066
+ solution_id: { type: "string", description: "The solution ID" },
1067
+ limit: { type: "number", description: "Max entries, newest first (default 20)" },
1068
+ },
1069
+ required: ["solution_id"],
1070
+ },
1071
+ },
1072
+
1020
1073
  {
1021
1074
  name: "ateam_create_connector",
1022
1075
  core: true,
@@ -2287,7 +2340,22 @@ function toText(data) { return { content: [{ type: "text", text: JSON.stringify(
2287
2340
  // into the call args; refuse to operate without it (prevents cross-actor leaks).
2288
2341
  function getActorId(args) {
2289
2342
  const id = args?._adas_actor;
2290
- if (!id) throw new Error("${connectorId}: no actor context _adas_actor missing.");
2343
+ // Name BOTH causes. "actor context missing" reads as "Core did not send it",
2344
+ // and that misreading cost a full day on 2026-08-20: Core HAD injected it and
2345
+ // the connector's own schema validation stripped it, because that one tool's
2346
+ // inputSchema omitted _adas_actor. An MCP server drops arguments a tool did
2347
+ // not declare, so the field vanishes silently — and only on the tools that
2348
+ // forgot it, which is why read tools kept working and the first write failed.
2349
+ if (!id) {
2350
+ throw new Error(
2351
+ "${connectorId}: no actor context — _adas_actor missing. TWO possible causes: " +
2352
+ "(1) this tool's inputSchema does not DECLARE _adas_actor, so MCP stripped it " +
2353
+ "before your handler ran — add it to inputSchema.properties (see toolSchemas() " +
2354
+ "below, every data tool must spread ...actor); or " +
2355
+ "(2) the caller is not actor-scoped — ateam_test_connector runs as _system_service, " +
2356
+ "so use ateam_test_skill or a real conversation to exercise per-user tools."
2357
+ );
2358
+ }
2291
2359
  return id;
2292
2360
  }
2293
2361
  ${uiCapable ? `
@@ -2317,6 +2385,13 @@ function discoverPlugins() {
2317
2385
  // ── Tool definitions ── Core reads this list. A tool named "ui.listPlugins"
2318
2386
  // is how Core knows this connector is UI-capable.
2319
2387
  function toolSchemas() {
2388
+ // MUST be spread into the inputSchema.properties of EVERY per-actor tool.
2389
+ // Not decoration: MCP strips arguments a tool did not declare, so a tool that
2390
+ // omits these gets them removed before the handler runs and getActorId()
2391
+ // throws — while the tools that DID declare them keep working. The result is
2392
+ // a connector that looks healthy (deploys, lists tools, answers reads) and
2393
+ // fails on the first write. Do not "fix" that with a default actor id: one
2394
+ // shared actor pools every user's data.
2320
2395
  const actor = { _adas_actor: { type: "string" }, _adas_tenant: { type: "string" } };
2321
2396
  return [
2322
2397
  {
@@ -2340,7 +2415,33 @@ async function handle(req) {
2340
2415
 
2341
2416
  if (method === "tools/call") {
2342
2417
  const name = params?.name;
2343
- const args = params?.arguments || {};
2418
+ // CALLER CONTEXT COMES FROM THE ENVELOPE FIRST.
2419
+ //
2420
+ // Core sends identity two ways: as _adas_* ARGUMENTS, and on params._meta
2421
+ // beside the arguments object. The argument channel is fragile — a server drops
2422
+ // arguments a tool did not declare, so a tool whose inputSchema omits
2423
+ // _adas_actor loses it silently and only per-user WRITES fail, while reads
2424
+ // keep working. The envelope cannot be stripped: it is not part of the
2425
+ // validated argument object.
2426
+ //
2427
+ // This server reads params directly (no SDK zod validation), so _meta is
2428
+ // simply available — no wrapper, no callback plumbing. Merge it UNDER args
2429
+ // so an explicitly declared argument still wins, which keeps a delegation
2430
+ // tool's own actor_id PARAMETER untouched: caller identity is transport,
2431
+ // subject identity is payload, and they must not collide.
2432
+ //
2433
+ // ONLY the _adas_ prefix. _meta is the MCP envelope's OWN namespace, not
2434
+ // ours — the spec puts progressToken in there, and clients that request
2435
+ // progress send it on every call. Spreading the whole envelope would hand a
2436
+ // transport token to tools as a user argument: schemas with
2437
+ // additionalProperties:false would start rejecting previously-valid calls,
2438
+ // tools that log or persist their arguments would record it as user data,
2439
+ // and a future _meta key colliding with a real parameter name would
2440
+ // overwrite it. Read the namespace we own; do not treat the envelope as input.
2441
+ const ctx = Object.fromEntries(
2442
+ Object.entries(params?._meta || {}).filter(([k]) => k.startsWith("_adas_")),
2443
+ );
2444
+ const args = { ...ctx, ...(params?.arguments || {}) };
2344
2445
  try {
2345
2446
  ${uiCapable ? ` // ── UI registry plumbing (no actor required) ──
2346
2447
  if (name === "ui.listPlugins") {
@@ -4954,6 +5055,23 @@ const handlers = {
4954
5055
  };
4955
5056
  },
4956
5057
 
5058
+ ateam_log_lesson: async ({ solution_id, tool, error, workaround, worked, kind }, sid) => {
5059
+ if (!solution_id) throw new Error("solution_id required");
5060
+ if (!tool) throw new Error("tool required — the tool that misled you");
5061
+ if (!error) throw new Error("error required — quote it VERBATIM, do not paraphrase");
5062
+ return await post(
5063
+ `/solutions/${solution_id}/lessons`,
5064
+ { tool, error, workaround, worked, kind },
5065
+ sid,
5066
+ );
5067
+ },
5068
+
5069
+ ateam_get_lessons: async ({ solution_id, limit }, sid) => {
5070
+ if (!solution_id) throw new Error("solution_id required");
5071
+ const qs = Number.isFinite(limit) ? `?limit=${limit}` : "";
5072
+ return await get(`/solutions/${solution_id}/lessons${qs}`, sid);
5073
+ },
5074
+
4957
5075
  ateam_show_solution_minimal: async ({ solution_id }, sid) => {
4958
5076
  if (!solution_id) throw new Error("solution_id required");
4959
5077
  const full = await get(`/deploy/solutions/${solution_id}/definition`, sid);