skybridge 0.0.0-dev.e56312b → 0.0.0-dev.e57854a

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 (188) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/build-helpers.d.ts +5 -1
  3. package/dist/cli/build-helpers.js +30 -10
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +58 -3
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +73 -0
  9. package/dist/cli/build-steps.js.map +1 -0
  10. package/dist/cli/build-steps.test.d.ts +1 -0
  11. package/dist/cli/build-steps.test.js +52 -0
  12. package/dist/cli/build-steps.test.js.map +1 -0
  13. package/dist/cli/header.d.ts +1 -1
  14. package/dist/cli/run-plain.d.ts +18 -0
  15. package/dist/cli/run-plain.js +89 -0
  16. package/dist/cli/run-plain.js.map +1 -0
  17. package/dist/cli/use-nodemon.d.ts +14 -0
  18. package/dist/cli/use-nodemon.js +71 -60
  19. package/dist/cli/use-nodemon.js.map +1 -1
  20. package/dist/cli/use-typescript-check.d.ts +8 -2
  21. package/dist/cli/use-typescript-check.js +70 -67
  22. package/dist/cli/use-typescript-check.js.map +1 -1
  23. package/dist/commands/build.d.ts +0 -2
  24. package/dist/commands/build.js +2 -61
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/dev.d.ts +1 -0
  27. package/dist/commands/dev.js +32 -0
  28. package/dist/commands/dev.js.map +1 -1
  29. package/dist/server/auth/discovery.d.ts +32 -0
  30. package/dist/server/auth/discovery.js +56 -0
  31. package/dist/server/auth/discovery.js.map +1 -0
  32. package/dist/server/auth/discovery.test.d.ts +1 -0
  33. package/dist/server/auth/discovery.test.js +93 -0
  34. package/dist/server/auth/discovery.test.js.map +1 -0
  35. package/dist/server/auth/index.d.ts +18 -0
  36. package/dist/server/auth/index.js +2 -0
  37. package/dist/server/auth/index.js.map +1 -0
  38. package/dist/server/auth/providers/auth0.d.ts +18 -0
  39. package/dist/server/auth/providers/auth0.js +31 -0
  40. package/dist/server/auth/providers/auth0.js.map +1 -0
  41. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  42. package/dist/server/auth/providers/auth0.test.js +48 -0
  43. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  44. package/dist/server/auth/providers/clerk.d.ts +14 -0
  45. package/dist/server/auth/providers/clerk.js +16 -0
  46. package/dist/server/auth/providers/clerk.js.map +1 -0
  47. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  48. package/dist/server/auth/providers/clerk.test.js +28 -0
  49. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  50. package/dist/server/auth/providers/custom.d.ts +30 -0
  51. package/dist/server/auth/providers/custom.js +40 -0
  52. package/dist/server/auth/providers/custom.js.map +1 -0
  53. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  54. package/dist/server/auth/providers/custom.test.js +128 -0
  55. package/dist/server/auth/providers/custom.test.js.map +1 -0
  56. package/dist/server/auth/providers/descope.d.ts +15 -0
  57. package/dist/server/auth/providers/descope.js +35 -0
  58. package/dist/server/auth/providers/descope.js.map +1 -0
  59. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  60. package/dist/server/auth/providers/descope.test.js +39 -0
  61. package/dist/server/auth/providers/descope.test.js.map +1 -0
  62. package/dist/server/auth/providers/shared.d.ts +2 -0
  63. package/dist/server/auth/providers/shared.js +6 -0
  64. package/dist/server/auth/providers/shared.js.map +1 -0
  65. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  66. package/dist/server/auth/providers/shared.test.js +10 -0
  67. package/dist/server/auth/providers/shared.test.js.map +1 -0
  68. package/dist/server/auth/providers/stytch.d.ts +12 -0
  69. package/dist/server/auth/providers/stytch.js +13 -0
  70. package/dist/server/auth/providers/stytch.js.map +1 -0
  71. package/dist/server/auth/providers/workos.d.ts +11 -0
  72. package/dist/server/auth/providers/workos.js +12 -0
  73. package/dist/server/auth/providers/workos.js.map +1 -0
  74. package/dist/server/auth/setup.d.ts +4 -0
  75. package/dist/server/auth/setup.js +51 -0
  76. package/dist/server/auth/setup.js.map +1 -0
  77. package/dist/server/auth/setup.test.d.ts +1 -0
  78. package/dist/server/auth/setup.test.js +185 -0
  79. package/dist/server/auth/setup.test.js.map +1 -0
  80. package/dist/server/auth/verify.d.ts +12 -0
  81. package/dist/server/auth/verify.js +38 -0
  82. package/dist/server/auth/verify.js.map +1 -0
  83. package/dist/server/auth/verify.test.d.ts +1 -0
  84. package/dist/server/auth/verify.test.js +100 -0
  85. package/dist/server/auth/verify.test.js.map +1 -0
  86. package/dist/server/index.d.ts +9 -1
  87. package/dist/server/index.js +8 -1
  88. package/dist/server/index.js.map +1 -1
  89. package/dist/server/requestOrigin.d.ts +7 -0
  90. package/dist/server/requestOrigin.js +25 -0
  91. package/dist/server/requestOrigin.js.map +1 -0
  92. package/dist/server/server.d.ts +32 -5
  93. package/dist/server/server.js +139 -126
  94. package/dist/server/server.js.map +1 -1
  95. package/dist/server/skills-integration.test.d.ts +1 -0
  96. package/dist/server/skills-integration.test.js +63 -0
  97. package/dist/server/skills-integration.test.js.map +1 -0
  98. package/dist/server/skills.d.ts +23 -0
  99. package/dist/server/skills.js +178 -0
  100. package/dist/server/skills.js.map +1 -0
  101. package/dist/server/skills.test.d.ts +1 -0
  102. package/dist/server/skills.test.js +210 -0
  103. package/dist/server/skills.test.js.map +1 -0
  104. package/dist/server/view-name.test-d.d.ts +1 -0
  105. package/dist/server/view-name.test-d.js +8 -0
  106. package/dist/server/view-name.test-d.js.map +1 -0
  107. package/dist/server/view-resource-resolution.test.js +93 -10
  108. package/dist/server/view-resource-resolution.test.js.map +1 -1
  109. package/dist/test/view.test.js +70 -102
  110. package/dist/test/view.test.js.map +1 -1
  111. package/dist/web/bridges/adaptor.d.ts +51 -0
  112. package/dist/web/bridges/adaptor.js +330 -0
  113. package/dist/web/bridges/adaptor.js.map +1 -0
  114. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  115. package/dist/web/bridges/adaptor.test.js +208 -0
  116. package/dist/web/bridges/adaptor.test.js.map +1 -0
  117. package/dist/web/bridges/apps-sdk/bridge.d.ts +6 -2
  118. package/dist/web/bridges/apps-sdk/bridge.js +15 -4
  119. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  120. package/dist/web/bridges/apps-sdk/index.d.ts +0 -1
  121. package/dist/web/bridges/apps-sdk/index.js +0 -1
  122. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  123. package/dist/web/bridges/get-adaptor.d.ts +4 -4
  124. package/dist/web/bridges/get-adaptor.js +6 -11
  125. package/dist/web/bridges/get-adaptor.js.map +1 -1
  126. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  127. package/dist/web/bridges/get-adaptor.test.js +32 -0
  128. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  129. package/dist/web/bridges/mcp-app/bridge.d.ts +13 -2
  130. package/dist/web/bridges/mcp-app/bridge.js +46 -4
  131. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  132. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  133. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  134. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  135. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  136. package/dist/web/bridges/mcp-app/index.js +0 -1
  137. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  138. package/dist/web/bridges/mcp-app/view-tools.test.js +5 -6
  139. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  140. package/dist/web/bridges/types.d.ts +10 -0
  141. package/dist/web/bridges/types.js +14 -1
  142. package/dist/web/bridges/types.js.map +1 -1
  143. package/dist/web/bridges/types.test.d.ts +1 -0
  144. package/dist/web/bridges/types.test.js +19 -0
  145. package/dist/web/bridges/types.test.js.map +1 -0
  146. package/dist/web/components/modal-provider.d.ts +1 -1
  147. package/dist/web/components/modal-provider.js +4 -3
  148. package/dist/web/components/modal-provider.js.map +1 -1
  149. package/dist/web/create-store.test.js +8 -5
  150. package/dist/web/create-store.test.js.map +1 -1
  151. package/dist/web/data-llm.d.ts +1 -1
  152. package/dist/web/data-llm.test.js +17 -5
  153. package/dist/web/data-llm.test.js.map +1 -1
  154. package/dist/web/hooks/use-call-tool.test.js +37 -23
  155. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  156. package/dist/web/hooks/use-display-mode.test.js +56 -20
  157. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  158. package/dist/web/hooks/use-download.test.js +11 -3
  159. package/dist/web/hooks/use-download.test.js.map +1 -1
  160. package/dist/web/hooks/use-files.test.js +10 -2
  161. package/dist/web/hooks/use-files.test.js.map +1 -1
  162. package/dist/web/hooks/use-layout.test.js +59 -26
  163. package/dist/web/hooks/use-layout.test.js.map +1 -1
  164. package/dist/web/hooks/use-open-external.test.js +13 -3
  165. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  166. package/dist/web/hooks/use-request-close.test.js +35 -40
  167. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  168. package/dist/web/hooks/use-request-modal.test.js +10 -0
  169. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  170. package/dist/web/hooks/use-request-size.test.js +35 -53
  171. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  172. package/dist/web/hooks/use-set-open-in-app-url.test.js +28 -8
  173. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  174. package/dist/web/hooks/use-tool-info.test.js +37 -27
  175. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  176. package/dist/web/hooks/use-user.test.js +81 -35
  177. package/dist/web/hooks/use-user.test.js.map +1 -1
  178. package/dist/web/hooks/use-view-state.test.js +6 -2
  179. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  180. package/dist/web/plugin/plugin.js +0 -1
  181. package/dist/web/plugin/plugin.js.map +1 -1
  182. package/package.json +21 -19
  183. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -29
  184. package/dist/web/bridges/apps-sdk/adaptor.js +0 -117
  185. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  186. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -53
  187. package/dist/web/bridges/mcp-app/adaptor.js +0 -283
  188. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
