skybridge 0.0.0-dev.fecd520 → 0.0.0-dev.fef24cf

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 (307) hide show
  1. package/README.md +123 -116
  2. package/dist/cli/detect-port.js.map +1 -1
  3. package/dist/cli/header.js +1 -1
  4. package/dist/cli/header.js.map +1 -1
  5. package/dist/cli/run-command.js.map +1 -1
  6. package/dist/cli/telemetry.js.map +1 -1
  7. package/dist/cli/tunnel-control-server.d.ts +9 -0
  8. package/dist/cli/tunnel-control-server.js +31 -0
  9. package/dist/cli/tunnel-control-server.js.map +1 -0
  10. package/dist/cli/tunnel-control-server.test.js +39 -0
  11. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  12. package/dist/cli/tunnel-handler.d.ts +3 -0
  13. package/dist/cli/tunnel-handler.js +48 -0
  14. package/dist/cli/tunnel-handler.js.map +1 -0
  15. package/dist/cli/tunnel-handler.test.js +105 -0
  16. package/dist/cli/tunnel-handler.test.js.map +1 -0
  17. package/dist/cli/tunnel.d.ts +57 -0
  18. package/dist/cli/tunnel.js +154 -0
  19. package/dist/cli/tunnel.js.map +1 -0
  20. package/dist/cli/tunnel.test.js +190 -0
  21. package/dist/cli/tunnel.test.js.map +1 -0
  22. package/dist/cli/types.d.ts +5 -0
  23. package/dist/cli/types.js +2 -0
  24. package/dist/cli/types.js.map +1 -0
  25. package/dist/cli/use-execute-steps.js.map +1 -1
  26. package/dist/cli/use-messages.d.ts +3 -0
  27. package/dist/cli/use-messages.js +11 -0
  28. package/dist/cli/use-messages.js.map +1 -0
  29. package/dist/cli/use-nodemon.d.ts +2 -7
  30. package/dist/cli/use-nodemon.js +18 -21
  31. package/dist/cli/use-nodemon.js.map +1 -1
  32. package/dist/cli/use-open-browser.d.ts +1 -0
  33. package/dist/cli/use-open-browser.js +44 -0
  34. package/dist/cli/use-open-browser.js.map +1 -0
  35. package/dist/cli/use-tunnel.d.ts +14 -0
  36. package/dist/cli/use-tunnel.js +131 -0
  37. package/dist/cli/use-tunnel.js.map +1 -0
  38. package/dist/cli/use-typescript-check.d.ts +1 -0
  39. package/dist/cli/use-typescript-check.js +42 -7
  40. package/dist/cli/use-typescript-check.js.map +1 -1
  41. package/dist/commands/build.js +63 -7
  42. package/dist/commands/build.js.map +1 -1
  43. package/dist/commands/create.d.ts +9 -0
  44. package/dist/commands/create.js +30 -0
  45. package/dist/commands/create.js.map +1 -0
  46. package/dist/commands/dev.d.ts +3 -1
  47. package/dist/commands/dev.js +46 -8
  48. package/dist/commands/dev.js.map +1 -1
  49. package/dist/commands/start.js +7 -10
  50. package/dist/commands/start.js.map +1 -1
  51. package/dist/commands/telemetry/disable.js.map +1 -1
  52. package/dist/commands/telemetry/enable.js.map +1 -1
  53. package/dist/commands/telemetry/status.js.map +1 -1
  54. package/dist/server/asset-base-url-transform-plugin.d.ts +6 -6
  55. package/dist/server/asset-base-url-transform-plugin.js +25 -11
  56. package/dist/server/asset-base-url-transform-plugin.js.map +1 -1
  57. package/dist/server/asset-base-url-transform-plugin.test.js +92 -14
  58. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -1
  59. package/dist/server/auth.d.ts +20 -0
  60. package/dist/server/auth.js +28 -0
  61. package/dist/server/auth.js.map +1 -0
  62. package/dist/server/content-helpers.d.ts +67 -0
  63. package/dist/server/content-helpers.js +79 -0
  64. package/dist/server/content-helpers.js.map +1 -0
  65. package/dist/server/content-helpers.test.d.ts +1 -0
  66. package/dist/server/content-helpers.test.js +70 -0
  67. package/dist/server/content-helpers.test.js.map +1 -0
  68. package/dist/server/express.d.ts +7 -5
  69. package/dist/server/express.js +52 -23
  70. package/dist/server/express.js.map +1 -1
  71. package/dist/server/express.test.js +381 -25
  72. package/dist/server/express.test.js.map +1 -1
  73. package/dist/server/file-ref.d.ts +28 -0
  74. package/dist/server/file-ref.js +27 -0
  75. package/dist/server/file-ref.js.map +1 -0
  76. package/dist/server/index.d.ts +7 -4
  77. package/dist/server/index.js +5 -2
  78. package/dist/server/index.js.map +1 -1
  79. package/dist/server/inferUtilityTypes.d.ts +6 -6
  80. package/dist/server/inferUtilityTypes.js.map +1 -1
  81. package/dist/server/metric.d.ts +14 -0
  82. package/dist/server/metric.js +62 -0
  83. package/dist/server/metric.js.map +1 -0
  84. package/dist/server/middleware.d.ts +47 -6
  85. package/dist/server/middleware.js.map +1 -1
  86. package/dist/server/middleware.test-d.js +41 -18
  87. package/dist/server/middleware.test-d.js.map +1 -1
  88. package/dist/server/middleware.test.js +115 -5
  89. package/dist/server/middleware.test.js.map +1 -1
  90. package/dist/server/server.d.ts +334 -75
  91. package/dist/server/server.js +419 -117
  92. package/dist/server/server.js.map +1 -1
  93. package/dist/server/templateHelper.d.ts +5 -8
  94. package/dist/server/templateHelper.js +3 -22
  95. package/dist/server/templateHelper.js.map +1 -1
  96. package/dist/server/templates.generated.d.ts +4 -0
  97. package/dist/server/templates.generated.js +47 -0
  98. package/dist/server/templates.generated.js.map +1 -0
  99. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  100. package/dist/server/tunnel-proxy-router.js +110 -0
  101. package/dist/server/tunnel-proxy-router.js.map +1 -0
  102. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  103. package/dist/server/tunnel-proxy-router.test.js +229 -0
  104. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  105. package/dist/server/viewsDevServer.d.ts +14 -0
  106. package/dist/server/viewsDevServer.js +45 -0
  107. package/dist/server/viewsDevServer.js.map +1 -0
  108. package/dist/test/utils.d.ts +13 -21
  109. package/dist/test/utils.js +42 -37
  110. package/dist/test/utils.js.map +1 -1
  111. package/dist/test/view.test.d.ts +1 -0
  112. package/dist/test/view.test.js +568 -0
  113. package/dist/test/view.test.js.map +1 -0
  114. package/dist/version.d.ts +1 -0
  115. package/dist/version.js +3 -0
  116. package/dist/version.js.map +1 -0
  117. package/dist/web/bridges/apps-sdk/adaptor.d.ts +10 -4
  118. package/dist/web/bridges/apps-sdk/adaptor.js +55 -17
  119. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -1
  120. package/dist/web/bridges/apps-sdk/bridge.d.ts +1 -0
  121. package/dist/web/bridges/apps-sdk/bridge.js +1 -0
  122. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  123. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  124. package/dist/web/bridges/apps-sdk/types.d.ts +18 -6
  125. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  126. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  127. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  128. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  129. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  130. package/dist/web/bridges/get-adaptor.js +7 -0
  131. package/dist/web/bridges/get-adaptor.js.map +1 -1
  132. package/dist/web/bridges/index.js.map +1 -1
  133. package/dist/web/bridges/mcp-app/adaptor.d.ts +24 -8
  134. package/dist/web/bridges/mcp-app/adaptor.js +152 -62
  135. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -1
  136. package/dist/web/bridges/mcp-app/bridge.d.ts +14 -30
  137. package/dist/web/bridges/mcp-app/bridge.js +44 -201
  138. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  139. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  140. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  141. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +17 -3
  142. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +14 -2
  143. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  144. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -41
  145. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  146. package/dist/web/bridges/types.d.ts +80 -11
  147. package/dist/web/bridges/types.js.map +1 -1
  148. package/dist/web/bridges/use-host-context.d.ts +5 -0
  149. package/dist/web/bridges/use-host-context.js +5 -0
  150. package/dist/web/bridges/use-host-context.js.map +1 -1
  151. package/dist/web/components/modal-provider.js +3 -5
  152. package/dist/web/components/modal-provider.js.map +1 -1
  153. package/dist/web/create-store.d.ts +26 -0
  154. package/dist/web/create-store.js +43 -3
  155. package/dist/web/create-store.js.map +1 -1
  156. package/dist/web/create-store.test.js +17 -17
  157. package/dist/web/create-store.test.js.map +1 -1
  158. package/dist/web/data-llm.d.ts +34 -1
  159. package/dist/web/data-llm.js +31 -3
  160. package/dist/web/data-llm.js.map +1 -1
  161. package/dist/web/data-llm.test.js +23 -22
  162. package/dist/web/data-llm.test.js.map +1 -1
  163. package/dist/web/generate-helpers.d.ts +22 -18
  164. package/dist/web/generate-helpers.js +22 -18
  165. package/dist/web/generate-helpers.js.map +1 -1
  166. package/dist/web/generate-helpers.test-d.js +26 -26
  167. package/dist/web/generate-helpers.test-d.js.map +1 -1
  168. package/dist/web/generate-helpers.test.js.map +1 -1
  169. package/dist/web/helpers/state.d.ts +2 -2
  170. package/dist/web/helpers/state.js +11 -11
  171. package/dist/web/helpers/state.js.map +1 -1
  172. package/dist/web/helpers/state.test.js +9 -9
  173. package/dist/web/helpers/state.test.js.map +1 -1
  174. package/dist/web/hooks/index.d.ts +4 -1
  175. package/dist/web/hooks/index.js +4 -1
  176. package/dist/web/hooks/index.js.map +1 -1
  177. package/dist/web/hooks/test/utils.d.ts +6 -2
  178. package/dist/web/hooks/test/utils.js +17 -2
  179. package/dist/web/hooks/test/utils.js.map +1 -1
  180. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  181. package/dist/web/hooks/use-call-tool.js +28 -0
  182. package/dist/web/hooks/use-call-tool.js.map +1 -1
  183. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  184. package/dist/web/hooks/use-call-tool.test.js +27 -6
  185. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  186. package/dist/web/hooks/use-display-mode.d.ts +20 -0
  187. package/dist/web/hooks/use-display-mode.js +20 -0
  188. package/dist/web/hooks/use-display-mode.js.map +1 -1
  189. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -1
  190. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  191. package/dist/web/hooks/use-download.d.ts +5 -0
  192. package/dist/web/hooks/use-download.js +8 -0
  193. package/dist/web/hooks/use-download.js.map +1 -0
  194. package/dist/web/hooks/use-download.test.d.ts +1 -0
  195. package/dist/web/hooks/use-download.test.js +95 -0
  196. package/dist/web/hooks/use-download.test.js.map +1 -0
  197. package/dist/web/hooks/use-files.d.ts +34 -1
  198. package/dist/web/hooks/use-files.js +33 -0
  199. package/dist/web/hooks/use-files.js.map +1 -1
  200. package/dist/web/hooks/use-files.test.js +22 -2
  201. package/dist/web/hooks/use-files.test.js.map +1 -1
  202. package/dist/web/hooks/use-layout.d.ts +2 -0
  203. package/dist/web/hooks/use-layout.js +2 -0
  204. package/dist/web/hooks/use-layout.js.map +1 -1
  205. package/dist/web/hooks/use-layout.test.js +3 -3
  206. package/dist/web/hooks/use-layout.test.js.map +1 -1
  207. package/dist/web/hooks/use-open-external.d.ts +17 -0
  208. package/dist/web/hooks/use-open-external.js +16 -0
  209. package/dist/web/hooks/use-open-external.js.map +1 -1
  210. package/dist/web/hooks/use-open-external.test.js +15 -10
  211. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  212. package/dist/web/hooks/use-request-close.d.ts +16 -0
  213. package/dist/web/hooks/use-request-close.js +21 -0
  214. package/dist/web/hooks/use-request-close.js.map +1 -0
  215. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  216. package/dist/web/hooks/use-request-close.test.js +52 -0
  217. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  218. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  219. package/dist/web/hooks/use-request-modal.js +19 -4
  220. package/dist/web/hooks/use-request-modal.js.map +1 -1
  221. package/dist/web/hooks/use-request-modal.test.js +5 -1
  222. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  223. package/dist/web/hooks/use-request-size.d.ts +20 -0
  224. package/dist/web/hooks/use-request-size.js +24 -0
  225. package/dist/web/hooks/use-request-size.js.map +1 -0
  226. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  227. package/dist/web/hooks/use-request-size.test.js +65 -0
  228. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  229. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  230. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  231. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  232. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  233. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  234. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  235. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  236. package/dist/web/hooks/use-tool-info.d.ts +33 -0
  237. package/dist/web/hooks/use-tool-info.js +26 -0
  238. package/dist/web/hooks/use-tool-info.js.map +1 -1
  239. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  240. package/dist/web/hooks/use-tool-info.test.js +1 -1
  241. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  242. package/dist/web/hooks/use-user.d.ts +2 -0
  243. package/dist/web/hooks/use-user.js +20 -2
  244. package/dist/web/hooks/use-user.js.map +1 -1
  245. package/dist/web/hooks/use-user.test.js +29 -1
  246. package/dist/web/hooks/use-user.test.js.map +1 -1
  247. package/dist/web/hooks/use-view-state.d.ts +25 -0
  248. package/dist/web/hooks/use-view-state.js +32 -0
  249. package/dist/web/hooks/use-view-state.js.map +1 -0
  250. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  251. package/dist/web/hooks/use-view-state.test.js +177 -0
  252. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  253. package/dist/web/index.d.ts +1 -2
  254. package/dist/web/index.js +1 -2
  255. package/dist/web/index.js.map +1 -1
  256. package/dist/web/mount-view.d.ts +20 -0
  257. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  258. package/dist/web/mount-view.js.map +1 -0
  259. package/dist/web/plugin/data-llm.test.js.map +1 -1
  260. package/dist/web/plugin/plugin.d.ts +32 -1
  261. package/dist/web/plugin/plugin.js +160 -25
  262. package/dist/web/plugin/plugin.js.map +1 -1
  263. package/dist/web/plugin/scan-views.d.ts +16 -0
  264. package/dist/web/plugin/scan-views.js +88 -0
  265. package/dist/web/plugin/scan-views.js.map +1 -0
  266. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  267. package/dist/web/plugin/scan-views.test.js +99 -0
  268. package/dist/web/plugin/scan-views.test.js.map +1 -0
  269. package/dist/web/plugin/transform-data-llm.js +1 -1
  270. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  271. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  272. package/dist/web/plugin/validate-view.d.ts +1 -0
  273. package/dist/web/plugin/validate-view.js +9 -0
  274. package/dist/web/plugin/validate-view.js.map +1 -0
  275. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  276. package/dist/web/plugin/validate-view.test.js +24 -0
  277. package/dist/web/plugin/validate-view.test.js.map +1 -0
  278. package/dist/web/proxy.js.map +1 -1
  279. package/dist/web/types.d.ts +4 -0
  280. package/dist/web/types.js.map +1 -1
  281. package/package.json +35 -21
  282. package/tsconfig.base.json +5 -0
  283. package/dist/server/const.d.ts +0 -1
  284. package/dist/server/const.js +0 -2
  285. package/dist/server/const.js.map +0 -1
  286. package/dist/server/templates/development.hbs +0 -67
  287. package/dist/server/templates/production.hbs +0 -6
  288. package/dist/server/widgetsDevServer.d.ts +0 -12
  289. package/dist/server/widgetsDevServer.js +0 -63
  290. package/dist/server/widgetsDevServer.js.map +0 -1
  291. package/dist/test/widget.test.js +0 -261
  292. package/dist/test/widget.test.js.map +0 -1
  293. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  294. package/dist/web/hooks/use-widget-state.js +0 -32
  295. package/dist/web/hooks/use-widget-state.js.map +0 -1
  296. package/dist/web/hooks/use-widget-state.test.js +0 -64
  297. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  298. package/dist/web/mount-widget.d.ts +0 -1
  299. package/dist/web/mount-widget.js.map +0 -1
  300. package/dist/web/plugin/validate-widget.d.ts +0 -5
  301. package/dist/web/plugin/validate-widget.js +0 -27
  302. package/dist/web/plugin/validate-widget.js.map +0 -1
  303. package/dist/web/plugin/validate-widget.test.js +0 -42
  304. package/dist/web/plugin/validate-widget.test.js.map +0 -1
  305. /package/dist/{test/widget.test.d.ts → cli/tunnel-control-server.test.d.ts} +0 -0
  306. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/tunnel-handler.test.d.ts} +0 -0
  307. /package/dist/{web/plugin/validate-widget.test.d.ts → cli/tunnel.test.d.ts} +0 -0
