@agent-native/core 0.128.4 → 0.129.0

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 (343) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +84 -0
  3. package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
  4. package/corpus/core/package.json +6 -3
  5. package/corpus/core/src/a2a/client.ts +18 -4
  6. package/corpus/core/src/a2a/server.ts +19 -3
  7. package/corpus/core/src/a2a/types.ts +7 -0
  8. package/corpus/core/src/action.ts +43 -16
  9. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +14 -10
  10. package/corpus/core/src/agent/production-agent.ts +41 -3
  11. package/corpus/core/src/agent/thread-data-builder.ts +5 -0
  12. package/corpus/core/src/chat-threads/migrations.ts +53 -0
  13. package/corpus/core/src/cli/create.ts +4 -0
  14. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
  15. package/corpus/core/src/cli/skills.ts +16 -0
  16. package/corpus/core/src/client/AgentPanel.tsx +9 -5
  17. package/corpus/core/src/client/AssistantChat.tsx +138 -46
  18. package/corpus/core/src/client/MultiTabAssistantChat.tsx +16 -10
  19. package/corpus/core/src/client/agent-chat-adapter.ts +21 -3
  20. package/corpus/core/src/client/analytics.ts +159 -102
  21. package/corpus/core/src/client/chat/message-components.tsx +12 -5
  22. package/corpus/core/src/client/chat/runtime.ts +2 -1
  23. package/corpus/core/src/client/chat/tool-call-display.tsx +25 -2
  24. package/corpus/core/src/client/chat-model-groups.ts +3 -0
  25. package/corpus/core/src/client/client-status-requests.ts +161 -0
  26. package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
  27. package/corpus/core/src/client/sse-event-processor.ts +15 -3
  28. package/corpus/core/src/client/use-agent-engine-configured.ts +54 -50
  29. package/corpus/core/src/client/use-chat-models.ts +16 -11
  30. package/corpus/core/src/client/use-chat-threads.ts +32 -9
  31. package/corpus/core/src/client/use-session.ts +4 -5
  32. package/corpus/core/src/db/client.ts +83 -8
  33. package/corpus/core/src/db/ensure-additive-columns.ts +31 -20
  34. package/corpus/core/src/db/migrations.ts +22 -2
  35. package/corpus/core/src/mcp/approval-store.ts +99 -0
  36. package/corpus/core/src/mcp/build-server.ts +579 -303
  37. package/corpus/core/src/mcp/embed-app.ts +1 -1
  38. package/corpus/core/src/mcp/oauth-client-metadata.ts +380 -0
  39. package/corpus/core/src/mcp/oauth-route.ts +57 -52
  40. package/corpus/core/src/mcp/screen-memory-stdio.ts +400 -378
  41. package/corpus/core/src/mcp/server.ts +29 -145
  42. package/corpus/core/src/mcp/stdio.ts +72 -80
  43. package/corpus/core/src/mcp-client/manager.ts +6 -10
  44. package/corpus/core/src/mcp-client/oauth-client.ts +127 -36
  45. package/corpus/core/src/mcp-client/oauth-routes.ts +16 -6
  46. package/corpus/core/src/mcp-client/routes.ts +6 -5
  47. package/corpus/core/src/server/agent-capabilities.ts +20 -0
  48. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +27 -0
  49. package/corpus/core/src/server/agent-chat-plugin.ts +18 -0
  50. package/corpus/core/src/server/transcribe-voice.ts +14 -5
  51. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +13 -2
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  55. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +13 -2
  56. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -10
  57. package/corpus/templates/analytics/app/global.css +0 -31
  58. package/corpus/templates/analytics/app/lib/sql-query.ts +46 -20
  59. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboard-loading-states-now-use-a-simpler-standar.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboards-now-load-first-party-charts-reliably-in.md +6 -0
  61. package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +42 -16
  62. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
  63. package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
  64. package/corpus/templates/assets/.agents/skills/security/SKILL.md +13 -2
  65. package/corpus/templates/brain/.agents/skills/security/SKILL.md +13 -2
  66. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +13 -2
  67. package/corpus/templates/chat/.agents/skills/security/SKILL.md +13 -2
  68. package/corpus/templates/chat/README.md +0 -2
  69. package/corpus/templates/clips/.agents/skills/security/SKILL.md +13 -2
  70. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -6
  71. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -2
  72. package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -1
  73. package/corpus/templates/clips/changelog/2026-07-28-copied-share-links-no-longer-leave-an-unnecessary-confirmati.md +6 -0
  74. package/corpus/templates/clips/changelog/2026-07-28-playback-skip-controls-no-longer-show-overlapping-numbers.md +6 -0
  75. package/corpus/templates/clips/changelog/2026-07-28-public-clips-share-buttons-now-use-a-clean-text-only-label.md +6 -0
  76. package/corpus/templates/clips/desktop/src/app.tsx +14 -17
  77. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +3 -1
  78. package/corpus/templates/clips/desktop/src/styles.css +13 -10
  79. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +2 -2
  80. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +36 -0
  81. package/corpus/templates/content/.agents/skills/security/SKILL.md +13 -2
  82. package/corpus/templates/content/actions/_builder-cms-read-client.ts +155 -34
  83. package/corpus/templates/content/actions/_builder-docs-client.ts +151 -30
  84. package/corpus/templates/content/actions/stage-builder-source-bulk-update.ts +5 -2
  85. package/corpus/templates/content/app/root.tsx +35 -14
  86. package/corpus/templates/content/changelog/2026-07-28-builder-backed-files-media-fields-now-accept-direct-file-url.md +6 -0
  87. package/corpus/templates/content/changelog/2026-07-28-builder-content-reads-now-negotiate-the-newest-mcp-protocol-.md +6 -0
  88. package/corpus/templates/content/changelog/2026-07-28-public-content-pages-load-faster-before-the-optional-ask-sid.md +6 -0
  89. package/corpus/templates/design/.agents/skills/security/SKILL.md +13 -2
  90. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +36 -16
  91. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +42 -3
  92. package/corpus/templates/design/actions/open-visual-edit.ts +2 -1
  93. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  94. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +14 -15
  95. package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +314 -0
  96. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +88 -3
  97. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
  98. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +7 -6
  99. package/corpus/templates/design/app/i18n-data.ts +56 -11
  100. package/corpus/templates/design/app/i18n-responsive-interact.ts +183 -0
  101. package/corpus/templates/design/app/lib/agent-chat.ts +60 -0
  102. package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +89 -0
  103. package/corpus/templates/design/changelog/2026-07-28-design-edits-can-be-applied-through-the-host-coding-agent-fr.md +6 -0
  104. package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +6 -0
  105. package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +6 -0
  106. package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +2 -2
  107. package/corpus/templates/design/changelog/2026-07-28-visual-edit-now-always-shows-the-live-running-app-in-the-can.md +6 -0
  108. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +13 -2
  109. package/corpus/templates/forms/.agents/skills/security/SKILL.md +13 -2
  110. package/corpus/templates/macros/.agents/skills/security/SKILL.md +13 -2
  111. package/corpus/templates/mail/.agents/skills/security/SKILL.md +13 -2
  112. package/corpus/templates/plan/.agents/skills/security/SKILL.md +13 -2
  113. package/corpus/templates/slides/.agents/skills/security/SKILL.md +13 -2
  114. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +13 -2
  115. package/corpus/toolkit/CHANGELOG.md +13 -0
  116. package/corpus/toolkit/package.json +1 -1
  117. package/corpus/toolkit/src/chat-history.css +1 -2
  118. package/corpus/toolkit/src/composer/TiptapComposer.tsx +45 -0
  119. package/dist/a2a/client.d.ts +7 -0
  120. package/dist/a2a/client.d.ts.map +1 -1
  121. package/dist/a2a/client.js +8 -3
  122. package/dist/a2a/client.js.map +1 -1
  123. package/dist/a2a/server.d.ts.map +1 -1
  124. package/dist/a2a/server.js +18 -3
  125. package/dist/a2a/server.js.map +1 -1
  126. package/dist/a2a/types.d.ts +7 -0
  127. package/dist/a2a/types.d.ts.map +1 -1
  128. package/dist/a2a/types.js.map +1 -1
  129. package/dist/action.d.ts +15 -1
  130. package/dist/action.d.ts.map +1 -1
  131. package/dist/action.js +39 -16
  132. package/dist/action.js.map +1 -1
  133. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  134. package/dist/agent/engine/ai-sdk-engine.js +14 -10
  135. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  136. package/dist/agent/production-agent.d.ts.map +1 -1
  137. package/dist/agent/production-agent.js +35 -7
  138. package/dist/agent/production-agent.js.map +1 -1
  139. package/dist/agent/thread-data-builder.d.ts +2 -0
  140. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  141. package/dist/agent/thread-data-builder.js +3 -0
  142. package/dist/agent/thread-data-builder.js.map +1 -1
  143. package/dist/chat-threads/migrations.d.ts +21 -0
  144. package/dist/chat-threads/migrations.d.ts.map +1 -0
  145. package/dist/chat-threads/migrations.js +45 -0
  146. package/dist/chat-threads/migrations.js.map +1 -0
  147. package/dist/cli/create.d.ts.map +1 -1
  148. package/dist/cli/create.js +4 -0
  149. package/dist/cli/create.js.map +1 -1
  150. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  151. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  152. package/dist/cli/skills-content/design-visual-edit-skill.js +36 -16
  153. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  154. package/dist/cli/skills.d.ts.map +1 -1
  155. package/dist/cli/skills.js +15 -0
  156. package/dist/cli/skills.js.map +1 -1
  157. package/dist/client/AgentPanel.d.ts.map +1 -1
  158. package/dist/client/AgentPanel.js +6 -5
  159. package/dist/client/AgentPanel.js.map +1 -1
  160. package/dist/client/AssistantChat.d.ts +37 -0
  161. package/dist/client/AssistantChat.d.ts.map +1 -1
  162. package/dist/client/AssistantChat.js +41 -8
  163. package/dist/client/AssistantChat.js.map +1 -1
  164. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  165. package/dist/client/MultiTabAssistantChat.js +11 -10
  166. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  167. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  168. package/dist/client/agent-chat-adapter.js +19 -3
  169. package/dist/client/agent-chat-adapter.js.map +1 -1
  170. package/dist/client/analytics.d.ts.map +1 -1
  171. package/dist/client/analytics.js +150 -101
  172. package/dist/client/analytics.js.map +1 -1
  173. package/dist/client/chat/message-components.d.ts +2 -1
  174. package/dist/client/chat/message-components.d.ts.map +1 -1
  175. package/dist/client/chat/message-components.js +11 -4
  176. package/dist/client/chat/message-components.js.map +1 -1
  177. package/dist/client/chat/runtime.d.ts.map +1 -1
  178. package/dist/client/chat/runtime.js +2 -1
  179. package/dist/client/chat/runtime.js.map +1 -1
  180. package/dist/client/chat/tool-call-display.d.ts +4 -1
  181. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  182. package/dist/client/chat/tool-call-display.js +14 -8
  183. package/dist/client/chat/tool-call-display.js.map +1 -1
  184. package/dist/client/chat-model-groups.d.ts.map +1 -1
  185. package/dist/client/chat-model-groups.js +3 -0
  186. package/dist/client/chat-model-groups.js.map +1 -1
  187. package/dist/client/client-status-requests.d.ts +14 -0
  188. package/dist/client/client-status-requests.d.ts.map +1 -0
  189. package/dist/client/client-status-requests.js +126 -0
  190. package/dist/client/client-status-requests.js.map +1 -0
  191. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  192. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  193. package/dist/client/sse-event-processor.d.ts +7 -0
  194. package/dist/client/sse-event-processor.d.ts.map +1 -1
  195. package/dist/client/sse-event-processor.js +8 -3
  196. package/dist/client/sse-event-processor.js.map +1 -1
  197. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  198. package/dist/client/use-agent-engine-configured.js +29 -43
  199. package/dist/client/use-agent-engine-configured.js.map +1 -1
  200. package/dist/client/use-chat-models.d.ts.map +1 -1
  201. package/dist/client/use-chat-models.js +11 -11
  202. package/dist/client/use-chat-models.js.map +1 -1
  203. package/dist/client/use-chat-threads.d.ts.map +1 -1
  204. package/dist/client/use-chat-threads.js +23 -7
  205. package/dist/client/use-chat-threads.js.map +1 -1
  206. package/dist/client/use-session.d.ts.map +1 -1
  207. package/dist/client/use-session.js +4 -4
  208. package/dist/client/use-session.js.map +1 -1
  209. package/dist/collab/awareness.d.ts +2 -2
  210. package/dist/collab/awareness.d.ts.map +1 -1
  211. package/dist/collab/struct-routes.d.ts +1 -1
  212. package/dist/db/client.d.ts.map +1 -1
  213. package/dist/db/client.js +48 -4
  214. package/dist/db/client.js.map +1 -1
  215. package/dist/db/ensure-additive-columns.d.ts.map +1 -1
  216. package/dist/db/ensure-additive-columns.js +32 -21
  217. package/dist/db/ensure-additive-columns.js.map +1 -1
  218. package/dist/db/migrations.d.ts +9 -0
  219. package/dist/db/migrations.d.ts.map +1 -1
  220. package/dist/db/migrations.js +14 -3
  221. package/dist/db/migrations.js.map +1 -1
  222. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  223. package/dist/mcp/approval-store.d.ts +16 -0
  224. package/dist/mcp/approval-store.d.ts.map +1 -0
  225. package/dist/mcp/approval-store.js +85 -0
  226. package/dist/mcp/approval-store.js.map +1 -0
  227. package/dist/mcp/build-server.d.ts +1 -34
  228. package/dist/mcp/build-server.d.ts.map +1 -1
  229. package/dist/mcp/build-server.js +220 -23
  230. package/dist/mcp/build-server.js.map +1 -1
  231. package/dist/mcp/embed-app.js +1 -1
  232. package/dist/mcp/embed-app.js.map +1 -1
  233. package/dist/mcp/oauth-client-metadata.d.ts +15 -0
  234. package/dist/mcp/oauth-client-metadata.d.ts.map +1 -0
  235. package/dist/mcp/oauth-client-metadata.js +297 -0
  236. package/dist/mcp/oauth-client-metadata.js.map +1 -0
  237. package/dist/mcp/oauth-route.d.ts.map +1 -1
  238. package/dist/mcp/oauth-route.js +39 -53
  239. package/dist/mcp/oauth-route.js.map +1 -1
  240. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  241. package/dist/mcp/screen-memory-stdio.js +304 -296
  242. package/dist/mcp/screen-memory-stdio.js.map +1 -1
  243. package/dist/mcp/server.d.ts +12 -25
  244. package/dist/mcp/server.d.ts.map +1 -1
  245. package/dist/mcp/server.js +24 -133
  246. package/dist/mcp/server.js.map +1 -1
  247. package/dist/mcp/stdio.d.ts.map +1 -1
  248. package/dist/mcp/stdio.js +36 -35
  249. package/dist/mcp/stdio.js.map +1 -1
  250. package/dist/mcp-client/manager.d.ts.map +1 -1
  251. package/dist/mcp-client/manager.js +6 -6
  252. package/dist/mcp-client/manager.js.map +1 -1
  253. package/dist/mcp-client/oauth-client.d.ts +13 -17
  254. package/dist/mcp-client/oauth-client.d.ts.map +1 -1
  255. package/dist/mcp-client/oauth-client.js +74 -16
  256. package/dist/mcp-client/oauth-client.js.map +1 -1
  257. package/dist/mcp-client/oauth-routes.d.ts +2 -2
  258. package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
  259. package/dist/mcp-client/oauth-routes.js +16 -6
  260. package/dist/mcp-client/oauth-routes.js.map +1 -1
  261. package/dist/mcp-client/routes.js +5 -5
  262. package/dist/mcp-client/routes.js.map +1 -1
  263. package/dist/notifications/routes.d.ts +1 -1
  264. package/dist/observability/routes.d.ts +3 -3
  265. package/dist/progress/routes.d.ts +1 -1
  266. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  267. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  268. package/dist/resources/handlers.d.ts +1 -1
  269. package/dist/secrets/routes.d.ts +9 -9
  270. package/dist/server/agent-capabilities.d.ts.map +1 -1
  271. package/dist/server/agent-capabilities.js +21 -0
  272. package/dist/server/agent-capabilities.js.map +1 -1
  273. package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -0
  274. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  275. package/dist/server/agent-chat/action-filters-a2a.js +16 -0
  276. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  277. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  278. package/dist/server/agent-chat-plugin.js +11 -1
  279. package/dist/server/agent-chat-plugin.js.map +1 -1
  280. package/dist/server/realtime-token.d.ts +1 -1
  281. package/dist/server/transcribe-voice.d.ts +1 -1
  282. package/dist/server/transcribe-voice.js +12 -6
  283. package/dist/server/transcribe-voice.js.map +1 -1
  284. package/dist/templates/chat/.agents/skills/security/SKILL.md +13 -2
  285. package/dist/templates/chat/README.md +0 -2
  286. package/dist/templates/default/.agents/skills/security/SKILL.md +13 -2
  287. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  288. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  289. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
  290. package/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
  291. package/package.json +7 -4
  292. package/src/a2a/client.ts +18 -4
  293. package/src/a2a/server.ts +19 -3
  294. package/src/a2a/types.ts +7 -0
  295. package/src/action.ts +43 -16
  296. package/src/agent/engine/ai-sdk-engine.ts +14 -10
  297. package/src/agent/production-agent.ts +41 -3
  298. package/src/agent/thread-data-builder.ts +5 -0
  299. package/src/chat-threads/migrations.ts +53 -0
  300. package/src/cli/create.ts +4 -0
  301. package/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
  302. package/src/cli/skills.ts +16 -0
  303. package/src/client/AgentPanel.tsx +9 -5
  304. package/src/client/AssistantChat.tsx +138 -46
  305. package/src/client/MultiTabAssistantChat.tsx +16 -10
  306. package/src/client/agent-chat-adapter.ts +21 -3
  307. package/src/client/analytics.ts +159 -102
  308. package/src/client/chat/message-components.tsx +12 -5
  309. package/src/client/chat/runtime.ts +2 -1
  310. package/src/client/chat/tool-call-display.tsx +25 -2
  311. package/src/client/chat-model-groups.ts +3 -0
  312. package/src/client/client-status-requests.ts +161 -0
  313. package/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
  314. package/src/client/sse-event-processor.ts +15 -3
  315. package/src/client/use-agent-engine-configured.ts +54 -50
  316. package/src/client/use-chat-models.ts +16 -11
  317. package/src/client/use-chat-threads.ts +32 -9
  318. package/src/client/use-session.ts +4 -5
  319. package/src/db/client.ts +83 -8
  320. package/src/db/ensure-additive-columns.ts +31 -20
  321. package/src/db/migrations.ts +22 -2
  322. package/src/mcp/approval-store.ts +99 -0
  323. package/src/mcp/build-server.ts +579 -303
  324. package/src/mcp/embed-app.ts +1 -1
  325. package/src/mcp/oauth-client-metadata.ts +380 -0
  326. package/src/mcp/oauth-route.ts +57 -52
  327. package/src/mcp/screen-memory-stdio.ts +400 -378
  328. package/src/mcp/server.ts +29 -145
  329. package/src/mcp/stdio.ts +72 -80
  330. package/src/mcp-client/manager.ts +6 -10
  331. package/src/mcp-client/oauth-client.ts +127 -36
  332. package/src/mcp-client/oauth-routes.ts +16 -6
  333. package/src/mcp-client/routes.ts +6 -5
  334. package/src/server/agent-capabilities.ts +20 -0
  335. package/src/server/agent-chat/action-filters-a2a.ts +27 -0
  336. package/src/server/agent-chat-plugin.ts +18 -0
  337. package/src/server/transcribe-voice.ts +14 -5
  338. package/src/templates/chat/.agents/skills/security/SKILL.md +13 -2
  339. package/src/templates/chat/README.md +0 -2
  340. package/src/templates/default/.agents/skills/security/SKILL.md +13 -2
  341. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
  342. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
  343. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-client.js","sourceRoot":"","sources":["../../src/mcp-client/oauth-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth 2.1 client support for remote MCP servers.\n *\n * MCP servers advertise their OAuth endpoints through the standard protected\n * resource and authorization-server metadata documents. The SDK handles the\n * protocol details; this module owns the framework-specific encrypted storage\n * and refresh boundary.\n */\n\nimport {\n auth,\n refreshAuthorization,\n type OAuthClientProvider,\n} from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n AuthorizationServerMetadata,\n OAuthClientInformationMixed,\n OAuthClientMetadata,\n OAuthProtectedResourceMetadata,\n OAuthTokens,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\nimport {\n deleteOAuthTokens,\n getOAuthTokens,\n saveOAuthTokens,\n} from \"../oauth-tokens/store.js\";\nimport { validateRemoteUrl } from \"./remote-url.js\";\n\nconst TOKEN_EXPIRY_SKEW_MS = 60_000;\nconst MAX_OAUTH_REDIRECTS = 5;\n\ntype GuardedFetch = (\n url: string | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nfunction checkedRemoteUrl(value: string | URL, label: string): URL {\n const result = validateRemoteUrl(String(value));\n if (!result.ok || !result.url) {\n throw new Error(\n `MCP OAuth ${label} is not allowed: ${result.error ?? \"invalid URL\"}`,\n );\n }\n return result.url;\n}\n\nfunction guardedOAuthFetch(): GuardedFetch {\n return async (url, init) => {\n let currentUrl = checkedRemoteUrl(url, \"request\");\n let currentInit: RequestInit = { ...init, redirect: \"manual\" };\n\n for (let redirectCount = 0; ; redirectCount += 1) {\n const response = await fetch(currentUrl, currentInit);\n if (![301, 302, 303, 307, 308].includes(response.status)) {\n return response;\n }\n if (redirectCount >= MAX_OAUTH_REDIRECTS) {\n throw new Error(\"MCP OAuth redirect limit exceeded.\");\n }\n const location = response.headers.get(\"location\");\n if (!location) throw new Error(\"MCP OAuth redirect is missing a target.\");\n\n let nextUrl: URL;\n try {\n nextUrl = checkedRemoteUrl(\n new URL(location, currentUrl),\n \"redirect target\",\n );\n } catch {\n throw new Error(\"MCP OAuth redirect target is not allowed.\");\n }\n await response.body?.cancel().catch(() => undefined);\n\n const nextHeaders = new Headers(currentInit.headers);\n if (nextUrl.origin !== currentUrl.origin) {\n nextHeaders.delete(\"authorization\");\n nextHeaders.delete(\"cookie\");\n nextHeaders.delete(\"proxy-authorization\");\n }\n const nextInit: RequestInit = {\n ...currentInit,\n headers: nextHeaders,\n };\n if (\n response.status === 303 ||\n ((response.status === 301 || response.status === 302) &&\n (currentInit.method ?? \"GET\").toUpperCase() === \"POST\")\n ) {\n nextInit.method = \"GET\";\n delete nextInit.body;\n nextHeaders.delete(\"content-length\");\n nextHeaders.delete(\"content-type\");\n }\n currentUrl = nextUrl;\n currentInit = nextInit;\n }\n };\n}\n\nfunction validateDiscoveryUrls(state: {\n authorizationServerUrl: string;\n authorizationServerMetadata?: AuthorizationServerMetadata;\n resourceMetadata?: OAuthProtectedResourceMetadata;\n resourceMetadataUrl?: string;\n}): void {\n checkedRemoteUrl(state.authorizationServerUrl, \"authorization server\");\n if (state.resourceMetadataUrl) {\n checkedRemoteUrl(state.resourceMetadataUrl, \"resource metadata\");\n }\n for (const url of state.resourceMetadata?.authorization_servers ?? []) {\n checkedRemoteUrl(url, \"discovered authorization server\");\n }\n for (const field of [\n \"authorization_endpoint\",\n \"token_endpoint\",\n \"registration_endpoint\",\n \"introspection_endpoint\",\n \"revocation_endpoint\",\n ] as const) {\n const url = (\n state.authorizationServerMetadata as Record<string, unknown> | undefined\n )?.[field];\n if (typeof url === \"string\") {\n checkedRemoteUrl(url, `OAuth ${field}`);\n }\n }\n}\n\nfunction credentialOwner(options: { scope: \"user\" | \"org\"; scopeId: string }) {\n return `${options.scope}:${options.scopeId}`;\n}\n\nexport interface McpOAuthDiscoveryState {\n authorizationServerUrl: string;\n authorizationServerMetadata?: AuthorizationServerMetadata;\n resourceMetadata?: OAuthProtectedResourceMetadata;\n resourceMetadataUrl?: string;\n}\n\nexport interface McpOAuthCredentialBundle {\n serverUrl: string;\n clientInformation: OAuthClientInformationMixed;\n discoveryState?: McpOAuthDiscoveryState;\n tokens: OAuthTokens;\n tokenExpiresAt?: number;\n}\n\nexport interface McpOAuthStartResult {\n authorizationUrl: URL;\n codeVerifier: string;\n state: string;\n clientInformation: OAuthClientInformationMixed;\n discoveryState?: McpOAuthDiscoveryState;\n}\n\nexport interface McpOAuthCallbackResult {\n credentials: McpOAuthCredentialBundle;\n}\n\nexport interface McpOAuthProviderOptions {\n serverUrl: string;\n redirectUrl: string;\n state: string;\n clientInformation?: OAuthClientInformationMixed;\n codeVerifier?: string;\n discoveryState?: McpOAuthDiscoveryState;\n}\n\n/**\n * A small adapter around the MCP SDK's OAuth provider interface. The route\n * stores the adapter's state in an encrypted, short-lived browser cookie; the\n * durable credential bundle is written only after the callback succeeds.\n */\nexport class McpOAuthClientProvider implements OAuthClientProvider {\n private readonly redirectUrlValue: string;\n private readonly stateValue: string;\n private readonly metadata: OAuthClientMetadata;\n private clientInfo?: OAuthClientInformationMixed;\n private savedTokens?: OAuthTokens;\n private savedCodeVerifier?: string;\n private savedDiscovery?: McpOAuthDiscoveryState;\n private authorizationUrl?: URL;\n\n constructor(options: McpOAuthProviderOptions) {\n this.redirectUrlValue = options.redirectUrl;\n this.stateValue = options.state;\n this.clientInfo = options.clientInformation;\n this.savedCodeVerifier = options.codeVerifier;\n this.savedDiscovery = options.discoveryState;\n this.metadata = {\n redirect_uris: [options.redirectUrl],\n token_endpoint_auth_method: \"none\",\n grant_types: [\"authorization_code\"],\n response_types: [\"code\"],\n client_name: \"Agent Native MCP connector\",\n };\n }\n\n get redirectUrl(): string {\n return this.redirectUrlValue;\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return this.metadata;\n }\n\n state(): string {\n return this.stateValue;\n }\n\n clientInformation(): OAuthClientInformationMixed | undefined {\n return this.clientInfo;\n }\n\n saveClientInformation(info: OAuthClientInformationMixed): void {\n this.clientInfo = info;\n }\n\n tokens(): OAuthTokens | undefined {\n return this.savedTokens;\n }\n\n saveTokens(tokens: OAuthTokens): void {\n this.savedTokens = tokens;\n }\n\n redirectToAuthorization(authorizationUrl: URL): void {\n this.authorizationUrl = checkedRemoteUrl(\n authorizationUrl,\n \"authorization redirect\",\n );\n }\n\n saveCodeVerifier(codeVerifier: string): void {\n this.savedCodeVerifier = codeVerifier;\n }\n\n codeVerifier(): string {\n if (!this.savedCodeVerifier) {\n throw new Error(\"MCP OAuth code verifier is missing\");\n }\n return this.savedCodeVerifier;\n }\n\n saveDiscoveryState(state: {\n authorizationServerUrl: string;\n authorizationServerMetadata?: AuthorizationServerMetadata;\n resourceMetadata?: OAuthProtectedResourceMetadata;\n resourceMetadataUrl?: string;\n }): void {\n validateDiscoveryUrls(state);\n this.savedDiscovery = state;\n }\n\n discoveryState(): McpOAuthDiscoveryState | undefined {\n return this.savedDiscovery;\n }\n\n get authorizationRedirect(): URL | undefined {\n return this.authorizationUrl;\n }\n\n get savedCodeVerifierValue(): string | undefined {\n return this.savedCodeVerifier;\n }\n\n get savedTokensValue(): OAuthTokens | undefined {\n return this.savedTokens;\n }\n\n get savedClientInformation(): OAuthClientInformationMixed | undefined {\n return this.clientInfo;\n }\n}\n\nexport async function startMcpOAuthAuthorization(\n options: McpOAuthProviderOptions & { scope?: string },\n): Promise<McpOAuthStartResult> {\n checkedRemoteUrl(options.serverUrl, \"server\");\n const provider = new McpOAuthClientProvider(options);\n const result = await auth(provider, {\n serverUrl: options.serverUrl,\n scope: options.scope,\n fetchFn: guardedOAuthFetch(),\n });\n if (result !== \"REDIRECT\" || !provider.authorizationRedirect) {\n throw new Error(\"MCP server did not start an interactive OAuth flow\");\n }\n const clientInformation = provider.savedClientInformation;\n if (!clientInformation) {\n throw new Error(\"MCP OAuth client registration did not complete\");\n }\n return {\n authorizationUrl: provider.authorizationRedirect,\n codeVerifier: provider.savedCodeVerifierValue ?? provider.codeVerifier(),\n state: options.state,\n clientInformation,\n discoveryState: provider.discoveryState(),\n };\n}\n\nexport async function finishMcpOAuthAuthorization(\n options: McpOAuthProviderOptions & { authorizationCode: string },\n): Promise<McpOAuthCallbackResult> {\n checkedRemoteUrl(options.serverUrl, \"server\");\n const provider = new McpOAuthClientProvider(options);\n const result = await auth(provider, {\n serverUrl: options.serverUrl,\n authorizationCode: options.authorizationCode,\n fetchFn: guardedOAuthFetch(),\n });\n if (result !== \"AUTHORIZED\" || !provider.savedTokensValue) {\n throw new Error(\"MCP OAuth token exchange did not complete\");\n }\n const tokens = provider.savedTokensValue;\n return {\n credentials: {\n serverUrl: options.serverUrl,\n clientInformation: provider.savedClientInformation!,\n discoveryState: provider.discoveryState(),\n tokens,\n tokenExpiresAt: tokenExpiresAt(tokens),\n },\n };\n}\n\nexport function tokenExpiresAt(tokens: OAuthTokens): number | undefined {\n const expiresIn = Number(tokens.expires_in);\n if (!Number.isFinite(expiresIn) || expiresIn <= 0) return undefined;\n return Date.now() + expiresIn * 1_000;\n}\n\nexport async function saveMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n credentials: McpOAuthCredentialBundle;\n}): Promise<void> {\n checkedRemoteUrl(options.credentials.serverUrl, \"server\");\n if (options.credentials.discoveryState) {\n validateDiscoveryUrls(options.credentials.discoveryState);\n }\n await saveOAuthTokens(\n \"mcp\",\n options.key,\n options.credentials as unknown as Record<string, unknown>,\n `${options.scope}:${options.scopeId}`,\n );\n}\n\nexport async function readMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n}): Promise<McpOAuthCredentialBundle | null> {\n const stored = await getOAuthTokens(\n \"mcp\",\n options.key,\n credentialOwner(options),\n );\n if (!stored) return null;\n const parsed = stored as Partial<McpOAuthCredentialBundle>;\n if (\n typeof parsed.serverUrl !== \"string\" ||\n !parsed.clientInformation ||\n !parsed.tokens ||\n typeof parsed.tokens.access_token !== \"string\"\n ) {\n return null;\n }\n if (!validateRemoteUrl(parsed.serverUrl).ok) return null;\n if (parsed.discoveryState) {\n try {\n validateDiscoveryUrls(parsed.discoveryState);\n } catch {\n return null;\n }\n }\n return parsed as McpOAuthCredentialBundle;\n}\n\nexport async function deleteMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n}): Promise<boolean> {\n return (\n (await deleteOAuthTokens(\"mcp\", options.key, credentialOwner(options))) > 0\n );\n}\n\n/**\n * Resolve an access token for the MCP manager. Refreshing happens only when a\n * token is near expiry, so ordinary manager reconfiguration does not perform\n * a network request for every connector.\n */\nexport async function getMcpOAuthAccessToken(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n serverUrl: string;\n}): Promise<string | null> {\n if (!validateRemoteUrl(options.serverUrl).ok) return null;\n const credentials = await readMcpOAuthCredentials(options);\n if (!credentials || credentials.serverUrl !== options.serverUrl) return null;\n\n const accessToken = credentials.tokens.access_token;\n if (\n typeof credentials.tokenExpiresAt !== \"number\" ||\n credentials.tokenExpiresAt - Date.now() > TOKEN_EXPIRY_SKEW_MS\n ) {\n return accessToken;\n }\n\n const refreshToken = credentials.tokens.refresh_token;\n const discovery = credentials.discoveryState;\n if (!refreshToken || !discovery?.authorizationServerUrl) {\n return accessToken;\n }\n\n try {\n const resource = discovery.resourceMetadata?.resource\n ? checkedRemoteUrl(discovery.resourceMetadata.resource, \"resource\")\n : undefined;\n const authorizationServerUrl = checkedRemoteUrl(\n discovery.authorizationServerUrl,\n \"authorization server\",\n );\n const refreshed = await refreshAuthorization(authorizationServerUrl, {\n metadata: discovery.authorizationServerMetadata,\n clientInformation: credentials.clientInformation,\n refreshToken,\n resource,\n fetchFn: guardedOAuthFetch(),\n });\n const nextTokens: OAuthTokens = {\n ...credentials.tokens,\n ...refreshed,\n ...(refreshed.refresh_token\n ? { refresh_token: refreshed.refresh_token }\n : credentials.tokens.refresh_token\n ? { refresh_token: credentials.tokens.refresh_token }\n : {}),\n };\n const next: McpOAuthCredentialBundle = {\n ...credentials,\n tokens: nextTokens,\n tokenExpiresAt: tokenExpiresAt(nextTokens),\n };\n await saveMcpOAuthCredentials({\n ...options,\n credentials: next,\n });\n return nextTokens.access_token;\n } catch {\n // Keep the old token so the MCP request can return the provider's normal\n // auth error. A single expired connector must not remove every server from\n // the process-wide manager during a config refresh.\n return accessToken;\n }\n}\n"]}
