skybridge 0.0.0-dev.faa58ad → 0.0.0-dev.faf20cc

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 (340) hide show
  1. package/README.md +17 -14
  2. package/dist/cli/build-helpers.d.ts +6 -2
  3. package/dist/cli/build-helpers.js +39 -14
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +73 -5
  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.js +52 -0
  11. package/dist/cli/build-steps.test.js.map +1 -0
  12. package/dist/cli/detect-port.js +0 -1
  13. package/dist/cli/detect-port.js.map +1 -1
  14. package/dist/cli/header.d.ts +1 -1
  15. package/dist/cli/resolve-skybridge-config.d.ts +5 -0
  16. package/dist/cli/{resolve-views-dir.js → resolve-skybridge-config.js} +4 -3
  17. package/dist/cli/resolve-skybridge-config.js.map +1 -0
  18. package/dist/cli/run-plain.d.ts +18 -0
  19. package/dist/cli/run-plain.js +90 -0
  20. package/dist/cli/run-plain.js.map +1 -0
  21. package/dist/cli/telemetry.js +2 -0
  22. package/dist/cli/telemetry.js.map +1 -1
  23. package/dist/cli/use-execute-steps.d.ts +1 -1
  24. package/dist/cli/use-nodemon.d.ts +25 -1
  25. package/dist/cli/use-nodemon.js +96 -63
  26. package/dist/cli/use-nodemon.js.map +1 -1
  27. package/dist/cli/use-typescript-check.d.ts +8 -2
  28. package/dist/cli/use-typescript-check.js +70 -67
  29. package/dist/cli/use-typescript-check.js.map +1 -1
  30. package/dist/commands/build.d.ts +0 -2
  31. package/dist/commands/build.js +2 -61
  32. package/dist/commands/build.js.map +1 -1
  33. package/dist/commands/dev.d.ts +1 -0
  34. package/dist/commands/dev.js +38 -6
  35. package/dist/commands/dev.js.map +1 -1
  36. package/dist/commands/start.js +2 -2
  37. package/dist/commands/start.js.map +1 -1
  38. package/dist/context-warnings.d.ts +5 -0
  39. package/dist/context-warnings.js +31 -0
  40. package/dist/context-warnings.js.map +1 -0
  41. package/dist/context-warnings.test.js +28 -0
  42. package/dist/context-warnings.test.js.map +1 -0
  43. package/dist/server/app.d.ts +194 -0
  44. package/dist/server/app.js +266 -0
  45. package/dist/server/app.js.map +1 -0
  46. package/dist/server/app.test.js +97 -0
  47. package/dist/server/app.test.js.map +1 -0
  48. package/dist/server/auth/discovery.d.ts +2 -1
  49. package/dist/server/auth/discovery.js +2 -2
  50. package/dist/server/auth/discovery.js.map +1 -1
  51. package/dist/server/auth/index.d.ts +35 -5
  52. package/dist/server/auth/index.js.map +1 -1
  53. package/dist/server/auth/providers/auth0.d.ts +25 -3
  54. package/dist/server/auth/providers/auth0.js +13 -8
  55. package/dist/server/auth/providers/auth0.js.map +1 -1
  56. package/dist/server/auth/providers/auth0.test.js +5 -3
  57. package/dist/server/auth/providers/auth0.test.js.map +1 -1
  58. package/dist/server/auth/providers/authplane.d.ts +49 -0
  59. package/dist/server/auth/providers/authplane.js +57 -0
  60. package/dist/server/auth/providers/authplane.js.map +1 -0
  61. package/dist/server/auth/providers/authplane.test.js +143 -0
  62. package/dist/server/auth/providers/authplane.test.js.map +1 -0
  63. package/dist/server/auth/providers/clerk.d.ts +40 -3
  64. package/dist/server/auth/providers/clerk.js +4 -1
  65. package/dist/server/auth/providers/clerk.js.map +1 -1
  66. package/dist/server/auth/providers/clerk.test.js +5 -3
  67. package/dist/server/auth/providers/clerk.test.js.map +1 -1
  68. package/dist/server/auth/providers/custom.d.ts +24 -6
  69. package/dist/server/auth/providers/custom.js +33 -11
  70. package/dist/server/auth/providers/custom.js.map +1 -1
  71. package/dist/server/auth/providers/custom.test.js +71 -17
  72. package/dist/server/auth/providers/custom.test.js.map +1 -1
  73. package/dist/server/auth/providers/descope.d.ts +32 -3
  74. package/dist/server/auth/providers/descope.js +12 -2
  75. package/dist/server/auth/providers/descope.js.map +1 -1
  76. package/dist/server/auth/providers/descope.test.js +42 -18
  77. package/dist/server/auth/providers/descope.test.js.map +1 -1
  78. package/dist/server/auth/providers/stytch.d.ts +16 -3
  79. package/dist/server/auth/providers/stytch.js +4 -1
  80. package/dist/server/auth/providers/stytch.js.map +1 -1
  81. package/dist/server/auth/providers/verify-spy.d.ts +12 -0
  82. package/dist/server/auth/providers/verify-spy.js +21 -0
  83. package/dist/server/auth/providers/verify-spy.js.map +1 -0
  84. package/dist/server/auth/providers/workos.d.ts +28 -5
  85. package/dist/server/auth/providers/workos.js +6 -2
  86. package/dist/server/auth/providers/workos.js.map +1 -1
  87. package/dist/server/auth/security-schemes.d.ts +23 -0
  88. package/dist/server/auth/security-schemes.js +64 -0
  89. package/dist/server/auth/security-schemes.js.map +1 -0
  90. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  91. package/dist/server/auth/security-schemes.test.js +99 -0
  92. package/dist/server/auth/security-schemes.test.js.map +1 -0
  93. package/dist/server/auth/setup.d.ts +3 -1
  94. package/dist/server/auth/setup.js +66 -26
  95. package/dist/server/auth/setup.js.map +1 -1
  96. package/dist/server/auth/setup.test.js +349 -20
  97. package/dist/server/auth/setup.test.js.map +1 -1
  98. package/dist/server/auth/verify.d.ts +42 -6
  99. package/dist/server/auth/verify.js +27 -3
  100. package/dist/server/auth/verify.js.map +1 -1
  101. package/dist/server/auth/verify.test.js +65 -0
  102. package/dist/server/auth/verify.test.js.map +1 -1
  103. package/dist/server/auth-extra.test-d.js +130 -0
  104. package/dist/server/auth-extra.test-d.js.map +1 -0
  105. package/dist/server/auth.d.ts +43 -6
  106. package/dist/server/auth.js +4 -5
  107. package/dist/server/auth.js.map +1 -1
  108. package/dist/server/build-manifest.test.js +7 -6
  109. package/dist/server/build-manifest.test.js.map +1 -1
  110. package/dist/server/content-helpers.d.ts +1 -1
  111. package/dist/server/content-helpers.js.map +1 -1
  112. package/dist/server/express.d.ts +23 -3
  113. package/dist/server/express.js +38 -32
  114. package/dist/server/express.js.map +1 -1
  115. package/dist/server/express.test.js +220 -103
  116. package/dist/server/express.test.js.map +1 -1
  117. package/dist/server/file-ref.d.ts +1 -1
  118. package/dist/server/file-ref.js +1 -1
  119. package/dist/server/file-ref.js.map +1 -1
  120. package/dist/server/host.d.ts +2 -0
  121. package/dist/server/host.js +11 -0
  122. package/dist/server/host.js.map +1 -0
  123. package/dist/server/host.test.d.ts +1 -0
  124. package/dist/server/host.test.js +13 -0
  125. package/dist/server/host.test.js.map +1 -0
  126. package/dist/server/index.d.ts +16 -9
  127. package/dist/server/index.js +9 -3
  128. package/dist/server/index.js.map +1 -1
  129. package/dist/server/mcp-errors.test.d.ts +1 -0
  130. package/dist/server/mcp-errors.test.js +41 -0
  131. package/dist/server/mcp-errors.test.js.map +1 -0
  132. package/dist/server/middleware.d.ts +35 -10
  133. package/dist/server/middleware.js +33 -0
  134. package/dist/server/middleware.js.map +1 -1
  135. package/dist/server/middleware.test-d.js +1 -1
  136. package/dist/server/middleware.test-d.js.map +1 -1
  137. package/dist/server/middleware.test.js +242 -134
  138. package/dist/server/middleware.test.js.map +1 -1
  139. package/dist/server/register-tool.test.d.ts +1 -0
  140. package/dist/server/register-tool.test.js +110 -0
  141. package/dist/server/register-tool.test.js.map +1 -0
  142. package/dist/server/server.d.ts +242 -128
  143. package/dist/server/server.js +263 -274
  144. package/dist/server/server.js.map +1 -1
  145. package/dist/server/skills-integration.test.d.ts +1 -0
  146. package/dist/server/skills-integration.test.js +86 -0
  147. package/dist/server/skills-integration.test.js.map +1 -0
  148. package/dist/server/skills.d.ts +27 -0
  149. package/dist/server/skills.js +188 -0
  150. package/dist/server/skills.js.map +1 -0
  151. package/dist/server/skills.test.d.ts +1 -0
  152. package/dist/server/skills.test.js +243 -0
  153. package/dist/server/skills.test.js.map +1 -0
  154. package/dist/server/templateHelper.d.ts +0 -3
  155. package/dist/server/templateHelper.js.map +1 -1
  156. package/dist/server/templates.generated.js +4 -8
  157. package/dist/server/templates.generated.js.map +1 -1
  158. package/dist/server/tool-extra.test.d.ts +1 -0
  159. package/dist/server/tool-extra.test.js +88 -0
  160. package/dist/server/tool-extra.test.js.map +1 -0
  161. package/dist/server/view-resource-resolution.test.js +18 -13
  162. package/dist/server/view-resource-resolution.test.js.map +1 -1
  163. package/dist/server/viewsDevServer.js +4 -1
  164. package/dist/server/viewsDevServer.js.map +1 -1
  165. package/dist/test/utils.d.ts +9 -11
  166. package/dist/test/utils.js +220 -201
  167. package/dist/test/utils.js.map +1 -1
  168. package/dist/test/view.test.js +44 -40
  169. package/dist/test/view.test.js.map +1 -1
  170. package/dist/views/index.d.ts +10 -0
  171. package/dist/views/index.js +3 -0
  172. package/dist/views/index.js.map +1 -0
  173. package/dist/{web/plugin → views}/scan-views.js +1 -1
  174. package/dist/views/scan-views.js.map +1 -0
  175. package/dist/views/scan-views.test.d.ts +1 -0
  176. package/dist/views/scan-views.test.js.map +1 -0
  177. package/dist/views/validate-view.d.ts +1 -0
  178. package/dist/{web/plugin → views}/validate-view.js +2 -2
  179. package/dist/views/validate-view.js.map +1 -0
  180. package/dist/views/validate-view.test.d.ts +1 -0
  181. package/dist/views/validate-view.test.js.map +1 -0
  182. package/dist/web/bridges/adaptor.d.ts +8 -3
  183. package/dist/web/bridges/adaptor.js +100 -16
  184. package/dist/web/bridges/adaptor.js.map +1 -1
  185. package/dist/web/bridges/adaptor.test.js +78 -11
  186. package/dist/web/bridges/adaptor.test.js.map +1 -1
  187. package/dist/web/bridges/apps-sdk/bridge.js +1 -1
  188. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  189. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +4 -4
  190. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +4 -4
  191. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  192. package/dist/web/bridges/get-adaptor.test.js +2 -2
  193. package/dist/web/bridges/get-adaptor.test.js.map +1 -1
  194. package/dist/web/bridges/mcp-app/bridge.d.ts +1 -1
  195. package/dist/web/bridges/mcp-app/bridge.js +15 -6
  196. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  197. package/dist/web/bridges/mcp-app/bridge.test.js +2 -2
  198. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -1
  199. package/dist/web/bridges/mcp-app/types.d.ts +19 -2
  200. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  201. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +2 -2
  202. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  203. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  204. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -1
  205. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  206. package/dist/web/bridges/mcp-app/view-tools.test.js +1 -1
  207. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -1
  208. package/dist/web/bridges/types.d.ts +47 -16
  209. package/dist/web/bridges/types.js +1 -1
  210. package/dist/web/bridges/types.js.map +1 -1
  211. package/dist/web/components/modal-provider.d.ts +1 -1
  212. package/dist/web/create-store.test.js +2 -2
  213. package/dist/web/create-store.test.js.map +1 -1
  214. package/dist/web/data-llm.d.ts +1 -1
  215. package/dist/web/data-llm.js +3 -2
  216. package/dist/web/data-llm.js.map +1 -1
  217. package/dist/web/data-llm.test.js +17 -2
  218. package/dist/web/data-llm.test.js.map +1 -1
  219. package/dist/web/generate-helpers.d.ts +23 -19
  220. package/dist/web/generate-helpers.js +21 -17
  221. package/dist/web/generate-helpers.js.map +1 -1
  222. package/dist/web/generate-helpers.test-d.js +3 -3
  223. package/dist/web/generate-helpers.test-d.js.map +1 -1
  224. package/dist/web/generate-helpers.test.js +2 -2
  225. package/dist/web/generate-helpers.test.js.map +1 -1
  226. package/dist/web/hooks/index.d.ts +5 -1
  227. package/dist/web/hooks/index.js +5 -1
  228. package/dist/web/hooks/index.js.map +1 -1
  229. package/dist/web/hooks/openai-extensions.test.d.ts +1 -0
  230. package/dist/web/hooks/openai-extensions.test.js +107 -0
  231. package/dist/web/hooks/openai-extensions.test.js.map +1 -0
  232. package/dist/web/hooks/test/utils.d.ts +2 -1
  233. package/dist/web/hooks/test/utils.js +1 -1
  234. package/dist/web/hooks/test/utils.js.map +1 -1
  235. package/dist/web/hooks/use-call-tool.d.ts +2 -2
  236. package/dist/web/hooks/use-call-tool.js +15 -10
  237. package/dist/web/hooks/use-call-tool.js.map +1 -1
  238. package/dist/web/hooks/use-call-tool.test.js +15 -4
  239. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  240. package/dist/web/hooks/use-deep-link.d.ts +22 -0
  241. package/dist/web/hooks/use-deep-link.js +34 -0
  242. package/dist/web/hooks/use-deep-link.js.map +1 -0
  243. package/dist/web/hooks/use-display-mode.d.ts +1 -1
  244. package/dist/web/hooks/use-display-mode.js +1 -1
  245. package/dist/web/hooks/use-display-mode.js.map +1 -1
  246. package/dist/web/hooks/use-display-mode.test.js +1 -1
  247. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  248. package/dist/web/hooks/use-download.d.ts +1 -3
  249. package/dist/web/hooks/use-download.js +1 -2
  250. package/dist/web/hooks/use-download.js.map +1 -1
  251. package/dist/web/hooks/use-download.test.js +7 -7
  252. package/dist/web/hooks/use-download.test.js.map +1 -1
  253. package/dist/web/hooks/use-files.test.js +1 -1
  254. package/dist/web/hooks/use-files.test.js.map +1 -1
  255. package/dist/web/hooks/use-host.d.ts +44 -0
  256. package/dist/web/hooks/use-host.js +45 -0
  257. package/dist/web/hooks/use-host.js.map +1 -0
  258. package/dist/web/hooks/use-host.test.d.ts +1 -0
  259. package/dist/web/hooks/use-host.test.js +59 -0
  260. package/dist/web/hooks/use-host.test.js.map +1 -0
  261. package/dist/web/hooks/use-model-context.d.ts +44 -0
  262. package/dist/web/hooks/use-model-context.js +63 -0
  263. package/dist/web/hooks/use-model-context.js.map +1 -0
  264. package/dist/web/hooks/use-open-external.test.js +2 -2
  265. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  266. package/dist/web/hooks/use-open-file.d.ts +20 -0
  267. package/dist/web/hooks/use-open-file.js +25 -0
  268. package/dist/web/hooks/use-open-file.js.map +1 -0
  269. package/dist/web/hooks/use-register-view-tool.d.ts +3 -4
  270. package/dist/web/hooks/use-register-view-tool.js +1 -1
  271. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  272. package/dist/web/hooks/use-request-close.test.js +1 -1
  273. package/dist/web/hooks/use-request-close.test.js.map +1 -1
  274. package/dist/web/hooks/use-request-modal.test.js +1 -1
  275. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  276. package/dist/web/hooks/use-request-size.d.ts +1 -1
  277. package/dist/web/hooks/use-request-size.js +1 -1
  278. package/dist/web/hooks/use-request-size.js.map +1 -1
  279. package/dist/web/hooks/use-request-size.test.js +1 -1
  280. package/dist/web/hooks/use-request-size.test.js.map +1 -1
  281. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  282. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  283. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  284. package/dist/web/hooks/use-set-open-in-app-url.test.js +2 -8
  285. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  286. package/dist/web/hooks/use-tool-info.d.ts +1 -20
  287. package/dist/web/hooks/use-tool-info.js +0 -1
  288. package/dist/web/hooks/use-tool-info.js.map +1 -1
  289. package/dist/web/hooks/use-tool-info.test-d.js +0 -5
  290. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  291. package/dist/web/hooks/use-tool-info.test.js +2 -7
  292. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  293. package/dist/web/hooks/use-user.d.ts +3 -2
  294. package/dist/web/hooks/use-user.js +4 -3
  295. package/dist/web/hooks/use-user.js.map +1 -1
  296. package/dist/web/hooks/use-user.test.js +5 -3
  297. package/dist/web/hooks/use-user.test.js.map +1 -1
  298. package/dist/web/hooks/use-view-state.js +19 -9
  299. package/dist/web/hooks/use-view-state.js.map +1 -1
  300. package/dist/web/hooks/use-view-state.test.js +33 -2
  301. package/dist/web/hooks/use-view-state.test.js.map +1 -1
  302. package/dist/web/hooks/use-viewport.d.ts +20 -0
  303. package/dist/web/hooks/use-viewport.js +21 -0
  304. package/dist/web/hooks/use-viewport.js.map +1 -0
  305. package/dist/web/hooks/use-viewport.test.d.ts +1 -0
  306. package/dist/web/hooks/{use-layout.test.js → use-viewport.test.js} +12 -32
  307. package/dist/web/hooks/use-viewport.test.js.map +1 -0
  308. package/dist/web/mount-view.d.ts +3 -2
  309. package/dist/web/mount-view.js +5 -8
  310. package/dist/web/mount-view.js.map +1 -1
  311. package/package.json +32 -29
  312. package/dist/cli/resolve-views-dir.d.ts +0 -1
  313. package/dist/cli/resolve-views-dir.js.map +0 -1
  314. package/dist/web/hooks/use-layout.d.ts +0 -24
  315. package/dist/web/hooks/use-layout.js +0 -25
  316. package/dist/web/hooks/use-layout.js.map +0 -1
  317. package/dist/web/hooks/use-layout.test.js.map +0 -1
  318. package/dist/web/plugin/data-llm.test.js +0 -81
  319. package/dist/web/plugin/data-llm.test.js.map +0 -1
  320. package/dist/web/plugin/plugin.d.ts +0 -33
  321. package/dist/web/plugin/plugin.js +0 -189
  322. package/dist/web/plugin/plugin.js.map +0 -1
  323. package/dist/web/plugin/scan-views.js.map +0 -1
  324. package/dist/web/plugin/scan-views.test.js.map +0 -1
  325. package/dist/web/plugin/transform-data-llm.d.ts +0 -12
  326. package/dist/web/plugin/transform-data-llm.js +0 -96
  327. package/dist/web/plugin/transform-data-llm.js.map +0 -1
  328. package/dist/web/plugin/transform-data-llm.test.js +0 -81
  329. package/dist/web/plugin/transform-data-llm.test.js.map +0 -1
  330. package/dist/web/plugin/validate-view.d.ts +0 -1
  331. package/dist/web/plugin/validate-view.js.map +0 -1
  332. package/dist/web/plugin/validate-view.test.js.map +0 -1
  333. /package/dist/{web/hooks/use-layout.test.d.ts → cli/build-steps.test.d.ts} +0 -0
  334. /package/dist/{web/plugin/data-llm.test.d.ts → context-warnings.test.d.ts} +0 -0
  335. /package/dist/{web/plugin/scan-views.test.d.ts → server/app.test.d.ts} +0 -0
  336. /package/dist/{web/plugin/validate-view.test.d.ts → server/auth/providers/authplane.test.d.ts} +0 -0
  337. /package/dist/{web/plugin/transform-data-llm.test.d.ts → server/auth-extra.test-d.d.ts} +0 -0
  338. /package/dist/{web/plugin → views}/scan-views.d.ts +0 -0
  339. /package/dist/{web/plugin → views}/scan-views.test.js +0 -0
  340. /package/dist/{web/plugin → views}/validate-view.test.js +0 -0
