@ateam-ai/mcp 0.4.53 → 0.4.58

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 +133 -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.58",
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
@@ -512,6 +512,19 @@ export const tools = [
512
512
  {
513
513
  name: "ateam_design_advisor",
514
514
  core: true,
515
+ // MEASURED, not estimated. 6 successful calls against dev on 2026-08-21,
516
+ // distinct goals, spaced to avoid provider rate-limiting:
517
+ // 19048 21123 23359 23739 24462 24699 ms (median 23.7s, max 24.7s)
518
+ // It is ONE LLM call over the capability catalog, so the cost is provider
519
+ // latency and there is no meaningful warm path to under-report.
520
+ //
521
+ // WHY IT MATTERS: Core derives its timeout from this (p95 x 4, floored at
522
+ // 30s). Undeclared, the advisor sat under a 30s default while taking ~25s —
523
+ // one bad provider spike from failing, and it failed exactly that way on
524
+ // 2026-08-21 ("HTTP connector timeout after 30000ms"). It is also the FIRST
525
+ // call a building agent makes and it carries the storage decision, so when
526
+ // it times out the run proceeds with no capability guidance at all.
527
+ monitoring: { safe: true, cost: "normal", latency_ms_p95: 25000, output: "bounded" },
515
528
  description:
516
529
  "CONSULT THIS DURING DESIGN — before and while you design a skill/solution. Describe what you're building; it returns POINTERS to the platform capabilities that fit (per-actor storage, widgets, triggers, sub-agents, mobile data, run-scripts, multi-skill, GitHub, …), each with the /spec topic to read next (via ateam_get_spec) and the tool to wire it. Also returns 'missing' hints (capabilities your goal implies but the design hasn't wired) and lifecycle hints (e.g. connect GitHub when the project will iterate). ADVISORY ONLY — you decide and own the design. Stateless: pass the current design_state each call; consult it as often as you like as the design evolves.",
517
530
  inputSchema: {
@@ -1017,6 +1030,59 @@ export const tools = [
1017
1030
  },
1018
1031
  },
1019
1032
 
1033
+ {
1034
+ name: "ateam_log_lesson",
1035
+ core: true,
1036
+ description:
1037
+ "Record ONE lesson this run learned, so the NEXT run does not relearn it. " +
1038
+ "A building agent starts every run empty — it does not know which tool " +
1039
+ "misled the last run or the workaround that got past it. Log a lesson the " +
1040
+ "moment a tool misleads you AND you find a way through.\n\n" +
1041
+ "APPEND-ONLY. You cannot edit or delete earlier lessons, and you do not " +
1042
+ "supply the timestamp, job or actor — the server stamps those.\n\n" +
1043
+ "LOG ONLY WHAT YOU OBSERVED. Quote the error VERBATIM; never paraphrase it " +
1044
+ "and never write a theory about platform internals. A wrong lesson is worse " +
1045
+ "than no lesson, because the next run cannot check it and will act on it.\n\n" +
1046
+ "Use kind='misleading_success' when a call REPORTED success while the thing " +
1047
+ "you wanted did not happen — that class is the most expensive to rediscover " +
1048
+ "and it is invisible to a failures-only log.",
1049
+ inputSchema: {
1050
+ type: "object",
1051
+ properties: {
1052
+ solution_id: { type: "string", description: "The solution this lesson belongs to" },
1053
+ tool: { type: "string", description: "The tool that misled you, e.g. \"ateam_build_and_run\"" },
1054
+ error: { type: "string", description: "The VERBATIM error or failed_steps fragment. Not a paraphrase." },
1055
+ workaround: { type: "string", description: "What you did instead (optional)" },
1056
+ worked: { type: "boolean", description: "Did the workaround work? Omit if you never found out — 'unknown' is a real answer" },
1057
+ kind: {
1058
+ type: "string",
1059
+ enum: ["failure", "surprise", "misleading_success"],
1060
+ description: "failure = it errored; surprise = it worked but not as documented; misleading_success = it REPORTED success while the intended effect did not happen",
1061
+ },
1062
+ },
1063
+ required: ["solution_id", "tool", "error"],
1064
+ },
1065
+ },
1066
+
1067
+ {
1068
+ name: "ateam_get_lessons",
1069
+ core: true,
1070
+ description:
1071
+ "Read what EARLIER runs on this solution learned — newest first, bounded. " +
1072
+ "Call this during orientation, BEFORE planning: it is the only thing that " +
1073
+ "carries context across runs, and it is cheap. Each entry says which tool " +
1074
+ "misled a previous run, the verbatim error, what was tried instead, and " +
1075
+ "whether that worked. An empty list is a real answer (nothing learned yet).",
1076
+ inputSchema: {
1077
+ type: "object",
1078
+ properties: {
1079
+ solution_id: { type: "string", description: "The solution ID" },
1080
+ limit: { type: "number", description: "Max entries, newest first (default 20)" },
1081
+ },
1082
+ required: ["solution_id"],
1083
+ },
1084
+ },
1085
+
1020
1086
  {
1021
1087
  name: "ateam_create_connector",
1022
1088
  core: true,
@@ -2287,7 +2353,22 @@ function toText(data) { return { content: [{ type: "text", text: JSON.stringify(
2287
2353
  // into the call args; refuse to operate without it (prevents cross-actor leaks).
2288
2354
  function getActorId(args) {
2289
2355
  const id = args?._adas_actor;
2290
- if (!id) throw new Error("${connectorId}: no actor context _adas_actor missing.");
2356
+ // Name BOTH causes. "actor context missing" reads as "Core did not send it",
2357
+ // and that misreading cost a full day on 2026-08-20: Core HAD injected it and
2358
+ // the connector's own schema validation stripped it, because that one tool's
2359
+ // inputSchema omitted _adas_actor. An MCP server drops arguments a tool did
2360
+ // not declare, so the field vanishes silently — and only on the tools that
2361
+ // forgot it, which is why read tools kept working and the first write failed.
2362
+ if (!id) {
2363
+ throw new Error(
2364
+ "${connectorId}: no actor context — _adas_actor missing. TWO possible causes: " +
2365
+ "(1) this tool's inputSchema does not DECLARE _adas_actor, so MCP stripped it " +
2366
+ "before your handler ran — add it to inputSchema.properties (see toolSchemas() " +
2367
+ "below, every data tool must spread ...actor); or " +
2368
+ "(2) the caller is not actor-scoped — ateam_test_connector runs as _system_service, " +
2369
+ "so use ateam_test_skill or a real conversation to exercise per-user tools."
2370
+ );
2371
+ }
2291
2372
  return id;
2292
2373
  }
2293
2374
  ${uiCapable ? `
@@ -2317,6 +2398,13 @@ function discoverPlugins() {
2317
2398
  // ── Tool definitions ── Core reads this list. A tool named "ui.listPlugins"
2318
2399
  // is how Core knows this connector is UI-capable.
2319
2400
  function toolSchemas() {
2401
+ // MUST be spread into the inputSchema.properties of EVERY per-actor tool.
2402
+ // Not decoration: MCP strips arguments a tool did not declare, so a tool that
2403
+ // omits these gets them removed before the handler runs and getActorId()
2404
+ // throws — while the tools that DID declare them keep working. The result is
2405
+ // a connector that looks healthy (deploys, lists tools, answers reads) and
2406
+ // fails on the first write. Do not "fix" that with a default actor id: one
2407
+ // shared actor pools every user's data.
2320
2408
  const actor = { _adas_actor: { type: "string" }, _adas_tenant: { type: "string" } };
2321
2409
  return [
2322
2410
  {
@@ -2340,7 +2428,33 @@ async function handle(req) {
2340
2428
 
2341
2429
  if (method === "tools/call") {
2342
2430
  const name = params?.name;
2343
- const args = params?.arguments || {};
2431
+ // CALLER CONTEXT COMES FROM THE ENVELOPE FIRST.
2432
+ //
2433
+ // Core sends identity two ways: as _adas_* ARGUMENTS, and on params._meta
2434
+ // beside the arguments object. The argument channel is fragile — a server drops
2435
+ // arguments a tool did not declare, so a tool whose inputSchema omits
2436
+ // _adas_actor loses it silently and only per-user WRITES fail, while reads
2437
+ // keep working. The envelope cannot be stripped: it is not part of the
2438
+ // validated argument object.
2439
+ //
2440
+ // This server reads params directly (no SDK zod validation), so _meta is
2441
+ // simply available — no wrapper, no callback plumbing. Merge it UNDER args
2442
+ // so an explicitly declared argument still wins, which keeps a delegation
2443
+ // tool's own actor_id PARAMETER untouched: caller identity is transport,
2444
+ // subject identity is payload, and they must not collide.
2445
+ //
2446
+ // ONLY the _adas_ prefix. _meta is the MCP envelope's OWN namespace, not
2447
+ // ours — the spec puts progressToken in there, and clients that request
2448
+ // progress send it on every call. Spreading the whole envelope would hand a
2449
+ // transport token to tools as a user argument: schemas with
2450
+ // additionalProperties:false would start rejecting previously-valid calls,
2451
+ // tools that log or persist their arguments would record it as user data,
2452
+ // and a future _meta key colliding with a real parameter name would
2453
+ // overwrite it. Read the namespace we own; do not treat the envelope as input.
2454
+ const ctx = Object.fromEntries(
2455
+ Object.entries(params?._meta || {}).filter(([k]) => k.startsWith("_adas_")),
2456
+ );
2457
+ const args = { ...ctx, ...(params?.arguments || {}) };
2344
2458
  try {
2345
2459
  ${uiCapable ? ` // ── UI registry plumbing (no actor required) ──
2346
2460
  if (name === "ui.listPlugins") {
@@ -4954,6 +5068,23 @@ const handlers = {
4954
5068
  };
4955
5069
  },
4956
5070
 
5071
+ ateam_log_lesson: async ({ solution_id, tool, error, workaround, worked, kind }, sid) => {
5072
+ if (!solution_id) throw new Error("solution_id required");
5073
+ if (!tool) throw new Error("tool required — the tool that misled you");
5074
+ if (!error) throw new Error("error required — quote it VERBATIM, do not paraphrase");
5075
+ return await post(
5076
+ `/deploy/solutions/${solution_id}/lessons`,
5077
+ { tool, error, workaround, worked, kind },
5078
+ sid,
5079
+ );
5080
+ },
5081
+
5082
+ ateam_get_lessons: async ({ solution_id, limit }, sid) => {
5083
+ if (!solution_id) throw new Error("solution_id required");
5084
+ const qs = Number.isFinite(limit) ? `?limit=${limit}` : "";
5085
+ return await get(`/deploy/solutions/${solution_id}/lessons${qs}`, sid);
5086
+ },
5087
+
4957
5088
  ateam_show_solution_minimal: async ({ solution_id }, sid) => {
4958
5089
  if (!solution_id) throw new Error("solution_id required");
4959
5090
  const full = await get(`/deploy/solutions/${solution_id}/definition`, sid);