skybridge 0.0.0-dev.a471f12 → 0.0.0-dev.a49f377

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 (245) hide show
  1. package/README.md +157 -0
  2. package/bin/run.js +0 -4
  3. package/dist/cli/detect-port.d.ts +18 -0
  4. package/dist/cli/detect-port.js +61 -0
  5. package/dist/cli/detect-port.js.map +1 -0
  6. package/dist/cli/header.d.ts +4 -0
  7. package/dist/cli/header.js +6 -0
  8. package/dist/cli/header.js.map +1 -0
  9. package/dist/cli/run-command.d.ts +2 -0
  10. package/dist/cli/run-command.js +43 -0
  11. package/dist/cli/run-command.js.map +1 -0
  12. package/dist/cli/telemetry.d.ts +7 -0
  13. package/dist/cli/telemetry.js +123 -0
  14. package/dist/cli/telemetry.js.map +1 -0
  15. package/dist/cli/types.d.ts +5 -0
  16. package/dist/cli/types.js +2 -0
  17. package/dist/cli/types.js.map +1 -0
  18. package/dist/cli/use-execute-steps.d.ts +11 -0
  19. package/dist/cli/use-execute-steps.js +36 -0
  20. package/dist/cli/use-execute-steps.js.map +1 -0
  21. package/dist/cli/use-nodemon.d.ts +2 -0
  22. package/dist/cli/use-nodemon.js +80 -0
  23. package/dist/cli/use-nodemon.js.map +1 -0
  24. package/dist/cli/use-tunnel.d.ts +8 -0
  25. package/dist/cli/use-tunnel.js +101 -0
  26. package/dist/cli/use-tunnel.js.map +1 -0
  27. package/dist/cli/use-typescript-check.d.ts +8 -0
  28. package/dist/cli/use-typescript-check.js +59 -0
  29. package/dist/cli/use-typescript-check.js.map +1 -0
  30. package/dist/commands/build.d.ts +9 -0
  31. package/dist/commands/build.js +46 -0
  32. package/dist/commands/build.js.map +1 -0
  33. package/dist/commands/dev.d.ts +4 -1
  34. package/dist/commands/dev.js +35 -21
  35. package/dist/commands/dev.js.map +1 -1
  36. package/dist/commands/start.d.ts +9 -0
  37. package/dist/commands/start.js +52 -0
  38. package/dist/commands/start.js.map +1 -0
  39. package/dist/commands/telemetry/disable.d.ts +5 -0
  40. package/dist/commands/telemetry/disable.js +14 -0
  41. package/dist/commands/telemetry/disable.js.map +1 -0
  42. package/dist/commands/telemetry/enable.d.ts +5 -0
  43. package/dist/commands/telemetry/enable.js +14 -0
  44. package/dist/commands/telemetry/enable.js.map +1 -0
  45. package/dist/commands/telemetry/status.d.ts +5 -0
  46. package/dist/commands/telemetry/status.js +14 -0
  47. package/dist/commands/telemetry/status.js.map +1 -0
  48. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  49. package/dist/server/asset-base-url-transform-plugin.js +34 -0
  50. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  51. package/dist/server/asset-base-url-transform-plugin.test.js +56 -0
  52. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  53. package/dist/server/express.d.ts +15 -0
  54. package/dist/server/express.js +77 -0
  55. package/dist/server/express.js.map +1 -0
  56. package/dist/server/express.test.d.ts +1 -0
  57. package/dist/server/express.test.js +252 -0
  58. package/dist/server/express.test.js.map +1 -0
  59. package/dist/server/index.d.ts +1 -0
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/server/middleware.d.ts +124 -0
  62. package/dist/server/middleware.js +93 -0
  63. package/dist/server/middleware.js.map +1 -0
  64. package/dist/server/middleware.test-d.d.ts +1 -0
  65. package/dist/server/middleware.test-d.js +75 -0
  66. package/dist/server/middleware.test-d.js.map +1 -0
  67. package/dist/server/middleware.test.d.ts +1 -0
  68. package/dist/server/middleware.test.js +490 -0
  69. package/dist/server/middleware.test.js.map +1 -0
  70. package/dist/server/server.d.ts +54 -5
  71. package/dist/server/server.js +215 -59
  72. package/dist/server/server.js.map +1 -1
  73. package/dist/server/templates/development.hbs +1 -55
  74. package/dist/server/templates/production.hbs +1 -2
  75. package/dist/server/widgetsDevServer.d.ts +2 -1
  76. package/dist/server/widgetsDevServer.js +12 -2
  77. package/dist/server/widgetsDevServer.js.map +1 -1
  78. package/dist/test/widget.test.js +50 -21
  79. package/dist/test/widget.test.js.map +1 -1
  80. package/dist/web/bridges/apps-sdk/adaptor.d.ts +22 -0
  81. package/dist/web/bridges/apps-sdk/adaptor.js +75 -0
  82. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -0
  83. package/dist/web/bridges/apps-sdk/bridge.d.ts +10 -0
  84. package/dist/web/bridges/{apps-sdk-bridge.js → apps-sdk/bridge.js} +2 -2
  85. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  86. package/dist/web/bridges/apps-sdk/index.d.ts +5 -0
  87. package/dist/web/bridges/apps-sdk/index.js +5 -0
  88. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  89. package/dist/web/bridges/apps-sdk/types.d.ts +121 -0
  90. package/dist/web/bridges/apps-sdk/types.js +10 -0
  91. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  92. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +2 -0
  93. package/dist/web/bridges/{hooks/use-apps-sdk-bridge.js → apps-sdk/use-apps-sdk-context.js} +3 -3
  94. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  95. package/dist/web/bridges/get-adaptor.d.ts +2 -0
  96. package/dist/web/bridges/get-adaptor.js +8 -0
  97. package/dist/web/bridges/get-adaptor.js.map +1 -0
  98. package/dist/web/bridges/index.d.ts +5 -4
  99. package/dist/web/bridges/index.js +5 -4
  100. package/dist/web/bridges/index.js.map +1 -1
  101. package/dist/web/bridges/mcp-app/adaptor.d.ts +38 -0
  102. package/dist/web/bridges/mcp-app/adaptor.js +184 -0
  103. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -0
  104. package/dist/web/bridges/mcp-app/bridge.d.ts +26 -0
  105. package/dist/web/bridges/mcp-app/bridge.js +102 -0
  106. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  107. package/dist/web/bridges/mcp-app/index.d.ts +4 -0
  108. package/dist/web/bridges/mcp-app/index.js +4 -0
  109. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  110. package/dist/web/bridges/mcp-app/types.d.ts +8 -0
  111. package/dist/web/bridges/mcp-app/types.js +2 -0
  112. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  113. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +7 -0
  114. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +7 -0
  115. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  116. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  117. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  118. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  119. package/dist/web/bridges/types.d.ts +73 -27
  120. package/dist/web/bridges/use-host-context.d.ts +2 -0
  121. package/dist/web/bridges/use-host-context.js +8 -0
  122. package/dist/web/bridges/use-host-context.js.map +1 -0
  123. package/dist/web/components/modal-provider.d.ts +4 -0
  124. package/dist/web/components/modal-provider.js +45 -0
  125. package/dist/web/components/modal-provider.js.map +1 -0
  126. package/dist/web/create-store.js +6 -7
  127. package/dist/web/create-store.js.map +1 -1
  128. package/dist/web/create-store.test.js +113 -52
  129. package/dist/web/create-store.test.js.map +1 -1
  130. package/dist/web/data-llm.js +5 -3
  131. package/dist/web/data-llm.js.map +1 -1
  132. package/dist/web/data-llm.test.js +131 -65
  133. package/dist/web/data-llm.test.js.map +1 -1
  134. package/dist/web/generate-helpers.d.ts +3 -2
  135. package/dist/web/generate-helpers.js +1 -1
  136. package/dist/web/generate-helpers.js.map +1 -1
  137. package/dist/web/helpers/state.js +13 -8
  138. package/dist/web/helpers/state.js.map +1 -1
  139. package/dist/web/hooks/index.d.ts +2 -2
  140. package/dist/web/hooks/index.js +1 -1
  141. package/dist/web/hooks/index.js.map +1 -1
  142. package/dist/web/hooks/test/utils.d.ts +8 -2
  143. package/dist/web/hooks/test/utils.js +37 -13
  144. package/dist/web/hooks/test/utils.js.map +1 -1
  145. package/dist/web/hooks/use-call-tool.d.ts +3 -2
  146. package/dist/web/hooks/use-call-tool.js +2 -2
  147. package/dist/web/hooks/use-call-tool.js.map +1 -1
  148. package/dist/web/hooks/use-call-tool.test-d.js +1 -1
  149. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  150. package/dist/web/hooks/use-call-tool.test.js +3 -3
  151. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  152. package/dist/web/hooks/use-display-mode.d.ts +3 -3
  153. package/dist/web/hooks/use-display-mode.js +3 -4
  154. package/dist/web/hooks/use-display-mode.js.map +1 -1
  155. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  156. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  157. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  158. package/dist/web/hooks/use-files.d.ts +2 -6
  159. package/dist/web/hooks/use-files.js +4 -2
  160. package/dist/web/hooks/use-files.js.map +1 -1
  161. package/dist/web/hooks/use-files.test.js +10 -5
  162. package/dist/web/hooks/use-files.test.js.map +1 -1
  163. package/dist/web/hooks/use-layout.d.ts +2 -2
  164. package/dist/web/hooks/use-layout.js +4 -4
  165. package/dist/web/hooks/use-layout.js.map +1 -1
  166. package/dist/web/hooks/use-layout.test.js +7 -6
  167. package/dist/web/hooks/use-layout.test.js.map +1 -1
  168. package/dist/web/hooks/use-open-external.d.ts +3 -1
  169. package/dist/web/hooks/use-open-external.js +3 -3
  170. package/dist/web/hooks/use-open-external.js.map +1 -1
  171. package/dist/web/hooks/use-open-external.test.js +27 -12
  172. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  173. package/dist/web/hooks/use-request-modal.d.ts +2 -2
  174. package/dist/web/hooks/use-request-modal.js +9 -7
  175. package/dist/web/hooks/use-request-modal.js.map +1 -1
  176. package/dist/web/hooks/use-request-modal.test.js +5 -1
  177. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  178. package/dist/web/hooks/use-send-follow-up-message.js +2 -2
  179. package/dist/web/hooks/use-set-open-in-app-url.d.ts +1 -0
  180. package/dist/web/hooks/use-set-open-in-app-url.js +8 -0
  181. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  182. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  183. package/dist/web/hooks/use-set-open-in-app-url.test.js +43 -0
  184. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  185. package/dist/web/hooks/use-tool-info.js +4 -4
  186. package/dist/web/hooks/use-tool-info.js.map +1 -1
  187. package/dist/web/hooks/use-tool-info.test.js +5 -5
  188. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  189. package/dist/web/hooks/use-user.d.ts +1 -1
  190. package/dist/web/hooks/use-user.js +20 -4
  191. package/dist/web/hooks/use-user.js.map +1 -1
  192. package/dist/web/hooks/use-user.test.js +33 -4
  193. package/dist/web/hooks/use-user.test.js.map +1 -1
  194. package/dist/web/hooks/use-widget-state.js +10 -10
  195. package/dist/web/hooks/use-widget-state.js.map +1 -1
  196. package/dist/web/hooks/use-widget-state.test.js +9 -6
  197. package/dist/web/hooks/use-widget-state.test.js.map +1 -1
  198. package/dist/web/mount-widget.js +9 -1
  199. package/dist/web/mount-widget.js.map +1 -1
  200. package/dist/web/plugin/plugin.js +24 -9
  201. package/dist/web/plugin/plugin.js.map +1 -1
  202. package/dist/web/plugin/validate-widget.d.ts +5 -0
  203. package/dist/web/plugin/validate-widget.js +27 -0
  204. package/dist/web/plugin/validate-widget.js.map +1 -0
  205. package/dist/web/plugin/validate-widget.test.d.ts +1 -0
  206. package/dist/web/plugin/validate-widget.test.js +42 -0
  207. package/dist/web/plugin/validate-widget.test.js.map +1 -0
  208. package/dist/web/proxy.js +0 -1
  209. package/dist/web/proxy.js.map +1 -1
  210. package/dist/web/types.d.ts +0 -133
  211. package/dist/web/types.js +0 -9
  212. package/dist/web/types.js.map +1 -1
  213. package/package.json +36 -25
  214. package/tsconfig.base.json +31 -0
  215. package/dist/cli/use-version.d.ts +0 -1
  216. package/dist/cli/use-version.js +0 -33
  217. package/dist/cli/use-version.js.map +0 -1
  218. package/dist/web/bridges/adaptors/apps-sdk-adaptor.d.ts +0 -13
  219. package/dist/web/bridges/adaptors/apps-sdk-adaptor.js +0 -33
  220. package/dist/web/bridges/adaptors/apps-sdk-adaptor.js.map +0 -1
  221. package/dist/web/bridges/adaptors/mcp-app-adaptor.d.ts +0 -16
  222. package/dist/web/bridges/adaptors/mcp-app-adaptor.js +0 -115
  223. package/dist/web/bridges/adaptors/mcp-app-adaptor.js.map +0 -1
  224. package/dist/web/bridges/apps-sdk-bridge.d.ts +0 -10
  225. package/dist/web/bridges/apps-sdk-bridge.js.map +0 -1
  226. package/dist/web/bridges/hooks/use-adaptor.d.ts +0 -2
  227. package/dist/web/bridges/hooks/use-adaptor.js +0 -8
  228. package/dist/web/bridges/hooks/use-adaptor.js.map +0 -1
  229. package/dist/web/bridges/hooks/use-apps-sdk-bridge.d.ts +0 -2
  230. package/dist/web/bridges/hooks/use-apps-sdk-bridge.js.map +0 -1
  231. package/dist/web/bridges/hooks/use-bridge.d.ts +0 -2
  232. package/dist/web/bridges/hooks/use-bridge.js +0 -8
  233. package/dist/web/bridges/hooks/use-bridge.js.map +0 -1
  234. package/dist/web/bridges/hooks/use-mcp-app-bridge.d.ts +0 -5
  235. package/dist/web/bridges/hooks/use-mcp-app-bridge.js +0 -7
  236. package/dist/web/bridges/hooks/use-mcp-app-bridge.js.map +0 -1
  237. package/dist/web/bridges/hooks/use-mcp-app-bridge.test.js +0 -62
  238. package/dist/web/bridges/hooks/use-mcp-app-bridge.test.js.map +0 -1
  239. package/dist/web/bridges/mcp-app-bridge.d.ts +0 -46
  240. package/dist/web/bridges/mcp-app-bridge.js +0 -217
  241. package/dist/web/bridges/mcp-app-bridge.js.map +0 -1
  242. package/dist/web/hooks/use-openai-global.d.ts +0 -3
  243. package/dist/web/hooks/use-openai-global.js +0 -6
  244. package/dist/web/hooks/use-openai-global.js.map +0 -1
  245. /package/dist/{web/bridges/hooks/use-mcp-app-bridge.test.d.ts → server/asset-base-url-transform-plugin.test.d.ts} +0 -0
