@ateam-ai/mcp 0.4.37 → 0.4.39

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 +40 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.37",
3
+ "version": "0.4.39",
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
@@ -1026,6 +1026,7 @@ export const tools = [
1026
1026
  " • github:true + files:[] — GitHub state at `ref` as BASE, your files overlay on top (incoming wins).\n" +
1027
1027
  " • files:[] (no github) — default MERGE with GitHub state at `ref`. Refuses if no GitHub base exists (no silent nuke).\n" +
1028
1028
  " • files:[] + replace:true — full replace. Wipes connector dir + writes only the provided files. Use deliberately.\n\n" +
1029
+ "Multi-file connectors (server.js + dashboard HTML + RN bundle + package/manifest): pass each file with content_base64 (a single-line, escape-safe base64 string) instead of content — so you don't hand-escape ~90KB of HTML/JS/JSON inside one tool call. This is the CANONICAL agent path for a full connector; do NOT hand-roll `curl` against the raw endpoint (that skips connector registration / PAT provisioning).\n\n" +
1029
1030
  "Common traps this design prevents:\n" +
1030
1031
  " • Pre-fix bug (2026-06-06): sending just ui-dist HTML wiped server.js + node_modules — connector broke until a full re-upload. Now: those files merge with the GitHub base.\n" +
1031
1032
  " • Pre-fix bug: github:true silently read from `main` even when patches were on `dev`. Now: defaults to dev; pass ref:'main' to opt into the legacy path.",
@@ -1054,16 +1055,21 @@ export const tools = [
1054
1055
  type: "object",
1055
1056
  properties: {
1056
1057
  path: { type: "string", description: "Relative file path (e.g. 'server.js', 'ui-dist/panel/index.html')" },
1057
- content: { type: "string", description: "File content" },
1058
+ content: { type: "string", description: "File content as an inline string. Prefer content_base64 when the content has complex escaping (HTML/JS/JSON)." },
1059
+ content_base64: { type: "string", description: "File content as a single-line base64 string — escape-safe. PREFERRED for a multi-file connector so large HTML/JS/bundles don't need hand-escaping in the tool call. Provide exactly ONE of content / content_base64 per file." },
1058
1060
  },
1059
- required: ["path", "content"],
1061
+ required: ["path"],
1060
1062
  },
1061
- description: "Files to upload. By default merges with the GitHub state at `ref`. Set replace:true to wipe the connector dir and write only these files.",
1063
+ description: "Files to upload — each needs 'path' plus ONE of content (inline string) or content_base64 (escape-safe base64; preferred for multi-file connectors). By default merges with the GitHub state at `ref`. Set replace:true to wipe the connector dir and write only these files.",
1062
1064
  },
1063
1065
  replace: {
1064
1066
  type: "boolean",
1065
1067
  description: "Opt into FULL REPLACE: wipe the connector dir and write only the provided `files`. Default: false (= merge with GitHub state at `ref`). Use with intent — sending an incomplete file set with replace:true will break the connector.",
1066
1068
  },
1069
+ force: {
1070
+ type: "boolean",
1071
+ description: "RECOVERY: respawn the connector + re-inject its CURRENT env even when the source is UNCHANGED. Normally an unchanged-source upload no-ops (unchanged:true) and leaves the process running. But a connector spawned before a shared-secret rotation keeps the STALE secret — it still lists tools (looks healthy) yet 401s on every per-actor call, with no recovery short of a fake source edit. Use `ateam_upload_connector(solution_id, connector_id, github:true, force:true)` to pull the current source and force a fresh respawn (which picks up the current secret). Default: false.",
1072
+ },
1067
1073
  },
1068
1074
  required: ["solution_id", "connector_id"],
1069
1075
  },
@@ -4462,15 +4468,44 @@ const handlers = {
4462
4468
  return del(`/deploy/solutions/${solution_id}/connectors/${connector_id}`, sid);
4463
4469
  },
4464
4470
 
4465
- ateam_upload_connector: async ({ solution_id, connector_id, github, files, ref, replace }, sid) => {
4471
+ ateam_upload_connector: async ({ solution_id, connector_id, github, files, ref, replace, force }, sid) => {
4472
+ // OPEN-32: accept content_base64 per file (single-line, escape-safe) and
4473
+ // decode it to plain content here, so an agent can upload a multi-file
4474
+ // connector without hand-escaping ~90KB of HTML/JS/JSON in one tool call —
4475
+ // and via THIS registered path (not a raw curl that skips PAT provisioning).
4476
+ let normFiles = files;
4477
+ if (Array.isArray(files)) {
4478
+ normFiles = files.map((f, i) => {
4479
+ if (!f || typeof f !== "object" || !f.path) {
4480
+ throw new Error(`ateam_upload_connector: files[${i}] must be an object with a 'path'.`);
4481
+ }
4482
+ const hasContent = typeof f.content === "string";
4483
+ const hasB64 = typeof f.content_base64 === "string";
4484
+ if (hasContent && hasB64) {
4485
+ throw new Error(`ateam_upload_connector: files[${i}] ("${f.path}") has BOTH content and content_base64 — provide exactly one.`);
4486
+ }
4487
+ if (!hasContent && !hasB64) {
4488
+ throw new Error(`ateam_upload_connector: files[${i}] ("${f.path}") needs 'content' (inline string) or 'content_base64' (escape-safe base64).`);
4489
+ }
4490
+ if (hasB64) {
4491
+ const decoded = Buffer.from(f.content_base64, "base64").toString("utf8");
4492
+ if (!decoded && f.content_base64.trim()) {
4493
+ throw new Error(`ateam_upload_connector: files[${i}] ("${f.path}") content_base64 did not decode to any content — check the encoding.`);
4494
+ }
4495
+ return { path: f.path, content: decoded };
4496
+ }
4497
+ return { path: f.path, content: f.content };
4498
+ });
4499
+ }
4466
4500
  // Async-first: this runs npm install + build in Core (up to ~7min) and is a
4467
4501
  // prime Cloudflare-524 culprit. Kick async → poll /deploy/jobs; fall back to
4468
4502
  // sync for older backends that don't honor async. Mirrors ateam_github_pull.
4469
4503
  const body = {
4470
4504
  github,
4471
- files,
4505
+ files: normFiles,
4472
4506
  ...(ref ? { ref } : {}),
4473
4507
  ...(replace === true ? { replace: true } : {}),
4508
+ ...(force === true ? { force: true } : {}),
4474
4509
  };
4475
4510
  const url = `/deploy/solutions/${solution_id}/connectors/${connector_id}/upload`;
4476
4511
  let kicked;