skybridge 0.0.0-dev.ff50fdb → 0.0.0-dev.ffaef7a

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 (437) hide show
  1. package/README.md +124 -114
  2. package/dist/cli/build-helpers.d.ts +10 -0
  3. package/dist/cli/build-helpers.js +93 -0
  4. package/dist/cli/build-helpers.js.map +1 -0
  5. package/dist/cli/build-helpers.test.js +89 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -0
  7. package/dist/cli/build-steps.d.ts +2 -0
  8. package/dist/cli/build-steps.js +68 -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.d.ts +18 -0
  13. package/dist/cli/detect-port.js +50 -0
  14. package/dist/cli/detect-port.js.map +1 -0
  15. package/dist/cli/header.d.ts +1 -1
  16. package/dist/cli/header.js +1 -1
  17. package/dist/cli/header.js.map +1 -1
  18. package/dist/cli/resolve-views-dir.d.ts +1 -0
  19. package/dist/cli/resolve-views-dir.js +17 -0
  20. package/dist/cli/resolve-views-dir.js.map +1 -0
  21. package/dist/cli/run-command.js.map +1 -1
  22. package/dist/cli/run-plain.d.ts +18 -0
  23. package/dist/cli/run-plain.js +89 -0
  24. package/dist/cli/run-plain.js.map +1 -0
  25. package/dist/cli/telemetry.js.map +1 -1
  26. package/dist/cli/tunnel-control-server.d.ts +9 -0
  27. package/dist/cli/tunnel-control-server.js +31 -0
  28. package/dist/cli/tunnel-control-server.js.map +1 -0
  29. package/dist/cli/tunnel-control-server.test.d.ts +1 -0
  30. package/dist/cli/tunnel-control-server.test.js +39 -0
  31. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  32. package/dist/cli/tunnel-handler.d.ts +3 -0
  33. package/dist/cli/tunnel-handler.js +48 -0
  34. package/dist/cli/tunnel-handler.js.map +1 -0
  35. package/dist/cli/tunnel-handler.test.d.ts +1 -0
  36. package/dist/cli/tunnel-handler.test.js +105 -0
  37. package/dist/cli/tunnel-handler.test.js.map +1 -0
  38. package/dist/cli/tunnel.d.ts +57 -0
  39. package/dist/cli/tunnel.js +154 -0
  40. package/dist/cli/tunnel.js.map +1 -0
  41. package/dist/cli/tunnel.test.d.ts +1 -0
  42. package/dist/cli/tunnel.test.js +190 -0
  43. package/dist/cli/tunnel.test.js.map +1 -0
  44. package/dist/cli/types.d.ts +5 -0
  45. package/dist/cli/types.js +2 -0
  46. package/dist/cli/types.js.map +1 -0
  47. package/dist/cli/use-execute-steps.d.ts +3 -2
  48. package/dist/cli/use-execute-steps.js +6 -1
  49. package/dist/cli/use-execute-steps.js.map +1 -1
  50. package/dist/cli/use-messages.d.ts +3 -0
  51. package/dist/cli/use-messages.js +11 -0
  52. package/dist/cli/use-messages.js.map +1 -0
  53. package/dist/cli/use-nodemon.d.ts +16 -0
  54. package/dist/cli/use-nodemon.js +84 -0
  55. package/dist/cli/use-nodemon.js.map +1 -0
  56. package/dist/cli/use-open-browser.d.ts +1 -0
  57. package/dist/cli/use-open-browser.js +44 -0
  58. package/dist/cli/use-open-browser.js.map +1 -0
  59. package/dist/cli/use-tunnel.d.ts +14 -0
  60. package/dist/cli/use-tunnel.js +131 -0
  61. package/dist/cli/use-tunnel.js.map +1 -0
  62. package/dist/cli/use-typescript-check.d.ts +15 -0
  63. package/dist/cli/use-typescript-check.js +97 -0
  64. package/dist/cli/use-typescript-check.js.map +1 -0
  65. package/dist/commands/build.d.ts +0 -3
  66. package/dist/commands/build.js +3 -16
  67. package/dist/commands/build.js.map +1 -1
  68. package/dist/commands/create.d.ts +9 -0
  69. package/dist/commands/create.js +30 -0
  70. package/dist/commands/create.js.map +1 -0
  71. package/dist/commands/dev.d.ts +5 -1
  72. package/dist/commands/dev.js +109 -13
  73. package/dist/commands/dev.js.map +1 -1
  74. package/dist/commands/start.d.ts +3 -1
  75. package/dist/commands/start.js +37 -15
  76. package/dist/commands/start.js.map +1 -1
  77. package/dist/commands/telemetry/disable.js.map +1 -1
  78. package/dist/commands/telemetry/enable.js.map +1 -1
  79. package/dist/commands/telemetry/status.js.map +1 -1
  80. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  81. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  82. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  83. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  84. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  85. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  86. package/dist/server/auth/discovery.d.ts +32 -0
  87. package/dist/server/auth/discovery.js +56 -0
  88. package/dist/server/auth/discovery.js.map +1 -0
  89. package/dist/server/auth/discovery.test.d.ts +1 -0
  90. package/dist/server/auth/discovery.test.js +93 -0
  91. package/dist/server/auth/discovery.test.js.map +1 -0
  92. package/dist/server/auth/index.d.ts +18 -0
  93. package/dist/server/auth/index.js +2 -0
  94. package/dist/server/auth/index.js.map +1 -0
  95. package/dist/server/auth/providers/auth0.d.ts +18 -0
  96. package/dist/server/auth/providers/auth0.js +31 -0
  97. package/dist/server/auth/providers/auth0.js.map +1 -0
  98. package/dist/server/auth/providers/auth0.test.d.ts +1 -0
  99. package/dist/server/auth/providers/auth0.test.js +48 -0
  100. package/dist/server/auth/providers/auth0.test.js.map +1 -0
  101. package/dist/server/auth/providers/clerk.d.ts +14 -0
  102. package/dist/server/auth/providers/clerk.js +16 -0
  103. package/dist/server/auth/providers/clerk.js.map +1 -0
  104. package/dist/server/auth/providers/clerk.test.d.ts +1 -0
  105. package/dist/server/auth/providers/clerk.test.js +28 -0
  106. package/dist/server/auth/providers/clerk.test.js.map +1 -0
  107. package/dist/server/auth/providers/custom.d.ts +24 -0
  108. package/dist/server/auth/providers/custom.js +37 -0
  109. package/dist/server/auth/providers/custom.js.map +1 -0
  110. package/dist/server/auth/providers/custom.test.d.ts +1 -0
  111. package/dist/server/auth/providers/custom.test.js +107 -0
  112. package/dist/server/auth/providers/custom.test.js.map +1 -0
  113. package/dist/server/auth/providers/descope.d.ts +15 -0
  114. package/dist/server/auth/providers/descope.js +33 -0
  115. package/dist/server/auth/providers/descope.js.map +1 -0
  116. package/dist/server/auth/providers/descope.test.d.ts +1 -0
  117. package/dist/server/auth/providers/descope.test.js +37 -0
  118. package/dist/server/auth/providers/descope.test.js.map +1 -0
  119. package/dist/server/auth/providers/shared.d.ts +2 -0
  120. package/dist/server/auth/providers/shared.js +6 -0
  121. package/dist/server/auth/providers/shared.js.map +1 -0
  122. package/dist/server/auth/providers/shared.test.d.ts +1 -0
  123. package/dist/server/auth/providers/shared.test.js +10 -0
  124. package/dist/server/auth/providers/shared.test.js.map +1 -0
  125. package/dist/server/auth/providers/stytch.d.ts +12 -0
  126. package/dist/server/auth/providers/stytch.js +13 -0
  127. package/dist/server/auth/providers/stytch.js.map +1 -0
  128. package/dist/server/auth/providers/workos.d.ts +11 -0
  129. package/dist/server/auth/providers/workos.js +12 -0
  130. package/dist/server/auth/providers/workos.js.map +1 -0
  131. package/dist/server/auth/security-schemes.d.ts +13 -0
  132. package/dist/server/auth/security-schemes.js +53 -0
  133. package/dist/server/auth/security-schemes.js.map +1 -0
  134. package/dist/server/auth/security-schemes.test.d.ts +1 -0
  135. package/dist/server/auth/security-schemes.test.js +90 -0
  136. package/dist/server/auth/security-schemes.test.js.map +1 -0
  137. package/dist/server/auth/setup.d.ts +6 -0
  138. package/dist/server/auth/setup.js +98 -0
  139. package/dist/server/auth/setup.js.map +1 -0
  140. package/dist/server/auth/setup.test.d.ts +1 -0
  141. package/dist/server/auth/setup.test.js +450 -0
  142. package/dist/server/auth/setup.test.js.map +1 -0
  143. package/dist/server/auth/verify.d.ts +12 -0
  144. package/dist/server/auth/verify.js +38 -0
  145. package/dist/server/auth/verify.js.map +1 -0
  146. package/dist/server/auth/verify.test.d.ts +1 -0
  147. package/dist/server/auth/verify.test.js +100 -0
  148. package/dist/server/auth/verify.test.js.map +1 -0
  149. package/dist/server/auth.d.ts +20 -0
  150. package/dist/server/auth.js +28 -0
  151. package/dist/server/auth.js.map +1 -0
  152. package/dist/server/build-manifest.test.d.ts +1 -0
  153. package/dist/server/build-manifest.test.js +27 -0
  154. package/dist/server/build-manifest.test.js.map +1 -0
  155. package/dist/server/content-helpers.d.ts +67 -0
  156. package/dist/server/content-helpers.js +79 -0
  157. package/dist/server/content-helpers.js.map +1 -0
  158. package/dist/server/content-helpers.test.d.ts +1 -0
  159. package/dist/server/content-helpers.test.js +70 -0
  160. package/dist/server/content-helpers.test.js.map +1 -0
  161. package/dist/server/express.d.ts +11 -0
  162. package/dist/server/express.js +101 -0
  163. package/dist/server/express.js.map +1 -0
  164. package/dist/server/express.test.d.ts +1 -0
  165. package/dist/server/express.test.js +491 -0
  166. package/dist/server/express.test.js.map +1 -0
  167. package/dist/server/file-ref.d.ts +28 -0
  168. package/dist/server/file-ref.js +27 -0
  169. package/dist/server/file-ref.js.map +1 -0
  170. package/dist/server/index.d.ts +14 -3
  171. package/dist/server/index.js +11 -2
  172. package/dist/server/index.js.map +1 -1
  173. package/dist/server/inferUtilityTypes.d.ts +6 -6
  174. package/dist/server/inferUtilityTypes.js.map +1 -1
  175. package/dist/server/metric.d.ts +14 -0
  176. package/dist/server/metric.js +62 -0
  177. package/dist/server/metric.js.map +1 -0
  178. package/dist/server/middleware.d.ts +137 -0
  179. package/dist/server/middleware.js +93 -0
  180. package/dist/server/middleware.js.map +1 -0
  181. package/dist/server/middleware.test-d.d.ts +1 -0
  182. package/dist/server/middleware.test-d.js +75 -0
  183. package/dist/server/middleware.test-d.js.map +1 -0
  184. package/dist/server/middleware.test.d.ts +1 -0
  185. package/dist/server/middleware.test.js +493 -0
  186. package/dist/server/middleware.test.js.map +1 -0
  187. package/dist/server/requestOrigin.d.ts +7 -0
  188. package/dist/server/requestOrigin.js +25 -0
  189. package/dist/server/requestOrigin.js.map +1 -0
  190. package/dist/server/server.d.ts +391 -58
  191. package/dist/server/server.js +644 -97
  192. package/dist/server/server.js.map +1 -1
  193. package/dist/server/templateHelper.d.ts +5 -7
  194. package/dist/server/templateHelper.js +3 -22
  195. package/dist/server/templateHelper.js.map +1 -1
  196. package/dist/server/templates.generated.d.ts +4 -0
  197. package/dist/server/templates.generated.js +47 -0
  198. package/dist/server/templates.generated.js.map +1 -0
  199. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  200. package/dist/server/tunnel-proxy-router.js +110 -0
  201. package/dist/server/tunnel-proxy-router.js.map +1 -0
  202. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  203. package/dist/server/tunnel-proxy-router.test.js +229 -0
  204. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  205. package/dist/server/view-name.test-d.d.ts +1 -0
  206. package/dist/server/view-name.test-d.js +8 -0
  207. package/dist/server/view-name.test-d.js.map +1 -0
  208. package/dist/server/view-resource-resolution.test.d.ts +6 -0
  209. package/dist/server/view-resource-resolution.test.js +171 -0
  210. package/dist/server/view-resource-resolution.test.js.map +1 -0
  211. package/dist/server/viewsDevServer.d.ts +14 -0
  212. package/dist/server/viewsDevServer.js +45 -0
  213. package/dist/server/viewsDevServer.js.map +1 -0
  214. package/dist/test/utils.d.ts +13 -21
  215. package/dist/test/utils.js +42 -37
  216. package/dist/test/utils.js.map +1 -1
  217. package/dist/test/view.test.d.ts +1 -0
  218. package/dist/test/view.test.js +536 -0
  219. package/dist/test/view.test.js.map +1 -0
  220. package/dist/version.d.ts +1 -0
  221. package/dist/version.js +3 -0
  222. package/dist/version.js.map +1 -0
  223. package/dist/web/bridges/adaptor.d.ts +51 -0
  224. package/dist/web/bridges/adaptor.js +330 -0
  225. package/dist/web/bridges/adaptor.js.map +1 -0
  226. package/dist/web/bridges/adaptor.test.d.ts +1 -0
  227. package/dist/web/bridges/adaptor.test.js +208 -0
  228. package/dist/web/bridges/adaptor.test.js.map +1 -0
  229. package/dist/web/bridges/apps-sdk/bridge.d.ts +7 -2
  230. package/dist/web/bridges/apps-sdk/bridge.js +15 -3
  231. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  232. package/dist/web/bridges/apps-sdk/index.d.ts +1 -2
  233. package/dist/web/bridges/apps-sdk/index.js +0 -1
  234. package/dist/web/bridges/apps-sdk/index.js.map +1 -1
  235. package/dist/web/bridges/apps-sdk/types.d.ts +32 -14
  236. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  237. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +11 -0
  238. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +11 -0
  239. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  240. package/dist/web/bridges/get-adaptor.d.ts +7 -0
  241. package/dist/web/bridges/get-adaptor.js +9 -7
  242. package/dist/web/bridges/get-adaptor.js.map +1 -1
  243. package/dist/web/bridges/get-adaptor.test.d.ts +1 -0
  244. package/dist/web/bridges/get-adaptor.test.js +32 -0
  245. package/dist/web/bridges/get-adaptor.test.js.map +1 -0
  246. package/dist/web/bridges/index.js.map +1 -1
  247. package/dist/web/bridges/mcp-app/bridge.d.ts +27 -31
  248. package/dist/web/bridges/mcp-app/bridge.js +109 -198
  249. package/dist/web/bridges/mcp-app/bridge.js.map +1 -1
  250. package/dist/web/bridges/mcp-app/bridge.test.d.ts +1 -0
  251. package/dist/web/bridges/mcp-app/bridge.test.js +17 -0
  252. package/dist/web/bridges/mcp-app/bridge.test.js.map +1 -0
  253. package/dist/web/bridges/mcp-app/index.d.ts +0 -1
  254. package/dist/web/bridges/mcp-app/index.js +0 -1
  255. package/dist/web/bridges/mcp-app/index.js.map +1 -1
  256. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  257. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +17 -3
  258. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +14 -2
  259. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  260. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +1 -41
  261. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -1
  262. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  263. package/dist/web/bridges/mcp-app/view-tools.test.js +143 -0
  264. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  265. package/dist/web/bridges/types.d.ts +130 -14
  266. package/dist/web/bridges/types.js +14 -1
  267. package/dist/web/bridges/types.js.map +1 -1
  268. package/dist/web/bridges/types.test.d.ts +1 -0
  269. package/dist/web/bridges/types.test.js +19 -0
  270. package/dist/web/bridges/types.test.js.map +1 -0
  271. package/dist/web/bridges/use-host-context.d.ts +5 -0
  272. package/dist/web/bridges/use-host-context.js +5 -0
  273. package/dist/web/bridges/use-host-context.js.map +1 -1
  274. package/dist/web/components/modal-provider.d.ts +1 -1
  275. package/dist/web/components/modal-provider.js +5 -6
  276. package/dist/web/components/modal-provider.js.map +1 -1
  277. package/dist/web/create-store.d.ts +26 -0
  278. package/dist/web/create-store.js +43 -3
  279. package/dist/web/create-store.js.map +1 -1
  280. package/dist/web/create-store.test.js +31 -25
  281. package/dist/web/create-store.test.js.map +1 -1
  282. package/dist/web/data-llm.d.ts +35 -2
  283. package/dist/web/data-llm.js +31 -3
  284. package/dist/web/data-llm.js.map +1 -1
  285. package/dist/web/data-llm.test.js +50 -35
  286. package/dist/web/data-llm.test.js.map +1 -1
  287. package/dist/web/generate-helpers.d.ts +22 -18
  288. package/dist/web/generate-helpers.js +22 -18
  289. package/dist/web/generate-helpers.js.map +1 -1
  290. package/dist/web/generate-helpers.test-d.js +30 -28
  291. package/dist/web/generate-helpers.test-d.js.map +1 -1
  292. package/dist/web/generate-helpers.test.js.map +1 -1
  293. package/dist/web/helpers/state.d.ts +2 -2
  294. package/dist/web/helpers/state.js +11 -11
  295. package/dist/web/helpers/state.js.map +1 -1
  296. package/dist/web/helpers/state.test.js +9 -9
  297. package/dist/web/helpers/state.test.js.map +1 -1
  298. package/dist/web/hooks/index.d.ts +6 -2
  299. package/dist/web/hooks/index.js +5 -1
  300. package/dist/web/hooks/index.js.map +1 -1
  301. package/dist/web/hooks/test/utils.d.ts +6 -2
  302. package/dist/web/hooks/test/utils.js +17 -2
  303. package/dist/web/hooks/test/utils.js.map +1 -1
  304. package/dist/web/hooks/use-call-tool.d.ts +45 -0
  305. package/dist/web/hooks/use-call-tool.js +28 -0
  306. package/dist/web/hooks/use-call-tool.js.map +1 -1
  307. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -1
  308. package/dist/web/hooks/use-call-tool.test.js +62 -27
  309. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  310. package/dist/web/hooks/use-display-mode.d.ts +23 -3
  311. package/dist/web/hooks/use-display-mode.js +20 -0
  312. package/dist/web/hooks/use-display-mode.js.map +1 -1
  313. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  314. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  315. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  316. package/dist/web/hooks/use-display-mode.test.js +56 -20
  317. package/dist/web/hooks/use-display-mode.test.js.map +1 -1
  318. package/dist/web/hooks/use-download.d.ts +5 -0
  319. package/dist/web/hooks/use-download.js +8 -0
  320. package/dist/web/hooks/use-download.js.map +1 -0
  321. package/dist/web/hooks/use-download.test.d.ts +1 -0
  322. package/dist/web/hooks/use-download.test.js +103 -0
  323. package/dist/web/hooks/use-download.test.js.map +1 -0
  324. package/dist/web/hooks/use-files.d.ts +34 -1
  325. package/dist/web/hooks/use-files.js +33 -0
  326. package/dist/web/hooks/use-files.js.map +1 -1
  327. package/dist/web/hooks/use-files.test.js +35 -3
  328. package/dist/web/hooks/use-files.test.js.map +1 -1
  329. package/dist/web/hooks/use-layout.d.ts +2 -0
  330. package/dist/web/hooks/use-layout.js +2 -0
  331. package/dist/web/hooks/use-layout.js.map +1 -1
  332. package/dist/web/hooks/use-layout.test.js +62 -29
  333. package/dist/web/hooks/use-layout.test.js.map +1 -1
  334. package/dist/web/hooks/use-open-external.d.ts +20 -1
  335. package/dist/web/hooks/use-open-external.js +17 -1
  336. package/dist/web/hooks/use-open-external.js.map +1 -1
  337. package/dist/web/hooks/use-open-external.test.js +38 -13
  338. package/dist/web/hooks/use-open-external.test.js.map +1 -1
  339. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  340. package/dist/web/hooks/use-register-view-tool.js +50 -0
  341. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  342. package/dist/web/hooks/use-request-close.d.ts +16 -0
  343. package/dist/web/hooks/use-request-close.js +21 -0
  344. package/dist/web/hooks/use-request-close.js.map +1 -0
  345. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  346. package/dist/web/hooks/use-request-close.test.js +47 -0
  347. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  348. package/dist/web/hooks/use-request-modal.d.ts +16 -1
  349. package/dist/web/hooks/use-request-modal.js +19 -4
  350. package/dist/web/hooks/use-request-modal.js.map +1 -1
  351. package/dist/web/hooks/use-request-modal.test.js +15 -1
  352. package/dist/web/hooks/use-request-modal.test.js.map +1 -1
  353. package/dist/web/hooks/use-request-size.d.ts +20 -0
  354. package/dist/web/hooks/use-request-size.js +24 -0
  355. package/dist/web/hooks/use-request-size.js.map +1 -0
  356. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  357. package/dist/web/hooks/use-request-size.test.js +47 -0
  358. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  359. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -1
  360. package/dist/web/hooks/use-send-follow-up-message.js +19 -2
  361. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  362. package/dist/web/hooks/use-set-open-in-app-url.d.ts +17 -0
  363. package/dist/web/hooks/use-set-open-in-app-url.js +17 -0
  364. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -1
  365. package/dist/web/hooks/use-set-open-in-app-url.test.js +30 -16
  366. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -1
  367. package/dist/web/hooks/use-tool-info.d.ts +53 -2
  368. package/dist/web/hooks/use-tool-info.js +30 -7
  369. package/dist/web/hooks/use-tool-info.js.map +1 -1
  370. package/dist/web/hooks/use-tool-info.test-d.js +11 -29
  371. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -1
  372. package/dist/web/hooks/use-tool-info.test.js +43 -33
  373. package/dist/web/hooks/use-tool-info.test.js.map +1 -1
  374. package/dist/web/hooks/use-user.d.ts +2 -0
  375. package/dist/web/hooks/use-user.js +20 -2
  376. package/dist/web/hooks/use-user.js.map +1 -1
  377. package/dist/web/hooks/use-user.test.js +101 -27
  378. package/dist/web/hooks/use-user.test.js.map +1 -1
  379. package/dist/web/hooks/use-view-state.d.ts +25 -0
  380. package/dist/web/hooks/use-view-state.js +32 -0
  381. package/dist/web/hooks/use-view-state.js.map +1 -0
  382. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  383. package/dist/web/hooks/use-view-state.test.js +181 -0
  384. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  385. package/dist/web/index.d.ts +1 -2
  386. package/dist/web/index.js +1 -2
  387. package/dist/web/index.js.map +1 -1
  388. package/dist/web/mount-view.d.ts +20 -0
  389. package/dist/web/{mount-widget.js → mount-view.js} +21 -2
  390. package/dist/web/mount-view.js.map +1 -0
  391. package/dist/web/plugin/data-llm.test.js.map +1 -1
  392. package/dist/web/plugin/plugin.d.ts +32 -1
  393. package/dist/web/plugin/plugin.js +167 -18
  394. package/dist/web/plugin/plugin.js.map +1 -1
  395. package/dist/web/plugin/scan-views.d.ts +16 -0
  396. package/dist/web/plugin/scan-views.js +88 -0
  397. package/dist/web/plugin/scan-views.js.map +1 -0
  398. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  399. package/dist/web/plugin/scan-views.test.js +99 -0
  400. package/dist/web/plugin/scan-views.test.js.map +1 -0
  401. package/dist/web/plugin/transform-data-llm.js +1 -1
  402. package/dist/web/plugin/transform-data-llm.js.map +1 -1
  403. package/dist/web/plugin/transform-data-llm.test.js.map +1 -1
  404. package/dist/web/plugin/validate-view.d.ts +1 -0
  405. package/dist/web/plugin/validate-view.js +9 -0
  406. package/dist/web/plugin/validate-view.js.map +1 -0
  407. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  408. package/dist/web/plugin/validate-view.test.js +24 -0
  409. package/dist/web/plugin/validate-view.test.js.map +1 -0
  410. package/dist/web/proxy.js +0 -1
  411. package/dist/web/proxy.js.map +1 -1
  412. package/dist/web/types.d.ts +4 -0
  413. package/dist/web/types.js.map +1 -1
  414. package/package.json +51 -29
  415. package/tsconfig.base.json +33 -0
  416. package/dist/server/templates/development.hbs +0 -66
  417. package/dist/server/templates/production.hbs +0 -7
  418. package/dist/server/widgetsDevServer.d.ts +0 -12
  419. package/dist/server/widgetsDevServer.js +0 -47
  420. package/dist/server/widgetsDevServer.js.map +0 -1
  421. package/dist/test/widget.test.js +0 -255
  422. package/dist/test/widget.test.js.map +0 -1
  423. package/dist/web/bridges/apps-sdk/adaptor.d.ts +0 -22
  424. package/dist/web/bridges/apps-sdk/adaptor.js +0 -64
  425. package/dist/web/bridges/apps-sdk/adaptor.js.map +0 -1
  426. package/dist/web/bridges/mcp-app/adaptor.d.ts +0 -36
  427. package/dist/web/bridges/mcp-app/adaptor.js +0 -185
  428. package/dist/web/bridges/mcp-app/adaptor.js.map +0 -1
  429. package/dist/web/hooks/use-widget-state.d.ts +0 -4
  430. package/dist/web/hooks/use-widget-state.js +0 -32
  431. package/dist/web/hooks/use-widget-state.js.map +0 -1
  432. package/dist/web/hooks/use-widget-state.test.js +0 -61
  433. package/dist/web/hooks/use-widget-state.test.js.map +0 -1
  434. package/dist/web/mount-widget.d.ts +0 -1
  435. package/dist/web/mount-widget.js.map +0 -1
  436. /package/dist/{test/widget.test.d.ts → cli/build-helpers.test.d.ts} +0 -0
  437. /package/dist/{web/hooks/use-widget-state.test.d.ts → cli/build-steps.test.d.ts} +0 -0
