@ateam-ai/mcp 0.4.51 → 0.4.53

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.51",
3
+ "version": "0.4.53",
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/server.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  CallToolRequestSchema,
11
11
  ListToolsRequestSchema,
12
12
  } from "@modelcontextprotocol/sdk/types.js";
13
- import { tools, coreTools, handleToolCall } from "./tools.js";
13
+ import { tools, coreTools, handleToolCall, MCP_VERSION } from "./tools.js";
14
14
 
15
15
  /**
16
16
  * @param {string} sessionId — identifier for credential isolation.
@@ -18,7 +18,11 @@ import { tools, coreTools, handleToolCall } from "./tools.js";
18
18
  */
19
19
  export function createServer(sessionId = "stdio") {
20
20
  const server = new Server(
21
- { name: "ateam-mcp", version: "0.3.0" },
21
+ // Read the REAL version from package.json. This was hardcoded "0.3.0" while
22
+ // the package shipped 0.4.x — so the MCP handshake advertised a version that
23
+ // had been wrong for dozens of releases, and "which build am I talking to?"
24
+ // could not be answered from the protocol at all.
25
+ { name: "ateam-mcp", version: MCP_VERSION },
22
26
  {
23
27
  capabilities: { tools: {} },
24
28
  instructions: [
package/src/tools.js CHANGED
@@ -31,6 +31,18 @@ const STAMP_WHERE_TOOLS = new Set([
31
31
  import { renderAgentDocHeader, mergeAgentDoc, AGENT_DOC_SENTINEL } from "./agentDoc.js";
32
32
  import { deriveErrorCode, isLogicalFailure } from "./mcpFailure.js";
33
33
 
34
+ // The RUNNING version, read from package.json — never hardcoded. "Deployed" means
35
+ // three different things here (the mac1 container, npm, and each developer's local
36
+ // checkout+process), and a stale local PROCESS is indistinguishable from a broken
37
+ // fix without this. Surfaced in the MCP handshake and in ateam_bootstrap so
38
+ // "which build am I talking to?" is a five-second check, not a three-message
39
+ // round-trip (2026-08-16).
40
+ import { createRequire as _createRequire } from "node:module";
41
+ export const MCP_VERSION = (() => {
42
+ try { return _createRequire(import.meta.url)("../package.json").version; }
43
+ catch { return "unknown"; }
44
+ })();
45
+
34
46
  // ─── Async deploy helper ────────────────────────────────────────────
35
47
  //
36
48
  // All long-running deploy endpoints (build_and_run, redeploy, github_pull)
@@ -450,9 +462,9 @@ export const tools = [
450
462
  properties: {
451
463
  topic: {
452
464
  type: "string",
453
- enum: ["overview", "skill", "solution", "enums", "connector-multi-user", "python_helpers", "widgets", "ui-plugins", "actor-storage", "voice", "voice-native", "triggers", "sub-agent", "consumer-roles", "mobile-connector"],
465
+ enum: ["overview", "skill", "solution", "enums", "connector-multi-user", "python_helpers", "widgets", "ui-plugins", "actor-storage", "voice", "voice-native", "triggers", "sub-agent", "consumer-roles", "mobile-connector", "monitoring"],
454
466
  description:
455
- "What to fetch: 'overview' = API overview + endpoints, 'skill' = full skill spec, 'solution' = full solution spec, 'enums' = all enum values, 'connector-multi-user' = multi-user connector guide, 'python_helpers' = adas.* helper namespace for run_python_script orchestration (read this when designing personas that read state → call tools → checkpoint → status; without it, scripts hand-roll JSON parsing and tool delegation = 5-10x larger and brittler), 'widgets' = widget (UI plugin) spec: catalog model, how_to_use block shape (solution.json snippet + opener_call + persona_phrasing + binding_notes), and rules for declaring ui_plugins. Pair with ateam_get_widget_catalog for the live per-tenant inventory. 'ui-plugins' = the DEEP React Native (mobile) plugin build guide: author in rn-src/, compile with a build:rn esbuild script (format=cjs, target=es2015, external react/react-native/@adas/plugin-sdk) to rn-bundle/index.bundle.js, plain-object export — read this before authoring any MOBILE widget.",
467
+ "What to fetch: 'overview' = API overview + endpoints, 'skill' = full skill spec, 'solution' = full solution spec, 'enums' = all enum values, 'connector-multi-user' = multi-user connector guide, 'python_helpers' = adas.* helper namespace for run_python_script orchestration (read this when designing personas that read state → call tools → checkpoint → status; without it, scripts hand-roll JSON parsing and tool delegation = 5-10x larger and brittler), 'widgets' = widget (UI plugin) spec: catalog model, how_to_use block shape (solution.json snippet + opener_call + persona_phrasing + binding_notes), and rules for declaring ui_plugins. Pair with ateam_get_widget_catalog for the live per-tenant inventory. 'ui-plugins' = the DEEP React Native (mobile) plugin build guide: author in rn-src/, compile with a build:rn esbuild script (format=cjs, target=es2015, external react/react-native/@adas/plugin-sdk) to rn-bundle/index.bundle.js, plain-object export — read this before authoring any MOBILE widget. 'monitoring' = THE MONITORING CONTRACT: which tools are safe to call in a poll loop (with cost / poll interval / whether output stays bounded as the run grows), which are not and what to use instead, plus the running ateam-mcp version. Read this BEFORE writing any loop that watches a build — the safe poll is ateam_chain_status, never ateam_get_chain.",
456
468
  },
457
469
  section: {
458
470
  type: "string",
@@ -1356,6 +1368,10 @@ export const tools = [
1356
1368
  {
1357
1369
  name: "ateam_test_status",
1358
1370
  core: true,
1371
+ // Monitoring-safe for ONE test job (bounded), but include_chain:true pulls the
1372
+ // full tree — that call is NOT safe to loop.
1373
+ monitoring: { safe: true, cost: "cheap", latency_ms_p95: 500, output: "bounded", poll_interval_s: 2,
1374
+ note: "safe:false when include_chain:true (that fetches the full tree)." },
1359
1375
  description:
1360
1376
  "Poll the progress of an async skill test. Returns iteration count, tool call steps, status (running/completed/failed), and result when done.\n\n" +
1361
1377
  "Set include_chain:true to ALSO include the full chain tree (every job in the chain, rooted at this job_id, with parent/child linkage). Use when this job dispatched askAnySkill subcalls and you want a single snapshot of the whole multi-skill state instead of polling each child job_id separately.",
@@ -1386,6 +1402,10 @@ export const tools = [
1386
1402
  {
1387
1403
  name: "ateam_get_chain",
1388
1404
  core: true,
1405
+ // NOT monitoring-safe: returns the FULL job tree — output grows with the run
1406
+ // (a 200-step job returns 200 steps), which is the property that silently
1407
+ // degrades. Use once at the end; poll ateam_chain_status instead.
1408
+ monitoring: { safe: false, cost: "heavy", output: "grows_with_run", use_instead: "ateam_chain_status" },
1389
1409
  description:
1390
1410
  "Inspect the full chain tree for any job — rooted at the given job_id, walking down through every handoff and askAnySkill subcall.\n\n" +
1391
1411
  "Use when a chain has already run and you want to analyze the structure: which skill called which, how deep the call tree went, which tool inside which job invoked which sub-tool. The two main shapes:\n" +
@@ -1411,6 +1431,17 @@ export const tools = [
1411
1431
  {
1412
1432
  name: "ateam_chain_status",
1413
1433
  core: true,
1434
+ // MONITORING-SAFE — the one tool built for a poll loop. See MONITORING_CONTRACT.
1435
+ // cheap: one status read, no tree walk, no LLM. bounded: the response does NOT
1436
+ // grow with the run (a 200-step job returns the same shape as a 2-step one).
1437
+ monitoring: {
1438
+ safe: true,
1439
+ cost: "cheap",
1440
+ latency_ms_p95: 500,
1441
+ output: "bounded",
1442
+ poll_interval_s: 2,
1443
+ note: "Returns last_activity_at / idle_seconds / activity_source. A LARGE idle_seconds does NOT mean dead — on this platform a healthy build sits minutes inside a single provider call. Read activity_source (what it was doing) with it; never apply an 'idle > N ⇒ dead' rule.",
1444
+ },
1414
1445
  description:
1415
1446
  "SLIM chain status — the chip-quick poll. Given a chain_id (from ateam_conversation), returns the WHOLE-CHAIN aggregate status cheaply: chain_status + chain_done (true only when the ENTIRE chain — root job + every handoff + askAnySkill subcall — is terminal), plus pending_question, result, and a short progress line.\n\n" +
1416
1447
  "This is what you poll on a loop after ateam_conversation — NOT ateam_get_chain (that returns the full tree; too heavy for periodic polling). A single job can finish while the chain is still running, so poll chain_done, not a job's status.\n\n" +
@@ -1543,6 +1574,7 @@ export const tools = [
1543
1574
  },
1544
1575
  {
1545
1576
  name: "ateam_get_metrics",
1577
+ monitoring: { safe: true, cost: "cheap", latency_ms_p95: 1000, output: "bounded", poll_interval_s: 30 },
1546
1578
  // Advertised (was core:false): these are the RUNTIME DIAGNOSTICS a caller needs
1547
1579
  // mid-run, but a connector-wildcard grant expands over ADVERTISED tools only, so
1548
1580
  // hiding them made them ungrantable — invisible to every agent that needed them.
@@ -1571,6 +1603,9 @@ export const tools = [
1571
1603
  {
1572
1604
  name: "ateam_verify",
1573
1605
  core: true,
1606
+ // Real end-state check — probes connectors/widgets/skills. Correct but SLOW;
1607
+ // for a run in flight poll ateam_chain_status and call this once at the end.
1608
+ monitoring: { safe: false, cost: "heavy", output: "bounded", use_instead: "ateam_chain_status" },
1574
1609
  description:
1575
1610
  "ONE call that returns the REAL runtime end-state of a solution — connectors connected + tools discovered, every declared widget actually rendering, skills deployed — with the EXACT failing gaps. Use this instead of guess-and-check after a deploy/patch: it tells you the truth (what's actually live) and names precisely what's broken, not a generic warning. Reliable from any connection (routes through the Builder, not a direct Core call).",
1576
1611
  inputSchema: {
@@ -1877,7 +1912,7 @@ export const tools = [
1877
1912
  "SHIP DEV TO PROD. Merges the `dev` branch into `main` and auto-tags the new main HEAD as safe-YYYY-MM-DD-NNN. " +
1878
1913
  "Use after testing your dev work, when you're ready to deploy changes to production.\n\n" +
1879
1914
  "Workflow: 1) ateam_github_patch (writes to dev) → 2) ateam_github_promote (merges dev→main) → 3) ateam_build_and_run (deploys main).\n\n" +
1880
- "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.",
1915
+ "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).",
1881
1916
  inputSchema: {
1882
1917
  type: "object",
1883
1918
  properties: {
@@ -1901,6 +1936,31 @@ export const tools = [
1901
1936
  required: ["solution_id"],
1902
1937
  },
1903
1938
  },
1939
+ {
1940
+ name: "ateam_github_sync_from_main",
1941
+ core: true,
1942
+ description:
1943
+ "BRING `dev` UP TO DATE WITH `main` — merges main into dev. The mirror of ateam_github_promote.\n\n" +
1944
+ "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" +
1945
+ "Workflow on a 409: 1) ateam_github_diff (confirm status:'diverged') → 2) ateam_github_sync_from_main → 3) ateam_github_promote.\n\n" +
1946
+ "Pass dry_run:true FIRST to see exactly which commits and files would come into dev without changing anything.\n\n" +
1947
+ "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).",
1948
+ monitoring: { safe: true, cost: "low", latency_ms_p95: 2500, output: "bounded" },
1949
+ inputSchema: {
1950
+ type: "object",
1951
+ properties: {
1952
+ solution_id: {
1953
+ type: "string",
1954
+ description: "The solution ID",
1955
+ },
1956
+ dry_run: {
1957
+ type: "boolean",
1958
+ description: "If true: show the commits + files that would merge into dev, change nothing. Default: false. Call this first.",
1959
+ },
1960
+ },
1961
+ required: ["solution_id"],
1962
+ },
1963
+ },
1904
1964
  {
1905
1965
  name: "ateam_github_rollback",
1906
1966
  core: true,
@@ -1976,6 +2036,8 @@ export const tools = [
1976
2036
  {
1977
2037
  name: "ateam_connector_logs",
1978
2038
  core: true,
2039
+ // Bounded by the caller's line limit, but it reads container logs — poll slowly.
2040
+ monitoring: { safe: true, cost: "moderate", latency_ms_p95: 3000, output: "bounded", poll_interval_s: 30 },
1979
2041
  description:
1980
2042
  "Read what a connector process actually PRINTED to stderr. This is the only place a connector's " +
1981
2043
  "internal failure is visible: a tool that catches its own error still returns ok:true, and the widget " +
@@ -2027,6 +2089,8 @@ export const tools = [
2027
2089
  {
2028
2090
  name: "ateam_status_all",
2029
2091
  core: true,
2092
+ // Safe but not cheap-per-second: health across ALL solutions. Poll sparingly.
2093
+ monitoring: { safe: true, cost: "moderate", latency_ms_p95: 3000, output: "bounded", poll_interval_s: 30 },
2030
2094
  description:
2031
2095
  "Show GitHub sync status for ALL tenants and solutions in one call. Requires master key authentication. Returns a summary table of every tenant's solutions with their GitHub sync state.",
2032
2096
  inputSchema: {
@@ -2061,6 +2125,23 @@ export const tools = [
2061
2125
  */
2062
2126
  export const coreTools = tools.filter(t => t.core !== false);
2063
2127
 
2128
+ // MONITORING CONTRACT — machine-filterable answer to "what may I poll on a loop?"
2129
+ // The knowledge used to exist only as prose, scattered and contradictory across
2130
+ // tool descriptions ("too heavy to loop on" in one, "poll every ~2s" in another,
2131
+ // different words, different tools), so a caller had to read paragraphs carefully
2132
+ // to learn which call was safe in a loop. Now it is a field.
2133
+ // safe — may be called repeatedly in a poll loop
2134
+ // cost — cheap | moderate | heavy
2135
+ // output — "bounded" means bounded IN THE RUN'S SIZE, not merely small
2136
+ // today. The silent-degradation failure is a tool that is
2137
+ // concise on a 5-step job and returns 200 steps on a 200-step
2138
+ // job; that is output:"grows_with_run", never safe.
2139
+ // poll_interval_s — the interval the tool is designed for
2140
+ // A tool with NO monitoring field is UNCLASSIFIED — treat as unsafe to poll.
2141
+ export const monitoringTools = tools
2142
+ .filter(t => t.monitoring?.safe === true)
2143
+ .map(t => ({ name: t.name, ...t.monitoring }));
2144
+
2064
2145
  // ─── Tool handlers ──────────────────────────────────────────────────
2065
2146
 
2066
2147
  const SPEC_PATHS = {
@@ -2612,6 +2693,11 @@ module.exports.default = plugin;
2612
2693
 
2613
2694
  const handlers = {
2614
2695
  ateam_bootstrap: async () => ({
2696
+ runtime: {
2697
+ ateam_mcp_version: MCP_VERSION,
2698
+ base_url: getBaseUrl(),
2699
+ _note: "The version of the ateam-mcp process actually serving this call, and the API it talks to. If a fix looks missing, check this FIRST — a local MCP process keeps running the code it loaded at session start, so a pushed/published fix is not live until the process restarts.",
2700
+ },
2615
2701
  platform_positioning: {
2616
2702
  name: "A-Team",
2617
2703
  category: "AI Team Solution Platform",
@@ -2977,6 +3063,25 @@ const handlers = {
2977
3063
  },
2978
3064
 
2979
3065
  ateam_get_spec: async ({ topic, section, search }, sid) => {
3066
+ // Served LOCALLY (no round-trip): the monitoring contract is a property of
3067
+ // THIS ateam-mcp build, so it must answer even when the API is unreachable —
3068
+ // that is exactly when a caller is asking "what can I poll to find out?".
3069
+ if (topic === "monitoring") {
3070
+ return {
3071
+ ateam_mcp_version: MCP_VERSION,
3072
+ safe_to_poll: monitoringTools,
3073
+ not_safe_to_poll: tools
3074
+ .filter(t => t.monitoring?.safe === false)
3075
+ .map(t => ({ name: t.name, cost: t.monitoring.cost, output: t.monitoring.output, use_instead: t.monitoring.use_instead })),
3076
+ unclassified_are_unsafe: true,
3077
+ rules: [
3078
+ "output:'bounded' means bounded IN THE RUN'S SIZE — not merely small today. A tool that returns 200 steps for a 200-step job is grows_with_run and is never poll-safe.",
3079
+ "A tool with no monitoring field is UNCLASSIFIED — treat it as unsafe to poll.",
3080
+ "NEVER apply an 'idle_seconds > N ⇒ dead' rule. On this platform a healthy build regularly sits minutes inside a single provider call; read activity_source alongside it.",
3081
+ ],
3082
+ watching_a_run: "Poll ateam_chain_status (every ~2s, or ~30s for a long build) and read chain_done + last_activity_at/idle_seconds/activity_source. Call ateam_get_chain ONCE at the end for the full tree.",
3083
+ };
3084
+ }
2980
3085
  let path = SPEC_PATHS[topic];
2981
3086
  const params = new URLSearchParams();
2982
3087
  if (section) params.set('section', section);
@@ -4722,6 +4827,9 @@ const handlers = {
4722
4827
  ateam_github_promote: async ({ solution_id, label, dry_run, skip_tag }, sid) =>
4723
4828
  post(`/deploy/solutions/${solution_id}/promote`, { label, dry_run, skip_tag }, sid),
4724
4829
 
4830
+ ateam_github_sync_from_main: async ({ solution_id, dry_run }, sid) =>
4831
+ post(`/deploy/solutions/${solution_id}/sync-from-main`, { dry_run }, sid),
4832
+
4725
4833
  ateam_github_rollback: async ({ solution_id, target, tag }, sid) =>
4726
4834
  // Accept both `target` (new spec) and `tag` (legacy callers)
4727
4835
  post(`/deploy/solutions/${solution_id}/rollback`, { target: target || tag }, sid),