@brander/mcp-tools 0.2.2 → 0.2.4

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.
@@ -4,6 +4,12 @@
4
4
  import { BrandSettings, ProjectConfig } from "./brand-types.js";
5
5
  interface BrandLoaderOptions {
6
6
  projectId: string;
7
+ /**
8
+ * Public design-partner key (bux_dp_xxx). This is a publishable identifier
9
+ * (like a Stripe publishable key) — it scopes API access to a specific project
10
+ * but does not grant write access or expose secrets. Safe to embed in client
11
+ * configs, MCP tool results, and localStorage.
12
+ */
7
13
  betaKey: string;
8
14
  apiBaseUrl?: string;
9
15
  brandSettingsPath?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"brand-loader.d.ts","sourceRoot":"","sources":["../../../src/brand/brand-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAA0B,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAExF,UAAU,kBAAkB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4B3F;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAG3F"}
1
+ {"version":3,"file":"brand-loader.d.ts","sourceRoot":"","sources":["../../../src/brand/brand-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAA0B,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAExF,UAAU,kBAAkB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4B3F;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAG3F"}
@@ -69,7 +69,7 @@ async function loadConfigFromApi(options) {
69
69
  const response = await fetch(url.toString(), {
70
70
  method: "GET",
71
71
  headers: {
72
- "Content-Type": "application/json",
72
+ Accept: "application/json",
73
73
  },
74
74
  });
75
75
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"file":"click-behaviors.d.ts","sourceRoot":"","sources":["../../../src/elements/click-behaviors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,WAAW,EAAE,mBAAmB,CA6D9E,CAAC;AAEF,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,mBAAmB,GAAG,SAAS,CAE1F"}
1
+ {"version":3,"file":"click-behaviors.d.ts","sourceRoot":"","sources":["../../../src/elements/click-behaviors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAiE9E,CAAC;AAEF,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,mBAAmB,GAAG,SAAS,CAE1F"}
@@ -60,6 +60,10 @@ export const ELEMENT_BEHAVIOR_REGISTRY = {
60
60
  queryTemplate: "[actionQuery]",
61
61
  description: "Alert action button triggers the configured query",
62
62
  },
63
+ [ElementType.VIDEO]: {
64
+ queryTemplate: "[action]",
65
+ description: "Discuss button fires the configured action query about the video",
66
+ },
63
67
  [ElementType.SCREEN]: {
64
68
  queryTemplate: "",
65
69
  description: "Screen composition — click behaviors are per-element",
@@ -1 +1 @@
1
- {"version":3,"file":"element-functions.d.ts","sourceRoot":"","sources":["../../../src/elements/element-functions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;AAEzE,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE,eAAe,CAsDlE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAGT;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAC5C,WAAW,EACX,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4E/D,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAsER"}
1
+ {"version":3,"file":"element-functions.d.ts","sourceRoot":"","sources":["../../../src/elements/element-functions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;AAEzE,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE,eAAe,CAwDlE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAGT;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAC5C,WAAW,EACX,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiF/D,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAwER"}
@@ -33,6 +33,7 @@ export const VISIBILITY_CHECKS = {
33
33
  [ElementType.FORM]: (data) => Array.isArray(data?.fields) && data.fields.length > 0,
34
34
  [ElementType.BUTTON]: (data) => Boolean(data),
35
35
  [ElementType.ALERT]: (data) => Boolean(data?.message) && typeof data.message === "string" && data.message.trim().length > 0,
36
+ [ElementType.VIDEO]: (data) => Boolean(data?.src),
36
37
  [ElementType.SCREEN]: (data) => Array.isArray(data?.elements) && data.elements.length > 0,
37
38
  };
38
39
  /** Check if tool input data is valid for the given element type */
@@ -105,6 +106,10 @@ export const CLICK_METADATA_ENRICHMENT = {
105
106
  elementType: "alert",
106
107
  actionType: "alert_action_click",
107
108
  }),
109
+ [ElementType.VIDEO]: (data) => ({
110
+ ...data,
111
+ elementType: "video",
112
+ }),
108
113
  [ElementType.SCREEN]: (data) => ({ ...data }),
109
114
  };
110
115
  /**
@@ -157,6 +162,7 @@ export function buildContentSummary(elementType, data) {
157
162
  },
158
163
  [ElementType.BUTTON]: (d) => `Rendered button: "${d.label}"`,
159
164
  [ElementType.ALERT]: (d) => `Displayed ${d.severity || "info"} alert: "${d.message}"`,
165
+ [ElementType.VIDEO]: (d) => `Rendered video player: "${d.title || d.src}"`,
160
166
  [ElementType.SCREEN]: (d) => {
161
167
  const elements = d.elements;
162
168
  return `Rendered screen with ${elements?.length || 0} elements`;
@@ -14,7 +14,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
14
  export interface BranderToolsConfig {
15
15
  /** BranderUX project ID — identifies which project's brand + screens to load */
16
16
  projectId: string;
17
- /** Beta design partner key (bux_dp_xxx) for authentication */
17
+ /**
18
+ * Public design-partner key (bux_dp_xxx). This is a publishable identifier — it
19
+ * scopes API access to a specific project but does not grant write access or expose
20
+ * secrets. Safe to include in client-side configs and version control.
21
+ */
18
22
  betaKey: string;
19
23
  /** BranderUX API base URL (defaults to https://branderux.com) */
20
24
  apiBaseUrl?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAEhB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource-registry.d.ts","sourceRoot":"","sources":["../../../src/resource/resource-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,eAAO,MAAM,YAAY,kCAAkC,CAAC;AAkB5D;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAwBhG"}
1
+ {"version":3,"file":"resource-registry.d.ts","sourceRoot":"","sources":["../../../src/resource/resource-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,eAAO,MAAM,YAAY,kCAAkC,CAAC;AAoB5D;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAwBhG"}
@@ -16,7 +16,9 @@ function injectInitialConfig(html, projectConfig) {
16
16
  screenVisibility: projectConfig.screenVisibility,
17
17
  customScreens: projectConfig.customScreens,
18
18
  };
19
- const script = `<script>window.__BRANDER_INITIAL_CONFIG__=${JSON.stringify(config)};</script>`;
19
+ // Escape </ sequences to prevent script tag injection (e.g. "</script>" in config values)
20
+ const safeJson = JSON.stringify(config).replace(/</g, "\\u003c");
21
+ const script = `<script>window.__BRANDER_INITIAL_CONFIG__=${safeJson};</script>`;
20
22
  // Insert before closing </head> so it runs before the app bundle
21
23
  return html.replace("</head>", `${script}</head>`);
22
24
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Element definitions — static metadata for the 14 BranderUX element types.
2
+ * Element definitions — static metadata for the 15 BranderUX element types.
3
3
  *
4
4
  * Inlined here so the compiled dist/server can run as standalone Node.js without
5
5
  * depending on @brander/elements TypeScript source at runtime (CJS/ESM interop issue).
@@ -9,6 +9,7 @@ interface ElementInfo {
9
9
  name: string;
10
10
  description: string;
11
11
  }
12
+ export declare const ELEMENT_INFO: ElementInfo[];
12
13
  /** Get element info by type (for names, click behaviors, summaries) */
13
14
  export declare function getElementDefinition(elementType: string): ElementInfo | undefined;
14
15
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"element-definitions.d.ts","sourceRoot":"","sources":["../../../src/tools/element-definitions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AA6CD,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjF"}
1
+ {"version":3,"file":"element-definitions.d.ts","sourceRoot":"","sources":["../../../src/tools/element-definitions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,WAAW,EA4CrC,CAAC;AAIF,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjF"}
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Element definitions — static metadata for the 14 BranderUX element types.
2
+ * Element definitions — static metadata for the 15 BranderUX element types.
3
3
  *
4
4
  * Inlined here so the compiled dist/server can run as standalone Node.js without
5
5
  * depending on @brander/elements TypeScript source at runtime (CJS/ESM interop issue).
6
6
  */
7
- const ELEMENT_INFO = [
7
+ export const ELEMENT_INFO = [
8
8
  { id: "header", name: "Header", description: "Page header with title and subtitle" },
9
9
  { id: "stats-grid", name: "Stats Grid", description: "Grid of KPI statistics with trends" },
10
10
  {
@@ -43,6 +43,11 @@ const ELEMENT_INFO = [
43
43
  name: "Alert",
44
44
  description: "Notification banner for messages, warnings, and feedback",
45
45
  },
46
+ {
47
+ id: "video",
48
+ name: "Video Player",
49
+ description: "Embedded video player for YouTube URLs or direct mp4/webm files",
50
+ },
46
51
  ];
47
52
  const ELEMENT_INFO_MAP = new Map(ELEMENT_INFO.map((e) => [e.id, e]));
48
53
  /** Get element info by type (for names, click behaviors, summaries) */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Self-contained generate_screen Zod schema + tool description for the MCP server.
3
3
  *
4
- * All 14 element prop schemas are defined here so the compiled dist/server can run
4
+ * All 15 element prop schemas are defined here so the compiled dist/server can run
5
5
  * as a standalone Node.js server without depending on @brander/elements at runtime.
6
6
  * (Avoids CJS/ESM interop issues — brander-elements is CJS but mcp-tools is ESM.)
7
7
  */
@@ -255,8 +255,39 @@ export declare const generateScreenInputSchema: z.ZodObject<{
255
255
  actionQuery: z.ZodOptional<z.ZodString>;
256
256
  }, z.core.$strip>;
257
257
  clickQuery: z.ZodOptional<z.ZodString>;
258
+ }, z.core.$strip>, z.ZodObject<{
259
+ elementType: z.ZodLiteral<"video">;
260
+ props: z.ZodObject<{
261
+ id: z.ZodString;
262
+ src: z.ZodString;
263
+ title: z.ZodOptional<z.ZodString>;
264
+ description: z.ZodOptional<z.ZodString>;
265
+ action: z.ZodOptional<z.ZodString>;
266
+ aspectRatio: z.ZodOptional<z.ZodEnum<{
267
+ "16:9": "16:9";
268
+ "4:3": "4:3";
269
+ "1:1": "1:1";
270
+ }>>;
271
+ autoplay: z.ZodOptional<z.ZodBoolean>;
272
+ }, z.core.$strip>;
273
+ clickQuery: z.ZodOptional<z.ZodString>;
258
274
  }, z.core.$strip>], "elementType">>;
259
275
  }, z.core.$strip>;
260
- /** Tool description for generate_screen */
261
- export declare const GENERATE_SCREEN_DESCRIPTION: string;
276
+ interface DescriptionConfig {
277
+ elementVisibility?: Record<string, boolean>;
278
+ customScreens?: Array<{
279
+ name: string;
280
+ config?: {
281
+ elements?: Array<{
282
+ elementType?: string;
283
+ }>;
284
+ };
285
+ elements?: Array<{
286
+ elementType?: string;
287
+ }>;
288
+ }>;
289
+ }
290
+ /** Build the generate_screen tool description dynamically from project config */
291
+ export declare function buildGenerateScreenDescription(config?: DescriptionConfig): string;
292
+ export {};
262
293
  //# sourceMappingURL=generate-screen-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-screen-schema.d.ts","sourceRoot":"","sources":["../../../src/tools/generate-screen-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+OxB,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAC;AAEH,2CAA2C;AAC3C,eAAO,MAAM,2BAA2B,QAO8H,CAAC"}
1
+ {"version":3,"file":"generate-screen-schema.d.ts","sourceRoot":"","sources":["../../../src/tools/generate-screen-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6PxB,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAC;AAMH,UAAU,iBAAiB;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,KAAK,CAAC;gBAAE,WAAW,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC;QACxD,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC5C,CAAC,CAAC;CACJ;AAED,iFAAiF;AACjF,wBAAgB,8BAA8B,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAqCjF"}
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * Self-contained generate_screen Zod schema + tool description for the MCP server.
3
3
  *
4
- * All 14 element prop schemas are defined here so the compiled dist/server can run
4
+ * All 15 element prop schemas are defined here so the compiled dist/server can run
5
5
  * as a standalone Node.js server without depending on @brander/elements at runtime.
6
6
  * (Avoids CJS/ESM interop issues — brander-elements is CJS but mcp-tools is ESM.)
7
7
  */
8
8
  import { z } from "zod";
9
+ import { ELEMENT_INFO } from "./element-definitions.js";
9
10
  // ============================================================================
10
- // ELEMENT PROP SCHEMAS (14 element types)
11
+ // ELEMENT PROP SCHEMAS (15 element types)
11
12
  // ============================================================================
12
13
  const headerPropsSchema = z.object({
13
14
  title: z.string().describe("Main page title"),
@@ -87,10 +88,7 @@ const itemGridPropsSchema = z.object({
87
88
  title: z.string().describe("Item name"),
88
89
  description: z.string().optional().describe("Item description"),
89
90
  price: z.string().describe("Item price"),
90
- image: z
91
- .string()
92
- .optional()
93
- .describe("REAL image URL (e.g., https://images.unsplash.com/...)"),
91
+ image: z.string().optional().describe("Image URL"),
94
92
  category: z.string().optional().describe("Item category"),
95
93
  rating: z.number().optional().describe("Rating score"),
96
94
  stock: z.number().optional().describe("Stock quantity"),
@@ -188,8 +186,22 @@ const alertPropsSchema = z.object({
188
186
  actionText: z.string().optional().describe("Optional action button text"),
189
187
  actionQuery: z.string().optional().describe("Query to send when action button clicked"),
190
188
  });
189
+ const videoPropsSchema = z.object({
190
+ id: z.string().describe("Unique video element identifier"),
191
+ src: z
192
+ .string()
193
+ .describe("Video URL — YouTube (youtube.com/watch or youtu.be), or direct .mp4/.webm file URL"),
194
+ title: z.string().optional().describe("Video title shown below the player"),
195
+ description: z.string().optional().describe("Brief description shown below the title"),
196
+ action: z
197
+ .string()
198
+ .optional()
199
+ .describe("Query sent to the AI when the user clicks the Discuss button"),
200
+ aspectRatio: z.enum(["16:9", "4:3", "1:1"]).optional().describe("Video player aspect ratio"),
201
+ autoplay: z.boolean().optional().describe("Auto-play video when rendered"),
202
+ });
191
203
  // ============================================================================
192
- // SCREEN SCHEMA — discriminated union of all 14 element types
204
+ // SCREEN SCHEMA — discriminated union of all 15 element types
193
205
  // ============================================================================
194
206
  const clickQuery = z
195
207
  .string()
@@ -210,6 +222,7 @@ const screenElementSchema = z.discriminatedUnion("elementType", [
210
222
  z.object({ elementType: z.literal("form"), props: formPropsSchema, clickQuery }),
211
223
  z.object({ elementType: z.literal("button"), props: buttonPropsSchema, clickQuery }),
212
224
  z.object({ elementType: z.literal("alert"), props: alertPropsSchema, clickQuery }),
225
+ z.object({ elementType: z.literal("video"), props: videoPropsSchema, clickQuery }),
213
226
  ]);
214
227
  /** Full input schema for the MCP `generate_screen` tool */
215
228
  export const generateScreenInputSchema = z.object({
@@ -217,11 +230,34 @@ export const generateScreenInputSchema = z.object({
217
230
  .array(screenElementSchema)
218
231
  .describe("Ordered array of elements to render. Each element has an elementType and props."),
219
232
  });
220
- /** Tool description for generate_screen */
221
- export const GENERATE_SCREEN_DESCRIPTION = "**REQUIRED FOR ALL VISUAL RESPONSES** - Render branded, interactive UI components. " +
222
- "You MUST use this tool instead of writing React code for dashboards, data tables, charts, stats, or any visual content. " +
223
- "Provide an ordered array of elements: for dashboards use header + stats-grid + data-table + charts; " +
224
- "for simple text use chat-bubble. For clickable elements, add a `clickQuery` with placeholders [field] for dynamic values. " +
225
- "Example: clickQuery: 'Show detailed analytics for [title] including sales trends and inventory'. " +
226
- "Use [title], [id], [name] placeholders that will be filled when user clicks. DO NOT write React code - use this tool. " +
227
- "Available elements: header, chat-bubble, stats-grid, data-table, line-chart, pie-chart, bar-chart, item-grid, item-card, image, details-data, form, button, alert.";
233
+ /** Build the generate_screen tool description dynamically from project config */
234
+ export function buildGenerateScreenDescription(config) {
235
+ const elementVisibility = config?.elementVisibility ?? {};
236
+ const customScreens = config?.customScreens ?? [];
237
+ // Filter elements by visibility (default = enabled if not in map)
238
+ const enabledElements = ELEMENT_INFO.filter((e) => elementVisibility[e.id] !== false);
239
+ const enabledSet = new Set(enabledElements.map((e) => e.id));
240
+ const elementList = enabledElements.map((e) => e.id).join(", ");
241
+ // Build screen patterns from the project's custom screens
242
+ const patterns = [];
243
+ for (const screen of customScreens) {
244
+ const els = (screen.config?.elements ?? screen.elements ?? [])
245
+ .map((e) => e.elementType)
246
+ .filter((t) => !!t && enabledSet.has(t));
247
+ if (els.length > 0) {
248
+ const unique = [...new Set(els)];
249
+ patterns.push(`- ${screen.name}: ${unique.join(" → ")}`);
250
+ }
251
+ }
252
+ const patternsSection = patterns.length > 0
253
+ ? "Compose screens from an ordered array of elements. Available screen patterns:\n" +
254
+ patterns.join("\n") +
255
+ "\n\n"
256
+ : "";
257
+ return ("Render branded, interactive UI screens. Outputs styled visual components (charts, tables, grids, forms) " +
258
+ "using the project's brand colors, fonts, and layout — displayed as a rich visual panel.\n\n" +
259
+ patternsSection +
260
+ "For interactivity, add clickQuery with [placeholder] tokens filled from element data on click. " +
261
+ 'Example: clickQuery: "Show details for [title] with full order history"\n\n' +
262
+ `Available elements: ${elementList}`);
263
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMlD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAuBN"}
1
+ {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAOlD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAsCN"}
@@ -4,9 +4,10 @@
4
4
  * Uses the high-level McpServer.registerTool() API for composability — customers
5
5
  * can register their own tools alongside BranderUX tools on the same server.
6
6
  */
7
- import { generateScreenInputSchema, GENERATE_SCREEN_DESCRIPTION, } from "./generate-screen-schema.js";
7
+ import { generateScreenInputSchema, buildGenerateScreenDescription, } from "./generate-screen-schema.js";
8
8
  import { createScreenHandler } from "./tool-handler.js";
9
9
  import { RESOURCE_URI } from "../resource/resource-registry.js";
10
+ import { ELEMENT_INFO } from "./element-definitions.js";
10
11
  const TOOL_NAME = "generate_screen";
11
12
  /**
12
13
  * Register the BranderUX generate_screen tool with the MCP server.
@@ -14,8 +15,16 @@ const TOOL_NAME = "generate_screen";
14
15
  */
15
16
  export function registerTools(server, projectConfig, apiConfig) {
16
17
  const handler = createScreenHandler(projectConfig, apiConfig);
18
+ // Build description dynamically from project's element/screen visibility + custom screens
19
+ const description = buildGenerateScreenDescription({
20
+ elementVisibility: projectConfig.settings.elementVisibility,
21
+ customScreens: projectConfig.customScreens,
22
+ });
23
+ // Count enabled elements
24
+ const elementVisibility = projectConfig.settings.elementVisibility ?? {};
25
+ const enabledCount = ELEMENT_INFO.filter((e) => elementVisibility[e.id] !== false).length;
17
26
  server.registerTool(TOOL_NAME, {
18
- description: GENERATE_SCREEN_DESCRIPTION,
27
+ description,
19
28
  inputSchema: generateScreenInputSchema,
20
29
  _meta: {
21
30
  ui: { resourceUri: RESOURCE_URI },
@@ -26,5 +35,6 @@ export function registerTools(server, projectConfig, apiConfig) {
26
35
  // but our handler expects Record<string, unknown>
27
36
  return handler(args);
28
37
  });
29
- console.error(`Registered BranderUX tool: ${TOOL_NAME} ` + `(14 element types, resource: ${RESOURCE_URI})`);
38
+ console.error(`Registered BranderUX tool: ${TOOL_NAME} ` +
39
+ `(${enabledCount} element types, resource: ${RESOURCE_URI})`);
30
40
  }
@@ -17,21 +17,7 @@ export declare enum ElementType {
17
17
  BUTTON = "button",
18
18
  BAR_CHART = "bar-chart",
19
19
  ALERT = "alert",
20
+ VIDEO = "video",
20
21
  SCREEN = "screen"
21
22
  }
22
- export interface ToolSchema {
23
- name: string;
24
- description: string;
25
- input_schema: {
26
- type: "object";
27
- properties: Record<string, unknown>;
28
- required?: string[];
29
- };
30
- }
31
- export interface ElementDefinition {
32
- id: ElementType;
33
- name: string;
34
- description: string;
35
- toolSchema: ToolSchema;
36
- }
37
23
  //# sourceMappingURL=element-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"element-types.d.ts","sourceRoot":"","sources":["../../../src/types/element-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oBAAY,WAAW;IACrB,MAAM,WAAW;IACjB,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAC3B,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE;QACZ,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,WAAW,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;CACxB"}
1
+ {"version":3,"file":"element-types.d.ts","sourceRoot":"","sources":["../../../src/types/element-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oBAAY,WAAW;IACrB,MAAM,WAAW;IACjB,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAC3B,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,MAAM,WAAW;CAClB"}
@@ -18,5 +18,6 @@ export var ElementType;
18
18
  ElementType["BUTTON"] = "button";
19
19
  ElementType["BAR_CHART"] = "bar-chart";
20
20
  ElementType["ALERT"] = "alert";
21
+ ElementType["VIDEO"] = "video";
21
22
  ElementType["SCREEN"] = "screen";
22
23
  })(ElementType || (ElementType = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brander/mcp-tools",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "BranderUX MCP Tools — Add branded interactive UI to any MCP server",
6
6
  "main": "dist/server/lib-entry.js",