@@ -0,0 +1,450 @@
1
+ // @vitest-environment node
2
+ import http from "node:http";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
5
+ import * as jose from "jose";
6
+ import { afterEach, describe, expect, it, vi } from "vitest";
7
+ import { McpServer } from "../server.js";
8
+ vi.mock("@skybridge/devtools", () => ({
9
+ devtoolsStaticServer: () => ((_req, _res, next) => next()),
10
+ }));
11
+ vi.mock("../viewsDevServer.js", () => ({
12
+ viewsDevServer: (_httpServer) => ((_req, _res, next) => next()),
13
+ }));
14
+ const ISSUER = "https://issuer.test";
15
+ const AUDIENCE = "api://default";
16
+ let jwksServer;
17
+ let appServer;
18
+ afterEach(() => {
19
+ jwksServer?.close();
20
+ appServer?.close();
21
+ });
22
+ async function startJwks() {
23
+ const { publicKey, privateKey } = await jose.generateKeyPair("RS256");
24
+ const jwk = {
25
+ ...(await jose.exportJWK(publicKey)),
26
+ kid: "test-key",
27
+ alg: "RS256",
28
+ use: "sig",
29
+ };
30
+ const server = http.createServer((_req, res) => {
31
+ res.setHeader("content-type", "application/json");
32
+ res.end(JSON.stringify({ keys: [jwk] }));
33
+ });
34
+ await new Promise((resolve) => server.listen(0, resolve));
35
+ jwksServer = server;
36
+ const port = server.address().port;
37
+ return { privateKey, jwksUri: `http://localhost:${port}/jwks` };
38
+ }
39
+ function signToken(key, scope = "openid email") {
40
+ return new jose.SignJWT({
41
+ client_id: "client-1",
42
+ scope,
43
+ sub: "user-1",
44
+ })
45
+ .setProtectedHeader({ alg: "RS256", kid: "test-key" })
46
+ .setIssuer(ISSUER)
47
+ .setAudience(AUDIENCE)
48
+ .setExpirationTime("1h")
49
+ .sign(key);
50
+ }
51
+ async function bootServer(jwksUri, { baseUrl = "https://app.example.test" } = {}) {
52
+ const { createApp } = await import("../express.js");
53
+ const server = new McpServer({ name: "auth-test", version: "0.0.0" }, { capabilities: {} }, {
54
+ oauth: {
55
+ ...(baseUrl === null ? {} : { baseUrl }),
56
+ oauthMetadata: {
57
+ issuer: ISSUER,
58
+ authorization_endpoint: `${ISSUER}/authorize`,
59
+ token_endpoint: `${ISSUER}/token`,
60
+ response_types_supported: ["code"],
61
+ },
62
+ verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
63
+ scopesSupported: ["openid", "email"],
64
+ requiredScopes: ["openid"],
65
+ },
66
+ }).registerTool({
67
+ name: "whoami",
68
+ description: "Returns the caller identity.",
69
+ inputSchema: {},
70
+ }, (_args, extra) => ({
71
+ structuredContent: { clientId: extra.authInfo?.clientId ?? null },
72
+ content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
73
+ }));
74
+ const httpServer = http.createServer();
75
+ await createApp({ mcpServer: server, httpServer });
76
+ const listening = http.createServer(server.express);
77
+ await new Promise((resolve) => listening.listen(0, resolve));
78
+ appServer = listening;
79
+ const port = listening.address().port;
80
+ return `http://localhost:${port}`;
81
+ }
82
+ describe("setupOAuth wiring", () => {
83
+ it("serves protected-resource metadata", async () => {
84
+ const { jwksUri } = await startJwks();
85
+ const base = await bootServer(jwksUri);
86
+ const res = await fetch(`${base}/.well-known/oauth-protected-resource`);
87
+ expect(res.status).toBe(200);
88
+ const body = (await res.json());
89
+ expect(body.resource).toBe("https://app.example.test/");
90
+ expect(body.authorization_servers).toContain(ISSUER);
91
+ expect(body.scopes_supported).toEqual(["openid", "email"]);
92
+ });
93
+ it("rejects /mcp without a token (401 + WWW-Authenticate)", async () => {
94
+ const { jwksUri } = await startJwks();
95
+ const base = await bootServer(jwksUri);
96
+ const res = await fetch(`${base}/mcp`, {
97
+ method: "POST",
98
+ headers: { "Content-Type": "application/json" },
99
+ body: JSON.stringify({ jsonrpc: "2.0", method: "initialize", id: 1 }),
100
+ });
101
+ expect(res.status).toBe(401);
102
+ expect(res.headers.get("www-authenticate")).toMatch(/resource_metadata=/);
103
+ });
104
+ it("threads authInfo into the tool handler for a valid token", async () => {
105
+ const { privateKey, jwksUri } = await startJwks();
106
+ const base = await bootServer(jwksUri);
107
+ const token = await signToken(privateKey);
108
+ const client = new Client({ name: "test-client", version: "0.0.0" });
109
+ const transport = new StreamableHTTPClientTransport(new URL(`${base}/mcp`), { requestInit: { headers: { Authorization: `Bearer ${token}` } } });
110
+ await client.connect(transport);
111
+ const result = (await client.callTool({
112
+ name: "whoami",
113
+ arguments: {},
114
+ }));
115
+ expect(result.content[0]?.text).toBe("client-1");
116
+ await client.close();
117
+ });
118
+ });
119
+ describe("baseUrl inferred from headers", () => {
120
+ it("derives the resource origin from x-forwarded-host", async () => {
121
+ const { jwksUri } = await startJwks();
122
+ const base = await bootServer(jwksUri, { baseUrl: null });
123
+ const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {
124
+ headers: { "x-forwarded-host": "infer.example.test" },
125
+ });
126
+ expect(res.status).toBe(200);
127
+ const body = (await res.json());
128
+ expect(body.resource).toBe("https://infer.example.test/");
129
+ });
130
+ it("uses the first hop of a forwarded-host chain", async () => {
131
+ const { jwksUri } = await startJwks();
132
+ const base = await bootServer(jwksUri, { baseUrl: null });
133
+ const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {
134
+ headers: {
135
+ "x-forwarded-host": "public.example, internal.local",
136
+ "x-forwarded-proto": "https, http",
137
+ },
138
+ });
139
+ expect(res.status).toBe(200);
140
+ const body = (await res.json());
141
+ expect(body.resource).toBe("https://public.example/");
142
+ });
143
+ it("ignores the client Origin header, using Host instead", async () => {
144
+ const { jwksUri } = await startJwks();
145
+ const base = await bootServer(jwksUri, { baseUrl: null });
146
+ const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {
147
+ headers: { origin: "https://chatgpt.com" },
148
+ });
149
+ expect(res.status).toBe(200);
150
+ const body = (await res.json());
151
+ expect(body.resource).toMatch(/^http:\/\/(localhost|127\.0\.0\.1):/);
152
+ });
153
+ it("points the 401 WWW-Authenticate at the inferred host", async () => {
154
+ const { jwksUri } = await startJwks();
155
+ const base = await bootServer(jwksUri, { baseUrl: null });
156
+ const res = await fetch(`${base}/mcp`, {
157
+ method: "POST",
158
+ headers: {
159
+ "Content-Type": "application/json",
160
+ "x-forwarded-host": "infer.example.test",
161
+ },
162
+ body: JSON.stringify({ jsonrpc: "2.0", method: "initialize", id: 1 }),
163
+ });
164
+ expect(res.status).toBe(401);
165
+ expect(res.headers.get("www-authenticate")).toMatch(/resource_metadata="https:\/\/infer\.example\.test\//);
166
+ });
167
+ });
168
+ async function bootMixedServer(jwksUri) {
169
+ const { createApp } = await import("../express.js");
170
+ const server = new McpServer({ name: "mixed-auth-test", version: "0.0.0" }, { capabilities: {} }, {
171
+ oauth: {
172
+ baseUrl: "https://app.example.test",
173
+ oauthMetadata: {
174
+ issuer: ISSUER,
175
+ authorization_endpoint: `${ISSUER}/authorize`,
176
+ token_endpoint: `${ISSUER}/token`,
177
+ response_types_supported: ["code"],
178
+ },
179
+ verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
180
+ },
181
+ })
182
+ .registerTool({
183
+ name: "public-whoami",
184
+ description: "Public.",
185
+ inputSchema: {},
186
+ auth: { public: true },
187
+ }, (_args, extra) => ({
188
+ content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
189
+ }))
190
+ .registerTool({
191
+ name: "private-whoami",
192
+ description: "Private.",
193
+ inputSchema: {},
194
+ auth: {},
195
+ }, (_args, extra) => ({
196
+ content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
197
+ }));
198
+ server.registerTool("legacy-whoami", {
199
+ description: "Registered via the legacy string overload.",
200
+ inputSchema: {},
201
+ }, (_args, extra) => ({
202
+ content: [{ type: "text", text: extra.authInfo?.clientId ?? "anon" }],
203
+ }));
204
+ const httpServer = http.createServer();
205
+ await createApp({ mcpServer: server, httpServer });
206
+ const listening = http.createServer(server.express);
207
+ await new Promise((resolve) => listening.listen(0, resolve));
208
+ appServer = listening;
209
+ const port = listening.address().port;
210
+ return `http://localhost:${port}`;
211
+ }
212
+ describe("mixed-auth door", () => {
213
+ it("lets an anonymous caller initialize and run a noauth tool", async () => {
214
+ const { jwksUri } = await startJwks();
215
+ const base = await bootMixedServer(jwksUri);
216
+ const client = new Client({ name: "test-client", version: "0.0.0" });
217
+ await client.connect(new StreamableHTTPClientTransport(new URL(`${base}/mcp`)));
218
+ const result = (await client.callTool({
219
+ name: "public-whoami",
220
+ arguments: {},
221
+ }));
222
+ expect(result.content[0]?.text).toBe("anon");
223
+ await client.close();
224
+ });
225
+ it("exposes securitySchemes at the top level of tools/list (not only _meta)", async () => {
226
+ const { jwksUri } = await startJwks();
227
+ const base = await bootMixedServer(jwksUri);
228
+ const headers = {
229
+ "Content-Type": "application/json",
230
+ Accept: "application/json, text/event-stream",
231
+ };
232
+ await fetch(`${base}/mcp`, {
233
+ method: "POST",
234
+ headers,
235
+ body: JSON.stringify({
236
+ jsonrpc: "2.0",
237
+ id: 1,
238
+ method: "initialize",
239
+ params: {
240
+ protocolVersion: "2025-06-18",
241
+ capabilities: {},
242
+ clientInfo: { name: "c", version: "0" },
243
+ },
244
+ }),
245
+ });
246
+ const res = await fetch(`${base}/mcp`, {
247
+ method: "POST",
248
+ headers,
249
+ body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }),
250
+ });
251
+ const text = await res.text();
252
+ const json = JSON.parse((text.match(/\{[\s\S]*\}/) ?? ["{}"])[0]);
253
+ const whoami = json.result.tools.find((t) => t.name === "private-whoami");
254
+ expect(whoami?.securitySchemes).toEqual([{ type: "oauth2" }]);
255
+ });
256
+ it("denies a protected tool inside an anonymous JSON-RPC batch", async () => {
257
+ const { jwksUri } = await startJwks();
258
+ const base = await bootMixedServer(jwksUri);
259
+ const res = await fetch(`${base}/mcp`, {
260
+ method: "POST",
261
+ headers: {
262
+ "Content-Type": "application/json",
263
+ Accept: "application/json, text/event-stream",
264
+ },
265
+ body: JSON.stringify([
266
+ {
267
+ jsonrpc: "2.0",
268
+ id: 1,
269
+ method: "tools/call",
270
+ params: { name: "private-whoami", arguments: {} },
271
+ },
272
+ ]),
273
+ });
274
+ expect(res.status).toBe(401);
275
+ const wwwAuthenticate = res.headers.get("www-authenticate") ?? "";
276
+ expect(wwwAuthenticate).toMatch(/^Bearer /);
277
+ expect(wwwAuthenticate).toContain("resource_metadata=");
278
+ const text = await res.text();
279
+ expect(text).not.toContain("client-1");
280
+ });
281
+ it("gates a tool registered via the legacy string overload (secure default)", async () => {
282
+ const { jwksUri } = await startJwks();
283
+ const base = await bootMixedServer(jwksUri);
284
+ const res = await fetch(`${base}/mcp`, {
285
+ method: "POST",
286
+ headers: {
287
+ "Content-Type": "application/json",
288
+ Accept: "application/json, text/event-stream",
289
+ },
290
+ body: JSON.stringify({
291
+ jsonrpc: "2.0",
292
+ id: 1,
293
+ method: "tools/call",
294
+ params: { name: "legacy-whoami", arguments: {} },
295
+ }),
296
+ });
297
+ expect(res.status).toBe(401);
298
+ });
299
+ it("returns 401 + WWW-Authenticate for a protected tool while anonymous", async () => {
300
+ const { jwksUri } = await startJwks();
301
+ const base = await bootMixedServer(jwksUri);
302
+ const res = await fetch(`${base}/mcp`, {
303
+ method: "POST",
304
+ headers: {
305
+ "Content-Type": "application/json",
306
+ Accept: "application/json, text/event-stream",
307
+ },
308
+ body: JSON.stringify({
309
+ jsonrpc: "2.0",
310
+ id: 1,
311
+ method: "tools/call",
312
+ params: { name: "private-whoami", arguments: {} },
313
+ }),
314
+ });
315
+ expect(res.status).toBe(401);
316
+ expect(res.headers.get("www-authenticate")).toMatch(/error="invalid_token"/);
317
+ expect(res.headers.get("www-authenticate")).toMatch(/resource_metadata=/);
318
+ });
319
+ it("returns an in-band mcp/www_authenticate array to ChatGPT (not a transport 401)", async () => {
320
+ const { jwksUri } = await startJwks();
321
+ const base = await bootMixedServer(jwksUri);
322
+ const res = await fetch(`${base}/mcp`, {
323
+ method: "POST",
324
+ headers: {
325
+ "Content-Type": "application/json",
326
+ Accept: "application/json, text/event-stream",
327
+ "User-Agent": "openai-mcp/1.0",
328
+ },
329
+ body: JSON.stringify({
330
+ jsonrpc: "2.0",
331
+ id: 7,
332
+ method: "tools/call",
333
+ params: { name: "private-whoami", arguments: {} },
334
+ }),
335
+ });
336
+ expect(res.status).toBe(200);
337
+ expect(res.headers.get("www-authenticate")).toBeNull();
338
+ const body = (await res.json());
339
+ expect(body.id).toBe(7);
340
+ expect(body.result.isError).toBe(true);
341
+ const challenge = body.result._meta["mcp/www_authenticate"];
342
+ expect(Array.isArray(challenge)).toBe(true);
343
+ expect(challenge[0]).toMatch(/error="invalid_token"/);
344
+ expect(challenge[0]).toMatch(/resource_metadata=/);
345
+ });
346
+ });
347
+ async function bootScopedServer(jwksUri) {
348
+ const { createApp } = await import("../express.js");
349
+ const server = new McpServer({ name: "scoped-auth-test", version: "0.0.0" }, { capabilities: {} }, {
350
+ oauth: {
351
+ baseUrl: "https://app.example.test",
352
+ oauthMetadata: {
353
+ issuer: ISSUER,
354
+ authorization_endpoint: `${ISSUER}/authorize`,
355
+ token_endpoint: `${ISSUER}/token`,
356
+ response_types_supported: ["code"],
357
+ },
358
+ verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },
359
+ },
360
+ }).registerTool({
361
+ name: "checkout",
362
+ description: "Needs the checkout scope.",
363
+ inputSchema: {},
364
+ auth: { scopes: ["checkout"] },
365
+ }, () => ({ content: [{ type: "text", text: "ok" }] }));
366
+ const httpServer = http.createServer();
367
+ await createApp({ mcpServer: server, httpServer });
368
+ const listening = http.createServer(server.express);
369
+ await new Promise((resolve) => listening.listen(0, resolve));
370
+ appServer = listening;
371
+ const port = listening.address().port;
372
+ return `http://localhost:${port}`;
373
+ }
374
+ describe("per-tool scope enforcement in fully-authenticated mode", () => {
375
+ it("returns 403 for a valid token missing the tool's scope", async () => {
376
+ const { privateKey, jwksUri } = await startJwks();
377
+ const base = await bootScopedServer(jwksUri);
378
+ const token = await signToken(privateKey, "openid");
379
+ const res = await fetch(`${base}/mcp`, {
380
+ method: "POST",
381
+ headers: {
382
+ "Content-Type": "application/json",
383
+ Accept: "application/json, text/event-stream",
384
+ Authorization: `Bearer ${token}`,
385
+ },
386
+ body: JSON.stringify({
387
+ jsonrpc: "2.0",
388
+ id: 1,
389
+ method: "tools/call",
390
+ params: { name: "checkout", arguments: {} },
391
+ }),
392
+ });
393
+ expect(res.status).toBe(403);
394
+ const header = res.headers.get("www-authenticate");
395
+ expect(header).toMatch(/error="insufficient_scope"/);
396
+ expect(header).toMatch(/scope="checkout"/);
397
+ });
398
+ it("allows a token carrying the tool's scope", async () => {
399
+ const { privateKey, jwksUri } = await startJwks();
400
+ const base = await bootScopedServer(jwksUri);
401
+ const token = await signToken(privateKey, "openid checkout");
402
+ const client = new Client({ name: "test-client", version: "0.0.0" });
403
+ await client.connect(new StreamableHTTPClientTransport(new URL(`${base}/mcp`), {
404
+ requestInit: { headers: { Authorization: `Bearer ${token}` } },
405
+ }));
406
+ const result = (await client.callTool({
407
+ name: "checkout",
408
+ arguments: {},
409
+ }));
410
+ expect(result.content[0]?.text).toBe("ok");
411
+ await client.close();
412
+ });
413
+ });
414
+ describe("auth shorthand validation", () => {
415
+ it("throws when `auth` requires sign-in but no oauth provider is configured", () => {
416
+ expect(() => new McpServer({ name: "t", version: "0" }).registerTool({ name: "x", inputSchema: {}, auth: {} }, () => ({ content: [{ type: "text", text: "" }] }))).toThrow(/no `oauth` provider/);
417
+ });
418
+ it("throws when `auth` sets scopes but no oauth provider is configured", () => {
419
+ expect(() => new McpServer({ name: "t", version: "0" }).registerTool({ name: "x", inputSchema: {}, auth: { scopes: ["checkout"] } }, () => ({ content: [{ type: "text", text: "" }] }))).toThrow(/no `oauth` provider/);
420
+ });
421
+ it("allows `auth: { public: true }` without an oauth provider", () => {
422
+ expect(() => new McpServer({ name: "t", version: "0" }).registerTool({ name: "x", inputSchema: {}, auth: { public: true } }, () => ({ content: [{ type: "text", text: "" }] }))).not.toThrow();
423
+ });
424
+ it("prefers `securitySchemes` over `auth` when both are set (untyped path)", () => {
425
+ expect(() => new McpServer({ name: "t", version: "0" }).registerTool({
426
+ name: "x",
427
+ inputSchema: {},
428
+ auth: {},
429
+ securitySchemes: [{ type: "oauth2" }],
430
+ }, () => ({ content: [{ type: "text", text: "" }] }))).not.toThrow();
431
+ });
432
+ });
433
+ describe("oauth config validation", () => {
434
+ const validMetadata = {
435
+ issuer: ISSUER,
436
+ authorization_endpoint: `${ISSUER}/authorize`,
437
+ token_endpoint: `${ISSUER}/token`,
438
+ response_types_supported: ["code"],
439
+ };
440
+ it("throws on a non-absolute baseUrl", () => {
441
+ expect(() => new McpServer({ name: "t", version: "0" }, undefined, {
442
+ oauth: {
443
+ baseUrl: "not-a-url",
444
+ oauthMetadata: validMetadata,
445
+ verify: { issuer: ISSUER, audience: AUDIENCE },
446
+ },
447
+ })).toThrow(/baseUrl must be a valid absolute URL/);
448
+ });
449
+ });
450
+ //# sourceMappingURL=setup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../../../src/server/auth/setup.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\nimport http from \"node:http\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { RequestHandler } from \"express\";\nimport * as jose from \"jose\";\nimport { afterEach, describe, expect, it, vi } from \"vitest\";\nimport { McpServer } from \"../server.js\";\n\nvi.mock(\"@skybridge/devtools\", () => ({\n devtoolsStaticServer: () =>\n ((_req: unknown, _res: unknown, next: () => void) =>\n next()) as RequestHandler,\n}));\nvi.mock(\"../viewsDevServer.js\", () => ({\n viewsDevServer: (_httpServer: unknown) =>\n ((_req: unknown, _res: unknown, next: () => void) =>\n next()) as RequestHandler,\n}));\n\nconst ISSUER = \"https://issuer.test\";\nconst AUDIENCE = \"api://default\";\n\nlet jwksServer: http.Server | undefined;\nlet appServer: http.Server | undefined;\nafterEach(() => {\n jwksServer?.close();\n appServer?.close();\n});\n\nasync function startJwks() {\n const { publicKey, privateKey } = await jose.generateKeyPair(\"RS256\");\n const jwk = {\n ...(await jose.exportJWK(publicKey)),\n kid: \"test-key\",\n alg: \"RS256\",\n use: \"sig\",\n };\n const server = http.createServer((_req, res) => {\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify({ keys: [jwk] }));\n });\n await new Promise<void>((resolve) => server.listen(0, resolve));\n jwksServer = server;\n const port = (server.address() as { port: number }).port;\n return { privateKey, jwksUri: `http://localhost:${port}/jwks` };\n}\n\nfunction signToken(key: CryptoKey, scope = \"openid email\") {\n return new jose.SignJWT({\n client_id: \"client-1\",\n scope,\n sub: \"user-1\",\n })\n .setProtectedHeader({ alg: \"RS256\", kid: \"test-key\" })\n .setIssuer(ISSUER)\n .setAudience(AUDIENCE)\n .setExpirationTime(\"1h\")\n .sign(key);\n}\n\nasync function bootServer(\n jwksUri: string,\n { baseUrl = \"https://app.example.test\" }: { baseUrl?: string | null } = {},\n) {\n const { createApp } = await import(\"../express.js\");\n const server = new McpServer(\n { name: \"auth-test\", version: \"0.0.0\" },\n { capabilities: {} },\n {\n oauth: {\n ...(baseUrl === null ? {} : { baseUrl }),\n oauthMetadata: {\n issuer: ISSUER,\n authorization_endpoint: `${ISSUER}/authorize`,\n token_endpoint: `${ISSUER}/token`,\n response_types_supported: [\"code\"],\n },\n verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },\n scopesSupported: [\"openid\", \"email\"],\n requiredScopes: [\"openid\"],\n },\n },\n ).registerTool(\n {\n name: \"whoami\",\n description: \"Returns the caller identity.\",\n inputSchema: {},\n },\n (_args, extra) => ({\n structuredContent: { clientId: extra.authInfo?.clientId ?? null },\n content: [{ type: \"text\", text: extra.authInfo?.clientId ?? \"anon\" }],\n }),\n );\n\n const httpServer = http.createServer();\n await createApp({ mcpServer: server, httpServer });\n const listening = http.createServer(server.express);\n await new Promise<void>((resolve) => listening.listen(0, resolve));\n appServer = listening;\n const port = (listening.address() as { port: number }).port;\n return `http://localhost:${port}`;\n}\n\ndescribe(\"setupOAuth wiring\", () => {\n it(\"serves protected-resource metadata\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri);\n\n const res = await fetch(`${base}/.well-known/oauth-protected-resource`);\n expect(res.status).toBe(200);\n const body = (await res.json()) as {\n resource: string;\n authorization_servers: string[];\n scopes_supported: string[];\n };\n expect(body.resource).toBe(\"https://app.example.test/\");\n expect(body.authorization_servers).toContain(ISSUER);\n expect(body.scopes_supported).toEqual([\"openid\", \"email\"]);\n });\n\n it(\"rejects /mcp without a token (401 + WWW-Authenticate)\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri);\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ jsonrpc: \"2.0\", method: \"initialize\", id: 1 }),\n });\n expect(res.status).toBe(401);\n expect(res.headers.get(\"www-authenticate\")).toMatch(/resource_metadata=/);\n });\n\n it(\"threads authInfo into the tool handler for a valid token\", async () => {\n const { privateKey, jwksUri } = await startJwks();\n const base = await bootServer(jwksUri);\n const token = await signToken(privateKey);\n\n const client = new Client({ name: \"test-client\", version: \"0.0.0\" });\n const transport = new StreamableHTTPClientTransport(\n new URL(`${base}/mcp`),\n { requestInit: { headers: { Authorization: `Bearer ${token}` } } },\n );\n await client.connect(transport);\n\n const result = (await client.callTool({\n name: \"whoami\",\n arguments: {},\n })) as unknown as {\n content: { type: string; text: string }[];\n };\n expect(result.content[0]?.text).toBe(\"client-1\");\n\n await client.close();\n });\n});\n\ndescribe(\"baseUrl inferred from headers\", () => {\n it(\"derives the resource origin from x-forwarded-host\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri, { baseUrl: null });\n\n const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {\n headers: { \"x-forwarded-host\": \"infer.example.test\" },\n });\n expect(res.status).toBe(200);\n const body = (await res.json()) as { resource: string };\n expect(body.resource).toBe(\"https://infer.example.test/\");\n });\n\n it(\"uses the first hop of a forwarded-host chain\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri, { baseUrl: null });\n\n const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {\n headers: {\n \"x-forwarded-host\": \"public.example, internal.local\",\n \"x-forwarded-proto\": \"https, http\",\n },\n });\n expect(res.status).toBe(200);\n const body = (await res.json()) as { resource: string };\n expect(body.resource).toBe(\"https://public.example/\");\n });\n\n it(\"ignores the client Origin header, using Host instead\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri, { baseUrl: null });\n\n const res = await fetch(`${base}/.well-known/oauth-protected-resource`, {\n headers: { origin: \"https://chatgpt.com\" },\n });\n expect(res.status).toBe(200);\n const body = (await res.json()) as { resource: string };\n expect(body.resource).toMatch(/^http:\\/\\/(localhost|127\\.0\\.0\\.1):/);\n });\n\n it(\"points the 401 WWW-Authenticate at the inferred host\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootServer(jwksUri, { baseUrl: null });\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-forwarded-host\": \"infer.example.test\",\n },\n body: JSON.stringify({ jsonrpc: \"2.0\", method: \"initialize\", id: 1 }),\n });\n expect(res.status).toBe(401);\n expect(res.headers.get(\"www-authenticate\")).toMatch(\n /resource_metadata=\"https:\\/\\/infer\\.example\\.test\\//,\n );\n });\n});\n\nasync function bootMixedServer(jwksUri: string) {\n const { createApp } = await import(\"../express.js\");\n const server = new McpServer(\n { name: \"mixed-auth-test\", version: \"0.0.0\" },\n { capabilities: {} },\n {\n oauth: {\n baseUrl: \"https://app.example.test\",\n oauthMetadata: {\n issuer: ISSUER,\n authorization_endpoint: `${ISSUER}/authorize`,\n token_endpoint: `${ISSUER}/token`,\n response_types_supported: [\"code\"],\n },\n verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },\n },\n },\n )\n .registerTool(\n {\n name: \"public-whoami\",\n description: \"Public.\",\n inputSchema: {},\n auth: { public: true },\n },\n (_args, extra) => ({\n content: [{ type: \"text\", text: extra.authInfo?.clientId ?? \"anon\" }],\n }),\n )\n .registerTool(\n {\n name: \"private-whoami\",\n description: \"Private.\",\n inputSchema: {},\n auth: {},\n },\n (_args, extra) => ({\n content: [{ type: \"text\", text: extra.authInfo?.clientId ?? \"anon\" }],\n }),\n );\n\n (server.registerTool as (...a: unknown[]) => unknown)(\n \"legacy-whoami\",\n {\n description: \"Registered via the legacy string overload.\",\n inputSchema: {},\n },\n (_args: unknown, extra: { authInfo?: { clientId?: string } }) => ({\n content: [{ type: \"text\", text: extra.authInfo?.clientId ?? \"anon\" }],\n }),\n );\n\n const httpServer = http.createServer();\n await createApp({ mcpServer: server, httpServer });\n const listening = http.createServer(server.express);\n await new Promise<void>((resolve) => listening.listen(0, resolve));\n appServer = listening;\n const port = (listening.address() as { port: number }).port;\n return `http://localhost:${port}`;\n}\n\ndescribe(\"mixed-auth door\", () => {\n it(\"lets an anonymous caller initialize and run a noauth tool\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n\n const client = new Client({ name: \"test-client\", version: \"0.0.0\" });\n await client.connect(\n new StreamableHTTPClientTransport(new URL(`${base}/mcp`)),\n );\n\n const result = (await client.callTool({\n name: \"public-whoami\",\n arguments: {},\n })) as unknown as { content: { text: string }[] };\n expect(result.content[0]?.text).toBe(\"anon\");\n\n await client.close();\n });\n\n it(\"exposes securitySchemes at the top level of tools/list (not only _meta)\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n const headers = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n };\n await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"initialize\",\n params: {\n protocolVersion: \"2025-06-18\",\n capabilities: {},\n clientInfo: { name: \"c\", version: \"0\" },\n },\n }),\n });\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ jsonrpc: \"2.0\", id: 2, method: \"tools/list\" }),\n });\n const text = await res.text();\n const json = JSON.parse((text.match(/\\{[\\s\\S]*\\}/) ?? [\"{}\"])[0]) as {\n result: { tools: Array<{ name: string; securitySchemes?: unknown }> };\n };\n const whoami = json.result.tools.find((t) => t.name === \"private-whoami\");\n expect(whoami?.securitySchemes).toEqual([{ type: \"oauth2\" }]);\n });\n\n it(\"denies a protected tool inside an anonymous JSON-RPC batch\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n },\n body: JSON.stringify([\n {\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: { name: \"private-whoami\", arguments: {} },\n },\n ]),\n });\n expect(res.status).toBe(401);\n const wwwAuthenticate = res.headers.get(\"www-authenticate\") ?? \"\";\n expect(wwwAuthenticate).toMatch(/^Bearer /);\n expect(wwwAuthenticate).toContain(\"resource_metadata=\");\n const text = await res.text();\n expect(text).not.toContain(\"client-1\");\n });\n\n it(\"gates a tool registered via the legacy string overload (secure default)\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: { name: \"legacy-whoami\", arguments: {} },\n }),\n });\n expect(res.status).toBe(401);\n });\n\n it(\"returns 401 + WWW-Authenticate for a protected tool while anonymous\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: { name: \"private-whoami\", arguments: {} },\n }),\n });\n expect(res.status).toBe(401);\n expect(res.headers.get(\"www-authenticate\")).toMatch(\n /error=\"invalid_token\"/,\n );\n expect(res.headers.get(\"www-authenticate\")).toMatch(/resource_metadata=/);\n });\n\n it(\"returns an in-band mcp/www_authenticate array to ChatGPT (not a transport 401)\", async () => {\n const { jwksUri } = await startJwks();\n const base = await bootMixedServer(jwksUri);\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n \"User-Agent\": \"openai-mcp/1.0\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 7,\n method: \"tools/call\",\n params: { name: \"private-whoami\", arguments: {} },\n }),\n });\n expect(res.status).toBe(200);\n expect(res.headers.get(\"www-authenticate\")).toBeNull();\n const body = (await res.json()) as {\n id: number;\n result: {\n isError: boolean;\n _meta: { \"mcp/www_authenticate\": string[] };\n };\n };\n expect(body.id).toBe(7);\n expect(body.result.isError).toBe(true);\n const challenge = body.result._meta[\"mcp/www_authenticate\"];\n expect(Array.isArray(challenge)).toBe(true);\n expect(challenge[0]).toMatch(/error=\"invalid_token\"/);\n expect(challenge[0]).toMatch(/resource_metadata=/);\n });\n});\n\nasync function bootScopedServer(jwksUri: string) {\n const { createApp } = await import(\"../express.js\");\n const server = new McpServer(\n { name: \"scoped-auth-test\", version: \"0.0.0\" },\n { capabilities: {} },\n {\n oauth: {\n baseUrl: \"https://app.example.test\",\n oauthMetadata: {\n issuer: ISSUER,\n authorization_endpoint: `${ISSUER}/authorize`,\n token_endpoint: `${ISSUER}/token`,\n response_types_supported: [\"code\"],\n },\n verify: { issuer: ISSUER, audience: AUDIENCE, jwksUri },\n },\n },\n ).registerTool(\n {\n name: \"checkout\",\n description: \"Needs the checkout scope.\",\n inputSchema: {},\n auth: { scopes: [\"checkout\"] },\n },\n () => ({ content: [{ type: \"text\", text: \"ok\" }] }),\n );\n\n const httpServer = http.createServer();\n await createApp({ mcpServer: server, httpServer });\n const listening = http.createServer(server.express);\n await new Promise<void>((resolve) => listening.listen(0, resolve));\n appServer = listening;\n const port = (listening.address() as { port: number }).port;\n return `http://localhost:${port}`;\n}\n\ndescribe(\"per-tool scope enforcement in fully-authenticated mode\", () => {\n it(\"returns 403 for a valid token missing the tool's scope\", async () => {\n const { privateKey, jwksUri } = await startJwks();\n const base = await bootScopedServer(jwksUri);\n const token = await signToken(privateKey, \"openid\");\n\n const res = await fetch(`${base}/mcp`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tools/call\",\n params: { name: \"checkout\", arguments: {} },\n }),\n });\n expect(res.status).toBe(403);\n const header = res.headers.get(\"www-authenticate\");\n expect(header).toMatch(/error=\"insufficient_scope\"/);\n expect(header).toMatch(/scope=\"checkout\"/);\n });\n\n it(\"allows a token carrying the tool's scope\", async () => {\n const { privateKey, jwksUri } = await startJwks();\n const base = await bootScopedServer(jwksUri);\n const token = await signToken(privateKey, \"openid checkout\");\n\n const client = new Client({ name: \"test-client\", version: \"0.0.0\" });\n await client.connect(\n new StreamableHTTPClientTransport(new URL(`${base}/mcp`), {\n requestInit: { headers: { Authorization: `Bearer ${token}` } },\n }),\n );\n\n const result = (await client.callTool({\n name: \"checkout\",\n arguments: {},\n })) as unknown as { isError?: boolean; content: { text: string }[] };\n expect(result.content[0]?.text).toBe(\"ok\");\n\n await client.close();\n });\n});\n\ndescribe(\"auth shorthand validation\", () => {\n it(\"throws when `auth` requires sign-in but no oauth provider is configured\", () => {\n expect(() =>\n new McpServer({ name: \"t\", version: \"0\" }).registerTool(\n { name: \"x\", inputSchema: {}, auth: {} },\n () => ({ content: [{ type: \"text\", text: \"\" }] }),\n ),\n ).toThrow(/no `oauth` provider/);\n });\n\n it(\"throws when `auth` sets scopes but no oauth provider is configured\", () => {\n expect(() =>\n new McpServer({ name: \"t\", version: \"0\" }).registerTool(\n { name: \"x\", inputSchema: {}, auth: { scopes: [\"checkout\"] } },\n () => ({ content: [{ type: \"text\", text: \"\" }] }),\n ),\n ).toThrow(/no `oauth` provider/);\n });\n\n it(\"allows `auth: { public: true }` without an oauth provider\", () => {\n expect(() =>\n new McpServer({ name: \"t\", version: \"0\" }).registerTool(\n { name: \"x\", inputSchema: {}, auth: { public: true } },\n () => ({ content: [{ type: \"text\", text: \"\" }] }),\n ),\n ).not.toThrow();\n });\n\n it(\"prefers `securitySchemes` over `auth` when both are set (untyped path)\", () => {\n expect(() =>\n (\n new McpServer({ name: \"t\", version: \"0\" }).registerTool as (\n ...a: unknown[]\n ) => unknown\n )(\n {\n name: \"x\",\n inputSchema: {},\n auth: {},\n securitySchemes: [{ type: \"oauth2\" }],\n },\n () => ({ content: [{ type: \"text\", text: \"\" }] }),\n ),\n ).not.toThrow();\n });\n});\n\ndescribe(\"oauth config validation\", () => {\n const validMetadata = {\n issuer: ISSUER,\n authorization_endpoint: `${ISSUER}/authorize`,\n token_endpoint: `${ISSUER}/token`,\n response_types_supported: [\"code\"],\n };\n\n it(\"throws on a non-absolute baseUrl\", () => {\n expect(\n () =>\n new McpServer({ name: \"t\", version: \"0\" }, undefined, {\n oauth: {\n baseUrl: \"not-a-url\",\n oauthMetadata: validMetadata,\n verify: { issuer: ISSUER, audience: AUDIENCE },\n },\n }),\n ).toThrow(/baseUrl must be a valid absolute URL/);\n });\n});\n"]}
@@ -0,0 +1,12 @@
1
+ import type { OAuthTokenVerifier } from "@modelcontextprotocol/sdk/server/auth/provider.js";
2
+ export type JwksVerifyConfig = {
3
+ /** Expected `iss` claim. */
4
+ issuer: string;
5
+ /** Expected `aud` claim. Omit to skip audience verification — for IdPs that
6
+ * don't bind an audience to their access tokens (e.g. Clerk). */
7
+ audience?: string;
8
+ /** Defaults to `${issuer}/.well-known/jwks.json`. */
9
+ jwksUri?: string;
10
+ };
11
+ /** Builds an `OAuthTokenVerifier` validating JWTs against a remote JWKS. Internal, not exported. */
12
+ export declare function createJwksVerifier(config: JwksVerifyConfig): OAuthTokenVerifier;
@@ -0,0 +1,38 @@
1
+ import { InvalidTokenError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
2
+ import * as jose from "jose";
3
+ /** Builds an `OAuthTokenVerifier` validating JWTs against a remote JWKS. Internal, not exported. */
4
+ export function createJwksVerifier(config) {
5
+ const jwksUri = config.jwksUri ??
6
+ `${config.issuer.replace(/\/$/, "")}/.well-known/jwks.json`;
7
+ const jwks = jose.createRemoteJWKSet(new URL(jwksUri));
8
+ return {
9
+ async verifyAccessToken(token) {
10
+ let payload;
11
+ try {
12
+ ({ payload } = await jose.jwtVerify(token, jwks, {
13
+ issuer: config.issuer,
14
+ // jose skips the aud check when `audience` is undefined.
15
+ ...(config.audience !== undefined && { audience: config.audience }),
16
+ }));
17
+ }
18
+ catch (err) {
19
+ const message = err instanceof Error ? err.message : String(err);
20
+ throw new InvalidTokenError(`Token verification failed: ${message}`);
21
+ }
22
+ const { client_id, scope, exp, sub, ...rest } = payload;
23
+ const scopes = Array.isArray(scope)
24
+ ? scope.map(String)
25
+ : typeof scope === "string"
26
+ ? scope.split(/\s+/).filter(Boolean)
27
+ : [];
28
+ return {
29
+ token,
30
+ clientId: client_id ?? "",
31
+ scopes,
32
+ expiresAt: exp,
33
+ extra: { subject: sub, ...rest },
34
+ };
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/server/auth/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAGpF,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAY7B,oGAAoG;AACpG,MAAM,UAAU,kBAAkB,CAChC,MAAwB;IAExB,MAAM,OAAO,GACX,MAAM,CAAC,OAAO;QACd,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,wBAAwB,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD,OAAO;QACL,KAAK,CAAC,iBAAiB,CAAC,KAAa;YACnC,IAAI,OAAwB,CAAC;YAC7B,IAAI,CAAC;gBACH,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;oBAC/C,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,yDAAyD;oBACzD,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;iBACpE,CAAC,CAAC,CAAC;YACN,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,MAAM,IAAI,iBAAiB,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,OAQ/C,CAAC;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBACjC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;gBACnB,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;oBACzB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;oBACpC,CAAC,CAAC,EAAE,CAAC;YAET,OAAO;gBACL,KAAK;gBACL,QAAQ,EAAE,SAAS,IAAI,EAAE;gBACzB,MAAM;gBACN,SAAS,EAAE,GAAG;gBACd,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE;aACd,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { InvalidTokenError } from \"@modelcontextprotocol/sdk/server/auth/errors.js\";\nimport type { OAuthTokenVerifier } from \"@modelcontextprotocol/sdk/server/auth/provider.js\";\nimport type { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport * as jose from \"jose\";\n\nexport type JwksVerifyConfig = {\n /** Expected `iss` claim. */\n issuer: string;\n /** Expected `aud` claim. Omit to skip audience verification — for IdPs that\n * don't bind an audience to their access tokens (e.g. Clerk). */\n audience?: string;\n /** Defaults to `${issuer}/.well-known/jwks.json`. */\n jwksUri?: string;\n};\n\n/** Builds an `OAuthTokenVerifier` validating JWTs against a remote JWKS. Internal, not exported. */\nexport function createJwksVerifier(\n config: JwksVerifyConfig,\n): OAuthTokenVerifier {\n const jwksUri =\n config.jwksUri ??\n `${config.issuer.replace(/\\/$/, \"\")}/.well-known/jwks.json`;\n const jwks = jose.createRemoteJWKSet(new URL(jwksUri));\n\n return {\n async verifyAccessToken(token: string): Promise<AuthInfo> {\n let payload: jose.JWTPayload;\n try {\n ({ payload } = await jose.jwtVerify(token, jwks, {\n issuer: config.issuer,\n // jose skips the aud check when `audience` is undefined.\n ...(config.audience !== undefined && { audience: config.audience }),\n }));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new InvalidTokenError(`Token verification failed: ${message}`);\n }\n\n const { client_id, scope, exp, sub, ...rest } = payload as Record<\n string,\n unknown\n > & {\n client_id?: string;\n scope?: string | string[];\n exp?: number;\n sub?: string;\n };\n\n const scopes = Array.isArray(scope)\n ? scope.map(String)\n : typeof scope === \"string\"\n ? scope.split(/\\s+/).filter(Boolean)\n : [];\n\n return {\n token,\n clientId: client_id ?? \"\",\n scopes,\n expiresAt: exp,\n extra: { subject: sub, ...rest },\n } satisfies AuthInfo;\n },\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};