1
+ {"version":3,"file":"oauth-client.js","sourceRoot":"","sources":["../../src/mcp-client/oauth-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth 2.1 client support for remote MCP servers.\n *\n * MCP servers advertise their OAuth endpoints through the standard protected\n * resource and authorization-server metadata documents. The SDK handles the\n * protocol details; this module owns the framework-specific encrypted storage\n * and refresh boundary.\n */\n\nimport {\n auth,\n refreshAuthorization,\n validateAuthorizationResponseIssuer,\n type AuthorizationServerMetadata,\n type OAuthClientInformationContext,\n type OAuthClientMetadata,\n type OAuthClientProvider,\n type OAuthDiscoveryState,\n OAuthProtectedResourceMetadata,\n type StoredOAuthClientInformation,\n type StoredOAuthTokens,\n OAuthTokens,\n} from \"@modelcontextprotocol/client\";\n\nimport {\n deleteOAuthTokens,\n getOAuthTokens,\n saveOAuthTokens,\n} from \"../oauth-tokens/store.js\";\nimport { validateRemoteUrl } from \"./remote-url.js\";\n\nconst TOKEN_EXPIRY_SKEW_MS = 60_000;\nconst MAX_OAUTH_REDIRECTS = 5;\n\ntype GuardedFetch = (\n url: string | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nfunction checkedRemoteUrl(value: string | URL, label: string): URL {\n const result = validateRemoteUrl(String(value));\n if (!result.ok || !result.url) {\n throw new Error(\n `MCP OAuth ${label} is not allowed: ${result.error ?? \"invalid URL\"}`,\n );\n }\n return result.url;\n}\n\nfunction guardedOAuthFetch(): GuardedFetch {\n return async (url, init) => {\n let currentUrl = checkedRemoteUrl(url, \"request\");\n let currentInit: RequestInit = { ...init, redirect: \"manual\" };\n\n for (let redirectCount = 0; ; redirectCount += 1) {\n const response = await fetch(currentUrl, currentInit);\n if (![301, 302, 303, 307, 308].includes(response.status)) {\n return response;\n }\n if (redirectCount >= MAX_OAUTH_REDIRECTS) {\n throw new Error(\"MCP OAuth redirect limit exceeded.\");\n }\n const location = response.headers.get(\"location\");\n if (!location) throw new Error(\"MCP OAuth redirect is missing a target.\");\n\n let nextUrl: URL;\n try {\n nextUrl = checkedRemoteUrl(\n new URL(location, currentUrl),\n \"redirect target\",\n );\n } catch {\n throw new Error(\"MCP OAuth redirect target is not allowed.\");\n }\n await response.body?.cancel().catch(() => undefined);\n\n const nextHeaders = new Headers(currentInit.headers);\n if (nextUrl.origin !== currentUrl.origin) {\n nextHeaders.delete(\"authorization\");\n nextHeaders.delete(\"cookie\");\n nextHeaders.delete(\"proxy-authorization\");\n }\n const nextInit: RequestInit = {\n ...currentInit,\n headers: nextHeaders,\n };\n if (\n response.status === 303 ||\n ((response.status === 301 || response.status === 302) &&\n (currentInit.method ?? \"GET\").toUpperCase() === \"POST\")\n ) {\n nextInit.method = \"GET\";\n delete nextInit.body;\n nextHeaders.delete(\"content-length\");\n nextHeaders.delete(\"content-type\");\n }\n currentUrl = nextUrl;\n currentInit = nextInit;\n }\n };\n}\n\nfunction validateDiscoveryUrls(state: {\n authorizationServerUrl: string;\n authorizationServerMetadata?: AuthorizationServerMetadata;\n resourceMetadata?: OAuthProtectedResourceMetadata;\n resourceMetadataUrl?: string;\n}): void {\n checkedRemoteUrl(state.authorizationServerUrl, \"authorization server\");\n if (state.resourceMetadataUrl) {\n checkedRemoteUrl(state.resourceMetadataUrl, \"resource metadata\");\n }\n for (const url of state.resourceMetadata?.authorization_servers ?? []) {\n checkedRemoteUrl(url, \"discovered authorization server\");\n }\n for (const field of [\n \"authorization_endpoint\",\n \"token_endpoint\",\n \"registration_endpoint\",\n \"introspection_endpoint\",\n \"revocation_endpoint\",\n ] as const) {\n const url = (\n state.authorizationServerMetadata as Record<string, unknown> | undefined\n )?.[field];\n if (typeof url === \"string\") {\n checkedRemoteUrl(url, `OAuth ${field}`);\n }\n }\n}\n\nfunction credentialOwner(options: { scope: \"user\" | \"org\"; scopeId: string }) {\n return `${options.scope}:${options.scopeId}`;\n}\n\nexport type McpOAuthDiscoveryState = OAuthDiscoveryState;\n\nexport interface McpOAuthCredentialBundle {\n serverUrl: string;\n clientInformation: StoredOAuthClientInformation;\n discoveryState?: McpOAuthDiscoveryState;\n tokens: StoredOAuthTokens;\n tokenExpiresAt?: number;\n}\n\nexport interface McpOAuthStartResult {\n authorizationUrl: URL;\n codeVerifier: string;\n state: string;\n clientInformation: StoredOAuthClientInformation;\n discoveryState?: McpOAuthDiscoveryState;\n}\n\nexport interface McpOAuthCallbackResult {\n credentials: McpOAuthCredentialBundle;\n}\n\nexport interface McpOAuthProviderOptions {\n serverUrl: string;\n redirectUrl: string;\n state: string;\n clientInformation?: StoredOAuthClientInformation;\n codeVerifier?: string;\n discoveryState?: McpOAuthDiscoveryState;\n}\n\nfunction issuerForDiscovery(\n discovery: McpOAuthDiscoveryState | undefined,\n): string | undefined {\n const issuer = discovery?.authorizationServerMetadata?.issuer;\n return typeof issuer === \"string\" && issuer ? issuer : undefined;\n}\n\nfunction withIssuer<T extends { issuer?: string }>(\n value: T,\n context: OAuthClientInformationContext | undefined,\n): T {\n if (value.issuer && context?.issuer && value.issuer !== context.issuer) {\n throw new Error(\"MCP OAuth credential issuer does not match discovery\");\n }\n const issuer = context?.issuer ?? value.issuer;\n return issuer ? { ...value, issuer } : value;\n}\n\nfunction isBoundToIssuer(\n value: { issuer?: string } | undefined,\n context: OAuthClientInformationContext | undefined,\n): boolean {\n return !context?.issuer || value?.issuer === context.issuer;\n}\n\nfunction applicationTypeForRedirect(redirectUrl: string): \"native\" | \"web\" {\n const url = new URL(redirectUrl);\n if (\n url.protocol !== \"https:\" ||\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"::1\" ||\n url.hostname === \"[::1]\"\n ) {\n return \"native\";\n }\n return \"web\";\n}\n\n/**\n * A small adapter around the MCP SDK's OAuth provider interface. The route\n * stores the adapter's state in an encrypted, short-lived browser cookie; the\n * durable credential bundle is written only after the callback succeeds.\n */\nexport class McpOAuthClientProvider implements OAuthClientProvider {\n private readonly redirectUrlValue: string;\n private readonly stateValue: string;\n private readonly metadata: OAuthClientMetadata;\n private clientInfo?: StoredOAuthClientInformation;\n private savedTokens?: StoredOAuthTokens;\n private savedCodeVerifier?: string;\n private savedDiscovery?: McpOAuthDiscoveryState;\n private authorizationUrl?: URL;\n\n constructor(options: McpOAuthProviderOptions) {\n this.redirectUrlValue = options.redirectUrl;\n this.stateValue = options.state;\n this.clientInfo = options.clientInformation;\n this.savedCodeVerifier = options.codeVerifier;\n this.savedDiscovery = options.discoveryState;\n const recordedIssuer = issuerForDiscovery(this.savedDiscovery);\n if (\n this.clientInfo &&\n !this.clientInfo.issuer &&\n recordedIssuer &&\n this.savedCodeVerifier\n ) {\n // A callback flow persists registration, discovery, PKCE, and state in\n // one encrypted cookie. Binding that pre-v2 in-flight registration to\n // its recorded issuer is safe; durable credentials are never inferred.\n this.clientInfo = { ...this.clientInfo, issuer: recordedIssuer };\n }\n this.metadata = {\n redirect_uris: [options.redirectUrl],\n token_endpoint_auth_method: \"none\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n application_type: applicationTypeForRedirect(options.redirectUrl),\n client_name: \"Agent Native MCP connector\",\n };\n }\n\n get redirectUrl(): string {\n return this.redirectUrlValue;\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return this.metadata;\n }\n\n state(): string {\n return this.stateValue;\n }\n\n clientInformation(\n context?: OAuthClientInformationContext,\n ): StoredOAuthClientInformation | undefined {\n return isBoundToIssuer(this.clientInfo, context)\n ? this.clientInfo\n : undefined;\n }\n\n saveClientInformation(\n info: StoredOAuthClientInformation,\n context?: OAuthClientInformationContext,\n ): void {\n this.clientInfo = withIssuer(info, context);\n }\n\n tokens(\n context?: OAuthClientInformationContext,\n ): StoredOAuthTokens | undefined {\n return isBoundToIssuer(this.savedTokens, context)\n ? this.savedTokens\n : undefined;\n }\n\n saveTokens(\n tokens: StoredOAuthTokens,\n context?: OAuthClientInformationContext,\n ): void {\n this.savedTokens = withIssuer(tokens, context);\n }\n\n redirectToAuthorization(authorizationUrl: URL): void {\n this.authorizationUrl = checkedRemoteUrl(\n authorizationUrl,\n \"authorization redirect\",\n );\n }\n\n saveCodeVerifier(codeVerifier: string): void {\n this.savedCodeVerifier = codeVerifier;\n }\n\n codeVerifier(): string {\n if (!this.savedCodeVerifier) {\n throw new Error(\"MCP OAuth code verifier is missing\");\n }\n return this.savedCodeVerifier;\n }\n\n saveDiscoveryState(state: {\n authorizationServerUrl: string;\n authorizationServerMetadata?: AuthorizationServerMetadata;\n resourceMetadata?: OAuthProtectedResourceMetadata;\n resourceMetadataUrl?: string;\n }): void {\n validateDiscoveryUrls(state);\n this.savedDiscovery = state;\n }\n\n discoveryState(): McpOAuthDiscoveryState | undefined {\n return this.savedDiscovery;\n }\n\n get authorizationRedirect(): URL | undefined {\n return this.authorizationUrl;\n }\n\n get savedCodeVerifierValue(): string | undefined {\n return this.savedCodeVerifier;\n }\n\n get savedTokensValue(): OAuthTokens | undefined {\n return this.savedTokens;\n }\n\n get savedClientInformation(): StoredOAuthClientInformation | undefined {\n return this.clientInfo;\n }\n}\n\nexport async function startMcpOAuthAuthorization(\n options: McpOAuthProviderOptions & { scope?: string },\n): Promise<McpOAuthStartResult> {\n checkedRemoteUrl(options.serverUrl, \"server\");\n const provider = new McpOAuthClientProvider(options);\n const result = await auth(provider, {\n serverUrl: options.serverUrl,\n scope: options.scope,\n fetchFn: guardedOAuthFetch(),\n });\n if (result !== \"REDIRECT\" || !provider.authorizationRedirect) {\n throw new Error(\"MCP server did not start an interactive OAuth flow\");\n }\n const clientInformation = provider.savedClientInformation;\n if (!clientInformation) {\n throw new Error(\"MCP OAuth client registration did not complete\");\n }\n return {\n authorizationUrl: provider.authorizationRedirect,\n codeVerifier: provider.savedCodeVerifierValue ?? provider.codeVerifier(),\n state: options.state,\n clientInformation,\n discoveryState: provider.discoveryState(),\n };\n}\n\nexport async function finishMcpOAuthAuthorization(\n options: McpOAuthProviderOptions & {\n authorizationCode: string;\n iss?: string;\n },\n): Promise<McpOAuthCallbackResult> {\n checkedRemoteUrl(options.serverUrl, \"server\");\n const provider = new McpOAuthClientProvider(options);\n const result = await auth(provider, {\n serverUrl: options.serverUrl,\n authorizationCode: options.authorizationCode,\n iss: options.iss,\n fetchFn: guardedOAuthFetch(),\n });\n if (result !== \"AUTHORIZED\" || !provider.savedTokensValue) {\n throw new Error(\"MCP OAuth token exchange did not complete\");\n }\n const tokens = provider.savedTokensValue;\n return {\n credentials: {\n serverUrl: options.serverUrl,\n clientInformation: provider.savedClientInformation!,\n discoveryState: provider.discoveryState(),\n tokens,\n tokenExpiresAt: tokenExpiresAt(tokens),\n },\n };\n}\n\nexport function validateMcpOAuthCallbackIssuer(\n discoveryState: McpOAuthDiscoveryState | undefined,\n iss: string | undefined,\n): void {\n validateAuthorizationResponseIssuer({\n iss,\n expectedIssuer: issuerForDiscovery(discoveryState),\n issParameterSupported:\n discoveryState?.authorizationServerMetadata\n ?.authorization_response_iss_parameter_supported === true,\n });\n}\n\nexport function tokenExpiresAt(tokens: OAuthTokens): number | undefined {\n const expiresIn = Number(tokens.expires_in);\n if (!Number.isFinite(expiresIn) || expiresIn <= 0) return undefined;\n return Date.now() + expiresIn * 1_000;\n}\n\nexport async function saveMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n credentials: McpOAuthCredentialBundle;\n}): Promise<void> {\n checkedRemoteUrl(options.credentials.serverUrl, \"server\");\n if (options.credentials.discoveryState) {\n validateDiscoveryUrls(options.credentials.discoveryState);\n }\n await saveOAuthTokens(\n \"mcp\",\n options.key,\n options.credentials as unknown as Record<string, unknown>,\n `${options.scope}:${options.scopeId}`,\n );\n}\n\nexport async function readMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n}): Promise<McpOAuthCredentialBundle | null> {\n const stored = await getOAuthTokens(\n \"mcp\",\n options.key,\n credentialOwner(options),\n );\n if (!stored) return null;\n const parsed = stored as Partial<McpOAuthCredentialBundle>;\n if (\n typeof parsed.serverUrl !== \"string\" ||\n !parsed.clientInformation ||\n !parsed.tokens ||\n typeof parsed.tokens.access_token !== \"string\"\n ) {\n return null;\n }\n if (!validateRemoteUrl(parsed.serverUrl).ok) return null;\n if (parsed.discoveryState) {\n try {\n validateDiscoveryUrls(parsed.discoveryState);\n } catch {\n return null;\n }\n }\n return parsed as McpOAuthCredentialBundle;\n}\n\nexport async function deleteMcpOAuthCredentials(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n}): Promise<boolean> {\n return (\n (await deleteOAuthTokens(\"mcp\", options.key, credentialOwner(options))) > 0\n );\n}\n\n/**\n * Resolve an access token for the MCP manager. Refreshing happens only when a\n * token is near expiry, so ordinary manager reconfiguration does not perform\n * a network request for every connector.\n */\nexport async function getMcpOAuthAccessToken(options: {\n key: string;\n scope: \"user\" | \"org\";\n scopeId: string;\n serverUrl: string;\n}): Promise<string | null> {\n if (!validateRemoteUrl(options.serverUrl).ok) return null;\n const credentials = await readMcpOAuthCredentials(options);\n if (!credentials || credentials.serverUrl !== options.serverUrl) return null;\n\n const accessToken = credentials.tokens.access_token;\n const now = Date.now();\n if (\n typeof credentials.tokenExpiresAt !== \"number\" ||\n credentials.tokenExpiresAt - now > TOKEN_EXPIRY_SKEW_MS\n ) {\n return accessToken;\n }\n const tokenIsExpired = credentials.tokenExpiresAt <= now;\n\n const refreshToken = credentials.tokens.refresh_token;\n const discovery = credentials.discoveryState;\n if (!refreshToken || !discovery?.authorizationServerUrl) {\n return tokenIsExpired ? null : accessToken;\n }\n\n try {\n const expectedIssuer = issuerForDiscovery(discovery);\n if (\n !expectedIssuer ||\n credentials.clientInformation.issuer !== expectedIssuer ||\n credentials.tokens.issuer !== expectedIssuer\n ) {\n return null;\n }\n const resource = discovery.resourceMetadata?.resource\n ? checkedRemoteUrl(discovery.resourceMetadata.resource, \"resource\")\n : undefined;\n const authorizationServerUrl = checkedRemoteUrl(\n discovery.authorizationServerUrl,\n \"authorization server\",\n );\n const refreshed = await refreshAuthorization(authorizationServerUrl, {\n metadata: discovery.authorizationServerMetadata,\n clientInformation: credentials.clientInformation,\n refreshToken,\n resource,\n fetchFn: guardedOAuthFetch(),\n });\n const nextTokens: StoredOAuthTokens = {\n ...credentials.tokens,\n ...refreshed,\n issuer: expectedIssuer,\n ...(refreshed.refresh_token\n ? { refresh_token: refreshed.refresh_token }\n : credentials.tokens.refresh_token\n ? { refresh_token: credentials.tokens.refresh_token }\n : {}),\n };\n const next: McpOAuthCredentialBundle = {\n ...credentials,\n tokens: nextTokens,\n tokenExpiresAt: tokenExpiresAt(nextTokens),\n };\n await saveMcpOAuthCredentials({\n ...options,\n credentials: next,\n });\n return nextTokens.access_token;\n } catch {\n // A still-valid token can survive a transient refresh failure. Once it has\n // expired, omit it so callers surface reauthorization instead of retrying\n // a credential that can never authenticate.\n return tokenIsExpired ? null : accessToken;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { OAuthClientInformationMixed } from "@modelcontextprotocol/sdk/shared/auth.js";
1
+ import type { StoredOAuthClientInformation } from "@modelcontextprotocol/client";
2
2
  import { type H3Event } from "h3";
3
3
  import { type McpOAuthDiscoveryState } from "./oauth-client.js";
4
4
  import { type RemoteMcpScope } from "./remote-store.js";
@@ -13,7 +13,7 @@ export interface McpOAuthFlow {
13
13
  redirectUri: string;
14
14
  state: string;
15
15
  codeVerifier: string;
16
- clientInformation: OAuthClientInformationMixed;
16
+ clientInformation: StoredOAuthClientInformation;
17
17
  discoveryState?: McpOAuthDiscoveryState;
18
18
  returnUrl?: string;
19
19
  expiresAt: number;
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-routes.d.ts","sourceRoot":"","sources":["../../src/mcp-client/oauth-routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,EASL,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAQZ,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,2BAA2B,CAAC;IAC/C,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,QAAQ,CASV;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CA6BN;AAyKD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,OAAO,GACd,IAAI,CAcN;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAiB1E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAK7D;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAcT"}
1
+ {"version":3,"file":"oauth-routes.d.ts","sourceRoot":"","sources":["../../src/mcp-client/oauth-routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EASL,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAQZ,OAAO,EAGL,KAAK,sBAAsB,EAE5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,4BAA4B,CAAC;IAChD,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,QAAQ,CASV;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CA6BN;AAkLD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,OAAO,GACd,IAAI,CAcN;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAiB1E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAK7D;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAcT"}
@@ -6,7 +6,7 @@ import { getSession, safeReturnPath } from "../server/auth.js";
6
6
  import { getH3App } from "../server/framework-request-handler.js";
7
7
  import { getAppUrl, resolveOAuthRedirectUri } from "../server/google-oauth.js";
8
8
  import { runWithRequestContext } from "../server/request-context.js";
9
- import { finishMcpOAuthAuthorization, startMcpOAuthAuthorization, } from "./oauth-client.js";
9
+ import { finishMcpOAuthAuthorization, startMcpOAuthAuthorization, validateMcpOAuthCallbackIssuer, } from "./oauth-client.js";
10
10
  import { addOAuthRemoteServer, normalizeServerName, validateRemoteUrl, } from "./remote-store.js";
11
11
  const FLOW_COOKIE = "an_mcp_oauth_flow";
12
12
  const FLOW_TTL_SECONDS = 10 * 60;
@@ -139,19 +139,28 @@ async function handleMcpOAuthCallback(event, options) {
139
139
  const query = getQuery(event);
140
140
  const code = text(query.code);
141
141
  const state = text(query.state);
142
+ const iss = text(query.iss);
142
143
  const providerError = text(query.error);
143
144
  const flow = readMcpOAuthFlowCookie(event);
144
145
  clearMcpOAuthFlowCookies(event);
145
- if (providerError || !code || !state) {
146
- setResponseStatus(event, 400);
147
- return { error: "MCP OAuth authorization was not completed." };
148
- }
149
146
  const org = flow?.scope === "org" ? await getOrgContext(event).catch(() => null) : null;
150
- if (!flow ||
147
+ if (!state ||
148
+ !flow ||
151
149
  !isValidMcpOAuthFlow(flow, session.email, org?.orgId ?? undefined, state)) {
152
150
  setResponseStatus(event, 400);
153
151
  return { error: "MCP OAuth state is invalid or expired." };
154
152
  }
153
+ try {
154
+ validateMcpOAuthCallbackIssuer(flow.discoveryState, iss);
155
+ }
156
+ catch {
157
+ setResponseStatus(event, 400);
158
+ return { error: "MCP OAuth authorization response issuer is invalid." };
159
+ }
160
+ if (providerError || !code) {
161
+ setResponseStatus(event, 400);
162
+ return { error: "MCP OAuth authorization was not completed." };
163
+ }
155
164
  if (flow.scope === "org" && !isOrgAdmin(org?.role)) {
156
165
  setResponseStatus(event, 403);
157
166
  return {
@@ -167,6 +176,7 @@ async function handleMcpOAuthCallback(event, options) {
167
176
  codeVerifier: flow.codeVerifier,
168
177
  discoveryState: flow.discoveryState,
169
178
  authorizationCode: code,
179
+ iss,
170
180
  }));
171
181
  const result = await addOAuthRemoteServer(flow.scope, flow.scopeId, {
172
182
  name: flow.name,
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-routes.js","sourceRoot":"","sources":["../../src/mcp-client/oauth-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nimport type { OAuthClientInformationMixed } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport {\n deleteCookie,\n defineEventHandler,\n getChunkedCookie,\n getCookie,\n getMethod,\n getQuery,\n setChunkedCookie,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\n\nimport { getOrgContext } from \"../org/context.js\";\nimport { decryptSecretValue, encryptSecretValue } from \"../secrets/crypto.js\";\nimport { getSession, safeReturnPath } from \"../server/auth.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { getAppUrl, resolveOAuthRedirectUri } from \"../server/google-oauth.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport {\n finishMcpOAuthAuthorization,\n startMcpOAuthAuthorization,\n type McpOAuthDiscoveryState,\n} from \"./oauth-client.js\";\nimport {\n addOAuthRemoteServer,\n normalizeServerName,\n validateRemoteUrl,\n type RemoteMcpScope,\n} from \"./remote-store.js\";\n\nconst FLOW_COOKIE = \"an_mcp_oauth_flow\";\nconst FLOW_TTL_SECONDS = 10 * 60;\nconst FLOW_COOKIE_CHUNK_SIZE = 2_800;\nconst FLOW_COOKIE_MAX_CHUNKS = 8;\nconst CHUNKED_COOKIE_PREFIX = \"__chunked__\";\n\nexport interface McpOAuthFlow {\n name: string;\n url: string;\n description?: string;\n scope: RemoteMcpScope;\n scopeId: string;\n owner: string;\n orgId?: string;\n redirectUri: string;\n state: string;\n codeVerifier: string;\n clientInformation: OAuthClientInformationMixed;\n discoveryState?: McpOAuthDiscoveryState;\n returnUrl?: string;\n expiresAt: number;\n}\n\nexport interface McpOAuthRoutesOptions {\n reconfigure: () => Promise<void>;\n}\n\nexport function redirectWithStagedCookies(\n event: H3Event,\n location: string,\n): Response {\n const headers = new Headers({\n Location: location,\n \"Cache-Control\": \"no-store\",\n });\n for (const cookie of event.res?.headers?.getSetCookie?.() ?? []) {\n headers.append(\"set-cookie\", cookie);\n }\n return new Response(null, { status: 302, headers });\n}\n\nexport function mountMcpOAuthRoutes(\n nitroApp: any,\n options: McpOAuthRoutesOptions,\n): void {\n const mountedApps: WeakSet<object> = ((\n globalThis as any\n ).__agentNativeMcpOAuthMountedApps ??= new WeakSet<object>());\n if (mountedApps.has(nitroApp)) return;\n mountedApps.add(nitroApp);\n\n getH3App(nitroApp).use(\n \"/_agent-native/mcp/servers/oauth\",\n defineEventHandler(async (event: H3Event) => {\n const method = getMethod(event);\n const pathname = (event.url?.pathname || \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n const parts = pathname ? pathname.split(\"/\") : [];\n if (method !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (parts.length === 1 && parts[0] === \"start\") {\n return handleMcpOAuthStart(event);\n }\n if (parts.length === 1 && parts[0] === \"callback\") {\n return handleMcpOAuthCallback(event, options);\n }\n setResponseStatus(event, 404);\n return { error: \"Not found\" };\n }),\n );\n}\n\nasync function handleMcpOAuthStart(\n event: H3Event,\n): Promise<Response | Record<string, unknown>> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) return unauthorized(event);\n\n const query = getQuery(event);\n const rawUrl = text(query.url);\n const rawName = text(query.name);\n const returnUrl = text(query.return);\n if (!rawUrl || !rawName) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth requires a server name and URL.\" };\n }\n const urlCheck = validateRemoteUrl(rawUrl);\n if (!urlCheck.ok) {\n setResponseStatus(event, 400);\n return { error: urlCheck.error ?? \"MCP server URL is not allowed.\" };\n }\n const name = normalizeServerName(rawName);\n if (!name) {\n setResponseStatus(event, 400);\n return { error: \"MCP server name is invalid.\" };\n }\n\n const requestedScope = query.scope === \"org\" ? \"org\" : \"user\";\n const requestedOrgId = text(query.orgId);\n const org =\n requestedScope === \"org\"\n ? await getOrgContext(event).catch(() => null)\n : null;\n const scope: RemoteMcpScope = requestedScope;\n const scopeId = scope === \"user\" ? session.email : (org?.orgId ?? \"\");\n if (scope === \"org\" && requestedOrgId && requestedOrgId !== scopeId) {\n setResponseStatus(event, 403);\n return {\n error: \"The selected organization is not the active organization.\",\n };\n }\n if (scope === \"org\" && (!scopeId || !isOrgAdmin(org?.role))) {\n setResponseStatus(event, scopeId ? 403 : 400);\n return {\n error: scopeId\n ? \"Only organization owners and admins can connect an org MCP server.\"\n : \"Join an organization before connecting an org MCP server.\",\n };\n }\n\n const redirectUri = resolveOAuthRedirectUri(\n event,\n \"/_agent-native/mcp/servers/oauth/callback\",\n );\n if (!redirectUri) {\n setResponseStatus(event, 400);\n return { error: \"Invalid MCP OAuth redirect URI.\" };\n }\n\n const state = crypto.randomUUID();\n const safeReturnUrl = returnUrl ? safeReturnPath(returnUrl) : undefined;\n try {\n const started = await runWithRequestContext(\n { userEmail: session.email, orgId: org?.orgId ?? undefined },\n () =>\n startMcpOAuthAuthorization({\n serverUrl: urlCheck.url!.toString(),\n redirectUrl: redirectUri,\n state,\n }),\n );\n const flow: McpOAuthFlow = {\n name,\n url: urlCheck.url!.toString(),\n description: text(query.description),\n scope,\n scopeId,\n owner: session.email,\n ...(org?.orgId ? { orgId: org.orgId } : {}),\n redirectUri,\n state: started.state,\n codeVerifier: started.codeVerifier,\n clientInformation: started.clientInformation,\n ...(started.discoveryState\n ? { discoveryState: started.discoveryState }\n : {}),\n ...(safeReturnUrl ? { returnUrl: safeReturnUrl } : {}),\n expiresAt: Date.now() + FLOW_TTL_SECONDS * 1_000,\n };\n setMcpOAuthFlowCookie(event, flow, redirectUri.startsWith(\"https://\"));\n return redirectWithStagedCookies(event, started.authorizationUrl.href);\n } catch {\n setResponseStatus(event, 400);\n return {\n error:\n \"This MCP server could not start OAuth. It may not support standard MCP OAuth discovery or dynamic client registration.\",\n };\n }\n}\n\nasync function handleMcpOAuthCallback(\n event: H3Event,\n options: McpOAuthRoutesOptions,\n): Promise<Response | Record<string, unknown>> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) return unauthorized(event);\n\n const query = getQuery(event);\n const code = text(query.code);\n const state = text(query.state);\n const providerError = text(query.error);\n const flow = readMcpOAuthFlowCookie(event);\n clearMcpOAuthFlowCookies(event);\n if (providerError || !code || !state) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth authorization was not completed.\" };\n }\n const org =\n flow?.scope === \"org\" ? await getOrgContext(event).catch(() => null) : null;\n if (\n !flow ||\n !isValidMcpOAuthFlow(flow, session.email, org?.orgId ?? undefined, state)\n ) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth state is invalid or expired.\" };\n }\n if (flow.scope === \"org\" && !isOrgAdmin(org?.role)) {\n setResponseStatus(event, 403);\n return {\n error:\n \"Only organization owners and admins can connect an org MCP server.\",\n };\n }\n\n try {\n const finished = await runWithRequestContext(\n { userEmail: session.email, orgId: org?.orgId ?? undefined },\n () =>\n finishMcpOAuthAuthorization({\n serverUrl: flow.url,\n redirectUrl: flow.redirectUri,\n state: flow.state,\n clientInformation: flow.clientInformation,\n codeVerifier: flow.codeVerifier,\n discoveryState: flow.discoveryState,\n authorizationCode: code,\n }),\n );\n const result = await addOAuthRemoteServer(flow.scope, flow.scopeId, {\n name: flow.name,\n url: flow.url,\n description: flow.description,\n credentials: finished.credentials,\n });\n if (!result.ok) {\n setResponseStatus(event, 400);\n return { error: result.error };\n }\n await options.reconfigure();\n const returnPath =\n flow.returnUrl ??\n `/settings/connections?connected=mcp-${encodeURIComponent(flow.name)}`;\n return redirectWithStagedCookies(event, getAppUrl(event, returnPath));\n } catch {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth authorization could not be completed.\" };\n }\n}\n\nexport function setMcpOAuthFlowCookie(\n event: H3Event,\n flow: McpOAuthFlow,\n secure: boolean,\n): void {\n const encrypted = encryptSecretValue(JSON.stringify(flow));\n const chunkCount = Math.ceil(encrypted.length / FLOW_COOKIE_CHUNK_SIZE);\n if (chunkCount > FLOW_COOKIE_MAX_CHUNKS) {\n throw new Error(\"MCP OAuth flow state exceeds the cookie size limit.\");\n }\n setChunkedCookie(event, FLOW_COOKIE, encrypted, {\n httpOnly: true,\n secure,\n sameSite: \"lax\",\n path: \"/\",\n maxAge: FLOW_TTL_SECONDS,\n chunkMaxLength: FLOW_COOKIE_CHUNK_SIZE,\n });\n}\n\nexport function readMcpOAuthFlowCookie(event: H3Event): McpOAuthFlow | null {\n const primaryCookie = getCookie(event, FLOW_COOKIE);\n if (!primaryCookie) return null;\n if (primaryCookie.startsWith(CHUNKED_COOKIE_PREFIX)) {\n const rawCount = primaryCookie.slice(CHUNKED_COOKIE_PREFIX.length);\n if (!/^\\d+$/.test(rawCount)) return null;\n const chunkCount = Number(rawCount);\n if (chunkCount < 2 || chunkCount > FLOW_COOKIE_MAX_CHUNKS) return null;\n }\n const encrypted = getChunkedCookie(event, FLOW_COOKIE);\n if (!encrypted) return null;\n try {\n const parsed = JSON.parse(decryptSecretValue(encrypted)) as McpOAuthFlow;\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function clearMcpOAuthFlowCookies(event: H3Event): void {\n deleteCookie(event, FLOW_COOKIE, { path: \"/\" });\n for (let index = 1; index <= FLOW_COOKIE_MAX_CHUNKS; index += 1) {\n deleteCookie(event, `${FLOW_COOKIE}.${index}`, { path: \"/\" });\n }\n}\n\nexport function isValidMcpOAuthFlow(\n flow: McpOAuthFlow,\n email: string,\n orgId: string | undefined,\n state: string,\n): boolean {\n const scopeMatches =\n flow.scope === \"user\"\n ? flow.scopeId === email && !flow.orgId\n : flow.scope === \"org\" && flow.scopeId === orgId && flow.orgId === orgId;\n return (\n flow.expiresAt >= Date.now() &&\n flow.owner === email &&\n flow.state === state &&\n scopeMatches &&\n typeof flow.scopeId === \"string\" &&\n typeof flow.redirectUri === \"string\" &&\n flow.redirectUri.includes(\"/_agent-native/mcp/servers/oauth/callback\")\n );\n}\n\nfunction isOrgAdmin(role: unknown): boolean {\n return role === \"owner\" || role === \"admin\";\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction unauthorized(event: H3Event) {\n setResponseStatus(event, 401);\n return { error: \"Authentication required\" };\n}\n"]}
1
+ {"version":3,"file":"oauth-routes.js","sourceRoot":"","sources":["../../src/mcp-client/oauth-routes.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nimport type { StoredOAuthClientInformation } from \"@modelcontextprotocol/client\";\nimport {\n deleteCookie,\n defineEventHandler,\n getChunkedCookie,\n getCookie,\n getMethod,\n getQuery,\n setChunkedCookie,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\n\nimport { getOrgContext } from \"../org/context.js\";\nimport { decryptSecretValue, encryptSecretValue } from \"../secrets/crypto.js\";\nimport { getSession, safeReturnPath } from \"../server/auth.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { getAppUrl, resolveOAuthRedirectUri } from \"../server/google-oauth.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport {\n finishMcpOAuthAuthorization,\n startMcpOAuthAuthorization,\n type McpOAuthDiscoveryState,\n validateMcpOAuthCallbackIssuer,\n} from \"./oauth-client.js\";\nimport {\n addOAuthRemoteServer,\n normalizeServerName,\n validateRemoteUrl,\n type RemoteMcpScope,\n} from \"./remote-store.js\";\n\nconst FLOW_COOKIE = \"an_mcp_oauth_flow\";\nconst FLOW_TTL_SECONDS = 10 * 60;\nconst FLOW_COOKIE_CHUNK_SIZE = 2_800;\nconst FLOW_COOKIE_MAX_CHUNKS = 8;\nconst CHUNKED_COOKIE_PREFIX = \"__chunked__\";\n\nexport interface McpOAuthFlow {\n name: string;\n url: string;\n description?: string;\n scope: RemoteMcpScope;\n scopeId: string;\n owner: string;\n orgId?: string;\n redirectUri: string;\n state: string;\n codeVerifier: string;\n clientInformation: StoredOAuthClientInformation;\n discoveryState?: McpOAuthDiscoveryState;\n returnUrl?: string;\n expiresAt: number;\n}\n\nexport interface McpOAuthRoutesOptions {\n reconfigure: () => Promise<void>;\n}\n\nexport function redirectWithStagedCookies(\n event: H3Event,\n location: string,\n): Response {\n const headers = new Headers({\n Location: location,\n \"Cache-Control\": \"no-store\",\n });\n for (const cookie of event.res?.headers?.getSetCookie?.() ?? []) {\n headers.append(\"set-cookie\", cookie);\n }\n return new Response(null, { status: 302, headers });\n}\n\nexport function mountMcpOAuthRoutes(\n nitroApp: any,\n options: McpOAuthRoutesOptions,\n): void {\n const mountedApps: WeakSet<object> = ((\n globalThis as any\n ).__agentNativeMcpOAuthMountedApps ??= new WeakSet<object>());\n if (mountedApps.has(nitroApp)) return;\n mountedApps.add(nitroApp);\n\n getH3App(nitroApp).use(\n \"/_agent-native/mcp/servers/oauth\",\n defineEventHandler(async (event: H3Event) => {\n const method = getMethod(event);\n const pathname = (event.url?.pathname || \"\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n const parts = pathname ? pathname.split(\"/\") : [];\n if (method !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (parts.length === 1 && parts[0] === \"start\") {\n return handleMcpOAuthStart(event);\n }\n if (parts.length === 1 && parts[0] === \"callback\") {\n return handleMcpOAuthCallback(event, options);\n }\n setResponseStatus(event, 404);\n return { error: \"Not found\" };\n }),\n );\n}\n\nasync function handleMcpOAuthStart(\n event: H3Event,\n): Promise<Response | Record<string, unknown>> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) return unauthorized(event);\n\n const query = getQuery(event);\n const rawUrl = text(query.url);\n const rawName = text(query.name);\n const returnUrl = text(query.return);\n if (!rawUrl || !rawName) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth requires a server name and URL.\" };\n }\n const urlCheck = validateRemoteUrl(rawUrl);\n if (!urlCheck.ok) {\n setResponseStatus(event, 400);\n return { error: urlCheck.error ?? \"MCP server URL is not allowed.\" };\n }\n const name = normalizeServerName(rawName);\n if (!name) {\n setResponseStatus(event, 400);\n return { error: \"MCP server name is invalid.\" };\n }\n\n const requestedScope = query.scope === \"org\" ? \"org\" : \"user\";\n const requestedOrgId = text(query.orgId);\n const org =\n requestedScope === \"org\"\n ? await getOrgContext(event).catch(() => null)\n : null;\n const scope: RemoteMcpScope = requestedScope;\n const scopeId = scope === \"user\" ? session.email : (org?.orgId ?? \"\");\n if (scope === \"org\" && requestedOrgId && requestedOrgId !== scopeId) {\n setResponseStatus(event, 403);\n return {\n error: \"The selected organization is not the active organization.\",\n };\n }\n if (scope === \"org\" && (!scopeId || !isOrgAdmin(org?.role))) {\n setResponseStatus(event, scopeId ? 403 : 400);\n return {\n error: scopeId\n ? \"Only organization owners and admins can connect an org MCP server.\"\n : \"Join an organization before connecting an org MCP server.\",\n };\n }\n\n const redirectUri = resolveOAuthRedirectUri(\n event,\n \"/_agent-native/mcp/servers/oauth/callback\",\n );\n if (!redirectUri) {\n setResponseStatus(event, 400);\n return { error: \"Invalid MCP OAuth redirect URI.\" };\n }\n\n const state = crypto.randomUUID();\n const safeReturnUrl = returnUrl ? safeReturnPath(returnUrl) : undefined;\n try {\n const started = await runWithRequestContext(\n { userEmail: session.email, orgId: org?.orgId ?? undefined },\n () =>\n startMcpOAuthAuthorization({\n serverUrl: urlCheck.url!.toString(),\n redirectUrl: redirectUri,\n state,\n }),\n );\n const flow: McpOAuthFlow = {\n name,\n url: urlCheck.url!.toString(),\n description: text(query.description),\n scope,\n scopeId,\n owner: session.email,\n ...(org?.orgId ? { orgId: org.orgId } : {}),\n redirectUri,\n state: started.state,\n codeVerifier: started.codeVerifier,\n clientInformation: started.clientInformation,\n ...(started.discoveryState\n ? { discoveryState: started.discoveryState }\n : {}),\n ...(safeReturnUrl ? { returnUrl: safeReturnUrl } : {}),\n expiresAt: Date.now() + FLOW_TTL_SECONDS * 1_000,\n };\n setMcpOAuthFlowCookie(event, flow, redirectUri.startsWith(\"https://\"));\n return redirectWithStagedCookies(event, started.authorizationUrl.href);\n } catch {\n setResponseStatus(event, 400);\n return {\n error:\n \"This MCP server could not start OAuth. It may not support standard MCP OAuth discovery or dynamic client registration.\",\n };\n }\n}\n\nasync function handleMcpOAuthCallback(\n event: H3Event,\n options: McpOAuthRoutesOptions,\n): Promise<Response | Record<string, unknown>> {\n const session = await getSession(event).catch(() => null);\n if (!session?.email) return unauthorized(event);\n\n const query = getQuery(event);\n const code = text(query.code);\n const state = text(query.state);\n const iss = text(query.iss);\n const providerError = text(query.error);\n const flow = readMcpOAuthFlowCookie(event);\n clearMcpOAuthFlowCookies(event);\n const org =\n flow?.scope === \"org\" ? await getOrgContext(event).catch(() => null) : null;\n if (\n !state ||\n !flow ||\n !isValidMcpOAuthFlow(flow, session.email, org?.orgId ?? undefined, state)\n ) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth state is invalid or expired.\" };\n }\n try {\n validateMcpOAuthCallbackIssuer(flow.discoveryState, iss);\n } catch {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth authorization response issuer is invalid.\" };\n }\n if (providerError || !code) {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth authorization was not completed.\" };\n }\n if (flow.scope === \"org\" && !isOrgAdmin(org?.role)) {\n setResponseStatus(event, 403);\n return {\n error:\n \"Only organization owners and admins can connect an org MCP server.\",\n };\n }\n\n try {\n const finished = await runWithRequestContext(\n { userEmail: session.email, orgId: org?.orgId ?? undefined },\n () =>\n finishMcpOAuthAuthorization({\n serverUrl: flow.url,\n redirectUrl: flow.redirectUri,\n state: flow.state,\n clientInformation: flow.clientInformation,\n codeVerifier: flow.codeVerifier,\n discoveryState: flow.discoveryState,\n authorizationCode: code,\n iss,\n }),\n );\n const result = await addOAuthRemoteServer(flow.scope, flow.scopeId, {\n name: flow.name,\n url: flow.url,\n description: flow.description,\n credentials: finished.credentials,\n });\n if (!result.ok) {\n setResponseStatus(event, 400);\n return { error: result.error };\n }\n await options.reconfigure();\n const returnPath =\n flow.returnUrl ??\n `/settings/connections?connected=mcp-${encodeURIComponent(flow.name)}`;\n return redirectWithStagedCookies(event, getAppUrl(event, returnPath));\n } catch {\n setResponseStatus(event, 400);\n return { error: \"MCP OAuth authorization could not be completed.\" };\n }\n}\n\nexport function setMcpOAuthFlowCookie(\n event: H3Event,\n flow: McpOAuthFlow,\n secure: boolean,\n): void {\n const encrypted = encryptSecretValue(JSON.stringify(flow));\n const chunkCount = Math.ceil(encrypted.length / FLOW_COOKIE_CHUNK_SIZE);\n if (chunkCount > FLOW_COOKIE_MAX_CHUNKS) {\n throw new Error(\"MCP OAuth flow state exceeds the cookie size limit.\");\n }\n setChunkedCookie(event, FLOW_COOKIE, encrypted, {\n httpOnly: true,\n secure,\n sameSite: \"lax\",\n path: \"/\",\n maxAge: FLOW_TTL_SECONDS,\n chunkMaxLength: FLOW_COOKIE_CHUNK_SIZE,\n });\n}\n\nexport function readMcpOAuthFlowCookie(event: H3Event): McpOAuthFlow | null {\n const primaryCookie = getCookie(event, FLOW_COOKIE);\n if (!primaryCookie) return null;\n if (primaryCookie.startsWith(CHUNKED_COOKIE_PREFIX)) {\n const rawCount = primaryCookie.slice(CHUNKED_COOKIE_PREFIX.length);\n if (!/^\\d+$/.test(rawCount)) return null;\n const chunkCount = Number(rawCount);\n if (chunkCount < 2 || chunkCount > FLOW_COOKIE_MAX_CHUNKS) return null;\n }\n const encrypted = getChunkedCookie(event, FLOW_COOKIE);\n if (!encrypted) return null;\n try {\n const parsed = JSON.parse(decryptSecretValue(encrypted)) as McpOAuthFlow;\n return parsed && typeof parsed === \"object\" ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function clearMcpOAuthFlowCookies(event: H3Event): void {\n deleteCookie(event, FLOW_COOKIE, { path: \"/\" });\n for (let index = 1; index <= FLOW_COOKIE_MAX_CHUNKS; index += 1) {\n deleteCookie(event, `${FLOW_COOKIE}.${index}`, { path: \"/\" });\n }\n}\n\nexport function isValidMcpOAuthFlow(\n flow: McpOAuthFlow,\n email: string,\n orgId: string | undefined,\n state: string,\n): boolean {\n const scopeMatches =\n flow.scope === \"user\"\n ? flow.scopeId === email && !flow.orgId\n : flow.scope === \"org\" && flow.scopeId === orgId && flow.orgId === orgId;\n return (\n flow.expiresAt >= Date.now() &&\n flow.owner === email &&\n flow.state === state &&\n scopeMatches &&\n typeof flow.scopeId === \"string\" &&\n typeof flow.redirectUri === \"string\" &&\n flow.redirectUri.includes(\"/_agent-native/mcp/servers/oauth/callback\")\n );\n}\n\nfunction isOrgAdmin(role: unknown): boolean {\n return role === \"owner\" || role === \"admin\";\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction unauthorized(event: H3Event) {\n setResponseStatus(event, 401);\n return { error: \"Authentication required\" };\n}\n"]}
@@ -777,10 +777,7 @@ async function handleTestExisting(event, _manager, id) {
777
777
  }
778
778
  async function tryConnect(url, headers) {
779
779
  try {
780
- const [{ Client }, { StreamableHTTPClientTransport }] = await Promise.all([
781
- import("@modelcontextprotocol/sdk/client/index.js"),
782
- import("@modelcontextprotocol/sdk/client/streamableHttp.js"),
783
- ]);
780
+ const { Client, StreamableHTTPClientTransport } = await import("@modelcontextprotocol/client");
784
781
  const requestInit = {};
785
782
  if (headers && Object.keys(headers).length > 0) {
786
783
  requestInit.headers = headers;
@@ -788,7 +785,10 @@ async function tryConnect(url, headers) {
788
785
  const transport = new StreamableHTTPClientTransport(new URL(url), {
789
786
  requestInit,
790
787
  });
791
- const client = new Client({ name: "agent-native-mcp-client-test", version: "1.0.0" }, { capabilities: {} });
788
+ const client = new Client({ name: "agent-native-mcp-client-test", version: "1.0.0" }, {
789
+ capabilities: {},
790
+ versionNegotiation: { mode: "auto" },
791
+ });
792
792
  try {
793
793
  await client.connect(transport);
794
794
  const listed = await client.listTools();