@@ -1,7 +1,11 @@
1
+ import crypto from "node:crypto";
1
2
  import { readFileSync } from "node:fs";
3
+ import http from "node:http";
2
4
  import path from "node:path";
3
5
  import { McpServer as McpServerBase, } from "@modelcontextprotocol/sdk/server/mcp.js";
4
6
  import { mergeWith, union } from "es-toolkit";
7
+ import { createApp } from "./express.js";
8
+ import { buildMiddlewareChain, getHandlerMaps } from "./middleware.js";
5
9
  import { templateHelper } from "./templateHelper.js";
6
10
  const mergeWithUnion = (target, source) => {
7
11
  return mergeWith(target, source, (targetVal, sourceVal) => {
@@ -11,68 +15,179 @@ const mergeWithUnion = (target, source) => {
11
15
  });
12
16
  };
13
17
  export class McpServer extends McpServerBase {
18
+ express;
19
+ customMiddleware = [];
20
+ customErrorMiddleware = [];
21
+ mcpMiddlewareEntries = [];
22
+ mcpMiddlewareApplied = false;
23
+ use(pathOrHandler, ...handlers) {
24
+ if (typeof pathOrHandler === "string") {
25
+ this.customMiddleware.push({
26
+ path: pathOrHandler,
27
+ handlers,
28
+ });
29
+ }
30
+ else {
31
+ this.customMiddleware.push({
32
+ handlers: [pathOrHandler, ...handlers],
33
+ });
34
+ }
35
+ return this;
36
+ }
37
+ useOnError(pathOrHandler, ...handlers) {
38
+ if (typeof pathOrHandler === "string") {
39
+ this.customErrorMiddleware.push({ path: pathOrHandler, handlers });
40
+ }
41
+ else {
42
+ this.customErrorMiddleware.push({
43
+ handlers: [pathOrHandler, ...handlers],
44
+ });
45
+ }
46
+ return this;
47
+ }
48
+ mcpMiddleware(filterOrHandler,
49
+ // biome-ignore lint/suspicious/noExplicitAny: overloads narrow the handler type at call sites; implementation must accept all variants
50
+ maybeHandler) {
51
+ if (this.mcpMiddlewareApplied) {
52
+ throw new Error("Cannot register MCP middleware after run() or connect() has been called");
53
+ }
54
+ const handler = maybeHandler;
55
+ if (typeof filterOrHandler === "function") {
56
+ this.mcpMiddlewareEntries.push({
57
+ filter: null,
58
+ handler: filterOrHandler,
59
+ });
60
+ }
61
+ else if (handler) {
62
+ this.mcpMiddlewareEntries.push({
63
+ filter: filterOrHandler,
64
+ handler,
65
+ });
66
+ }
67
+ else {
68
+ throw new Error("mcpMiddleware requires a handler function when a filter is provided");
69
+ }
70
+ return this;
71
+ }
72
+ applyMcpMiddleware() {
73
+ if (this.mcpMiddlewareApplied) {
74
+ return;
75
+ }
76
+ this.mcpMiddlewareApplied = true;
77
+ if (this.mcpMiddlewareEntries.length === 0) {
78
+ return;
79
+ }
80
+ const { requestHandlers, notificationHandlers } = getHandlerMaps(this.server);
81
+ const entries = this.mcpMiddlewareEntries;
82
+ // Wrap existing handlers and proxy future .set() for lazy SDK registration
83
+ const instrumentMap = (map, isNotification) => {
84
+ for (const [method, handler] of map) {
85
+ map.set(method, buildMiddlewareChain(method, isNotification, handler, entries));
86
+ }
87
+ const originalSet = map.set.bind(map);
88
+ map.set = (method, handler) => originalSet(method, buildMiddlewareChain(method, isNotification, handler, entries));
89
+ };
90
+ instrumentMap(requestHandlers, false);
91
+ instrumentMap(notificationHandlers, true);
92
+ }
93
+ async connect(transport) {
94
+ this.applyMcpMiddleware();
95
+ return super.connect(transport);
96
+ }
97
+ async run() {
98
+ this.applyMcpMiddleware();
99
+ const httpServer = http.createServer();
100
+ if (!this.express) {
101
+ this.express = await createApp({
102
+ mcpServer: this,
103
+ httpServer,
104
+ customMiddleware: this.customMiddleware,
105
+ errorMiddleware: this.customErrorMiddleware,
106
+ });
107
+ }
108
+ httpServer.on("request", this.express);
109
+ return new Promise((resolve, reject) => {
110
+ httpServer.on("error", (error) => {
111
+ console.error("Failed to start server:", error);
112
+ reject(error);
113
+ });
114
+ const port = parseInt(process.env.__PORT ?? "3000", 10);
115
+ httpServer.listen(port, () => {
116
+ resolve();
117
+ });
118
+ });
119
+ }
14
120
  registerWidget(name, resourceConfig, toolConfig, toolCallback) {
15
121
  const userMeta = resourceConfig._meta;
16
- const appsSdkResourceConfig = {
17
- hostType: "apps-sdk",
18
- uri: `ui://widgets/apps-sdk/${name}.html`,
19
- mimeType: "text/html+skybridge",
20
- buildContentMeta: ({ resourceDomains, connectDomains, domain }) => {
21
- const userUi = userMeta?.ui;
22
- const userCsp = userUi?.csp;
23
- const defaults = {
24
- "openai/widgetCSP": {
25
- resource_domains: resourceDomains,
26
- connect_domains: connectDomains,
27
- },
28
- "openai/widgetDomain": domain,
29
- "openai/widgetDescription": toolConfig.description,
30
- };
31
- const fromUi = {
32
- "openai/widgetCSP": {
33
- resource_domains: userCsp?.resourceDomains,
34
- connect_domains: userCsp?.connectDomains,
35
- frame_domains: userCsp?.frameDomains,
36
- redirect_domains: userCsp?.redirectDomains,
37
- },
38
- "openai/widgetDomain": userUi?.domain,
39
- "openai/widgetPrefersBorder": userUi?.prefersBorder,
40
- };
41
- const directOpenaiKeys = Object.fromEntries(Object.entries(userMeta ?? {}).filter(([key]) => key.startsWith("openai/")));
42
- return mergeWithUnion(mergeWithUnion(defaults, fromUi), directOpenaiKeys);
43
- },
122
+ const toolMeta = {
123
+ ...toolConfig._meta,
44
124
  };
45
- const extAppsResourceConfig = {
46
- hostType: "mcp-app",
47
- uri: `ui://widgets/ext-apps/${name}.html`,
48
- mimeType: "text/html;profile=mcp-app",
49
- buildContentMeta: ({ resourceDomains, connectDomains, domain }) => {
50
- const defaults = {
51
- ui: {
52
- csp: {
53
- resourceDomains,
54
- connectDomains,
125
+ if (!resourceConfig.hosts || resourceConfig.hosts.includes("apps-sdk")) {
126
+ const widgetConfig = {
127
+ hostType: "apps-sdk",
128
+ uri: `ui://widgets/apps-sdk/${name}.html`,
129
+ mimeType: "text/html+skybridge",
130
+ buildContentMeta: ({ resourceDomains, connectDomains, domain }, overrides) => {
131
+ const userUi = userMeta?.ui;
132
+ const userCsp = userUi?.csp;
133
+ const defaults = {
134
+ "openai/widgetCSP": {
135
+ resource_domains: resourceDomains,
136
+ connect_domains: connectDomains,
55
137
  },
56
- domain,
57
- },
58
- };
59
- return mergeWithUnion(defaults, { ui: userMeta?.ui });
60
- },
61
- };
62
- [appsSdkResourceConfig, extAppsResourceConfig].forEach((widgetConfig) => {
138
+ "openai/widgetDomain": domain,
139
+ "openai/widgetDescription": resourceConfig.description,
140
+ };
141
+ const fromUi = {
142
+ "openai/widgetCSP": {
143
+ resource_domains: userCsp?.resourceDomains,
144
+ connect_domains: userCsp?.connectDomains,
145
+ frame_domains: userCsp?.frameDomains,
146
+ redirect_domains: userCsp?.redirectDomains,
147
+ },
148
+ "openai/widgetDomain": userUi?.domain,
149
+ "openai/widgetPrefersBorder": userUi?.prefersBorder,
150
+ };
151
+ const directOpenaiKeys = Object.fromEntries(Object.entries(userMeta ?? {}).filter(([key]) => key.startsWith("openai/")));
152
+ return mergeWithUnion(mergeWithUnion(mergeWithUnion(defaults, fromUi), directOpenaiKeys), { "openai/widgetDomain": overrides.domain });
153
+ },
154
+ };
63
155
  this.registerWidgetResource({
64
156
  name,
65
157
  widgetConfig,
66
158
  resourceConfig,
67
159
  });
68
- });
69
- const toolMeta = {
70
- ...toolConfig._meta,
71
- "openai/outputTemplate": appsSdkResourceConfig.uri,
72
- ui: {
73
- resourceUri: extAppsResourceConfig.uri,
74
- },
75
- };
160
+ toolMeta["openai/outputTemplate"] = widgetConfig.uri;
161
+ }
162
+ if (!resourceConfig.hosts || resourceConfig.hosts.includes("mcp-app")) {
163
+ const widgetConfig = {
164
+ hostType: "mcp-app",
165
+ uri: `ui://widgets/ext-apps/${name}.html`,
166
+ mimeType: "text/html;profile=mcp-app",
167
+ buildContentMeta: ({ resourceDomains, connectDomains, domain }, overrides) => {
168
+ const defaults = {
169
+ ui: {
170
+ csp: {
171
+ resourceDomains,
172
+ connectDomains,
173
+ },
174
+ domain,
175
+ },
176
+ };
177
+ return mergeWithUnion(defaults, {
178
+ ui: { ...userMeta?.ui, ...overrides },
179
+ });
180
+ },
181
+ };
182
+ this.registerWidgetResource({
183
+ name,
184
+ widgetConfig,
185
+ resourceConfig,
186
+ });
187
+ // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
188
+ toolMeta["ui/resourceUri"] = widgetConfig.uri;
189
+ toolMeta.ui = { resourceUri: widgetConfig.uri };
190
+ }
76
191
  this.registerTool(name, {
77
192
  ...toolConfig,
78
193
  _meta: toolMeta,
@@ -87,9 +202,33 @@ export class McpServer extends McpServerBase {
87
202
  const { hostType, uri: widgetUri, mimeType, buildContentMeta, } = widgetConfig;
88
203
  this.registerResource(name, widgetUri, { ...resourceConfig, _meta: resourceConfig._meta }, async (uri, extra) => {
89
204
  const isProduction = process.env.NODE_ENV === "production";
90
- const serverUrl = isProduction
91
- ? `https://${extra?.requestInfo?.headers?.["x-forwarded-host"] ?? extra?.requestInfo?.headers?.host}`
92
- : "http://localhost:3000";
205
+ const isClaude = extra?.requestInfo?.headers?.["user-agent"] === "Claude-User";
206
+ const headers = extra?.requestInfo?.headers || {};
207
+ const header = (key) => {
208
+ const val = headers[key];
209
+ return Array.isArray(val) ? val[0] : val;
210
+ };
211
+ let serverUrl;
212
+ const forwardedHost = header("x-forwarded-host");
213
+ const origin = header("origin");
214
+ const host = header("host");
215
+ if (forwardedHost) {
216
+ const proto = header("x-forwarded-proto") || "https";
217
+ serverUrl = `${proto}://${forwardedHost}`;
218
+ }
219
+ else if (origin) {
220
+ serverUrl = origin;
221
+ }
222
+ else if (host) {
223
+ const proto = ["127.0.0.1:", "localhost:"].some((p) => host.startsWith(p))
224
+ ? "http"
225
+ : "https";
226
+ serverUrl = `${proto}://${host}`;
227
+ }
228
+ else {
229
+ const devPort = process.env.__PORT || "3000";
230
+ serverUrl = `http://localhost:${devPort}`;
231
+ }
93
232
  const html = isProduction
94
233
  ? templateHelper.renderProduction({
95
234
  hostType,
@@ -102,12 +241,29 @@ export class McpServer extends McpServerBase {
102
241
  serverUrl,
103
242
  widgetName: name,
104
243
  });
105
- const VITE_HMR_WEBSOCKET_DEFAULT_URL = "ws://localhost:24678";
244
+ const connectDomains = [serverUrl];
245
+ if (!isProduction) {
246
+ const wsUrl = new URL(serverUrl);
247
+ wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
248
+ connectDomains.push(wsUrl.origin);
249
+ }
250
+ let contentMetaOverrides = {};
251
+ if (isClaude) {
252
+ const pathname = extra?.requestInfo?.url?.pathname ?? "";
253
+ const url = `${serverUrl}${pathname}`;
254
+ const hash = crypto
255
+ .createHash("sha256")
256
+ .update(url)
257
+ .digest("hex")
258
+ .slice(0, 32);
259
+ contentMetaOverrides = { domain: `${hash}.claudemcpcontent.com` };
260
+ }
106
261
  const contentMeta = buildContentMeta({
107
262
  resourceDomains: [serverUrl],
108
- connectDomains: !isProduction ? [VITE_HMR_WEBSOCKET_DEFAULT_URL] : [],
263
+ connectDomains,
109
264
  domain: serverUrl,
110
- });
265
+ baseUriDomains: [serverUrl],
266
+ }, contentMetaOverrides);
111
267
  return {
112
268
  contents: [
113
269
  { uri: uri.href, mimeType, text: html, _meta: contentMeta },
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- <base href="{{serverUrl}}" />
2
- <script type="module">window.skybridge = { hostType: "{{hostType}}" };</script>
1
+ <script type="module">window.skybridge = { hostType: "{{hostType}}", serverUrl: "{{serverUrl}}" };</script>
3
2
  <script type="module">
4
3
  import { injectIntoGlobalHook } from "{{serverUrl}}/assets/@react-refresh";
5
4
  injectIntoGlobalHook(window); window.$RefreshReg$ = () => {};
@@ -7,59 +6,6 @@
7
6
  window.__vite_plugin_react_preamble_installed__ = true;
8
7
  </script>
9
8
  <script type="module" src="{{serverUrl}}/@vite/client"></script>
10
- <script type="module">
11
- // Checks for browser support and shows error if local network access is denied
12
- (async () => {
13
- if (!navigator.permissions?.query) {
14
- return;
15
- }
16
-
17
- // Skip for non-http(s) protocols (file://, custom protocols in Electron, etc.)
18
- const protocol = window.location.protocol;
19
- const isNonHttpProtocol = protocol !== 'http:' && protocol !== 'https:'
20
- if (isNonHttpProtocol) {
21
- return;
22
- }
23
-
24
- const host = window.location.hostname;
25
- const isLoopback = host === 'localhost'
26
- || /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.test(host)
27
- || host === '::1';
28
- if (isLoopback) {
29
- return;
30
- }
31
-
32
- try {
33
- const status = await navigator.permissions.query({ name: "local-network-access" });
34
- if (status.state === "denied") {
35
- const errorDiv = document.createElement("div");
36
- errorDiv.style.cssText = "background: #fef2f2; border: 2px solid #ef4444; border-radius: 8px; padding: 16px; text-align: center; z-index: 10000; font-family: system-ui, sans-serif;";
37
-
38
- const errorTitle = document.createElement("div");
39
- errorTitle.style.cssText = "color: #ef4444; font-size: 18px; font-weight: 600; margin-bottom: 8px;";
40
- errorTitle.textContent = "Error: Local network access permission is denied.";
41
-
42
- const errorMessage = document.createElement("div");
43
- errorMessage.style.cssText = "color: #ef4444; font-size: 14px;";
44
- errorMessage.textContent = "Local network access is required for your widget to connect to the local dev server. Please enable it in your browser settings. ";
45
-
46
- const link = document.createElement("a");
47
- link.href = "https://developer.chrome.com/blog/local-network-access";
48
- link.target = "_blank";
49
- link.rel = "noopener noreferrer";
50
- link.style.cssText = "color: #ef4444; text-decoration: underline;";
51
- link.textContent = "Learn more";
52
- errorMessage.appendChild(link);
53
-
54
- errorDiv.appendChild(errorTitle);
55
- errorDiv.appendChild(errorMessage);
56
- document.body.appendChild(errorDiv);
57
- }
58
- } catch (e) {
59
- // Permission API doesn't support local-network-access, ignore silently
60
- }
61
- })();
62
- </script>
63
9
  <div id="root"></div>
64
10
  <script type="module" id="dev-widget-entry">
65
11
  import('{{serverUrl}}/src/widgets/{{widgetName}}');
@@ -1,5 +1,4 @@
1
- <base href="{{serverUrl}}" />
2
- <script type="module">window.skybridge = { hostType: "{{hostType}}" };</script>
1
+ <script type="module">window.skybridge = { hostType: "{{hostType}}", serverUrl: "{{serverUrl}}" };</script>
3
2
  <div id="root"></div>
4
3
  <script type="module">
5
4
  import('{{serverUrl}}/assets/{{widgetFile}}');
@@ -1,3 +1,4 @@
1
+ import type http from "node:http";
1
2
  import { type Router } from "express";
2
3
  /**
3
4
  * Install Vite dev server
@@ -9,4 +10,4 @@ import { type Router } from "express";
9
10
  * app.use(await widgetsRouter());
10
11
  * }
11
12
  */
12
- export declare const widgetsDevServer: () => Promise<Router>;
13
+ export declare const widgetsDevServer: (httpServer: http.Server) => Promise<Router>;
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import cors from "cors";
4
4
  import express, {} from "express";
5
+ import { assetBaseUrlTransformPlugin } from "./asset-base-url-transform-plugin.js";
5
6
  /**
6
7
  * Install Vite dev server
7
8
  * This router MUST be installed at the application root, like so:
@@ -12,7 +13,7 @@ import express, {} from "express";
12
13
  * app.use(await widgetsRouter());
13
14
  * }
14
15
  */
15
- export const widgetsDevServer = async () => {
16
+ export const widgetsDevServer = async (httpServer) => {
16
17
  const router = express.Router();
17
18
  const { createServer, searchForWorkspaceRoot, loadConfigFromFile } = await import("vite");
18
19
  // Since 0.16.0, the template is a single package that does not rely on workspace.
@@ -26,7 +27,7 @@ export const widgetsDevServer = async () => {
26
27
  webAppRoot = path.join(workspaceRoot, "web");
27
28
  }
28
29
  const configResult = await loadConfigFromFile({ command: "serve", mode: "development" }, path.join(webAppRoot, "vite.config.ts"), webAppRoot);
29
- const { build, preview, ...devConfig } = configResult?.config || {};
30
+ const { build, preview, plugins: userPlugins = [], ...devConfig } = configResult?.config || {};
30
31
  const vite = await createServer({
31
32
  ...devConfig,
32
33
  configFile: false, // Keep this to prevent vite from trying to resolve path in the target config file
@@ -34,11 +35,20 @@ export const widgetsDevServer = async () => {
34
35
  server: {
35
36
  allowedHosts: true,
36
37
  middlewareMode: true,
38
+ hmr: {
39
+ server: httpServer,
40
+ },
37
41
  },
38
42
  root: webAppRoot,
39
43
  optimizeDeps: {
40
44
  include: ["react", "react-dom/client"],
41
45
  },
46
+ plugins: [
47
+ ...userPlugins,
48
+ assetBaseUrlTransformPlugin({
49
+ devServerOrigin: `http://localhost:${process.env.__PORT ?? "3000"}`,
50
+ }),
51
+ ],
42
52
  });
43
53
  router.use(cors());
44
54
  router.use("/", vite.middlewares);
@@ -1 +1 @@
1
- {"version":3,"file":"widgetsDevServer.js","sourceRoot":"","sources":["../../src/server/widgetsDevServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,EAAE,EAAe,MAAM,SAAS,CAAC;AAC/C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAqB,EAAE;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,GAChE,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAEvB,kFAAkF;IAClF,gFAAgF;IAChF,+FAA+F;IAC/F,IAAI,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAEjD,0DAA0D;IAC1D,MAAM,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAC3C,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,EACzC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EACvC,UAAU,CACX,CAAC;IAEF,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,GAAG,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC;IAEpE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC;QAC9B,GAAG,SAAS;QACZ,UAAU,EAAE,KAAK,EAAE,kFAAkF;QACrG,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE;YACN,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI;SACrB;QACD,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE;YACZ,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,CAAC;SACvC;KACF,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAElC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
1
+ {"version":3,"file":"widgetsDevServer.js","sourceRoot":"","sources":["../../src/server/widgetsDevServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,EAAE,EAAe,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AAEnF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,UAAuB,EACN,EAAE;IACnB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,MAAM,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,GAChE,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAEvB,kFAAkF;IAClF,gFAAgF;IAChF,+FAA+F;IAC/F,IAAI,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAEjD,0DAA0D;IAC1D,MAAM,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAC3C,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,EACzC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EACvC,UAAU,CACX,CAAC;IAEF,MAAM,EACJ,KAAK,EACL,OAAO,EACP,OAAO,EAAE,WAAW,GAAG,EAAE,EACzB,GAAG,SAAS,EACb,GAAG,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC;IAE/B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC;QAC9B,GAAG,SAAS;QACZ,UAAU,EAAE,KAAK,EAAE,kFAAkF;QACrG,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE;YACN,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI;YACpB,GAAG,EAAE;gBACH,MAAM,EAAE,UAAU;aACnB;SACF;QACD,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE;YACZ,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,CAAC;SACvC;QACD,OAAO,EAAE;YACP,GAAG,WAAW;YACd,2BAA2B,CAAC;gBAC1B,eAAe,EAAE,oBAAoB,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,EAAE;aACpE,CAAC;SACH;KACF,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAElC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
@@ -43,8 +43,10 @@ describe("McpServer.registerWidget", () => {
43
43
  const appsSdkResourceCallback = mockRegisterResource.mock
44
44
  .calls[0]?.[3];
45
45
  expect(appsSdkResourceCallback).toBeDefined();
46
- const serverUrl = "http://localhost:3000";
47
- const mockExtra = createMockExtra("__not_used__");
46
+ const host = "localhost:3000";
47
+ const serverUrl = `http://${host}`;
48
+ const hmrUrl = `ws://${host}`;
49
+ const mockExtra = createMockExtra(host);
48
50
  const result = await appsSdkResourceCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), mockExtra);
49
51
  expect(mockRegisterTool).toHaveBeenCalled();
50
52
  expect(result).toEqual({
@@ -56,10 +58,10 @@ describe("McpServer.registerWidget", () => {
56
58
  _meta: {
57
59
  "openai/widgetCSP": {
58
60
  resource_domains: [serverUrl],
59
- connect_domains: ["ws://localhost:24678"],
61
+ connect_domains: [serverUrl, hmrUrl],
60
62
  },
61
63
  "openai/widgetDomain": serverUrl,
62
- "openai/widgetDescription": "Test tool",
64
+ "openai/widgetDescription": "Test widget",
63
65
  },
64
66
  },
65
67
  ],
@@ -93,10 +95,10 @@ describe("McpServer.registerWidget", () => {
93
95
  _meta: {
94
96
  "openai/widgetCSP": {
95
97
  resource_domains: [serverUrl],
96
- connect_domains: [],
98
+ connect_domains: [serverUrl],
97
99
  },
98
100
  "openai/widgetDomain": serverUrl,
99
- "openai/widgetDescription": "Test tool",
101
+ "openai/widgetDescription": "Test widget",
100
102
  },
101
103
  },
102
104
  ],
@@ -134,7 +136,10 @@ describe("McpServer.registerWidget", () => {
134
136
  expect(mockRegisterResource).toHaveBeenCalledTimes(2);
135
137
  const appsSdkCallback = mockRegisterResource.mock
136
138
  .calls[0]?.[3];
137
- const appsSdkResult = await appsSdkCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), createMockExtra("__not_used__"));
139
+ const appsSdkResult = await appsSdkCallback(new URL("ui://widgets/apps-sdk/my-widget.html"), createMockExtra("localhost:3000"));
140
+ const host = "localhost:3000";
141
+ const serverUrl = `http://${host}`;
142
+ const hmrUrl = `ws://${host}`;
138
143
  expect(appsSdkResult).toEqual({
139
144
  contents: [
140
145
  {
@@ -143,21 +148,21 @@ describe("McpServer.registerWidget", () => {
143
148
  text: expect.stringContaining('<div id="root"></div>'),
144
149
  _meta: {
145
150
  "openai/widgetCSP": {
146
- resource_domains: ["http://localhost:3000"],
147
- connect_domains: ["ws://localhost:24678"],
151
+ resource_domains: [serverUrl],
152
+ connect_domains: [serverUrl, hmrUrl],
148
153
  },
149
- "openai/widgetDomain": "http://localhost:3000",
150
- "openai/widgetDescription": "Test tool",
154
+ "openai/widgetDomain": serverUrl,
155
+ "openai/widgetDescription": "Test widget",
151
156
  "openai/widgetPrefersBorder": true,
152
157
  },
153
158
  },
154
159
  ],
155
160
  });
156
- expect(appsSdkResult.contents[0]?.text).toContain('window.skybridge = { hostType: "apps-sdk" }');
161
+ expect(appsSdkResult.contents[0]?.text).toContain('window.skybridge = { hostType: "apps-sdk", serverUrl: "http://localhost:3000" };');
157
162
  const extAppsResourceCallback = mockRegisterResource.mock
158
163
  .calls[1]?.[3];
159
164
  expect(extAppsResourceCallback).toBeDefined();
160
- const extAppsResult = await extAppsResourceCallback(new URL("ui://widgets/ext-apps/my-widget.html"), createMockExtra("__not_used__"));
165
+ const extAppsResult = await extAppsResourceCallback(new URL("ui://widgets/ext-apps/my-widget.html"), createMockExtra(host));
161
166
  expect(extAppsResult).toEqual({
162
167
  contents: [
163
168
  {
@@ -167,16 +172,16 @@ describe("McpServer.registerWidget", () => {
167
172
  _meta: {
168
173
  ui: {
169
174
  csp: {
170
- resourceDomains: ["http://localhost:3000"],
171
- connectDomains: ["ws://localhost:24678"],
175
+ resourceDomains: [serverUrl],
176
+ connectDomains: [serverUrl, hmrUrl],
172
177
  },
173
- domain: "http://localhost:3000",
178
+ domain: serverUrl,
174
179
  },
175
180
  },
176
181
  },
177
182
  ],
178
183
  });
179
- expect(extAppsResult.contents[0]?.text).toContain('window.skybridge = { hostType: "mcp-app" }');
184
+ expect(extAppsResult.contents[0]?.text).toContain('window.skybridge = { hostType: "mcp-app", serverUrl: "http://localhost:3000" };');
180
185
  });
181
186
  it("should register tool with ui.resourceUri metadata (not deprecated ui/resourceUri)", async () => {
182
187
  const mockToolCallback = vi.fn();
@@ -214,12 +219,15 @@ describe("McpServer.registerWidget", () => {
214
219
  server.registerWidget("override-test", mockRegisterResourceConfig, mockToolConfig, mockToolCallback);
215
220
  const appsSdkCallback = mockRegisterResource.mock
216
221
  .calls[0]?.[3];
217
- const result = await appsSdkCallback(new URL("ui://widgets/apps-sdk/override-test.html"), createMockExtra("__not_used__"));
222
+ const host = `localhost:3000`;
223
+ const serverUrl = `http://${host}`;
224
+ const hmrUrl = `ws://${host}`;
225
+ const result = await appsSdkCallback(new URL("ui://widgets/apps-sdk/override-test.html"), createMockExtra(host));
218
226
  const meta = result.contents[0]?._meta;
219
227
  // CSP arrays are merged with union - all unique domains from defaults and user config are preserved
220
228
  expect(meta["openai/widgetCSP"]).toEqual({
221
- resource_domains: ["http://localhost:3000", "https://from-ui-csp.com"],
222
- connect_domains: ["ws://localhost:24678", "https://from-ui-csp.com"],
229
+ resource_domains: [serverUrl, "https://from-ui-csp.com"],
230
+ connect_domains: [serverUrl, hmrUrl, "https://from-ui-csp.com"],
223
231
  frame_domains: undefined,
224
232
  redirect_domains: undefined,
225
233
  });
@@ -228,7 +236,28 @@ describe("McpServer.registerWidget", () => {
228
236
  // PrefersBorder should be overridden by direct openai/* key (highest priority)
229
237
  expect(meta["openai/widgetPrefersBorder"]).toBe(true);
230
238
  // Description should be from defaults (toolConfig.description)
231
- expect(meta["openai/widgetDescription"]).toBe("Test tool");
239
+ expect(meta["openai/widgetDescription"]).toBe("Test widget");
240
+ });
241
+ it("should register tool with ui.resourceUri metadata only", async () => {
242
+ const mockToolCallback = vi.fn();
243
+ server.registerWidget("my-widget", { description: "Test widget", hosts: ["mcp-app"] }, { description: "Test tool" }, mockToolCallback);
244
+ expect(mockRegisterTool).toHaveBeenCalledTimes(1);
245
+ const toolCallArgs = mockRegisterTool.mock.calls[0];
246
+ const toolConfig = toolCallArgs?.[1];
247
+ expect(toolConfig._meta).toHaveProperty("ui");
248
+ expect(toolConfig._meta?.ui).toEqual({
249
+ resourceUri: "ui://widgets/ext-apps/my-widget.html",
250
+ });
251
+ expect(toolConfig._meta?.["openai/outputTemplate"]).to.be.undefined;
252
+ });
253
+ it("should register tool with uopenai/outputTemplate metadata only", async () => {
254
+ const mockToolCallback = vi.fn();
255
+ server.registerWidget("my-widget", { description: "Test widget", hosts: ["apps-sdk"] }, { description: "Test tool" }, mockToolCallback);
256
+ expect(mockRegisterTool).toHaveBeenCalledTimes(1);
257
+ const toolCallArgs = mockRegisterTool.mock.calls[0];
258
+ const toolConfig = toolCallArgs?.[1];
259
+ expect(toolConfig._meta).not.toHaveProperty("ui");
260
+ expect(toolConfig._meta?.["openai/outputTemplate"]).to.eq("ui://widgets/apps-sdk/my-widget.html");
232
261
  });
233
262
  });
234
263
  //# sourceMappingURL=widget.test.js.map