@ateam-ai/mcp 0.4.26 → 0.4.27

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 +111 -16
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.27",
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
@@ -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"],
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,7 @@ 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",
1865
1866
  };
1866
1867
 
1867
1868
  const EXAMPLE_PATHS = {
@@ -1871,6 +1872,7 @@ const EXAMPLE_PATHS = {
1871
1872
  "connector-ui": "/spec/examples/connector-ui",
1872
1873
  solution: "/spec/examples/solution",
1873
1874
  "script-cache-skill": "/spec/examples/script-cache-skill",
1875
+ "ui-plugin-native": "/spec/examples/ui-plugin-native",
1874
1876
  };
1875
1877
 
1876
1878
  // Tools that are tenant-aware — require EXPLICIT ateam_auth (env vars alone not enough).
@@ -2102,10 +2104,15 @@ the \`tools/call\` dispatch. Data tools are per-actor — call \`getActorId(args
2102
2104
  ## Adding UI plugins (ui_capable connectors)
2103
2105
 
2104
2106
  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.
2107
+ \`ui-dist/<plugin-name>/index.html\` with a \`ui-dist/<plugin-name>/manifest.json\`.
2108
+ RN plugins have editable source at \`rn-src/<plugin-name>.tsx\` (imported from
2109
+ \`@adas/plugin-sdk\`) AND a PRE-BUILT, COMMITTED bundle at
2110
+ \`rn-bundle/<plugin-name>.bundle.js\` the mobile
2111
+ app downloads the bundle, and Core never compiles the .tsx (deploys run
2112
+ \`npm install --no-optional\`, which skips esbuild). After editing the .tsx,
2113
+ rebuild the bundle with the esbuild command in its header and commit it. This
2114
+ connector's \`ui.listPlugins\` / \`ui.getPlugin\` read the manifests at call time,
2115
+ so a new plugin renders with NO server.js edit.
2109
2116
 
2110
2117
  ## Deploy
2111
2118
 
@@ -2187,15 +2194,24 @@ function _scaffoldPluginFiles({ connectorId, pluginName, kind }) {
2187
2194
  }
2188
2195
 
2189
2196
  if (kind === "rn" || kind === "adaptive") {
2190
- const tsx = `// ${pluginName} — React Native plugin. Generated by ateam_create_plugin.
2197
+ const tsx = `// ${pluginName} — React Native plugin SOURCE (editable). Generated by ateam_create_plugin.
2191
2198
  //
2192
- // Fill in the Component body. Imports, hooks, default export shape are
2193
- // template-provided Phase 7 of the strip eliminates this boilerplate.
2199
+ // ⚠️ Core does NOT compile this .tsx. Deploys run "npm install --production
2200
+ // --no-optional" (which skips esbuild's platform binary) and only ever run a
2201
+ // "build" script — never "build:rn". The mobile app therefore loads the
2202
+ // PRE-BUILT, COMMITTED bundle at rn-bundle/${pluginName}.bundle.js, NOT this
2203
+ // file. cp.getContextPlugin advertises reactNative.bundleUrl only when that
2204
+ // bundle exists on disk — no bundle → mobile has nothing to download.
2205
+ //
2206
+ // After editing this file, rebuild the bundle and commit it (target=es2015 is
2207
+ // REQUIRED — the mobile runtime evals the bundle with new Function(), which
2208
+ // cannot parse async/await; es2015 downlevels it):
2209
+ // 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
2210
 
2195
2211
  import React, { useState } from 'react';
2196
2212
  import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
2197
- import { useApi } from '../../plugin-sdk';
2198
- import type { PluginProps } from '../../plugin-sdk/types';
2213
+ import { useApi } from '@adas/plugin-sdk';
2214
+ import type { PluginProps } from '@adas/plugin-sdk';
2199
2215
 
2200
2216
  // Plain object export — NO PluginSDK.register() (pollutes shared registry).
2201
2217
  export default {
@@ -2214,7 +2230,7 @@ export default {
2214
2230
  const result = await api.call('${connectorId}.echo', { message: 'hello' });
2215
2231
  setOutput(JSON.stringify(result, null, 2));
2216
2232
  } catch (err: any) {
2217
- native?.haptics?.error?.();
2233
+ native?.haptics?.notification?.('error');
2218
2234
  setOutput('Error: ' + err.message);
2219
2235
  }
2220
2236
  };
@@ -2246,9 +2262,88 @@ export default {
2246
2262
  };
2247
2263
  `;
2248
2264
  files.push({
2249
- path: `plugins/${pluginName}/index.tsx`,
2265
+ path: `rn-src/${pluginName}.tsx`,
2250
2266
  content: tsx,
2251
2267
  });
2268
+
2269
+ // Pre-built RN bundle — THIS is the file the mobile app actually downloads.
2270
+ // cp.getContextPlugin only advertises reactNative.bundleUrl when a
2271
+ // rn-bundle/<pluginId>.bundle.js (or index.bundle.js) exists on disk; the
2272
+ // deploy pipeline can't produce it (npm install --no-optional skips esbuild,
2273
+ // and only a "build" script would run — not "build:rn"), so we SHIP it
2274
+ // pre-built and committed. Without this file the manifest carries
2275
+ // render.reactNative.component but no bundleUrl and mobile renders nothing
2276
+ // (the web iframe still works). Named per-plugin (matches cp.getContextPlugin's
2277
+ // \`${'$'}{pluginId}.bundle.js\` primary lookup) so multiple RN widgets can
2278
+ // coexist in one connector. Kept in sync with the .tsx above via the esbuild
2279
+ // command in its header. es2015 CJS, plain-object default export, no
2280
+ // async/await — passes the mobile new Function() load test.
2281
+ const rnBundle = `"use strict";
2282
+ // ${pluginName} — pre-built React Native bundle (es2015 CJS). Generated by
2283
+ // ateam_create_plugin from rn-src/${pluginName}.tsx. DO NOT hand-edit —
2284
+ // edit the .tsx and rerun the esbuild command in its header, then commit this.
2285
+ var React = require("react");
2286
+ var ReactNative = require("react-native");
2287
+ var sdk = require("@adas/plugin-sdk");
2288
+ var useState = React.useState;
2289
+ var h = React.createElement;
2290
+ var View = ReactNative.View;
2291
+ var Text = ReactNative.Text;
2292
+ var TouchableOpacity = ReactNative.TouchableOpacity;
2293
+ var StyleSheet = ReactNative.StyleSheet;
2294
+ var useApi = sdk.useApi;
2295
+
2296
+ function Component(props) {
2297
+ var native = props.native, theme = props.theme;
2298
+ var api = useApi(props.bridge);
2299
+ var _s = useState(""), output = _s[0], setOutput = _s[1];
2300
+
2301
+ function handlePress() {
2302
+ if (native && native.haptics && native.haptics.selection) native.haptics.selection();
2303
+ api.call("${connectorId}.echo", { message: "hello" }).then(function (result) {
2304
+ setOutput(JSON.stringify(result, null, 2));
2305
+ }, function (err) {
2306
+ if (native && native.haptics && native.haptics.notification) native.haptics.notification("error");
2307
+ setOutput("Error: " + (err && err.message ? err.message : String(err)));
2308
+ });
2309
+ }
2310
+
2311
+ var c = theme.colors;
2312
+ var styles = StyleSheet.create({
2313
+ container: { padding: 16, backgroundColor: c.bg, flex: 1 },
2314
+ card: { backgroundColor: c.surface, padding: 12, borderRadius: 8 },
2315
+ title: { fontSize: 18, fontWeight: "600", color: c.text, marginBottom: 8 },
2316
+ button: { backgroundColor: c.accent, padding: 12, borderRadius: 6, marginTop: 12 },
2317
+ buttonText: { color: "#fff", textAlign: "center", fontWeight: "600" },
2318
+ output: { color: c.textMuted, marginTop: 12, fontFamily: "Menlo" }
2319
+ });
2320
+
2321
+ return h(View, { style: styles.container },
2322
+ h(View, { style: styles.card },
2323
+ h(Text, { style: styles.title }, "${pluginName}"),
2324
+ h(Text, { style: { color: c.textMuted } }, "Plugin body — replace with your real UI."),
2325
+ h(TouchableOpacity, { style: styles.button, onPress: handlePress },
2326
+ h(Text, { style: styles.buttonText }, "Call sample tool")),
2327
+ output ? h(Text, { style: styles.output }, output) : null
2328
+ )
2329
+ );
2330
+ }
2331
+
2332
+ var plugin = {
2333
+ id: "${pluginName}",
2334
+ type: "ui",
2335
+ version: "1.0.0",
2336
+ capabilities: { haptics: true },
2337
+ Component: Component
2338
+ };
2339
+
2340
+ module.exports = plugin;
2341
+ module.exports.default = plugin;
2342
+ `;
2343
+ files.push({
2344
+ path: `rn-bundle/${pluginName}.bundle.js`,
2345
+ content: rnBundle,
2346
+ });
2252
2347
  }
2253
2348
 
2254
2349
  // Emit a manifest.json with the render block the platform requires. A plugin
@@ -4350,7 +4445,7 @@ const handlers = {
4350
4445
  verified,
4351
4446
  next_steps: [
4352
4447
  k === "rn" || k === "adaptive"
4353
- ? `Edit plugins/${plugin_name}/index.tsx — fill in the Component body.`
4448
+ ? `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
4449
  : null,
4355
4450
  k === "iframe" || k === "adaptive"
4356
4451
  ? `Edit ui-dist/${plugin_name}/index.html — replace the placeholder UI.`