@ateam-ai/mcp 0.4.52 → 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 +149 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.52",
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,
@@ -1912,7 +1965,7 @@ export const tools = [
1912
1965
  "SHIP DEV TO PROD. Merges the `dev` branch into `main` and auto-tags the new main HEAD as safe-YYYY-MM-DD-NNN. " +
1913
1966
  "Use after testing your dev work, when you're ready to deploy changes to production.\n\n" +
1914
1967
  "Workflow: 1) ateam_github_patch (writes to dev) → 2) ateam_github_promote (merges dev→main) → 3) ateam_build_and_run (deploys main).\n\n" +
1915
- "Pass dry_run:true to see what's about to ship without merging. On merge conflict the call returns 409 — resolve manually on GitHub (open a PR or use the web UI), then retry.",
1968
+ "Pass dry_run:true to see what's about to ship without merging.\n\nON 409 MERGE CONFLICT: main holds commits dev never received. Call ateam_github_sync_from_main(solution_id) to merge main into dev, then promote again. Only if THAT also returns 409 did both sides edit the same lines that one needs a human (open a PR on GitHub).",
1916
1969
  inputSchema: {
1917
1970
  type: "object",
1918
1971
  properties: {
@@ -1936,6 +1989,31 @@ export const tools = [
1936
1989
  required: ["solution_id"],
1937
1990
  },
1938
1991
  },
1992
+ {
1993
+ name: "ateam_github_sync_from_main",
1994
+ core: true,
1995
+ description:
1996
+ "BRING `dev` UP TO DATE WITH `main` — merges main into dev. The mirror of ateam_github_promote.\n\n" +
1997
+ "USE THIS WHEN PROMOTE RETURNS 409. promote only ships dev→main, so the moment anything lands on main directly — a hotfix, a manual edit, an ateam_github_rollback, or a write that mis-targeted the branch — dev falls behind and can never be promoted again. Without this tool that divergence is unfixable from A-Team: the only exits are the GitHub web UI or a raw API call.\n\n" +
1998
+ "Workflow on a 409: 1) ateam_github_diff (confirm status:'diverged') → 2) ateam_github_sync_from_main → 3) ateam_github_promote.\n\n" +
1999
+ "Pass dry_run:true FIRST to see exactly which commits and files would come into dev without changing anything.\n\n" +
2000
+ "This is a real merge, not a force: if main and dev edited the SAME lines it returns 409 too, and that one genuinely needs a human (open a PR).",
2001
+ monitoring: { safe: true, cost: "low", latency_ms_p95: 2500, output: "bounded" },
2002
+ inputSchema: {
2003
+ type: "object",
2004
+ properties: {
2005
+ solution_id: {
2006
+ type: "string",
2007
+ description: "The solution ID",
2008
+ },
2009
+ dry_run: {
2010
+ type: "boolean",
2011
+ description: "If true: show the commits + files that would merge into dev, change nothing. Default: false. Call this first.",
2012
+ },
2013
+ },
2014
+ required: ["solution_id"],
2015
+ },
2016
+ },
1939
2017
  {
1940
2018
  name: "ateam_github_rollback",
1941
2019
  core: true,
@@ -2262,7 +2340,22 @@ function toText(data) { return { content: [{ type: "text", text: JSON.stringify(
2262
2340
  // into the call args; refuse to operate without it (prevents cross-actor leaks).
2263
2341
  function getActorId(args) {
2264
2342
  const id = args?._adas_actor;
2265
- 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
+ }
2266
2359
  return id;
2267
2360
  }
2268
2361
  ${uiCapable ? `
@@ -2292,6 +2385,13 @@ function discoverPlugins() {
2292
2385
  // ── Tool definitions ── Core reads this list. A tool named "ui.listPlugins"
2293
2386
  // is how Core knows this connector is UI-capable.
2294
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.
2295
2395
  const actor = { _adas_actor: { type: "string" }, _adas_tenant: { type: "string" } };
2296
2396
  return [
2297
2397
  {
@@ -2315,7 +2415,33 @@ async function handle(req) {
2315
2415
 
2316
2416
  if (method === "tools/call") {
2317
2417
  const name = params?.name;
2318
- 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 || {}) };
2319
2445
  try {
2320
2446
  ${uiCapable ? ` // ── UI registry plumbing (no actor required) ──
2321
2447
  if (name === "ui.listPlugins") {
@@ -4802,6 +4928,9 @@ const handlers = {
4802
4928
  ateam_github_promote: async ({ solution_id, label, dry_run, skip_tag }, sid) =>
4803
4929
  post(`/deploy/solutions/${solution_id}/promote`, { label, dry_run, skip_tag }, sid),
4804
4930
 
4931
+ ateam_github_sync_from_main: async ({ solution_id, dry_run }, sid) =>
4932
+ post(`/deploy/solutions/${solution_id}/sync-from-main`, { dry_run }, sid),
4933
+
4805
4934
  ateam_github_rollback: async ({ solution_id, target, tag }, sid) =>
4806
4935
  // Accept both `target` (new spec) and `tag` (legacy callers)
4807
4936
  post(`/deploy/solutions/${solution_id}/rollback`, { target: target || tag }, sid),
@@ -4926,6 +5055,23 @@ const handlers = {
4926
5055
  };
4927
5056
  },
4928
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
+
4929
5075
  ateam_show_solution_minimal: async ({ solution_id }, sid) => {
4930
5076
  if (!solution_id) throw new Error("solution_id required");
4931
5077
  const full = await get(`/deploy/solutions/${solution_id}/definition`, sid);