@@ -1,12 +1,12 @@
1
1
  import type { AppsSdkContext } from "./types.js";
2
2
  /**
3
- * Read a single key from the raw Apps SDK (`window.openai`) context.
3
+ * Read a single key from the raw ChatGPT (`window.openai`) context.
4
4
  *
5
- * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
6
- * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
5
+ * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,
6
+ * `useToolInfo`, etc.) which work in both ChatGPT and MCP Apps. Reach for
7
7
  * this when you need ChatGPT-only fields not surfaced by the public hooks.
8
8
  *
9
- * Throws if called outside the Apps SDK runtime.
9
+ * Throws if called outside the ChatGPT (`window.openai`) runtime.
10
10
  *
11
11
  * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context
12
12
  */
@@ -1,13 +1,13 @@
1
1
  import { useSyncExternalStore } from "react";
2
2
  import { AppsSdkBridge } from "./bridge.js";
3
3
  /**
4
- * Read a single key from the raw Apps SDK (`window.openai`) context.
4
+ * Read a single key from the raw ChatGPT (`window.openai`) context.
5
5
  *
6
- * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,
7
- * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for
6
+ * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,
7
+ * `useToolInfo`, etc.) which work in both ChatGPT and MCP Apps. Reach for
8
8
  * this when you need ChatGPT-only fields not surfaced by the public hooks.
9
9
  *
10
- * Throws if called outside the Apps SDK runtime.
10
+ * Throws if called outside the ChatGPT (`window.openai`) runtime.
11
11
  *
12
12
  * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context
13
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"use-apps-sdk-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/use-apps-sdk-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAM;IAEN,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { AppsSdkBridge } from \"./bridge.js\";\nimport type { AppsSdkContext } from \"./types.js\";\n\n/**\n * Read a single key from the raw Apps SDK (`window.openai`) context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useLayout`, `useUser`,\n * `useToolInfo`, etc.) which work in both Apps SDK and MCP Apps. Reach for\n * this when you need ChatGPT-only fields not surfaced by the public hooks.\n *\n * Throws if called outside the Apps SDK runtime.\n *\n * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context\n */\nexport function useAppsSdkContext<K extends keyof AppsSdkContext>(\n key: K,\n): AppsSdkContext[K] {\n const bridge = AppsSdkBridge.getInstance();\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
1
+ {"version":3,"file":"use-apps-sdk-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/apps-sdk/use-apps-sdk-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAM;IAEN,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { AppsSdkBridge } from \"./bridge.js\";\nimport type { AppsSdkContext } from \"./types.js\";\n\n/**\n * Read a single key from the raw ChatGPT (`window.openai`) context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useViewport`, `useUser`,\n * `useToolInfo`, etc.) which work in both ChatGPT and MCP Apps. Reach for\n * this when you need ChatGPT-only fields not surfaced by the public hooks.\n *\n * Throws if called outside the ChatGPT (`window.openai`) runtime.\n *\n * @see https://docs.skybridge.tech/api-reference/use-apps-sdk-context\n */\nexport function useAppsSdkContext<K extends keyof AppsSdkContext>(\n key: K,\n): AppsSdkContext[K] {\n const bridge = AppsSdkBridge.getInstance();\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
@@ -17,12 +17,12 @@ describe("getAdaptor", () => {
17
17
  AppsSdkBridge.resetInstance();
18
18
  });
19
19
  it("returns a HostAdaptor instance", () => {
20
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
20
+ vi.stubGlobal("skybridge", {});
21
21
  vi.stubGlobal("openai", undefined);
22
22
  expect(getAdaptor()).toBeInstanceOf(HostAdaptor);
23
23
  });
24
24
  it("memoizes the instance", () => {
25
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
25
+ vi.stubGlobal("skybridge", {});
26
26
  vi.stubGlobal("openai", undefined);
27
27
  const a = getAdaptor();
28
28
  const b = getAdaptor();
@@ -1 +1 @@
1
- {"version":3,"file":"get-adaptor.test.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"./adaptor.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport { getAdaptor } from \"./get-adaptor.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\n\ndescribe(\"getAdaptor\", () => {\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"returns a HostAdaptor instance\", () => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"openai\", undefined);\n expect(getAdaptor()).toBeInstanceOf(HostAdaptor);\n });\n\n it(\"memoizes the instance\", () => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"openai\", undefined);\n const a = getAdaptor();\n const b = getAdaptor();\n expect(a).toBe(b);\n });\n});\n"]}
1
+ {"version":3,"file":"get-adaptor.test.js","sourceRoot":"","sources":["../../../src/web/bridges/get-adaptor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;QAC9B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,WAAW,CAAC,aAAa,EAAE,CAAC;QAC5B,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,aAAa,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { HostAdaptor } from \"./adaptor.js\";\nimport { AppsSdkBridge } from \"./apps-sdk/bridge.js\";\nimport { getAdaptor } from \"./get-adaptor.js\";\nimport { McpAppBridge } from \"./mcp-app/bridge.js\";\n\ndescribe(\"getAdaptor\", () => {\n beforeEach(() => {\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n HostAdaptor.resetInstance();\n McpAppBridge.resetInstance();\n AppsSdkBridge.resetInstance();\n });\n\n it(\"returns a HostAdaptor instance\", () => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n expect(getAdaptor()).toBeInstanceOf(HostAdaptor);\n });\n\n it(\"memoizes the instance\", () => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"openai\", undefined);\n const a = getAdaptor();\n const b = getAdaptor();\n expect(a).toBe(b);\n });\n});\n"]}
@@ -1,5 +1,5 @@
1
+ import type { Implementation } from "@modelcontextprotocol/client";
1
2
  import { App } from "@modelcontextprotocol/ext-apps";
2
- import { type Implementation } from "@modelcontextprotocol/sdk/types.js";
3
3
  import type { AnyViewToolHandler, Bridge, HostContextStore, Subscribe, ViewToolConfig } from "../types.js";
4
4
  import type { McpAppContext, McpAppContextKey } from "./types.js";
5
5
  /** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by `HostAdaptor`. */
@@ -1,7 +1,7 @@
1
+ import { ListToolsRequestSchema } from "@modelcontextprotocol/core";
1
2
  import { App } from "@modelcontextprotocol/ext-apps";
2
- import { ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { dequal } from "dequal/lite";
4
- import * as z from "zod";
4
+ import * as z from "zod/v4";
5
5
  function createMcpStore(bridge, keys, computeSnapshot) {
6
6
  let cachedValue;
7
7
  return {
@@ -24,6 +24,8 @@ export class McpAppBridge {
24
24
  toolInput: null,
25
25
  toolCancelled: null,
26
26
  toolResult: null,
27
+ hostInfo: null,
28
+ hostCapabilities: null,
27
29
  };
28
30
  listeners = new Map();
29
31
  app;
@@ -54,9 +56,11 @@ export class McpAppBridge {
54
56
  try {
55
57
  await this.app.connect();
56
58
  const hostContext = this.app.getHostContext();
57
- if (hostContext) {
58
- this.updateContext(hostContext);
59
- }
59
+ this.updateContext({
60
+ ...hostContext,
61
+ hostInfo: this.app.getHostVersion() ?? null,
62
+ hostCapabilities: this.app.getHostCapabilities() ?? null,
63
+ });
60
64
  }
61
65
  catch (err) {
62
66
  console.error(err);
@@ -138,7 +142,12 @@ export class McpAppBridge {
138
142
  },
139
143
  })),
140
144
  toolInput: createMcpStore(this, ["toolInput"], ({ toolInput }) => toolInput ?? null),
141
- toolOutput: createMcpStore(this, ["toolResult"], ({ toolResult }) => toolResult?.structuredContent ?? null),
145
+ toolOutput: createMcpStore(this, ["toolResult"], ({ toolResult }) => {
146
+ const structuredContent = toolResult?.structuredContent;
147
+ return typeof structuredContent === "object"
148
+ ? structuredContent
149
+ : null;
150
+ }),
142
151
  toolResponseMetadata: createMcpStore(this, ["toolResult"], ({ toolResult }) => toolResult?._meta ?? null),
143
152
  };
144
153
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { App } from \"@modelcontextprotocol/ext-apps\";\nimport {\n type Implementation,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { dequal } from \"dequal/lite\";\nimport * as z from \"zod\";\nimport type {\n AnyViewToolHandler,\n Bridge,\n HostContextStore,\n Subscribe,\n ViewToolConfig,\n} from \"../types.js\";\nimport type { McpAppContext, McpAppContextKey } from \"./types.js\";\n\ntype PickContext<K extends readonly McpAppContextKey[]> = {\n [P in K[number]]: McpAppContext[P];\n};\n\nfunction createMcpStore<const Keys extends readonly McpAppContextKey[], R>(\n bridge: McpAppBridge,\n keys: Keys,\n computeSnapshot: (context: PickContext<Keys>) => R,\n) {\n let cachedValue: R | undefined;\n return {\n subscribe: bridge.subscribe(keys),\n getSnapshot: () => {\n const context = Object.fromEntries(\n keys.map((k) => [k, bridge.getSnapshot(k)]),\n ) as PickContext<Keys>;\n const newValue = computeSnapshot(context);\n if (cachedValue !== undefined && dequal(cachedValue, newValue)) {\n return cachedValue;\n }\n cachedValue = newValue;\n return newValue;\n },\n };\n}\n\n/** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by `HostAdaptor`. */\nexport class McpAppBridge implements Bridge<McpAppContext> {\n private static instance: McpAppBridge | null = null;\n public context: McpAppContext = {\n toolInput: null,\n toolCancelled: null,\n toolResult: null,\n };\n private listeners = new Map<McpAppContextKey, Set<() => void>>();\n private app: App;\n private connectPromise: Promise<void>;\n\n constructor(options: { appInfo: Implementation }) {\n this.app = new App(options.appInfo, { tools: { listChanged: true } });\n\n this.app.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [],\n }));\n\n this.app.ontoolinput = (params) => {\n this.updateContext({ toolInput: params.arguments ?? {} });\n };\n\n this.app.ontoolinputpartial = (params) => {\n this.updateContext({ toolInput: params.arguments ?? {} });\n };\n\n this.app.ontoolresult = (params) => {\n this.updateContext({ toolResult: params });\n };\n\n this.app.ontoolcancelled = (params) => {\n this.updateContext({ toolCancelled: params });\n };\n\n this.app.onhostcontextchanged = (params) => {\n this.updateContext(params);\n };\n\n this.connectPromise = this.connect();\n }\n\n private async connect() {\n try {\n await this.app.connect();\n const hostContext = this.app.getHostContext();\n if (hostContext) {\n this.updateContext(hostContext);\n }\n } catch (err) {\n console.error(err);\n }\n }\n\n public async getApp(): Promise<App> {\n await this.connectPromise;\n return this.app;\n }\n\n public registerViewTool(\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): () => void {\n const inputSchema = config.inputSchema\n ? z.object(config.inputSchema)\n : z.object({});\n\n const registered = this.app.registerTool(\n config.name,\n {\n ...(config.title !== undefined ? { title: config.title } : {}),\n ...(config.description !== undefined\n ? { description: config.description }\n : {}),\n inputSchema,\n ...(config.annotations ? { annotations: config.annotations } : {}),\n },\n handler,\n );\n\n return () => {\n registered.remove();\n };\n }\n\n public static getInstance(\n options?: Partial<{ appInfo: Implementation }>,\n ): McpAppBridge {\n if (McpAppBridge.instance && options) {\n console.warn(\n \"McpAppBridge.getInstance: options ignored, instance already exists\",\n );\n }\n if (!McpAppBridge.instance) {\n const defaultOptions = {\n appInfo: { name: \"skybridge-app\", version: \"0.0.1\" },\n };\n McpAppBridge.instance = new McpAppBridge({\n ...defaultOptions,\n ...options,\n });\n }\n return McpAppBridge.instance;\n }\n\n public subscribe(key: McpAppContextKey): Subscribe;\n public subscribe(keys: readonly McpAppContextKey[]): Subscribe;\n public subscribe(\n keyOrKeys: McpAppContextKey | readonly McpAppContextKey[],\n ): Subscribe {\n const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];\n return (onChange: () => void) => {\n for (const key of keys) {\n this.listeners.set(\n key,\n new Set([...(this.listeners.get(key) || []), onChange]),\n );\n }\n return () => {\n for (const key of keys) {\n this.listeners.get(key)?.delete(onChange);\n }\n };\n };\n }\n\n public getSnapshot<K extends keyof McpAppContext>(key: K): McpAppContext[K] {\n return this.context[key];\n }\n\n public createContextStores(): {\n theme: HostContextStore<\"theme\">;\n locale: HostContextStore<\"locale\">;\n safeArea: HostContextStore<\"safeArea\">;\n displayMode: HostContextStore<\"displayMode\">;\n maxHeight: HostContextStore<\"maxHeight\">;\n userAgent: HostContextStore<\"userAgent\">;\n toolInput: HostContextStore<\"toolInput\">;\n toolOutput: HostContextStore<\"toolOutput\">;\n toolResponseMetadata: HostContextStore<\"toolResponseMetadata\">;\n } {\n return {\n theme: createMcpStore(this, [\"theme\"], ({ theme }) => theme ?? \"light\"),\n locale: createMcpStore(\n this,\n [\"locale\"],\n ({ locale }) => locale ?? \"en-US\",\n ),\n safeArea: createMcpStore(\n this,\n [\"safeAreaInsets\"],\n ({ safeAreaInsets }) => ({\n insets: safeAreaInsets ?? { top: 0, right: 0, bottom: 0, left: 0 },\n }),\n ),\n displayMode: createMcpStore(\n this,\n [\"displayMode\"],\n ({ displayMode }) => displayMode ?? \"inline\",\n ),\n maxHeight: createMcpStore(\n this,\n [\"containerDimensions\"],\n ({ containerDimensions }) => {\n if (containerDimensions && \"maxHeight\" in containerDimensions) {\n return containerDimensions.maxHeight;\n }\n return undefined;\n },\n ),\n userAgent: createMcpStore(\n this,\n [\"platform\", \"deviceCapabilities\"],\n ({ platform, deviceCapabilities }) => ({\n device: {\n type: platform === \"web\" ? \"desktop\" : (platform ?? \"unknown\"),\n },\n capabilities: {\n hover: true,\n touch: true,\n ...deviceCapabilities,\n },\n }),\n ),\n toolInput: createMcpStore(\n this,\n [\"toolInput\"],\n ({ toolInput }) => toolInput ?? null,\n ),\n toolOutput: createMcpStore(\n this,\n [\"toolResult\"],\n ({ toolResult }) => toolResult?.structuredContent ?? null,\n ),\n toolResponseMetadata: createMcpStore(\n this,\n [\"toolResult\"],\n ({ toolResult }) => toolResult?._meta ?? null,\n ),\n };\n }\n\n public cleanup = () => {\n this.listeners.clear();\n };\n\n public static resetInstance(): void {\n if (McpAppBridge.instance) {\n McpAppBridge.instance.cleanup();\n McpAppBridge.instance = null;\n }\n }\n\n private emit(key: McpAppContextKey) {\n this.listeners.get(key)?.forEach((listener) => {\n listener();\n });\n }\n\n private updateContext(context: Partial<McpAppContext>) {\n this.context = { ...this.context, ...context };\n for (const key of Object.keys(context)) {\n this.emit(key);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Implementation } from \"@modelcontextprotocol/client\";\nimport { ListToolsRequestSchema } from \"@modelcontextprotocol/core\";\nimport { App } from \"@modelcontextprotocol/ext-apps\";\nimport { dequal } from \"dequal/lite\";\nimport * as z from \"zod/v4\";\nimport type {\n AnyViewToolHandler,\n Bridge,\n HostContextStore,\n Subscribe,\n ViewToolConfig,\n} from \"../types.js\";\nimport type { McpAppContext, McpAppContextKey } from \"./types.js\";\n\ntype PickContext<K extends readonly McpAppContextKey[]> = {\n [P in K[number]]: McpAppContext[P];\n};\n\nfunction createMcpStore<const Keys extends readonly McpAppContextKey[], R>(\n bridge: McpAppBridge,\n keys: Keys,\n computeSnapshot: (context: PickContext<Keys>) => R,\n) {\n let cachedValue: R | undefined;\n return {\n subscribe: bridge.subscribe(keys),\n getSnapshot: () => {\n const context = Object.fromEntries(\n keys.map((k) => [k, bridge.getSnapshot(k)]),\n ) as PickContext<Keys>;\n const newValue = computeSnapshot(context);\n if (cachedValue !== undefined && dequal(cachedValue, newValue)) {\n return cachedValue;\n }\n cachedValue = newValue;\n return newValue;\n },\n };\n}\n\n/** @internal Singleton bridge over the `ext-apps` JSON-RPC App connection. Used by `HostAdaptor`. */\nexport class McpAppBridge implements Bridge<McpAppContext> {\n private static instance: McpAppBridge | null = null;\n public context: McpAppContext = {\n toolInput: null,\n toolCancelled: null,\n toolResult: null,\n hostInfo: null,\n hostCapabilities: null,\n };\n private listeners = new Map<McpAppContextKey, Set<() => void>>();\n private app: App;\n private connectPromise: Promise<void>;\n\n constructor(options: { appInfo: Implementation }) {\n this.app = new App(options.appInfo, { tools: { listChanged: true } });\n\n this.app.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [],\n }));\n\n this.app.ontoolinput = (params) => {\n this.updateContext({ toolInput: params.arguments ?? {} });\n };\n\n this.app.ontoolinputpartial = (params) => {\n this.updateContext({ toolInput: params.arguments ?? {} });\n };\n\n this.app.ontoolresult = (params) => {\n this.updateContext({ toolResult: params });\n };\n\n this.app.ontoolcancelled = (params) => {\n this.updateContext({ toolCancelled: params });\n };\n\n this.app.onhostcontextchanged = (params) => {\n this.updateContext(params);\n };\n\n this.connectPromise = this.connect();\n }\n\n private async connect() {\n try {\n await this.app.connect();\n const hostContext = this.app.getHostContext();\n this.updateContext({\n ...hostContext,\n hostInfo: this.app.getHostVersion() ?? null,\n hostCapabilities: this.app.getHostCapabilities() ?? null,\n });\n } catch (err) {\n console.error(err);\n }\n }\n\n public async getApp(): Promise<App> {\n await this.connectPromise;\n return this.app;\n }\n\n public registerViewTool(\n config: ViewToolConfig,\n handler: AnyViewToolHandler,\n ): () => void {\n const inputSchema = config.inputSchema\n ? z.object(config.inputSchema)\n : z.object({});\n\n const registered = this.app.registerTool(\n config.name,\n {\n ...(config.title !== undefined ? { title: config.title } : {}),\n ...(config.description !== undefined\n ? { description: config.description }\n : {}),\n inputSchema,\n ...(config.annotations ? { annotations: config.annotations } : {}),\n },\n handler,\n );\n\n return () => {\n registered.remove();\n };\n }\n\n public static getInstance(\n options?: Partial<{ appInfo: Implementation }>,\n ): McpAppBridge {\n if (McpAppBridge.instance && options) {\n console.warn(\n \"McpAppBridge.getInstance: options ignored, instance already exists\",\n );\n }\n if (!McpAppBridge.instance) {\n const defaultOptions = {\n appInfo: { name: \"skybridge-app\", version: \"0.0.1\" },\n };\n McpAppBridge.instance = new McpAppBridge({\n ...defaultOptions,\n ...options,\n });\n }\n return McpAppBridge.instance;\n }\n\n public subscribe(key: McpAppContextKey): Subscribe;\n public subscribe(keys: readonly McpAppContextKey[]): Subscribe;\n public subscribe(\n keyOrKeys: McpAppContextKey | readonly McpAppContextKey[],\n ): Subscribe {\n const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys];\n return (onChange: () => void) => {\n for (const key of keys) {\n this.listeners.set(\n key,\n new Set([...(this.listeners.get(key) || []), onChange]),\n );\n }\n return () => {\n for (const key of keys) {\n this.listeners.get(key)?.delete(onChange);\n }\n };\n };\n }\n\n public getSnapshot<K extends keyof McpAppContext>(key: K): McpAppContext[K] {\n return this.context[key];\n }\n\n public createContextStores(): {\n theme: HostContextStore<\"theme\">;\n locale: HostContextStore<\"locale\">;\n safeArea: HostContextStore<\"safeArea\">;\n displayMode: HostContextStore<\"displayMode\">;\n maxHeight: HostContextStore<\"maxHeight\">;\n userAgent: HostContextStore<\"userAgent\">;\n toolInput: HostContextStore<\"toolInput\">;\n toolOutput: HostContextStore<\"toolOutput\">;\n toolResponseMetadata: HostContextStore<\"toolResponseMetadata\">;\n } {\n return {\n theme: createMcpStore(this, [\"theme\"], ({ theme }) => theme ?? \"light\"),\n locale: createMcpStore(\n this,\n [\"locale\"],\n ({ locale }) => locale ?? \"en-US\",\n ),\n safeArea: createMcpStore(\n this,\n [\"safeAreaInsets\"],\n ({ safeAreaInsets }) => ({\n insets: safeAreaInsets ?? { top: 0, right: 0, bottom: 0, left: 0 },\n }),\n ),\n displayMode: createMcpStore(\n this,\n [\"displayMode\"],\n ({ displayMode }) => displayMode ?? \"inline\",\n ),\n maxHeight: createMcpStore(\n this,\n [\"containerDimensions\"],\n ({ containerDimensions }) => {\n if (containerDimensions && \"maxHeight\" in containerDimensions) {\n return containerDimensions.maxHeight;\n }\n return undefined;\n },\n ),\n userAgent: createMcpStore(\n this,\n [\"platform\", \"deviceCapabilities\"],\n ({ platform, deviceCapabilities }) => ({\n device: {\n type: platform === \"web\" ? \"desktop\" : (platform ?? \"unknown\"),\n },\n capabilities: {\n hover: true,\n touch: true,\n ...deviceCapabilities,\n },\n }),\n ),\n toolInput: createMcpStore(\n this,\n [\"toolInput\"],\n ({ toolInput }) => toolInput ?? null,\n ),\n toolOutput: createMcpStore(this, [\"toolResult\"], ({ toolResult }) => {\n const structuredContent = toolResult?.structuredContent;\n return typeof structuredContent === \"object\"\n ? (structuredContent as Record<string, unknown> | null)\n : null;\n }),\n toolResponseMetadata: createMcpStore(\n this,\n [\"toolResult\"],\n ({ toolResult }) => toolResult?._meta ?? null,\n ),\n };\n }\n\n public cleanup = () => {\n this.listeners.clear();\n };\n\n public static resetInstance(): void {\n if (McpAppBridge.instance) {\n McpAppBridge.instance.cleanup();\n McpAppBridge.instance = null;\n }\n }\n\n private emit(key: McpAppContextKey) {\n this.listeners.get(key)?.forEach((listener) => {\n listener();\n });\n }\n\n private updateContext(context: Partial<McpAppContext>) {\n this.context = { ...this.context, ...context };\n for (const key of Object.keys(context)) {\n this.emit(key);\n }\n }\n}\n"]}
@@ -9,8 +9,8 @@ describe("McpAppBridge.getInstance", () => {
9
9
  vi.unstubAllGlobals();
10
10
  McpAppBridge.resetInstance();
11
11
  });
12
- it("instantiates regardless of injected hostType", () => {
13
- vi.stubGlobal("skybridge", { hostType: "apps-sdk" });
12
+ it("instantiates without injected globals", () => {
13
+ vi.stubGlobal("skybridge", {});
14
14
  expect(() => McpAppBridge.getInstance()).not.toThrow();
15
15
  });
16
16
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/bridge.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,YAAY,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { McpAppBridge } from \"./bridge.js\";\n\ndescribe(\"McpAppBridge.getInstance\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n });\n\n it(\"instantiates regardless of injected hostType\", () => {\n vi.stubGlobal(\"skybridge\", { hostType: \"apps-sdk\" });\n expect(() => McpAppBridge.getInstance()).not.toThrow();\n });\n});\n"]}
1
+ {"version":3,"file":"bridge.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/bridge.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,UAAU,CAAC,GAAG,EAAE;QACd,YAAY,CAAC,aAAa,EAAE,CAAC;QAC7B,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,YAAY,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { McpAppBridge } from \"./bridge.js\";\n\ndescribe(\"McpAppBridge.getInstance\", () => {\n beforeEach(() => {\n McpAppBridge.resetInstance();\n vi.stubGlobal(\"parent\", { postMessage: vi.fn() });\n });\n afterEach(() => {\n vi.unstubAllGlobals();\n McpAppBridge.resetInstance();\n });\n\n it(\"instantiates without injected globals\", () => {\n vi.stubGlobal(\"skybridge\", {});\n expect(() => McpAppBridge.getInstance()).not.toThrow();\n });\n});\n"]}
@@ -1,8 +1,25 @@
1
- import type { McpUiHostContext, McpUiToolCancelledNotification, McpUiToolInputNotification, McpUiToolResultNotification } from "@modelcontextprotocol/ext-apps";
1
+ import type { Implementation } from "@modelcontextprotocol/client";
2
+ import type { McpUiHostCapabilities, McpUiHostContext, McpUiToolCancelledNotification, McpUiToolInputNotification, McpUiToolResultNotification, McpUiUpdateModelContextRequest } from "@modelcontextprotocol/ext-apps";
2
3
  export type McpToolState = {
3
4
  toolInput: NonNullable<McpUiToolInputNotification["params"]["arguments"]> | null;
4
5
  toolResult: McpUiToolResultNotification["params"] | null;
5
6
  toolCancelled: McpUiToolCancelledNotification["params"] | null;
7
+ hostInfo: Implementation | null;
8
+ hostCapabilities: McpUiHostCapabilities | null;
6
9
  };
7
- export type McpAppContext = McpUiHostContext & McpToolState;
10
+ /** ChatGPT-only host context keys from the OpenAI MCP extensions. */
11
+ export type OpenAIHostContext = {
12
+ /** App-relative URL the view was opened on through a deep link. */
13
+ "openai/deepLink"?: {
14
+ url: string;
15
+ };
16
+ /**
17
+ * Context this view attached to the conversation. `null` once the user
18
+ * removed it, for example by deleting its composer attachment.
19
+ */
20
+ "openai/modelContext"?: (McpUiUpdateModelContextRequest["params"] & {
21
+ updateId: string;
22
+ }) | null;
23
+ };
24
+ export type McpAppContext = McpUiHostContext & OpenAIHostContext & McpToolState;
8
25
  export type McpAppContextKey = keyof McpAppContext;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n McpUiHostContext,\n McpUiToolCancelledNotification,\n McpUiToolInputNotification,\n McpUiToolResultNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n\nexport type McpToolState = {\n toolInput: NonNullable<\n McpUiToolInputNotification[\"params\"][\"arguments\"]\n > | null;\n toolResult: McpUiToolResultNotification[\"params\"] | null;\n toolCancelled: McpUiToolCancelledNotification[\"params\"] | null;\n};\n\nexport type McpAppContext = McpUiHostContext & McpToolState;\n\nexport type McpAppContextKey = keyof McpAppContext;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Implementation } from \"@modelcontextprotocol/client\";\nimport type {\n McpUiHostCapabilities,\n McpUiHostContext,\n McpUiToolCancelledNotification,\n McpUiToolInputNotification,\n McpUiToolResultNotification,\n McpUiUpdateModelContextRequest,\n} from \"@modelcontextprotocol/ext-apps\";\n\nexport type McpToolState = {\n toolInput: NonNullable<\n McpUiToolInputNotification[\"params\"][\"arguments\"]\n > | null;\n toolResult: McpUiToolResultNotification[\"params\"] | null;\n toolCancelled: McpUiToolCancelledNotification[\"params\"] | null;\n hostInfo: Implementation | null;\n hostCapabilities: McpUiHostCapabilities | null;\n};\n\n/** ChatGPT-only host context keys from the OpenAI MCP extensions. */\nexport type OpenAIHostContext = {\n /** App-relative URL the view was opened on through a deep link. */\n \"openai/deepLink\"?: { url: string };\n /**\n * Context this view attached to the conversation. `null` once the user\n * removed it, for example by deleting its composer attachment.\n */\n \"openai/modelContext\"?:\n | (McpUiUpdateModelContextRequest[\"params\"] & { updateId: string })\n | null;\n};\n\nexport type McpAppContext = McpUiHostContext & OpenAIHostContext & McpToolState;\n\nexport type McpAppContextKey = keyof McpAppContext;\n"]}
@@ -1,4 +1,4 @@
1
- import type { Implementation } from "@modelcontextprotocol/sdk/types.js";
1
+ import type { Implementation } from "@modelcontextprotocol/client";
2
2
  import type { McpAppContext } from "./types.js";
3
3
  type McpAppInitializationOptions = {
4
4
  appInfo: Implementation;
@@ -7,7 +7,7 @@ type McpAppInitializationOptions = {
7
7
  * Read a single key from the raw MCP Apps (`ext-apps`) bridge context.
8
8
  *
9
9
  * Advanced escape hatch — prefer the cross-host hooks (`useToolInfo`,
10
- * `useLayout`, etc.) which work in both MCP Apps and Apps SDK. Reach for this
10
+ * `useViewport`, etc.) which work in both MCP Apps and ChatGPT. Reach for this
11
11
  * when you need protocol-level fields not surfaced by the public hooks.
12
12
  *
13
13
  * `options.appInfo` is honored only on the first call that creates the
@@ -4,7 +4,7 @@ import { McpAppBridge } from "./bridge.js";
4
4
  * Read a single key from the raw MCP Apps (`ext-apps`) bridge context.
5
5
  *
6
6
  * Advanced escape hatch — prefer the cross-host hooks (`useToolInfo`,
7
- * `useLayout`, etc.) which work in both MCP Apps and Apps SDK. Reach for this
7
+ * `useViewport`, etc.) which work in both MCP Apps and ChatGPT. Reach for this
8
8
  * when you need protocol-level fields not surfaced by the public hooks.
9
9
  *
10
10
  * `options.appInfo` is honored only on the first call that creates the
@@ -1 +1 @@
1
- {"version":3,"file":"use-mcp-app-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/use-mcp-app-context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAM,EACN,OAA8C;IAE9C,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import type { Implementation } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { useSyncExternalStore } from \"react\";\nimport { McpAppBridge } from \"./bridge.js\";\nimport type { McpAppContext } from \"./types.js\";\n\ntype McpAppInitializationOptions = {\n appInfo: Implementation;\n};\n\n/**\n * Read a single key from the raw MCP Apps (`ext-apps`) bridge context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useToolInfo`,\n * `useLayout`, etc.) which work in both MCP Apps and Apps SDK. Reach for this\n * when you need protocol-level fields not surfaced by the public hooks.\n *\n * `options.appInfo` is honored only on the first call that creates the\n * underlying bridge; subsequent calls reuse the singleton.\n *\n * @see https://docs.skybridge.tech/api-reference/use-mcp-app-context\n */\nexport function useMcpAppContext<K extends keyof McpAppContext>(\n key: K,\n options?: Partial<McpAppInitializationOptions>,\n): McpAppContext[K] {\n const bridge = McpAppBridge.getInstance(options);\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
1
+ {"version":3,"file":"use-mcp-app-context.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/use-mcp-app-context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAM,EACN,OAA8C;IAE9C,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CACxB,CAAC;AACJ,CAAC","sourcesContent":["import type { Implementation } from \"@modelcontextprotocol/client\";\n\nimport { useSyncExternalStore } from \"react\";\nimport { McpAppBridge } from \"./bridge.js\";\nimport type { McpAppContext } from \"./types.js\";\n\ntype McpAppInitializationOptions = {\n appInfo: Implementation;\n};\n\n/**\n * Read a single key from the raw MCP Apps (`ext-apps`) bridge context.\n *\n * Advanced escape hatch — prefer the cross-host hooks (`useToolInfo`,\n * `useViewport`, etc.) which work in both MCP Apps and ChatGPT. Reach for this\n * when you need protocol-level fields not surfaced by the public hooks.\n *\n * `options.appInfo` is honored only on the first call that creates the\n * underlying bridge; subsequent calls reuse the singleton.\n *\n * @see https://docs.skybridge.tech/api-reference/use-mcp-app-context\n */\nexport function useMcpAppContext<K extends keyof McpAppContext>(\n key: K,\n options?: Partial<McpAppInitializationOptions>,\n): McpAppContext[K] {\n const bridge = McpAppBridge.getInstance(options);\n return useSyncExternalStore(bridge.subscribe(key), () =>\n bridge.getSnapshot(key),\n );\n}\n"]}
@@ -5,7 +5,7 @@ import { McpAppBridge } from "./bridge.js";
5
5
  import { useMcpAppContext } from "./use-mcp-app-context.js";
6
6
  describe("useMcpAppContext", () => {
7
7
  beforeEach(async () => {
8
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
8
+ vi.stubGlobal("skybridge", {});
9
9
  vi.stubGlobal("ResizeObserver", MockResizeObserver);
10
10
  McpAppBridge.resetInstance();
11
11
  });
@@ -1 +1 @@
1
- {"version":3,"file":"use-mcp-app-context.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/use-mcp-app-context.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACpD,YAAY,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;YACtB,WAAW,EAAE,4BAA4B,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;QAE/D,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"../../hooks/test/utils.js\";\nimport { McpAppBridge } from \"./bridge.js\";\nimport { useMcpAppContext } from \"./use-mcp-app-context.js\";\n\ndescribe(\"useMcpAppContext\", () => {\n beforeEach(async () => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n McpAppBridge.resetInstance();\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.clearAllMocks();\n });\n\n it(\"should return the theme value from host context and update on notification\", async () => {\n vi.stubGlobal(\"parent\", {\n postMessage: getMcpAppHostPostMessageMock({ theme: \"light\" }),\n });\n const { result } = renderHook(() => useMcpAppContext(\"theme\"));\n\n await waitFor(() => {\n expect(result.current).toBe(\"light\");\n });\n });\n});\n"]}
1
+ {"version":3,"file":"use-mcp-app-context.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/use-mcp-app-context.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACpD,YAAY,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE;YACtB,WAAW,EAAE,4BAA4B,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;QAE/D,MAAM,OAAO,CAAC,GAAG,EAAE;YACjB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { renderHook, waitFor } from \"@testing-library/react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n getMcpAppHostPostMessageMock,\n MockResizeObserver,\n} from \"../../hooks/test/utils.js\";\nimport { McpAppBridge } from \"./bridge.js\";\nimport { useMcpAppContext } from \"./use-mcp-app-context.js\";\n\ndescribe(\"useMcpAppContext\", () => {\n beforeEach(async () => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n McpAppBridge.resetInstance();\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.clearAllMocks();\n });\n\n it(\"should return the theme value from host context and update on notification\", async () => {\n vi.stubGlobal(\"parent\", {\n postMessage: getMcpAppHostPostMessageMock({ theme: \"light\" }),\n });\n const { result } = renderHook(() => useMcpAppContext(\"theme\"));\n\n await waitFor(() => {\n expect(result.current).toBe(\"light\");\n });\n });\n});\n"]}
@@ -51,7 +51,7 @@ async function callHost(method, params = {}) {
51
51
  }
52
52
  describe("McpApp view tools", () => {
53
53
  beforeEach(() => {
54
- vi.stubGlobal("skybridge", { hostType: "mcp-app" });
54
+ vi.stubGlobal("skybridge", {});
55
55
  vi.stubGlobal("ResizeObserver", MockResizeObserver);
56
56
  McpAppBridge.resetInstance();
57
57
  installHostMock();
@@ -1 +1 @@
1
- {"version":3,"file":"view-tools.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/view-tools.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { waitFor } from \"@testing-library/react\";\nimport { act } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport * as z from \"zod\";\nimport { MockResizeObserver } from \"../../hooks/test/utils.js\";\nimport { HostAdaptor } from \"../adaptor.js\";\nimport { McpAppBridge } from \"./bridge.js\";\n\ntype JsonRpcMessage = {\n jsonrpc: \"2.0\";\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message: string };\n};\n\nconst outgoing: JsonRpcMessage[] = [];\n\n/**\n * Stand-in MCP Apps host: replies to `ui/initialize` and records every message\n * the app posts so tests can assert on responses and notifications.\n */\nfunction installHostMock() {\n outgoing.length = 0;\n const postMessage = vi.fn((message: JsonRpcMessage) => {\n outgoing.push(message);\n if (message.method === \"ui/initialize\" && message.id !== undefined) {\n act(() => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n source: window.parent,\n data: {\n jsonrpc: \"2.0\",\n id: message.id,\n result: {\n protocolVersion: \"2025-06-18\",\n hostInfo: { name: \"test-host\", version: \"1.0.0\" },\n hostCapabilities: {},\n hostContext: {},\n },\n },\n }),\n );\n });\n }\n });\n vi.stubGlobal(\"parent\", { postMessage });\n}\n\nlet nextId = 1000;\n\n/** Send a host → app JSON-RPC request and resolve with the full response (result or error). */\nasync function callHost(method: string, params: Record<string, unknown> = {}) {\n const id = ++nextId;\n act(() => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n source: window.parent,\n data: { jsonrpc: \"2.0\", id, method, params },\n }),\n );\n });\n await waitFor(() => {\n expect(outgoing.some((m) => m.id === id)).toBe(true);\n });\n return outgoing.find((m) => m.id === id);\n}\n\ndescribe(\"McpApp view tools\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"skybridge\", { hostType: \"mcp-app\" });\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n McpAppBridge.resetInstance();\n installHostMock();\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.clearAllMocks();\n });\n\n it(\"advertises the tools capability during ui/initialize\", async () => {\n await McpAppBridge.getInstance().getApp();\n const init = outgoing.find((m) => m.method === \"ui/initialize\");\n expect(init?.params?.appCapabilities).toMatchObject({\n tools: { listChanged: true },\n });\n });\n\n it(\"lists a registered view tool with its input schema\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n adaptor.registerViewTool(\n {\n name: \"chess_make_move\",\n description: \"Play a move\",\n inputSchema: { san: z.string() },\n annotations: { readOnlyHint: false },\n },\n () => ({ content: [{ type: \"text\", text: \"ok\" }] }),\n );\n\n const response = await callHost(\"tools/list\");\n const tools = response?.result?.tools as Array<{\n name: string;\n description?: string;\n inputSchema: { properties?: Record<string, unknown> };\n annotations?: { readOnlyHint?: boolean };\n }>;\n expect(tools).toHaveLength(1);\n const [tool] = tools;\n expect(tool?.name).toBe(\"chess_make_move\");\n expect(tool?.description).toBe(\"Play a move\");\n expect(tool?.inputSchema.properties).toHaveProperty(\"san\");\n expect(tool?.annotations?.readOnlyHint).toBe(false);\n });\n\n it(\"invokes the handler with validated args and returns its result\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const handler = vi.fn(({ san }: { san: string }) => ({\n content: [{ type: \"text\" as const, text: `played ${san}` }],\n structuredContent: { lastMove: san },\n }));\n\n adaptor.registerViewTool(\n { name: \"chess_make_move\", inputSchema: { san: z.string() } },\n handler as never,\n );\n\n const response = await callHost(\"tools/call\", {\n name: \"chess_make_move\",\n arguments: { san: \"e4\" },\n });\n const result = response?.result;\n\n // ext-apps invokes the callback as `(args, extra)`; assert on the args only.\n expect(handler.mock.calls[0]?.[0]).toEqual({ san: \"e4\" });\n expect(result?.structuredContent).toEqual({ lastMove: \"e4\" });\n expect(result?.isError).toBeFalsy();\n expect(result?.content).toEqual([{ type: \"text\", text: \"played e4\" }]);\n });\n\n it(\"rejects the call without invoking the handler when args are invalid\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const handler = vi.fn(() => ({ content: [] }));\n adaptor.registerViewTool(\n { name: \"chess_make_move\", inputSchema: { san: z.string() } },\n handler as never,\n );\n\n // ext-apps validates input against the schema and rejects with a JSON-RPC\n // error before the handler runs.\n const response = await callHost(\"tools/call\", {\n name: \"chess_make_move\",\n arguments: { san: 42 },\n });\n\n expect(handler).not.toHaveBeenCalled();\n expect(response?.error).toBeDefined();\n });\n\n it(\"rejects a call to an unknown tool\", async () => {\n await McpAppBridge.getInstance().getApp();\n const response = await callHost(\"tools/call\", {\n name: \"nope\",\n arguments: {},\n });\n expect(response?.error).toBeDefined();\n });\n\n it(\"removes the tool and notifies the host when unregistered\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const unregister = adaptor.registerViewTool(\n { name: \"chess_reset\" },\n () => ({ content: [{ type: \"text\", text: \"reset\" }] }),\n );\n\n await waitFor(() => {\n expect(\n outgoing.some((m) => m.method === \"notifications/tools/list_changed\"),\n ).toBe(true);\n });\n\n let listed = await callHost(\"tools/list\");\n expect(listed?.result?.tools).toHaveLength(1);\n\n unregister();\n listed = await callHost(\"tools/list\");\n expect(listed?.result?.tools).toHaveLength(0);\n });\n});\n"]}
1
+ {"version":3,"file":"view-tools.test.js","sourceRoot":"","sources":["../../../../src/web/bridges/mcp-app/view-tools.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { waitFor } from \"@testing-library/react\";\nimport { act } from \"react\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport * as z from \"zod\";\nimport { MockResizeObserver } from \"../../hooks/test/utils.js\";\nimport { HostAdaptor } from \"../adaptor.js\";\nimport { McpAppBridge } from \"./bridge.js\";\n\ntype JsonRpcMessage = {\n jsonrpc: \"2.0\";\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message: string };\n};\n\nconst outgoing: JsonRpcMessage[] = [];\n\n/**\n * Stand-in MCP Apps host: replies to `ui/initialize` and records every message\n * the app posts so tests can assert on responses and notifications.\n */\nfunction installHostMock() {\n outgoing.length = 0;\n const postMessage = vi.fn((message: JsonRpcMessage) => {\n outgoing.push(message);\n if (message.method === \"ui/initialize\" && message.id !== undefined) {\n act(() => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n source: window.parent,\n data: {\n jsonrpc: \"2.0\",\n id: message.id,\n result: {\n protocolVersion: \"2025-06-18\",\n hostInfo: { name: \"test-host\", version: \"1.0.0\" },\n hostCapabilities: {},\n hostContext: {},\n },\n },\n }),\n );\n });\n }\n });\n vi.stubGlobal(\"parent\", { postMessage });\n}\n\nlet nextId = 1000;\n\n/** Send a host → app JSON-RPC request and resolve with the full response (result or error). */\nasync function callHost(method: string, params: Record<string, unknown> = {}) {\n const id = ++nextId;\n act(() => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n source: window.parent,\n data: { jsonrpc: \"2.0\", id, method, params },\n }),\n );\n });\n await waitFor(() => {\n expect(outgoing.some((m) => m.id === id)).toBe(true);\n });\n return outgoing.find((m) => m.id === id);\n}\n\ndescribe(\"McpApp view tools\", () => {\n beforeEach(() => {\n vi.stubGlobal(\"skybridge\", {});\n vi.stubGlobal(\"ResizeObserver\", MockResizeObserver);\n McpAppBridge.resetInstance();\n installHostMock();\n });\n\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.clearAllMocks();\n });\n\n it(\"advertises the tools capability during ui/initialize\", async () => {\n await McpAppBridge.getInstance().getApp();\n const init = outgoing.find((m) => m.method === \"ui/initialize\");\n expect(init?.params?.appCapabilities).toMatchObject({\n tools: { listChanged: true },\n });\n });\n\n it(\"lists a registered view tool with its input schema\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n adaptor.registerViewTool(\n {\n name: \"chess_make_move\",\n description: \"Play a move\",\n inputSchema: { san: z.string() },\n annotations: { readOnlyHint: false },\n },\n () => ({ content: [{ type: \"text\", text: \"ok\" }] }),\n );\n\n const response = await callHost(\"tools/list\");\n const tools = response?.result?.tools as Array<{\n name: string;\n description?: string;\n inputSchema: { properties?: Record<string, unknown> };\n annotations?: { readOnlyHint?: boolean };\n }>;\n expect(tools).toHaveLength(1);\n const [tool] = tools;\n expect(tool?.name).toBe(\"chess_make_move\");\n expect(tool?.description).toBe(\"Play a move\");\n expect(tool?.inputSchema.properties).toHaveProperty(\"san\");\n expect(tool?.annotations?.readOnlyHint).toBe(false);\n });\n\n it(\"invokes the handler with validated args and returns its result\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const handler = vi.fn(({ san }: { san: string }) => ({\n content: [{ type: \"text\" as const, text: `played ${san}` }],\n structuredContent: { lastMove: san },\n }));\n\n adaptor.registerViewTool(\n { name: \"chess_make_move\", inputSchema: { san: z.string() } },\n handler as never,\n );\n\n const response = await callHost(\"tools/call\", {\n name: \"chess_make_move\",\n arguments: { san: \"e4\" },\n });\n const result = response?.result;\n\n // ext-apps invokes the callback as `(args, extra)`; assert on the args only.\n expect(handler.mock.calls[0]?.[0]).toEqual({ san: \"e4\" });\n expect(result?.structuredContent).toEqual({ lastMove: \"e4\" });\n expect(result?.isError).toBeFalsy();\n expect(result?.content).toEqual([{ type: \"text\", text: \"played e4\" }]);\n });\n\n it(\"rejects the call without invoking the handler when args are invalid\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const handler = vi.fn(() => ({ content: [] }));\n adaptor.registerViewTool(\n { name: \"chess_make_move\", inputSchema: { san: z.string() } },\n handler as never,\n );\n\n // ext-apps validates input against the schema and rejects with a JSON-RPC\n // error before the handler runs.\n const response = await callHost(\"tools/call\", {\n name: \"chess_make_move\",\n arguments: { san: 42 },\n });\n\n expect(handler).not.toHaveBeenCalled();\n expect(response?.error).toBeDefined();\n });\n\n it(\"rejects a call to an unknown tool\", async () => {\n await McpAppBridge.getInstance().getApp();\n const response = await callHost(\"tools/call\", {\n name: \"nope\",\n arguments: {},\n });\n expect(response?.error).toBeDefined();\n });\n\n it(\"removes the tool and notifies the host when unregistered\", async () => {\n const adaptor = new HostAdaptor();\n await McpAppBridge.getInstance().getApp();\n\n const unregister = adaptor.registerViewTool(\n { name: \"chess_reset\" },\n () => ({ content: [{ type: \"text\", text: \"reset\" }] }),\n );\n\n await waitFor(() => {\n expect(\n outgoing.some((m) => m.method === \"notifications/tools/list_changed\"),\n ).toBe(true);\n });\n\n let listed = await callHost(\"tools/list\");\n expect(listed?.result?.tools).toHaveLength(1);\n\n unregister();\n listed = await callHost(\"tools/list\");\n expect(listed?.result?.tools).toHaveLength(0);\n });\n});\n"]}
@@ -1,13 +1,12 @@
1
- import type { SchemaOutput, ZodRawShapeCompat } from "@modelcontextprotocol/sdk/server/zod-compat.js";
2
- import type { CallToolResult, EmbeddedResource, ResourceLink, ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
1
+ import type { CallToolResult, ContentBlock, EmbeddedResource, ResourceLink, ToolAnnotations } from "@modelcontextprotocol/client";
2
+ import type { McpUiUpdateModelContextRequest } from "@modelcontextprotocol/ext-apps";
3
3
  import type { useSyncExternalStore } from "react";
4
- import type { ViewHostType } from "../../server/index.js";
4
+ import type { output as ZodOutput, ZodType } from "zod/v4";
5
5
  /**
6
- * Globals injected on `window.skybridge` by the host. Tells the view which
7
- * runtime it's running under and where to reach the MCP server.
6
+ * Globals injected on `window.skybridge` by the host. Tells the view where to
7
+ * reach the MCP server.
8
8
  */
9
9
  export type SkybridgeProperties = {
10
- hostType: ViewHostType;
11
10
  serverUrl: string;
12
11
  };
13
12
  declare global {
@@ -17,6 +16,16 @@ declare global {
17
16
  }
18
17
  /** Arguments passed to a tool call. `null` for tools that take no input. */
19
18
  export type CallToolArgs = Record<string, unknown> | null;
19
+ /** Options for a tool call made from the view. */
20
+ export type CallToolOptions = {
21
+ /**
22
+ * Request timeout in milliseconds. Omit it to keep the SDK default (60s).
23
+ * Raise it for tools that wait on the user, such as ChatGPT forms.
24
+ */
25
+ timeout?: number;
26
+ };
27
+ /** Payload of `ui/update-model-context`. Content blocks may carry `_meta`. */
28
+ export type ModelContextParams = McpUiUpdateModelContextRequest["params"];
20
29
  /**
21
30
  * Result of a tool call as surfaced to the view: MCP `content` blocks plus
22
31
  * the typed `structuredContent` and optional `meta`. `isError` is set when
@@ -47,7 +56,7 @@ export type SafeAreaInsets = {
47
56
  bottom: number;
48
57
  left: number;
49
58
  };
50
- /** Wrapper around {@link SafeAreaInsets} exposed via {@link useLayout}. */
59
+ /** Wrapper around {@link SafeAreaInsets} exposed via {@link useViewport}. */
51
60
  export type SafeArea = {
52
61
  insets: SafeAreaInsets;
53
62
  };
@@ -63,7 +72,7 @@ export type UserAgent = {
63
72
  };
64
73
  /**
65
74
  * Full snapshot of state the host exposes to the view. Most fields are
66
- * better accessed through their dedicated hooks (`useLayout`, `useUser`,
75
+ * better accessed through their dedicated hooks (`useViewport`, `useUser`,
67
76
  * `useToolInfo`, etc.) — read this directly only for advanced cases.
68
77
  */
69
78
  export interface HostContext {
@@ -131,8 +140,21 @@ export type OpenExternalOptions = {
131
140
  };
132
141
  /** Options for {@link useSendFollowUpMessage}. */
133
142
  export type SendFollowUpMessageOptions = {
143
+ /** Apps SDK only: set to `false` to keep the chat scroll position. */
134
144
  scrollToBottom?: boolean;
145
+ /**
146
+ * ChatGPT only, from the OpenAI MCP extensions: `"new"` starts a new
147
+ * conversation with the message. Defaults to the active conversation.
148
+ * Rejects on hosts that don't advertise `openai/message`.
149
+ */
150
+ target?: "active" | "new";
135
151
  };
152
+ /**
153
+ * A follow-up message: plain text, or content blocks. On ChatGPT, a text or
154
+ * image block with `_meta["openai/title"]` becomes a labeled item the user can
155
+ * remove.
156
+ */
157
+ export type FollowUpMessage = string | ContentBlock[];
136
158
  /** Options for {@link useRequestSize}. Omit a dimension to leave it unchanged. */
137
159
  export type RequestSizeOptions = {
138
160
  width?: number;
@@ -144,21 +166,28 @@ export type DownloadParams = {
144
166
  export type DownloadResult = {
145
167
  isError?: boolean;
146
168
  };
169
+ /**
170
+ * Shape of a view tool's `inputSchema`: a map of zod schemas. Narrower than
171
+ * the server's `Record<string, StandardSchemaWithJSON>` input shape because the MCP Apps bridge validates with
172
+ * `z.object()` at runtime — other Standard Schema libraries would type-check
173
+ * but throw on the first call.
174
+ */
175
+ export type ViewToolInputShape = Record<string, ZodType>;
147
176
  /**
148
177
  * Args passed to a {@link ViewToolHandler}, inferred from the tool's
149
178
  * `inputSchema` (optionality preserved). Mirrors the server's `registerTool`.
150
179
  */
151
- export type InferViewToolArgs<Shape extends ZodRawShapeCompat> = {
152
- [K in keyof Shape as undefined extends SchemaOutput<Shape[K]> ? never : K]: SchemaOutput<Shape[K]>;
180
+ export type InferViewToolArgs<Shape extends ViewToolInputShape> = {
181
+ [K in keyof Shape as undefined extends ZodOutput<Shape[K]> ? never : K]: ZodOutput<Shape[K]>;
153
182
  } & {
154
- [K in keyof Shape as undefined extends SchemaOutput<Shape[K]> ? K : never]?: SchemaOutput<Shape[K]>;
183
+ [K in keyof Shape as undefined extends ZodOutput<Shape[K]> ? K : never]?: ZodOutput<Shape[K]>;
155
184
  };
156
185
  /**
157
186
  * Declares a tool the view exposes to the host/model (the MCP Apps
158
187
  * "app-provided tools" feature). Mirrors the server-side `registerTool` config.
159
188
  * Namespace `name` (e.g. `chess_make_move`) to avoid clashing with server tools.
160
189
  */
161
- export type ViewToolConfig<TInput extends ZodRawShapeCompat = ZodRawShapeCompat> = {
190
+ export type ViewToolConfig<TInput extends ViewToolInputShape = ViewToolInputShape> = {
162
191
  name: string;
163
192
  title?: string;
164
193
  description?: string;
@@ -172,7 +201,7 @@ export type ViewToolConfig<TInput extends ZodRawShapeCompat = ZodRawShapeCompat>
172
201
  */
173
202
  export type ViewToolResult = CallToolResult;
174
203
  /** Handler run when the host calls a view tool. Receives validated, typed args. */
175
- export type ViewToolHandler<TInput extends ZodRawShapeCompat = ZodRawShapeCompat> = (args: InferViewToolArgs<TInput>) => ViewToolResult | Promise<ViewToolResult>;
204
+ export type ViewToolHandler<TInput extends ViewToolInputShape = ViewToolInputShape> = (args: InferViewToolArgs<TInput>) => ViewToolResult | Promise<ViewToolResult>;
176
205
  /** @internal Untyped handler signature stored by the adaptor/bridge after type erasure. */
177
206
  export type AnyViewToolHandler = (args: Record<string, unknown>) => ViewToolResult | Promise<ViewToolResult>;
178
207
  /**
@@ -183,16 +212,18 @@ export type AnyViewToolHandler = (args: Record<string, unknown>) => ViewToolResu
183
212
  */
184
213
  export interface Adaptor {
185
214
  getHostContextStore<K extends keyof HostContext>(key: K): HostContextStore<K>;
186
- callTool<ToolArgs extends CallToolArgs = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs): Promise<ToolResponse>;
215
+ callTool<ToolArgs extends CallToolArgs = null, ToolResponse extends CallToolResponse = CallToolResponse>(name: string, args: ToolArgs, options?: CallToolOptions): Promise<ToolResponse>;
187
216
  requestDisplayMode(mode: RequestDisplayMode): Promise<{
188
217
  mode: RequestDisplayMode;
189
218
  }>;
190
219
  requestClose(): Promise<void>;
191
220
  requestSize(size: RequestSizeOptions): Promise<void>;
192
- sendFollowUpMessage(prompt: string, options?: SendFollowUpMessageOptions): Promise<void>;
221
+ sendFollowUpMessage(prompt: FollowUpMessage, options?: SendFollowUpMessageOptions): Promise<void>;
193
222
  openExternal(href: string, options?: OpenExternalOptions): void;
194
223
  download(params: DownloadParams): Promise<DownloadResult>;
195
224
  setViewState(stateOrUpdater: SetViewStateAction): Promise<void>;
225
+ updateModelContext(params: ModelContextParams): Promise<string | undefined>;
226
+ openFile(path: string): Promise<void>;
196
227
  uploadFile(file: File, options?: UploadFileOptions): Promise<FileMetadata>;
197
228
  getFileDownloadUrl(file: FileMetadata): Promise<{
198
229
  downloadUrl: string;
@@ -205,7 +236,7 @@ export interface Adaptor {
205
236
  }
206
237
  /**
207
238
  * Thrown when a host bridge method is called in a runtime that doesn't
208
- * support it (e.g. `uploadFile` outside the Apps SDK runtime).
239
+ * support it (e.g. `uploadFile` outside the ChatGPT runtime).
209
240
  */
210
241
  export declare class NotSupportedError extends Error {
211
242
  readonly method: string;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Thrown when a host bridge method is called in a runtime that doesn't
3
- * support it (e.g. `uploadFile` outside the Apps SDK runtime).
3
+ * support it (e.g. `uploadFile` outside the ChatGPT runtime).
4
4
  */
5
5
  export class NotSupportedError extends Error {
6
6
  method;