@ateam-ai/mcp 0.3.56 → 0.3.57

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 +122 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.3.56",
3
+ "version": "0.3.57",
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
@@ -131,15 +131,15 @@ export const tools = [
131
131
  name: "ateam_get_spec",
132
132
  core: true,
133
133
  description:
134
- "Get the A-Team specification — schemas, validation rules, system tools, agent guides, and templates. Start here after bootstrap to understand how to build skills and solutions. Use 'section' to get just one part of the skill spec (much smaller than the full spec). Use 'search' to find specific fields or concepts across the spec.\n\nWhen designing a persona that orchestrates logic via run_python_script (the Python-as-orchestrator pattern), also fetch topic='python_helpers' — that returns the adas.* helper namespace reference. Skills designed without knowing about adas.* produce 5-10x larger / brittler scripts.",
134
+ "Get the A-Team specification — schemas, validation rules, system tools, agent guides, and templates. Start here after bootstrap to understand how to build skills and solutions. Use 'section' to get just one part of the skill spec (much smaller than the full spec). Use 'search' to find specific fields or concepts across the spec.\n\nWhen designing a persona that orchestrates logic via run_python_script (the Python-as-orchestrator pattern), also fetch topic='python_helpers' — that returns the adas.* helper namespace reference. Skills designed without knowing about adas.* produce 5-10x larger / brittler scripts.\n\nWhen wiring widgets (UI plugins) into a solution, fetch topic='widgets' — that returns the widget spec (catalog model, how_to_use blocks, opener_call shape, persona phrasing rules, binding semantics) so you can declare `ui_plugins` correctly. For the live catalog of widgets actually available in a deployed tenant, use ateam_get_widget_catalog instead.",
135
135
  inputSchema: {
136
136
  type: "object",
137
137
  properties: {
138
138
  topic: {
139
139
  type: "string",
140
- enum: ["overview", "skill", "solution", "enums", "connector-multi-user", "python_helpers"],
140
+ enum: ["overview", "skill", "solution", "enums", "connector-multi-user", "python_helpers", "widgets"],
141
141
  description:
142
- "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).",
142
+ "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.",
143
143
  },
144
144
  section: {
145
145
  type: "string",
@@ -993,6 +993,45 @@ export const tools = [
993
993
  required: ["job_id"],
994
994
  },
995
995
  },
996
+ {
997
+ name: "ateam_get_widget_catalog",
998
+ core: true,
999
+ description:
1000
+ "Get the live catalog of widgets (UI plugins) available in this tenant's solution. Returns platform-bundled + solution-bundled + skill-declared widgets, each with a paste-ready how_to_use block (solution.json snippet + opener_call + persona_phrasing + binding_notes).\n\n" +
1001
+ "Use this when wiring widgets into a skill or solution — the how_to_use block is designed to be copied verbatim into the solution.json ui_plugins[] entry and into the persona's opener phrasing, so you don't have to hand-roll either. The catalog reflects what is actually deployed in the tenant right now, not the abstract spec (for the spec itself, use ateam_get_spec topic='widgets').\n\n" +
1002
+ "Origins:\n" +
1003
+ " • 'platform' = widgets bundled with the platform (always available).\n" +
1004
+ " • 'solution' = widgets bundled with this tenant's solution.\n" +
1005
+ " • 'skill' = widgets declared by a specific skill in the solution.\n\n" +
1006
+ "Auth: forwards your authed api_key to Core (no master-secret involvement). Tenant scope is pinned by the key itself.",
1007
+ inputSchema: {
1008
+ type: "object",
1009
+ properties: {
1010
+ solution_id: {
1011
+ type: "string",
1012
+ description: "Optional. The solution to query. Defaults to the tenant's current solution.",
1013
+ },
1014
+ origin: {
1015
+ type: "string",
1016
+ enum: ["all", "platform", "solution", "skill"],
1017
+ description:
1018
+ "Optional. Filter by widget origin. 'all' (default) returns everything. 'platform' = platform-bundled only. 'solution' = solution-bundled only. 'skill' = skill-declared only.",
1019
+ },
1020
+ include_unused: {
1021
+ type: "boolean",
1022
+ description:
1023
+ "Optional. If true, includes widgets that are available but not currently referenced by any skill or ui_plugins entry. Default false (only widgets actually wired into the solution).",
1024
+ },
1025
+ format: {
1026
+ type: "string",
1027
+ enum: ["summary", "full"],
1028
+ description:
1029
+ "Optional. 'full' (default) returns each widget with its paste-ready how_to_use block (solution.json snippet, opener_call, persona_phrasing, binding_notes). 'summary' returns just id/name/origin/description for a quick overview.",
1030
+ },
1031
+ },
1032
+ required: [],
1033
+ },
1034
+ },
996
1035
  {
997
1036
  name: "ateam_test_abort",
998
1037
  core: true,
@@ -1512,6 +1551,7 @@ const SPEC_PATHS = {
1512
1551
  enums: "/spec/enums",
1513
1552
  "connector-multi-user": "/spec/multi-user-connector",
1514
1553
  python_helpers: "/spec/python_helpers",
1554
+ widgets: "/spec/widgets",
1515
1555
  };
1516
1556
 
1517
1557
  const EXAMPLE_PATHS = {
@@ -1554,6 +1594,7 @@ const TENANT_TOOLS = new Set([
1554
1594
  "ateam_test_status",
1555
1595
  "ateam_test_abort",
1556
1596
  "ateam_get_chain",
1597
+ "ateam_get_widget_catalog",
1557
1598
  "ateam_get_connector_source",
1558
1599
  "ateam_get_metrics",
1559
1600
  "ateam_diff",
@@ -3097,6 +3138,84 @@ const handlers = {
3097
3138
  return data;
3098
3139
  },
3099
3140
 
3141
+ ateam_get_widget_catalog: async ({ origin, format }, sid) => {
3142
+ // Wraps Core's existing GET /api/ui-plugins (merged tenant plugin list)
3143
+ // and enriches each entry with the documentation/how-to-use layer.
3144
+ // Filtering by origin and the summary/full format projection happen
3145
+ // client-side here — Core just returns the raw merged plugins[].
3146
+ const creds = getCredentials(sid);
3147
+ const apiKey = creds?.apiKey;
3148
+ if (!apiKey) throw new Error("No api_key in session — call ateam_auth(api_key) first.");
3149
+ const coreUrl = process.env.ADAS_CORE_URL || "http://adas-backend:4000";
3150
+ const res = await fetch(`${coreUrl}/api/ui-plugins`, {
3151
+ method: "GET",
3152
+ headers: { "x-api-key": apiKey, "X-ADAS-SERVICE": "ateam-mcp.get_widget_catalog" },
3153
+ signal: AbortSignal.timeout(15_000),
3154
+ });
3155
+ const text = await res.text();
3156
+ let data;
3157
+ try { data = JSON.parse(text); } catch { data = { ok: false, error: text.slice(0, 400) }; }
3158
+ if (!res.ok) {
3159
+ throw new Error(`Core /api/ui-plugins returned ${res.status}: ${data.error || JSON.stringify(data).slice(0, 200)}`);
3160
+ }
3161
+
3162
+ // Project each plugin into the catalog shape with how_to_use guidance.
3163
+ const plugins = Array.isArray(data?.plugins) ? data.plugins : [];
3164
+ const wantSummary = format === "summary";
3165
+ const filterOrigin = origin && origin !== "all" ? origin : null;
3166
+
3167
+ const widgets = plugins.map((p) => {
3168
+ const id = p?.id || "";
3169
+ const shortId = id.split(":").pop() || id;
3170
+ // origin classification: platform vs solution vs skill
3171
+ const src = p?._source || "";
3172
+ const inferredOrigin = src === "mcp_introspection" ? "platform"
3173
+ : src === "skill_declared" ? "skill"
3174
+ : "solution";
3175
+ const opener = Array.isArray(p?.capabilities?.commands) && p.capabilities.commands.length > 0
3176
+ ? `ui.${shortId}.${p.capabilities.commands[0].name || "open"}({ /* args per input_schema */ })`
3177
+ : `sys.focusUiPlugin({ plugin_id: "${id}" })`;
3178
+ const entry = {
3179
+ id,
3180
+ name: p?.name,
3181
+ version: p?.version,
3182
+ description: p?.description,
3183
+ type: p?.type || "ui",
3184
+ origin: inferredOrigin,
3185
+ owned_by_connector: p?._connector_id,
3186
+ render: p?.render,
3187
+ surface: p?.surface,
3188
+ capabilities: p?.capabilities,
3189
+ channels: p?.channels,
3190
+ commands: p?.capabilities?.commands || p?.commands || [],
3191
+ uiActions: p?.uiActions,
3192
+ };
3193
+ if (!wantSummary) {
3194
+ entry.how_to_use = {
3195
+ solution_json_snippet: { id, name: p?.name, version: p?.version, render: p?.render },
3196
+ opener_call: opener,
3197
+ persona_phrasing: `When the user wants to view ${(p?.description || p?.name || shortId).toString().toLowerCase()}, call ${opener.split("(")[0]}.`,
3198
+ binding_notes: {
3199
+ commands_input_schemas: (p?.capabilities?.commands || []).map(c => ({ command: c.name, schema: c.input_schema })),
3200
+ deeplink_template: p?.uiActions?.deeplink || null,
3201
+ view_entity_kinds: p?.uiActions?.intents?.view_entity?.entity_kinds || null,
3202
+ host_auto_routes_intents: Object.keys(p?.uiActions?.intents || {}),
3203
+ },
3204
+ };
3205
+ }
3206
+ return entry;
3207
+ });
3208
+
3209
+ const filtered = filterOrigin ? widgets.filter(w => w.origin === filterOrigin) : widgets;
3210
+ const counts = {
3211
+ total: filtered.length,
3212
+ platform: filtered.filter(w => w.origin === "platform").length,
3213
+ solution: filtered.filter(w => w.origin === "solution").length,
3214
+ skill: filtered.filter(w => w.origin === "skill").length,
3215
+ };
3216
+ return { ok: true, generated_at: new Date().toISOString(), counts, widgets: filtered };
3217
+ },
3218
+
3100
3219
  ateam_test_abort: async ({ solution_id, skill_id, job_id }, sid) =>
3101
3220
  del(`/deploy/solutions/${solution_id}/skills/${skill_id}/test/${job_id}`, sid),
3102
3221