@brander/mcp-tools 0.2.4 → 0.2.6

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.
@@ -28,7 +28,7 @@ function injectInitialConfig(html, projectConfig) {
28
28
  */
29
29
  export function registerAppResourceHandler(server, projectConfig) {
30
30
  server.registerResource("BranderUX Element Renderer", RESOURCE_URI, {
31
- description: "Universal HTML renderer for all 14 BranderUX element types",
31
+ description: "Universal HTML renderer for all 15 BranderUX element types",
32
32
  mimeType: MCP_APP_MIME_TYPE,
33
33
  }, async (uri) => {
34
34
  const html = loadAppHtml();
@@ -1 +1 @@
1
- {"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../../../src/tools/tool-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,EAAE,iBAAiB,EAAiB,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAmBpF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,iBAAiB,CAoEvD"}
1
+ {"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../../../src/tools/tool-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAKxD,OAAO,EAAE,iBAAiB,EAAiB,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAwEpF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,iBAAiB,CAuEvD"}
@@ -6,25 +6,70 @@ import { buildContentSummary } from "../elements/element-functions.js";
6
6
  import { RESOURCE_URI } from "../resource/resource-registry.js";
7
7
  import { ElementType } from "../types/element-types.js";
8
8
  import { getElementDefinition } from "./element-definitions.js";
9
- /** Build _meta with resource URI and optional CSP connect domains */
10
- function buildMeta(apiConfig) {
9
+ /** Domains allowed for media loading (video, images, fonts) must use https:// prefix per MCP Apps spec */
10
+ const MEDIA_RESOURCE_DOMAINS = [
11
+ "https://fonts.googleapis.com",
12
+ "https://fonts.gstatic.com",
13
+ "https://lh3.googleusercontent.com",
14
+ "https://commondatastorage.googleapis.com",
15
+ "https://storage.googleapis.com",
16
+ "https://images.unsplash.com",
17
+ "https://res.cloudinary.com",
18
+ "https://i.imgur.com",
19
+ "https://img.youtube.com",
20
+ ];
21
+ /** Domains allowed for iframe embedding (e.g. YouTube) — must use https:// prefix per MCP Apps spec */
22
+ const FRAME_DOMAINS = ["https://www.youtube.com", "https://www.youtube-nocookie.com"];
23
+ /** YouTube URL patterns for detecting non-proxyable video sources */
24
+ const YOUTUBE_RE = /(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)/i;
25
+ /** Build _meta with resource URI, CSP connect/resource/frame domains */
26
+ function buildMeta(apiConfig, extraResourceDomains) {
11
27
  const meta = {
12
28
  ui: { resourceUri: RESOURCE_URI },
13
29
  "ui/resourceUri": RESOURCE_URI,
14
30
  };
31
+ const resourceDomains = [...MEDIA_RESOURCE_DOMAINS];
32
+ if (extraResourceDomains) {
33
+ for (const d of extraResourceDomains) {
34
+ if (!resourceDomains.includes(d))
35
+ resourceDomains.push(d);
36
+ }
37
+ }
38
+ const csp = {
39
+ resourceDomains,
40
+ frameDomains: [...FRAME_DOMAINS],
41
+ };
15
42
  if (apiConfig) {
16
- meta.ui.csp = {
17
- connectDomains: [new URL(apiConfig.apiBaseUrl).origin],
18
- };
43
+ csp.connectDomains = [new URL(apiConfig.apiBaseUrl).origin];
19
44
  }
45
+ meta.ui.csp = csp;
20
46
  return meta;
21
47
  }
48
+ /** Extract origins from direct (non-YouTube) video element sources */
49
+ function extractVideoOrigins(elements) {
50
+ const origins = [];
51
+ for (const el of elements) {
52
+ if (el.elementType !== ElementType.VIDEO)
53
+ continue;
54
+ const src = el.props?.src;
55
+ if (!src || YOUTUBE_RE.test(src))
56
+ continue;
57
+ try {
58
+ const origin = new URL(src).origin;
59
+ if (!origins.includes(origin))
60
+ origins.push(origin);
61
+ }
62
+ catch {
63
+ // invalid URL — skip
64
+ }
65
+ }
66
+ return origins;
67
+ }
22
68
  /**
23
69
  * Create the handler for the generate_screen tool.
24
70
  * Accepts an array of elements and returns them as a composed screen.
25
71
  */
26
72
  export function createScreenHandler(projectConfig, apiConfig) {
27
- const meta = buildMeta(apiConfig);
28
73
  const { brandSettings } = projectConfig;
29
74
  return (input) => {
30
75
  const rawElements = input.elements || [];
@@ -40,7 +85,7 @@ export function createScreenHandler(projectConfig, apiConfig) {
40
85
  customScreens: projectConfig.customScreens,
41
86
  apiConfig,
42
87
  },
43
- _meta: meta,
88
+ _meta: buildMeta(apiConfig),
44
89
  };
45
90
  }
46
91
  // Build screen elements with click behaviors
@@ -58,6 +103,9 @@ export function createScreenHandler(projectConfig, apiConfig) {
58
103
  }, // Fallback template system
59
104
  };
60
105
  });
106
+ // Extract video source origins for dynamic CSP whitelisting
107
+ const videoOrigins = extractVideoOrigins(rawElements);
108
+ const meta = buildMeta(apiConfig, videoOrigins.length > 0 ? videoOrigins : undefined);
61
109
  // Build text summary — per-element summaries joined
62
110
  const summaries = elements.map((el) => {
63
111
  const def = getElementDefinition(el.elementType);
@@ -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;AAOlD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAsCN"}
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,CAyDN"}
@@ -27,7 +27,26 @@ export function registerTools(server, projectConfig, apiConfig) {
27
27
  description,
28
28
  inputSchema: generateScreenInputSchema,
29
29
  _meta: {
30
- ui: { resourceUri: RESOURCE_URI },
30
+ ui: {
31
+ resourceUri: RESOURCE_URI,
32
+ csp: {
33
+ resourceDomains: [
34
+ "https://fonts.googleapis.com",
35
+ "https://fonts.gstatic.com",
36
+ "https://lh3.googleusercontent.com",
37
+ "https://commondatastorage.googleapis.com",
38
+ "https://storage.googleapis.com",
39
+ "https://images.unsplash.com",
40
+ "https://res.cloudinary.com",
41
+ "https://i.imgur.com",
42
+ "https://img.youtube.com",
43
+ ],
44
+ frameDomains: [
45
+ "https://www.youtube.com",
46
+ "https://www.youtube-nocookie.com",
47
+ ],
48
+ },
49
+ },
31
50
  "ui/resourceUri": RESOURCE_URI,
32
51
  },
33
52
  }, async (args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brander/mcp-tools",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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",