@@ -6,9 +6,12 @@ import { Server as SdkServer, } from "@modelcontextprotocol/sdk/server/index.js"
6
6
  import { McpServer as McpServerBase } from "@modelcontextprotocol/sdk/server/mcp.js";
7
7
  import { mergeWith, union } from "es-toolkit";
8
8
  import express, {} from "express";
9
+ import { setupOAuth } from "./auth/setup.js";
9
10
  import { createApp } from "./express.js";
10
11
  import { createMiddlewareEntry } from "./metric.js";
11
12
  import { buildMiddlewareChain, getHandlerMaps } from "./middleware.js";
13
+ import { resolveServerOrigin } from "./requestOrigin.js";
14
+ import { discoverSkills, registerSkills, SKILLS_EXTENSION_KEY, } from "./skills.js";
12
15
  import { templateHelper } from "./templateHelper.js";
13
16
  const mergeWithUnion = (target, source) => {
14
17
  return mergeWith(target, source, (targetVal, sourceVal) => {
@@ -17,6 +20,20 @@ const mergeWithUnion = (target, source) => {
17
20
  }
18
21
  });
19
22
  };
23
+ const SKILLS_DIR = "src/skills";
24
+ /**
25
+ * Normalize an `x-forwarded-prefix` value into a leading-slash, no-trailing-slash
26
+ * path. Takes the first hop of a comma-separated proxy chain.
27
+ * "/v1/", "v1", "/v1, /internal" → "/v1"; "", "/", undefined → "".
28
+ */
29
+ function normalizeForwardedPrefix(raw) {
30
+ const firstHop = raw?.split(",")[0]?.trim() ?? "";
31
+ const trimmed = firstHop.replace(/\/+$/, "");
32
+ if (trimmed === "") {
33
+ return "";
34
+ }
35
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
36
+ }
20
37
  /**
21
38
  * Drop the query string from a `ui://` view URI, leaving the bare path. The
22
39
  * `?v=` cache key is the only query we append, so a plain split is enough and
@@ -90,6 +107,27 @@ let pendingBuildManifest = null;
90
107
  export function __setBuildManifest(manifest) {
91
108
  pendingBuildManifest = manifest;
92
109
  }
110
+ let pendingSkillsManifest = null;
111
+ export function __setSkillsManifest(manifest) {
112
+ pendingSkillsManifest = manifest;
113
+ }
114
+ // Pure and `this`-free so it can run inside the `super(...)` call, before `this`
115
+ // exists — the capability must be present for the `initialize` response.
116
+ function withSkillsCapability(options, skybridgeOptions) {
117
+ if (!skybridgeOptions?.skills) {
118
+ return options;
119
+ }
120
+ return {
121
+ ...options,
122
+ capabilities: {
123
+ ...options?.capabilities,
124
+ extensions: {
125
+ ...options?.capabilities?.extensions,
126
+ [SKILLS_EXTENSION_KEY]: { directoryRead: true },
127
+ },
128
+ },
129
+ };
130
+ }
93
131
  export class McpServer extends McpServerBaseOmitted {
94
132
  /**
95
133
  * The underlying Express app. Use this to extend the HTTP server with
@@ -122,11 +160,15 @@ export class McpServer extends McpServerBaseOmitted {
122
160
  serverInfo;
123
161
  serverOptions;
124
162
  constructor(serverInfo, options, skybridgeOptions) {
125
- super(serverInfo, options);
163
+ const mergedOptions = withSkillsCapability(options, skybridgeOptions);
164
+ super(serverInfo, mergedOptions);
126
165
  this.serverInfo = serverInfo;
127
- this.serverOptions = options;
166
+ this.serverOptions = mergedOptions;
128
167
  this.express = express();
129
168
  this.express.use(express.json(skybridgeOptions?.json));
169
+ if (skybridgeOptions?.oauth) {
170
+ setupOAuth(this.express, skybridgeOptions.oauth);
171
+ }
130
172
  // Pick up the manifest if `dist/__entry.js` primed it before importing
131
173
  // user code. Consume-once: clear after the first construction so a
132
174
  // subsequent test that doesn't prime can't inherit stale state.
@@ -136,6 +178,19 @@ export class McpServer extends McpServerBaseOmitted {
136
178
  this.setViteManifest(pendingBuildManifest);
137
179
  pendingBuildManifest = null;
138
180
  }
181
+ this.setupSkills(Boolean(skybridgeOptions?.skills));
182
+ }
183
+ setupSkills(enabled) {
184
+ const manifest = pendingSkillsManifest;
185
+ pendingSkillsManifest = null;
186
+ if (!enabled) {
187
+ return;
188
+ }
189
+ const skills = manifest ?? discoverSkills(SKILLS_DIR);
190
+ if (skills.length === 0) {
191
+ console.warn(`skybridge: the "skills" option is enabled but no skills were found in "${SKILLS_DIR}". Add a <name>/SKILL.md there, or remove the option.`);
192
+ }
193
+ registerSkills(this, skills);
139
194
  }
140
195
  use(pathOrHandler, ...handlers) {
141
196
  // Branching is load-bearing: Express's `app.use` overloads can't be
@@ -231,7 +286,7 @@ export class McpServer extends McpServerBaseOmitted {
231
286
  const result = (await next());
232
287
  for (const content of result.contents ?? []) {
233
288
  if (typeof content.uri === "string" &&
234
- stripQuery(content.uri) === path) {
289
+ stripQuery(content.uri) === stripQuery(canonical)) {
235
290
  content.uri = requested;
236
291
  }
237
292
  }
@@ -377,27 +432,12 @@ export class McpServer extends McpServerBaseOmitted {
377
432
  return Array.isArray(val) ? val[0] : val;
378
433
  };
379
434
  const isClaude = header("user-agent") === "Claude-User";
380
- let serverUrl;
381
- const forwardedHost = header("x-forwarded-host");
382
- const origin = header("origin");
383
- const host = header("host");
384
- if (forwardedHost) {
385
- const proto = header("x-forwarded-proto") || "https";
386
- serverUrl = `${proto}://${forwardedHost}`;
387
- }
388
- else if (origin) {
389
- serverUrl = origin;
390
- }
391
- else if (host) {
392
- const proto = ["127.0.0.1:", "localhost:"].some((p) => host.startsWith(p))
393
- ? "http"
394
- : "https";
395
- serverUrl = `${proto}://${host}`;
396
- }
397
- else {
398
- const devPort = process.env.__PORT || "3000";
399
- serverUrl = `http://localhost:${devPort}`;
400
- }
435
+ const serverUrl = resolveServerOrigin(header);
436
+ // Path prefix the proxy routed this request under (e.g. `foo.com/v1`). Read
437
+ // per-request so one process can serve many hosts/prefixes at once: the
438
+ // origin is recovered from x-forwarded-host, the prefix from
439
+ // x-forwarded-prefix. Empty when served at the origin root.
440
+ const assetsBasePath = normalizeForwardedPrefix(header("x-forwarded-prefix"));
401
441
  const connectDomains = [serverUrl];
402
442
  if (!isProduction) {
403
443
  const wsUrl = new URL(serverUrl);
@@ -418,114 +458,77 @@ export class McpServer extends McpServerBaseOmitted {
418
458
  .slice(0, 32);
419
459
  contentMetaOverrides = { domain: `${hash}.claudemcpcontent.com` };
420
460
  }
421
- return { serverUrl, connectDomains, contentMetaOverrides };
461
+ return { serverUrl, assetsBasePath, connectDomains, contentMetaOverrides };
422
462
  }
423
463
  registerViewResources(toolName, view, toolMeta) {
424
- const hosts = view.hosts ?? ["apps-sdk", "mcp-app"];
425
464
  // Append a content-derived version param so hosts (e.g. ChatGPT) bust
426
465
  // their cache when the bundle changes, but keep the URI stable across
427
466
  // `tools/list` calls when the bundle hasn't changed.
428
467
  const versionParam = this.computeViewVersionParam(view.component);
429
- if (hosts.includes("apps-sdk")) {
430
- const viewResource = {
431
- hostType: "apps-sdk",
432
- uri: `ui://views/apps-sdk/${view.component}.html${versionParam}`,
433
- mimeType: "text/html+skybridge",
434
- buildContentMeta: ({ resourceDomains, connectDomains, domain }, overrides) => {
435
- const defaults = {
436
- "openai/widgetCSP": {
437
- resource_domains: resourceDomains,
438
- connect_domains: connectDomains,
439
- },
440
- "openai/widgetDomain": domain,
441
- "openai/widgetDescription": view.description,
442
- };
443
- const fromView = {
444
- "openai/widgetCSP": {
445
- resource_domains: view.csp?.resourceDomains,
446
- connect_domains: view.csp?.connectDomains,
447
- frame_domains: view.csp?.frameDomains,
448
- redirect_domains: view.csp?.redirectDomains,
449
- },
450
- "openai/widgetDomain": view.domain,
451
- "openai/widgetPrefersBorder": view.prefersBorder,
452
- };
453
- const base = mergeWithUnion(mergeWithUnion(defaults, fromView), {
454
- "openai/widgetDomain": overrides.domain,
455
- });
456
- if (view._meta) {
457
- return { ...base, ...view._meta };
458
- }
459
- return base;
460
- },
461
- };
462
- this.registerViewResource({
463
- name: toolName,
464
- viewResource,
465
- view,
466
- });
467
- toolMeta["openai/outputTemplate"] = viewResource.uri;
468
- }
469
- if (hosts.includes("mcp-app")) {
470
- const viewResource = {
471
- hostType: "mcp-app",
472
- uri: `ui://views/ext-apps/${view.component}.html${versionParam}`,
473
- mimeType: "text/html;profile=mcp-app",
474
- buildContentMeta: ({ resourceDomains, connectDomains, domain, baseUriDomains }, overrides) => {
475
- const defaults = {
476
- ui: {
477
- csp: {
478
- resourceDomains,
479
- connectDomains,
480
- baseUriDomains,
481
- },
482
- domain,
468
+ const viewResource = {
469
+ hostType: "mcp-app",
470
+ uri: `ui://views/ext-apps/${view.component}.html${versionParam}`,
471
+ mimeType: "text/html;profile=mcp-app",
472
+ buildContentMeta: ({ resourceDomains, connectDomains, domain, baseUriDomains }, overrides) => {
473
+ const defaults = {
474
+ ui: {
475
+ csp: {
476
+ resourceDomains,
477
+ connectDomains,
478
+ baseUriDomains,
483
479
  },
484
- };
485
- const fromView = {
486
- ui: {
487
- ...(view.description && { description: view.description }),
488
- ...(view.prefersBorder !== undefined && {
489
- prefersBorder: view.prefersBorder,
480
+ domain,
481
+ },
482
+ };
483
+ const fromView = {
484
+ ui: {
485
+ ...(view.description && { description: view.description }),
486
+ ...(view.prefersBorder !== undefined && {
487
+ prefersBorder: view.prefersBorder,
488
+ }),
489
+ ...(view.domain && { domain: view.domain }),
490
+ csp: {
491
+ ...(view.csp?.resourceDomains && {
492
+ resourceDomains: view.csp.resourceDomains,
493
+ }),
494
+ ...(view.csp?.connectDomains && {
495
+ connectDomains: view.csp.connectDomains,
496
+ }),
497
+ ...(view.csp?.frameDomains && {
498
+ frameDomains: view.csp.frameDomains,
499
+ }),
500
+ ...(view.csp?.baseUriDomains && {
501
+ baseUriDomains: view.csp.baseUriDomains,
490
502
  }),
491
- ...(view.domain && { domain: view.domain }),
492
- csp: {
493
- ...(view.csp?.resourceDomains && {
494
- resourceDomains: view.csp.resourceDomains,
495
- }),
496
- ...(view.csp?.connectDomains && {
497
- connectDomains: view.csp.connectDomains,
498
- }),
499
- ...(view.csp?.frameDomains && {
500
- frameDomains: view.csp.frameDomains,
501
- }),
502
- ...(view.csp?.baseUriDomains && {
503
- baseUriDomains: view.csp.baseUriDomains,
504
- }),
505
- ...(view.csp?.redirectDomains && {
506
- redirectDomains: view.csp.redirectDomains,
507
- }),
508
- },
509
503
  },
510
- };
511
- const base = mergeWithUnion(mergeWithUnion(defaults, fromView), {
512
- ui: overrides,
513
- });
514
- if (view._meta) {
515
- return { ...base, ...view._meta };
516
- }
517
- return base;
518
- },
519
- };
520
- this.registerViewResource({
521
- name: toolName,
522
- viewResource,
523
- view,
524
- });
525
- // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
526
- toolMeta["ui/resourceUri"] = viewResource.uri;
527
- toolMeta.ui = { ...toolMeta.ui, resourceUri: viewResource.uri };
528
- }
504
+ },
505
+ };
506
+ const ui = mergeWithUnion(mergeWithUnion(defaults, fromView), {
507
+ ui: overrides,
508
+ });
509
+ const base = {
510
+ ...ui,
511
+ ...(view.description && {
512
+ "openai/widgetDescription": view.description,
513
+ }),
514
+ ...(view.csp?.redirectDomains && {
515
+ "openai/widgetCSP": { redirect_domains: view.csp.redirectDomains },
516
+ }),
517
+ };
518
+ if (view._meta) {
519
+ return { ...base, ...view._meta };
520
+ }
521
+ return base;
522
+ },
523
+ };
524
+ this.registerViewResource({ name: toolName, viewResource, view });
525
+ // Advertise via the MCP Apps standard pointer only — ChatGPT renders from
526
+ // ui.resourceUri (verified), and not emitting openai/outputTemplate lets us
527
+ // retire the legacy apps-sdk resource later. The legacy apps-sdk URL is still
528
+ // served (see registerViewResource) so already-published apps keep resolving.
529
+ // @ts-expect-error - For backwards compatibility with Claude current implementation of the specs
530
+ toolMeta["ui/resourceUri"] = viewResource.uri;
531
+ toolMeta.ui = { ...toolMeta.ui, resourceUri: viewResource.uri };
529
532
  }
530
533
  registerViewResource({ name, viewResource, view, }) {
531
534
  const { hostType, uri: viewUri, mimeType, buildContentMeta } = viewResource;
@@ -540,19 +543,24 @@ export class McpServer extends McpServerBaseOmitted {
540
543
  };
541
544
  this.viewMetaBuilders.set(viewUri, buildMeta);
542
545
  this.viewUriByPath.set(stripQuery(viewUri), viewUri);
546
+ this.serveLegacyAppsSdkUrl(view.component, viewUri);
543
547
  this.registerResource(name, viewUri, { description: view.description }, async (uri, extra) => {
544
548
  const isProduction = process.env.NODE_ENV === "production";
545
- const { serverUrl } = this.resolveViewRequestContext(extra);
549
+ const { serverUrl, assetsBasePath } = this.resolveViewRequestContext(extra);
550
+ // The view resolves all assets (template imports + runtime lazy chunks
551
+ // via `window.skybridge.serverUrl`) against this base, so it carries the
552
+ // proxy path prefix. CSP domains in `buildMeta` stay the bare origin.
553
+ const viewBase = `${serverUrl}${assetsBasePath}`;
546
554
  const html = isProduction
547
555
  ? templateHelper.renderProduction({
548
556
  hostType,
549
- serverUrl,
557
+ serverUrl: viewBase,
550
558
  viewFile: this.lookupViewFile(view.component),
551
559
  styleFile: this.lookupDistFile("style.css") ?? "",
552
560
  })
553
561
  : templateHelper.renderDevelopment({
554
562
  hostType,
555
- serverUrl,
563
+ serverUrl: viewBase,
556
564
  viewName: view.component,
557
565
  });
558
566
  return {
@@ -562,6 +570,11 @@ export class McpServer extends McpServerBaseOmitted {
562
570
  };
563
571
  });
564
572
  }
573
+ serveLegacyAppsSdkUrl(component, canonicalUri) {
574
+ this.viewUriByPath.set(`ui://views/apps-sdk/${component}.html`, canonicalUri);
575
+ this.viewUriByPath.set(`ui://widgets/apps-sdk/${component}.html`, canonicalUri);
576
+ this.viewUriByPath.set(`ui://widgets/ext-apps/${component}.html`, canonicalUri);
577
+ }
565
578
  wrapHandler(cb, { attachViewUUID }) {
566
579
  return async (args, extra) => {
567
580
  const result = await cb(args, extra);