@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.
- package/package.json +1 -1
- package/src/tools.js +133 -18
package/package.json
CHANGED
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
|
-
|
|
2107
|
-
|
|
2108
|
-
plugin
|
|
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
|
-
//
|
|
2193
|
-
//
|
|
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 '
|
|
2198
|
-
import type { PluginProps } from '
|
|
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?.
|
|
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: `
|
|
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}
|
|
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
|
|
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.`
|