@@ -0,0 +1,67 @@
1
+ import type { AudioContent, EmbeddedResource, ImageContent, ResourceLink, TextContent } from "@modelcontextprotocol/sdk/types.js";
2
+ /**
3
+ * MCP content annotations applied to any returned block.
4
+ *
5
+ * - `audience` — who is meant to see the content (`"user"`, `"assistant"`, or both).
6
+ * - `priority` — relative importance hint for the host.
7
+ * - `lastModified` — ISO timestamp for when the content was produced.
8
+ */
9
+ type ContentAnnotations = {
10
+ audience?: ("user" | "assistant")[];
11
+ priority?: number;
12
+ lastModified?: string;
13
+ };
14
+ /**
15
+ * Build an MCP text content block.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * return { content: [text("Found 3 results.")] };
20
+ * ```
21
+ */
22
+ export declare function text(value: string, annotations?: ContentAnnotations): TextContent;
23
+ /**
24
+ * Build an MCP image content block.
25
+ *
26
+ * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is
27
+ * **already base64-encoded**. Passing a raw byte-string will produce invalid
28
+ * content.
29
+ */
30
+ export declare function image(data: string | Uint8Array, mimeType: string, annotations?: ContentAnnotations): ImageContent;
31
+ /**
32
+ * Build an MCP audio content block.
33
+ *
34
+ * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is
35
+ * **already base64-encoded**.
36
+ */
37
+ export declare function audio(data: string | Uint8Array, mimeType: string, annotations?: ContentAnnotations): AudioContent;
38
+ /**
39
+ * Build an MCP embedded resource — the full content travels inline. Use this
40
+ * when the client needs the bytes themselves rather than a link.
41
+ *
42
+ * Pass either `text` (UTF-8 string) or `blob` (base64-encoded bytes).
43
+ */
44
+ export declare function embeddedResource(resource: {
45
+ uri: string;
46
+ mimeType?: string;
47
+ text: string;
48
+ } | {
49
+ uri: string;
50
+ mimeType?: string;
51
+ blob: string;
52
+ }, annotations?: ContentAnnotations): EmbeddedResource;
53
+ /**
54
+ * Build an MCP resource link — a `type: "resource_link"` block carrying a URI
55
+ * the client can fetch (or subscribe to) on demand. Use a link when the
56
+ * client should retrieve the bytes itself; use {@link embeddedResource} when
57
+ * the content must travel inline with the response.
58
+ */
59
+ export declare function resourceLink(link: {
60
+ uri: string;
61
+ name: string;
62
+ title?: string;
63
+ description?: string;
64
+ mimeType?: string;
65
+ size?: number;
66
+ }, annotations?: ContentAnnotations): ResourceLink;
67
+ export {};
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Returns a base64-encoded string.
3
+ * - `Uint8Array` input is encoded via `Buffer.toString("base64")`.
4
+ * - `string` input is assumed to be **already base64-encoded** and is returned
5
+ * as-is. Passing raw/unencoded string bytes will produce invalid MCP content.
6
+ */
7
+ function toBase64(data) {
8
+ if (typeof data === "string") {
9
+ return data;
10
+ }
11
+ return Buffer.from(data).toString("base64");
12
+ }
13
+ /**
14
+ * Build an MCP text content block.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * return { content: [text("Found 3 results.")] };
19
+ * ```
20
+ */
21
+ export function text(value, annotations) {
22
+ return { type: "text", text: value, ...(annotations && { annotations }) };
23
+ }
24
+ /**
25
+ * Build an MCP image content block.
26
+ *
27
+ * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is
28
+ * **already base64-encoded**. Passing a raw byte-string will produce invalid
29
+ * content.
30
+ */
31
+ export function image(data, mimeType, annotations) {
32
+ return {
33
+ type: "image",
34
+ data: toBase64(data),
35
+ mimeType,
36
+ ...(annotations && { annotations }),
37
+ };
38
+ }
39
+ /**
40
+ * Build an MCP audio content block.
41
+ *
42
+ * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is
43
+ * **already base64-encoded**.
44
+ */
45
+ export function audio(data, mimeType, annotations) {
46
+ return {
47
+ type: "audio",
48
+ data: toBase64(data),
49
+ mimeType,
50
+ ...(annotations && { annotations }),
51
+ };
52
+ }
53
+ /**
54
+ * Build an MCP embedded resource — the full content travels inline. Use this
55
+ * when the client needs the bytes themselves rather than a link.
56
+ *
57
+ * Pass either `text` (UTF-8 string) or `blob` (base64-encoded bytes).
58
+ */
59
+ export function embeddedResource(resource, annotations) {
60
+ return {
61
+ type: "resource",
62
+ resource,
63
+ ...(annotations && { annotations }),
64
+ };
65
+ }
66
+ /**
67
+ * Build an MCP resource link — a `type: "resource_link"` block carrying a URI
68
+ * the client can fetch (or subscribe to) on demand. Use a link when the
69
+ * client should retrieve the bytes itself; use {@link embeddedResource} when
70
+ * the content must travel inline with the response.
71
+ */
72
+ export function resourceLink(link, annotations) {
73
+ return {
74
+ type: "resource_link",
75
+ ...link,
76
+ ...(annotations && { annotations }),
77
+ };
78
+ }
79
+ //# sourceMappingURL=content-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-helpers.js","sourceRoot":"","sources":["../../src/server/content-helpers.ts"],"names":[],"mappings":"AAqBA;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,IAAyB;IACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI,CAClB,KAAa,EACb,WAAgC;IAEhC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CACnB,IAAyB,EACzB,QAAgB,EAChB,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAEoD,EACpD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ;QACR,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAOC,EACD,WAAgC;IAEhC,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,GAAG,IAAI;QACP,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AudioContent,\n EmbeddedResource,\n ImageContent,\n ResourceLink,\n TextContent,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * MCP content annotations applied to any returned block.\n *\n * - `audience` — who is meant to see the content (`\"user\"`, `\"assistant\"`, or both).\n * - `priority` — relative importance hint for the host.\n * - `lastModified` — ISO timestamp for when the content was produced.\n */\ntype ContentAnnotations = {\n audience?: (\"user\" | \"assistant\")[];\n priority?: number;\n lastModified?: string;\n};\n\n/**\n * Returns a base64-encoded string.\n * - `Uint8Array` input is encoded via `Buffer.toString(\"base64\")`.\n * - `string` input is assumed to be **already base64-encoded** and is returned\n * as-is. Passing raw/unencoded string bytes will produce invalid MCP content.\n */\nfunction toBase64(data: string | Uint8Array): string {\n if (typeof data === \"string\") {\n return data;\n }\n return Buffer.from(data).toString(\"base64\");\n}\n\n/**\n * Build an MCP text content block.\n *\n * @example\n * ```ts\n * return { content: [text(\"Found 3 results.\")] };\n * ```\n */\nexport function text(\n value: string,\n annotations?: ContentAnnotations,\n): TextContent {\n return { type: \"text\", text: value, ...(annotations && { annotations }) };\n}\n\n/**\n * Build an MCP image content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**. Passing a raw byte-string will produce invalid\n * content.\n */\nexport function image(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): ImageContent {\n return {\n type: \"image\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP audio content block.\n *\n * `data` may be a `Uint8Array` (encoded to base64 for you) or a string that is\n * **already base64-encoded**.\n */\nexport function audio(\n data: string | Uint8Array,\n mimeType: string,\n annotations?: ContentAnnotations,\n): AudioContent {\n return {\n type: \"audio\",\n data: toBase64(data),\n mimeType,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP embedded resource — the full content travels inline. Use this\n * when the client needs the bytes themselves rather than a link.\n *\n * Pass either `text` (UTF-8 string) or `blob` (base64-encoded bytes).\n */\nexport function embeddedResource(\n resource:\n | { uri: string; mimeType?: string; text: string }\n | { uri: string; mimeType?: string; blob: string },\n annotations?: ContentAnnotations,\n): EmbeddedResource {\n return {\n type: \"resource\",\n resource,\n ...(annotations && { annotations }),\n };\n}\n\n/**\n * Build an MCP resource link — a `type: \"resource_link\"` block carrying a URI\n * the client can fetch (or subscribe to) on demand. Use a link when the\n * client should retrieve the bytes itself; use {@link embeddedResource} when\n * the content must travel inline with the response.\n */\nexport function resourceLink(\n link: {\n uri: string;\n name: string;\n title?: string;\n description?: string;\n mimeType?: string;\n size?: number;\n },\n annotations?: ContentAnnotations,\n): ResourceLink {\n return {\n type: \"resource_link\",\n ...link,\n ...(annotations && { annotations }),\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { audio, embeddedResource, image, resourceLink, text, } from "./content-helpers.js";
3
+ describe("text", () => {
4
+ it("returns a TextContent without annotations when none given", () => {
5
+ expect(text("hello")).toEqual({ type: "text", text: "hello" });
6
+ });
7
+ it("includes annotations when provided", () => {
8
+ expect(text("hi", { priority: 1 })).toEqual({
9
+ type: "text",
10
+ text: "hi",
11
+ annotations: { priority: 1 },
12
+ });
13
+ });
14
+ });
15
+ describe("image", () => {
16
+ it("base64-encodes Uint8Array data", () => {
17
+ const bytes = new Uint8Array([104, 105]);
18
+ expect(image(bytes, "image/png")).toEqual({
19
+ type: "image",
20
+ data: "aGk=",
21
+ mimeType: "image/png",
22
+ });
23
+ });
24
+ it("passes string data through unchanged (caller is responsible for base64)", () => {
25
+ expect(image("YWxyZWFkeS1iNjQ=", "image/png")).toEqual({
26
+ type: "image",
27
+ data: "YWxyZWFkeS1iNjQ=",
28
+ mimeType: "image/png",
29
+ });
30
+ });
31
+ });
32
+ describe("audio", () => {
33
+ it("base64-encodes Uint8Array data", () => {
34
+ const bytes = new Uint8Array([104, 105]);
35
+ expect(audio(bytes, "audio/mpeg")).toMatchObject({
36
+ type: "audio",
37
+ data: "aGk=",
38
+ mimeType: "audio/mpeg",
39
+ });
40
+ });
41
+ });
42
+ describe("embeddedResource", () => {
43
+ it("wraps a text resource with a type tag", () => {
44
+ expect(embeddedResource({
45
+ uri: "file:///a.txt",
46
+ mimeType: "text/plain",
47
+ text: "x",
48
+ })).toEqual({
49
+ type: "resource",
50
+ resource: { uri: "file:///a.txt", mimeType: "text/plain", text: "x" },
51
+ });
52
+ });
53
+ it("wraps a blob resource with a type tag", () => {
54
+ expect(embeddedResource({ uri: "file:///a.bin", blob: "YmFy" })).toEqual({
55
+ type: "resource",
56
+ resource: { uri: "file:///a.bin", blob: "YmFy" },
57
+ });
58
+ });
59
+ });
60
+ describe("resourceLink", () => {
61
+ it("spreads link fields alongside the type tag", () => {
62
+ expect(resourceLink({ uri: "file:///a", name: "a", title: "A" })).toEqual({
63
+ type: "resource_link",
64
+ uri: "file:///a",
65
+ name: "a",
66
+ title: "A",
67
+ });
68
+ });
69
+ });
70
+ //# sourceMappingURL=content-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-helpers.test.js","sourceRoot":"","sources":["../../src/server/content-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n audio,\n embeddedResource,\n image,\n resourceLink,\n text,\n} from \"./content-helpers.js\";\n\ndescribe(\"text\", () => {\n it(\"returns a TextContent without annotations when none given\", () => {\n expect(text(\"hello\")).toEqual({ type: \"text\", text: \"hello\" });\n });\n\n it(\"includes annotations when provided\", () => {\n expect(text(\"hi\", { priority: 1 })).toEqual({\n type: \"text\",\n text: \"hi\",\n annotations: { priority: 1 },\n });\n });\n});\n\ndescribe(\"image\", () => {\n it(\"base64-encodes Uint8Array data\", () => {\n const bytes = new Uint8Array([104, 105]);\n expect(image(bytes, \"image/png\")).toEqual({\n type: \"image\",\n data: \"aGk=\",\n mimeType: \"image/png\",\n });\n });\n\n it(\"passes string data through unchanged (caller is responsible for base64)\", () => {\n expect(image(\"YWxyZWFkeS1iNjQ=\", \"image/png\")).toEqual({\n type: \"image\",\n data: \"YWxyZWFkeS1iNjQ=\",\n mimeType: \"image/png\",\n });\n });\n});\n\ndescribe(\"audio\", () => {\n it(\"base64-encodes Uint8Array data\", () => {\n const bytes = new Uint8Array([104, 105]);\n expect(audio(bytes, \"audio/mpeg\")).toMatchObject({\n type: \"audio\",\n data: \"aGk=\",\n mimeType: \"audio/mpeg\",\n });\n });\n});\n\ndescribe(\"embeddedResource\", () => {\n it(\"wraps a text resource with a type tag\", () => {\n expect(\n embeddedResource({\n uri: \"file:///a.txt\",\n mimeType: \"text/plain\",\n text: \"x\",\n }),\n ).toEqual({\n type: \"resource\",\n resource: { uri: \"file:///a.txt\", mimeType: \"text/plain\", text: \"x\" },\n });\n });\n\n it(\"wraps a blob resource with a type tag\", () => {\n expect(embeddedResource({ uri: \"file:///a.bin\", blob: \"YmFy\" })).toEqual({\n type: \"resource\",\n resource: { uri: \"file:///a.bin\", blob: \"YmFy\" },\n });\n });\n});\n\ndescribe(\"resourceLink\", () => {\n it(\"spreads link fields alongside the type tag\", () => {\n expect(resourceLink({ uri: \"file:///a\", name: \"a\", title: \"A\" })).toEqual({\n type: \"resource_link\",\n uri: \"file:///a\",\n name: \"a\",\n title: \"A\",\n });\n });\n});\n"]}
@@ -1,9 +1,11 @@
1
+ import type http from "node:http";
1
2
  import express from "express";
