@ateam-ai/mcp 0.4.34 → 0.4.36

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 +58 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.34",
3
+ "version": "0.4.36",
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
@@ -116,6 +116,32 @@ function _summarizeDef(def) {
116
116
  };
117
117
  }
118
118
 
119
+ // OPEN-8: byte offset/limit paging for reads that can exceed the ~50KB output
120
+ // cap. Serializes the result to pretty JSON and returns a [offset, offset+limit)
121
+ // slice plus a cursor so an agent can page the rest (like Read offset/limit).
122
+ function _pageJson(data, offset = 0, limit) {
123
+ const full = typeof data === "string" ? data : JSON.stringify(data, null, 2);
124
+ const total = full.length;
125
+ const start = Math.min(Math.max(0, Math.trunc(offset) || 0), total);
126
+ const size = (limit != null) ? Math.max(1, Math.trunc(limit)) : (total - start);
127
+ const chunk = full.slice(start, start + size);
128
+ const end = start + chunk.length;
129
+ return {
130
+ ok: true,
131
+ _paging: {
132
+ offset: start,
133
+ limit: (limit != null) ? size : null,
134
+ returned_bytes: chunk.length,
135
+ total_bytes: total,
136
+ next_offset: end < total ? end : null,
137
+ has_more: end < total,
138
+ note: end < total ? `Truncated to bytes ${start}-${end} of ${total}. Fetch the next page with offset:${end}.` : `Complete (bytes ${start}-${end} of ${total}).`,
139
+ },
140
+ // Raw JSON text slice — parse only once you've concatenated all pages.
141
+ content: chunk,
142
+ };
143
+ }
144
+
119
145
  function _widgetHasRender(r) {
120
146
  if (!r || typeof r !== "object" || !r.mode) return false;
121
147
  const hasIframe = !!(r.iframeUrl || r.iframe?.iframeUrl);
@@ -779,6 +805,18 @@ export const tools = [
779
805
  type: "string",
780
806
  description: "Optional: read a specific skill by ID (original or internal)",
781
807
  },
808
+ section: {
809
+ type: "string",
810
+ description: "Optional (with skill_id): return ONLY this section of the skill instead of the whole definition — avoids the ~50KB output truncation on big skills. Dotted paths work (e.g. 'role', 'tools', 'intents.supported', 'policy', 'engine'). Omit for the full skill; use ateam_show_skill_minimal for the slim authoring view.",
811
+ },
812
+ offset: {
813
+ type: "number",
814
+ description: "Optional byte-paging: start returning the serialized result from this byte offset. Use with 'limit' to page a result larger than the ~50KB output cap; the response's _paging.next_offset gives the next page (null when done). Concatenate the `content` slices across pages, then JSON.parse.",
815
+ },
816
+ limit: {
817
+ type: "number",
818
+ description: "Optional byte-paging: max bytes of the serialized result to return in this page (pair with 'offset'). Omit both for the whole result (may truncate at the output cap).",
819
+ },
782
820
  },
783
821
  required: ["solution_id", "view"],
784
822
  },
@@ -3668,9 +3706,25 @@ const handlers = {
3668
3706
  return { ...raw, solutions: enriched };
3669
3707
  },
3670
3708
 
3671
- ateam_get_solution: async ({ solution_id, view, skill_id }, sid) => {
3709
+ ateam_get_solution: async ({ solution_id, view, skill_id, section, offset, limit }, sid) => {
3672
3710
  const base = `/deploy/solutions/${solution_id}`;
3673
- if (skill_id) return get(`${base}/skills/${skill_id}`, sid);
3711
+ const paged = (offset != null || limit != null);
3712
+ if (skill_id) {
3713
+ const r = await get(`${base}/skills/${skill_id}`, sid);
3714
+ // OPEN-8: a single skill def can be 50KB+ and truncate at the output cap.
3715
+ // `section` slices it to one field (dotted paths ok, e.g. intents.supported);
3716
+ // offset/limit page the raw bytes — so a big skill is always readable.
3717
+ let result = r;
3718
+ if (section) {
3719
+ const skill = r?.skill || r?.definition || r || {};
3720
+ const val = String(section).split(".").reduce((o, k) => (o == null ? undefined : o[k]), skill);
3721
+ result = {
3722
+ ok: true, solution_id, skill_id, section, [section]: val,
3723
+ _note: `Sliced to '${section}'. Omit 'section' for the full skill; ateam_show_skill_minimal gives the slim authoring view.`,
3724
+ };
3725
+ }
3726
+ return paged ? _pageJson(result, offset, limit) : result;
3727
+ }
3674
3728
  const paths = {
3675
3729
  definition: `${base}/definition`,
3676
3730
  skills: `${base}/skills`,
@@ -3680,7 +3734,8 @@ const handlers = {
3680
3734
  validate: `${base}/validate`,
3681
3735
  connectors_health: `${base}/connectors/health`,
3682
3736
  };
3683
- return get(paths[view], sid);
3737
+ const viewResult = await get(paths[view], sid);
3738
+ return paged ? _pageJson(viewResult, offset, limit) : viewResult;
3684
3739
  },
3685
3740
 
3686
3741
  ateam_update: async ({ solution_id, target, skill_id, updates }, sid) => {