@ateam-ai/mcp 0.4.26 → 0.4.28

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 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.4.26",
3
+ "version": "0.4.28",
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
@@ -12,7 +12,7 @@ import {
12
12
  get, post, patch, del,
13
13
  setSessionCredentials, isAuthenticated, isExplicitlyAuthenticated,
14
14
  getCredentials, parseApiKey, touchSession, getSessionContext,
15
- setAuthOverride, switchTenant, isMasterMode, listTenants, getWhere,
15
+ setAuthOverride, switchTenant, isMasterMode, listTenants, getWhere, getBaseUrl,
16
16
  } from "./api.js";
17
17
 
18
18
  // Mutating / stateful tools whose result should carry a `_where` stamp
@@ -332,9 +332,9 @@ export const tools = [
332
332
  properties: {
333
333
  topic: {
334
334
  type: "string",
335
- enum: ["overview", "skill", "solution", "enums", "connector-multi-user", "python_helpers", "widgets"],
335
+ 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"],
336
336
  description:
337
- "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.",
337
+ "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.",
338
338
  },
339
339
  section: {
340
340
  type: "string",
@@ -371,9 +371,9 @@ export const tools = [
371
371
  properties: {
372
372
  type: {
373
373
  type: "string",
374
- enum: ["skill", "connector", "connector-ui", "solution", "script-cache-skill", "index"],
374
+ enum: ["skill", "connector", "connector-ui", "solution", "script-cache-skill", "ui-plugin-native", "index"],
375
375
  description:
376
- "Example type: 'skill' = Order Support Agent, 'connector' = stdio MCP connector, 'connector-ui' = UI-capable connector, 'solution' = full 3-skill e-commerce solution, 'script-cache-skill' = fat-tool skill with script_cache opt-in (reference implementation of script-level JIT shortcuts — study this before building any browser-automation skill), 'index' = list all available examples",
376
+ "Example type: 'skill' = Order Support Agent, 'connector' = stdio MCP connector, 'connector-ui' = UI-capable connector, 'solution' = full 3-skill e-commerce solution, 'script-cache-skill' = fat-tool skill with script_cache opt-in (reference implementation of script-level JIT shortcuts — study this before building any browser-automation skill), 'ui-plugin-native' = complete working React Native (mobile) UI plugin (rn-src/index.tsx + esbuild build:rn → rn-bundle, @adas/plugin-sdk, es2015), 'index' = list all available examples",
377
377
  },
378
378
  },
379
379
  required: ["type"],
@@ -1862,6 +1862,17 @@ const SPEC_PATHS = {
1862
1862
  "connector-multi-user": "/spec/multi-user-connector",
1863
1863
  python_helpers: "/spec/python_helpers",
1864
1864
  widgets: "/spec/widgets",
1865
+ "ui-plugins": "/spec/ui-plugins",
1866
+ // Capability topics — MUST stay in sync with the capability catalog's
1867
+ // spec_topic values so every ateam_design_advisor `read_spec` pointer
1868
+ // resolves (was OPEN-19: advisor pointed at topics get_spec didn't accept).
1869
+ "actor-storage": "/spec/actor-storage",
1870
+ voice: "/spec/voice",
1871
+ "voice-native": "/spec/voice-native",
1872
+ triggers: "/spec/triggers",
1873
+ "sub-agent": "/spec/sub-agent",
1874
+ "consumer-roles": "/spec/consumer-roles",
1875
+ "mobile-connector": "/spec/mobile-connector",
1865
1876
  };
1866
1877
 
1867
1878
  const EXAMPLE_PATHS = {
@@ -1871,6 +1882,7 @@ const EXAMPLE_PATHS = {
1871
1882
  "connector-ui": "/spec/examples/connector-ui",
1872
1883
  solution: "/spec/examples/solution",
1873
1884
  "script-cache-skill": "/spec/examples/script-cache-skill",
1885
+ "ui-plugin-native": "/spec/examples/ui-plugin-native",
1874
1886
  };
1875
1887
 
1876
1888
  // Tools that are tenant-aware — require EXPLICIT ateam_auth (env vars alone not enough).
@@ -2102,10 +2114,15 @@ the \`tools/call\` dispatch. Data tools are per-actor — call \`getActorId(args
2102
2114
  ## Adding UI plugins (ui_capable connectors)
2103
2115
 
2104
2116
  Use \`ateam_create_plugin\` (or drop the files yourself): iframe plugins go under
2105
- \`ui-dist/<plugin-name>/index.html\` with a \`ui-dist/<plugin-name>/manifest.json\`
2106
- (RN under \`plugins/<plugin-name>/index.tsx\`). This connector's
2107
- \`ui.listPlugins\` / \`ui.getPlugin\` read those manifests at call time, so a new
2108
- plugin renders with NO server.js edit.
2117
+ \`ui-dist/<plugin-name>/index.html\` with a \`ui-dist/<plugin-name>/manifest.json\`.
2118
+ RN plugins have editable source at \`rn-src/<plugin-name>.tsx\` (imported from
2119
+ \`@adas/plugin-sdk\`) AND a PRE-BUILT, COMMITTED bundle at
2120
+ \`rn-bundle/<plugin-name>.bundle.js\` the mobile
2121
+ app downloads the bundle, and Core never compiles the .tsx (deploys run
2122
+ \`npm install --no-optional\`, which skips esbuild). After editing the .tsx,
2123
+ rebuild the bundle with the esbuild command in its header and commit it. This
2124
+ connector's \`ui.listPlugins\` / \`ui.getPlugin\` read the manifests at call time,
2125
+ so a new plugin renders with NO server.js edit.
2109
2126
 
2110
2127
  ## Deploy
2111
2128
 
@@ -2187,15 +2204,24 @@ function _scaffoldPluginFiles({ connectorId, pluginName, kind }) {
2187
2204
  }
2188
2205
 
2189
2206
  if (kind === "rn" || kind === "adaptive") {
2190
- const tsx = `// ${pluginName} — React Native plugin. Generated by ateam_create_plugin.
2207
+ const tsx = `// ${pluginName} — React Native plugin SOURCE (editable). Generated by ateam_create_plugin.
2191
2208
  //
2192
- // Fill in the Component body. Imports, hooks, default export shape are
2193
- // template-provided Phase 7 of the strip eliminates this boilerplate.
2209
+ // ⚠️ Core does NOT compile this .tsx. Deploys run "npm install --production
2210
+ // --no-optional" (which skips esbuild's platform binary) and only ever run a
2211
+ // "build" script — never "build:rn". The mobile app therefore loads the
2212
+ // PRE-BUILT, COMMITTED bundle at rn-bundle/${pluginName}.bundle.js, NOT this
2213
+ // file. cp.getContextPlugin advertises reactNative.bundleUrl only when that
2214
+ // bundle exists on disk — no bundle → mobile has nothing to download.
2215
+ //
2216
+ // After editing this file, rebuild the bundle and commit it (target=es2015 is
2217
+ // REQUIRED — the mobile runtime evals the bundle with new Function(), which
2218
+ // cannot parse async/await; es2015 downlevels it):
2219
+ // npx esbuild rn-src/${pluginName}.tsx --bundle --format=cjs --platform=neutral --target=es2015 --external:react --external:react-native --external:@adas/plugin-sdk --outfile=rn-bundle/${pluginName}.bundle.js
2194
2220
 
2195
2221
  import React, { useState } from 'react';
2196
2222
  import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
2197
- import { useApi } from '../../plugin-sdk';
2198
- import type { PluginProps } from '../../plugin-sdk/types';
2223
+ import { useApi } from '@adas/plugin-sdk';
2224
+ import type { PluginProps } from '@adas/plugin-sdk';
2199
2225
 
2200
2226
  // Plain object export — NO PluginSDK.register() (pollutes shared registry).
2201
2227
  export default {
@@ -2214,7 +2240,7 @@ export default {
2214
2240
  const result = await api.call('${connectorId}.echo', { message: 'hello' });
2215
2241
  setOutput(JSON.stringify(result, null, 2));
2216
2242
  } catch (err: any) {
2217
- native?.haptics?.error?.();
2243
+ native?.haptics?.notification?.('error');
2218
2244
  setOutput('Error: ' + err.message);
2219
2245
  }
2220
2246
  };
@@ -2246,9 +2272,88 @@ export default {
2246
2272
  };
2247
2273
  `;
2248
2274
  files.push({
2249
- path: `plugins/${pluginName}/index.tsx`,
2275
+ path: `rn-src/${pluginName}.tsx`,
2250
2276
  content: tsx,
2251
2277
  });
2278
+
2279
+ // Pre-built RN bundle — THIS is the file the mobile app actually downloads.
2280
+ // cp.getContextPlugin only advertises reactNative.bundleUrl when a
2281
+ // rn-bundle/<pluginId>.bundle.js (or index.bundle.js) exists on disk; the
2282
+ // deploy pipeline can't produce it (npm install --no-optional skips esbuild,
2283
+ // and only a "build" script would run — not "build:rn"), so we SHIP it
2284
+ // pre-built and committed. Without this file the manifest carries
2285
+ // render.reactNative.component but no bundleUrl and mobile renders nothing
2286
+ // (the web iframe still works). Named per-plugin (matches cp.getContextPlugin's
2287
+ // \`${'$'}{pluginId}.bundle.js\` primary lookup) so multiple RN widgets can
2288
+ // coexist in one connector. Kept in sync with the .tsx above via the esbuild
2289
+ // command in its header. es2015 CJS, plain-object default export, no
2290
+ // async/await — passes the mobile new Function() load test.
2291
+ const rnBundle = `"use strict";
2292
+ // ${pluginName} — pre-built React Native bundle (es2015 CJS). Generated by
2293
+ // ateam_create_plugin from rn-src/${pluginName}.tsx. DO NOT hand-edit —
2294
+ // edit the .tsx and rerun the esbuild command in its header, then commit this.
2295
+ var React = require("react");
2296
+ var ReactNative = require("react-native");
2297
+ var sdk = require("@adas/plugin-sdk");
2298
+ var useState = React.useState;
2299
+ var h = React.createElement;
2300
+ var View = ReactNative.View;
2301
+ var Text = ReactNative.Text;
2302
+ var TouchableOpacity = ReactNative.TouchableOpacity;
2303
+ var StyleSheet = ReactNative.StyleSheet;
2304
+ var useApi = sdk.useApi;
2305
+
2306
+ function Component(props) {
2307
+ var native = props.native, theme = props.theme;
2308
+ var api = useApi(props.bridge);
2309
+ var _s = useState(""), output = _s[0], setOutput = _s[1];
2310
+
2311
+ function handlePress() {
2312
+ if (native && native.haptics && native.haptics.selection) native.haptics.selection();
2313
+ api.call("${connectorId}.echo", { message: "hello" }).then(function (result) {
2314
+ setOutput(JSON.stringify(result, null, 2));
2315
+ }, function (err) {
2316
+ if (native && native.haptics && native.haptics.notification) native.haptics.notification("error");
2317
+ setOutput("Error: " + (err && err.message ? err.message : String(err)));
2318
+ });
2319
+ }
2320
+
2321
+ var c = theme.colors;
2322
+ var styles = StyleSheet.create({
2323
+ container: { padding: 16, backgroundColor: c.bg, flex: 1 },
2324
+ card: { backgroundColor: c.surface, padding: 12, borderRadius: 8 },
2325
+ title: { fontSize: 18, fontWeight: "600", color: c.text, marginBottom: 8 },
2326
+ button: { backgroundColor: c.accent, padding: 12, borderRadius: 6, marginTop: 12 },
2327
+ buttonText: { color: "#fff", textAlign: "center", fontWeight: "600" },
2328
+ output: { color: c.textMuted, marginTop: 12, fontFamily: "Menlo" }
2329
+ });
2330
+
2331
+ return h(View, { style: styles.container },
2332
+ h(View, { style: styles.card },
2333
+ h(Text, { style: styles.title }, "${pluginName}"),
2334
+ h(Text, { style: { color: c.textMuted } }, "Plugin body — replace with your real UI."),
2335
+ h(TouchableOpacity, { style: styles.button, onPress: handlePress },
2336
+ h(Text, { style: styles.buttonText }, "Call sample tool")),
2337
+ output ? h(Text, { style: styles.output }, output) : null
2338
+ )
2339
+ );
2340
+ }
2341
+
2342
+ var plugin = {
2343
+ id: "${pluginName}",
2344
+ type: "ui",
2345
+ version: "1.0.0",
2346
+ capabilities: { haptics: true },
2347
+ Component: Component
2348
+ };
2349
+
2350
+ module.exports = plugin;
2351
+ module.exports.default = plugin;
2352
+ `;
2353
+ files.push({
2354
+ path: `rn-bundle/${pluginName}.bundle.js`,
2355
+ content: rnBundle,
2356
+ });
2252
2357
  }
2253
2358
 
2254
2359
  // Emit a manifest.json with the render block the platform requires. A plugin
@@ -2628,10 +2733,20 @@ const handlers = {
2628
2733
  message: `Authenticated to tenant "${resolvedTenant}"${urlNote}. ${result.solutions?.length || 0} solution(s) found.`,
2629
2734
  };
2630
2735
  } catch (err) {
2736
+ // OPEN-18: a well-formed `adas_<tenant>_<hex>` key that's rejected is often
2737
+ // a key for the OTHER environment (a dev key against the prod base, or vice
2738
+ // versa). Surface the base we tried and, if it looks like that mismatch,
2739
+ // hint the dev-api retry — instead of a generic "invalid/unconfigured key".
2740
+ const base = getBaseUrl(sessionId) || "";
2741
+ const wellFormedKey = parseApiKey(api_key).isValid;
2742
+ const triedProd = /(?:^|\/\/)api\.ateam-ai\.com/.test(base);
2743
+ const hint = wellFormedKey && triedProd
2744
+ ? ` This is a well-formed tenant key ("adas_${resolvedTenant}_…") but ${base} rejected it — if it's a DEV key, retry: ateam_auth(api_key, url:"https://dev-api.ateam-ai.com").`
2745
+ : ` (tried ${base || "the default base"})`;
2631
2746
  return {
2632
2747
  ok: false,
2633
2748
  tenant: resolvedTenant,
2634
- message: `Authentication failed: ${err.message}. The user can get a valid API key at https://mcp.ateam-ai.com/get-api-key`,
2749
+ message: `Authentication failed: ${err.message}.${hint} The user can get a valid API key at https://mcp.ateam-ai.com/get-api-key`,
2635
2750
  };
2636
2751
  }
2637
2752
  },
@@ -4350,7 +4465,7 @@ const handlers = {
4350
4465
  verified,
4351
4466
  next_steps: [
4352
4467
  k === "rn" || k === "adaptive"
4353
- ? `Edit plugins/${plugin_name}/index.tsx — fill in the Component body.`
4468
+ ? `Edit rn-src/${plugin_name}.tsx — fill in the Component body, THEN rebuild + commit rn-bundle/${plugin_name}.bundle.js (esbuild command is in the .tsx header). Core does NOT compile the .tsx — mobile loads the committed bundle. A pre-built starter bundle ships with this scaffold, so it renders as-is until you edit it.`
4354
4469
  : null,
4355
4470
  k === "iframe" || k === "adaptive"
4356
4471
  ? `Edit ui-dist/${plugin_name}/index.html — replace the placeholder UI.`