2
- import type { McpServer } from "./server";
3
- export declare function createServer({ server, customMiddleware, }: {
4
- server: McpServer;
5
- customMiddleware?: {
3
+ import type { McpServer } from "./server.js";
4
+ export declare function createApp({ mcpServer, httpServer, errorMiddleware, }: {
5
+ mcpServer: McpServer;
6
+ httpServer: http.Server;
7
+ errorMiddleware?: {
6
8
  path?: string;
7
- handlers: express.RequestHandler[];
9
+ handlers: express.ErrorRequestHandler[];
8
10
  }[];
9
11
  }): Promise<express.Express>;
@@ -2,11 +2,18 @@ import path from "node:path";
2
2
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
3
  import cors from "cors";
4
4
  import express from "express";
5
- export async function createServer({ server, customMiddleware = [], }) {
6
- const app = express();
7
- app.use(express.json());
8
- const env = process.env.NODE_ENV || "development";
9
- for (const middleware of customMiddleware) {
5
+ function parseControlPort(raw) {
6
+ if (raw === undefined) {
7
+ return null;
8
+ }
9
+ const n = Number.parseInt(raw, 10);
10
+ if (!Number.isFinite(n) || n <= 0 || n >= 65536) {
11
+ return null;
12
+ }
13
+ return n;
14
+ }
15
+ function applyMiddlewares(app, middlewares) {
16
+ for (const middleware of middlewares) {
10
17
  if (middleware.path) {
11
18
  app.use(middleware.path, ...middleware.handlers);
12
19
  }
@@ -14,22 +21,47 @@ export async function createServer({ server, customMiddleware = [], }) {
14
21
  app.use(...middleware.handlers);
15
22
  }
16
23
  }
17
- if (env !== "production") {
24
+ }
25
+ function defaultErrorHandler(err, _req, res, _next) {
26
+ console.error("Error handling MCP request:", err);
27
+ if (!res.headersSent) {
28
+ res.status(500).json({
29
+ jsonrpc: "2.0",
30
+ error: { code: -32603, message: "Internal server error" },
31
+ id: null,
32
+ });
33
+ }
34
+ }
35
+ export async function createApp({ mcpServer, httpServer, errorMiddleware = [], }) {
36
+ const app = mcpServer.express;
37
+ // Read `process.env.NODE_ENV` inline: wrangler/esbuild only substitute the literal expression,
38
+ // so a local const would defeat dead-code elimination of the dev-only imports below.
39
+ if (process.env.NODE_ENV !== "production") {
18
40
  const { devtoolsStaticServer } = await import("@skybridge/devtools");
19
41
  app.use(await devtoolsStaticServer());
20
- const { widgetsDevServer } = await import("./widgetsDevServer.js");
21
- app.use(await widgetsDevServer());
42
+ const { viewsDevServer } = await import("./viewsDevServer.js");
43
+ app.use(await viewsDevServer(httpServer));
44
+ const controlPort = parseControlPort(process.env.__TUNNEL_CONTROL_PORT);
45
+ if (controlPort !== null) {
46
+ const { createTunnelProxyRouter } = await import("./tunnel-proxy-router.js");
47
+ app.use(createTunnelProxyRouter(controlPort));
48
+ }
49
+ else if (process.env.__TUNNEL_CONTROL_PORT !== undefined) {
50
+ console.warn(`Ignoring invalid __TUNNEL_CONTROL_PORT=${process.env.__TUNNEL_CONTROL_PORT}`);
51
+ }
22
52
  }
23
- if (env === "production") {
53
+ else {
24
54
  const assetsPath = path.join(process.cwd(), "dist", "assets");
25
55
  app.use("/assets", cors());
26
56
  app.use("/assets", express.static(assetsPath));
27
57
  }
28
- app.use("/mcp", mcpMiddleware(server));
58
+ app.use("/mcp", mcpMiddleware(mcpServer));
59
+ applyMiddlewares(app, errorMiddleware);
60
+ app.use("/mcp", defaultErrorHandler);
29
61
  return app;
30
62
  }
31
63
  const mcpMiddleware = (server) => {
32
- return async (req, res, _next) => {
64
+ return async (req, res, next) => {
33
65
  if (req.method !== "POST") {
34
66
  res.writeHead(405).end(JSON.stringify({
35
67
  jsonrpc: "2.0",
@@ -44,28 +76,25 @@ const mcpMiddleware = (server) => {
44
76
  try {
45
77
  const transport = new StreamableHTTPServerTransport({
46
78
  sessionIdGenerator: undefined,
79
+ // Respond with a single JSON body instead of SSE. Skybridge's stateless
80
+ // transport never streams server-initiated messages, so SSE adds no
81
+ // capability — and on workerd specifically, `cloudflare:node`'s http
82
+ // bridge silently drops chunked writes that happen after the request
83
+ // handler awaits, which manifests as a 200 with empty body for any
84
+ // async tools/call.
85
+ enableJsonResponse: true,
47
86
  });
48
87
  res.on("close", () => {
49
88
  transport.close();
50
89
  });
51
- await server.connect(transport);
90
+ await server.connectStatelessTransport(transport);
52
91
  // Express strips the mount path from req.url (e.g. "/mcp" becomes "/").
53
92
  // Restore it so the SDK builds the correct requestInfo.url.
54
93
  req.url = req.originalUrl;
55
94
  await transport.handleRequest(req, res, req.body);
56
95
  }
57
96
  catch (error) {
58
- console.error("Error handling MCP request:", error);
59
- if (!res.headersSent) {
60
- res.status(500).json({
61
- jsonrpc: "2.0",
62
- error: {
63
- code: -32603,
64
- message: "Internal server error",
65
- },
66
- id: null,
67
- });
68
- }
97
+ next(error);
69
98
  }
70
99
  };
71
100
  };
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/server/express.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/server/express.ts"],"names":[],"mappings":"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","sourcesContent":["import type http from \"node:http\";\nimport path from \"node:path\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport cors from \"cors\";\nimport express from \"express\";\nimport type { McpServer } from \"./server.js\";\n\nfunction parseControlPort(raw: string | undefined): number | null {\n if (raw === undefined) {\n return null;\n }\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n <= 0 || n >= 65536) {\n return null;\n }\n return n;\n}\n\nfunction applyMiddlewares(\n app: express.Express,\n middlewares: Array<{\n path?: string;\n handlers: express.ErrorRequestHandler[];\n }>,\n): void {\n for (const middleware of middlewares) {\n if (middleware.path) {\n app.use(middleware.path, ...middleware.handlers);\n } else {\n app.use(...middleware.handlers);\n }\n }\n}\n\nfunction defaultErrorHandler(\n err: unknown,\n _req: express.Request,\n res: express.Response,\n _next: express.NextFunction,\n) {\n console.error(\"Error handling MCP request:\", err);\n if (!res.headersSent) {\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Internal server error\" },\n id: null,\n });\n }\n}\n\nexport async function createApp({\n mcpServer,\n httpServer,\n errorMiddleware = [],\n}: {\n mcpServer: McpServer;\n httpServer: http.Server;\n errorMiddleware?: {\n path?: string;\n handlers: express.ErrorRequestHandler[];\n }[];\n}): Promise<express.Express> {\n const app = mcpServer.express;\n\n // Read `process.env.NODE_ENV` inline: wrangler/esbuild only substitute the literal expression,\n // so a local const would defeat dead-code elimination of the dev-only imports below.\n if (process.env.NODE_ENV !== \"production\") {\n const { devtoolsStaticServer } = await import(\"@skybridge/devtools\");\n app.use(await devtoolsStaticServer());\n const { viewsDevServer } = await import(\"./viewsDevServer.js\");\n app.use(await viewsDevServer(httpServer));\n\n const controlPort = parseControlPort(process.env.__TUNNEL_CONTROL_PORT);\n if (controlPort !== null) {\n const { createTunnelProxyRouter } = await import(\n \"./tunnel-proxy-router.js\"\n );\n app.use(createTunnelProxyRouter(controlPort));\n } else if (process.env.__TUNNEL_CONTROL_PORT !== undefined) {\n console.warn(\n `Ignoring invalid __TUNNEL_CONTROL_PORT=${process.env.__TUNNEL_CONTROL_PORT}`,\n );\n }\n } else {\n const assetsPath = path.join(process.cwd(), \"dist\", \"assets\");\n\n app.use(\"/assets\", cors());\n app.use(\"/assets\", express.static(assetsPath));\n }\n\n app.use(\"/mcp\", mcpMiddleware(mcpServer));\n\n applyMiddlewares(app, errorMiddleware);\n\n app.use(\"/mcp\", defaultErrorHandler);\n\n return app;\n}\n\nconst mcpMiddleware = (server: McpServer): express.RequestHandler => {\n return async (\n req: express.Request,\n res: express.Response,\n next: express.NextFunction,\n ) => {\n if (req.method !== \"POST\") {\n res.writeHead(405).end(\n JSON.stringify({\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: \"Method not allowed.\",\n },\n id: null,\n }),\n );\n return;\n }\n\n try {\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n // Respond with a single JSON body instead of SSE. Skybridge's stateless\n // transport never streams server-initiated messages, so SSE adds no\n // capability — and on workerd specifically, `cloudflare:node`'s http\n // bridge silently drops chunked writes that happen after the request\n // handler awaits, which manifests as a 200 with empty body for any\n // async tools/call.\n enableJsonResponse: true,\n });\n\n res.on(\"close\", () => {\n transport.close();\n });\n\n await server.connectStatelessTransport(transport);\n // Express strips the mount path from req.url (e.g. \"/mcp\" becomes \"/\").\n // Restore it so the SDK builds the correct requestInfo.url.\n req.url = req.originalUrl;\n await transport.handleRequest(req, res, req.body);\n } catch (error) {\n next(error);\n }\n };\n};\n"]}