@akon-labs/nexus-cli 0.1.9 → 0.1.10

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 (320) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +1 -0
  3. package/README.md +3 -2
  4. package/dist/app-bridge.bundle.js +67 -0
  5. package/dist/cli.js +20263 -2158
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +1 -1
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/auto-model.d.ts +1 -1
  10. package/dist/core/auto-model.d.ts.map +1 -1
  11. package/dist/core/auto-model.js +1 -1
  12. package/dist/core/auto-model.js.map +1 -1
  13. package/dist/core/model-resolver.d.ts +2 -2
  14. package/dist/core/model-resolver.d.ts.map +1 -1
  15. package/dist/core/model-resolver.js +3 -3
  16. package/dist/core/model-resolver.js.map +1 -1
  17. package/dist/core/package-manager.d.ts +15 -0
  18. package/dist/core/package-manager.d.ts.map +1 -1
  19. package/dist/core/package-manager.js +50 -0
  20. package/dist/core/package-manager.js.map +1 -1
  21. package/dist/core/sdk.d.ts.map +1 -1
  22. package/dist/core/sdk.js +1 -1
  23. package/dist/core/sdk.js.map +1 -1
  24. package/dist/core/slash-commands.d.ts.map +1 -1
  25. package/dist/core/slash-commands.js +3 -3
  26. package/dist/core/slash-commands.js.map +1 -1
  27. package/dist/core/system-prompt.d.ts.map +1 -1
  28. package/dist/core/system-prompt.js +1 -1
  29. package/dist/core/system-prompt.js.map +1 -1
  30. package/dist/core/tools/index.d.ts +1 -1
  31. package/dist/core/tools/index.d.ts.map +1 -1
  32. package/dist/core/tools/index.js +5 -5
  33. package/dist/core/tools/index.js.map +1 -1
  34. package/dist/core/tools/websearch.d.ts.map +1 -1
  35. package/dist/core/tools/websearch.js +3 -3
  36. package/dist/core/tools/websearch.js.map +1 -1
  37. package/dist/extensions/gitnexus/gateway.d.ts +6 -6
  38. package/dist/extensions/gitnexus/gateway.d.ts.map +1 -1
  39. package/dist/extensions/gitnexus/gateway.js +4 -4
  40. package/dist/extensions/gitnexus/gateway.js.map +1 -1
  41. package/dist/extensions/gitnexus/index.d.ts.map +1 -1
  42. package/dist/extensions/gitnexus/index.js +4 -2
  43. package/dist/extensions/gitnexus/index.js.map +1 -1
  44. package/dist/extensions/mcp/abort.d.ts +3 -0
  45. package/dist/extensions/mcp/abort.d.ts.map +1 -0
  46. package/dist/extensions/mcp/abort.js +41 -0
  47. package/dist/extensions/mcp/abort.js.map +1 -0
  48. package/dist/extensions/mcp/agent-dir.d.ts +6 -0
  49. package/dist/extensions/mcp/agent-dir.d.ts.map +1 -0
  50. package/dist/extensions/mcp/agent-dir.js +18 -0
  51. package/dist/extensions/mcp/agent-dir.js.map +1 -0
  52. package/dist/extensions/mcp/agent-plugin-loader.d.ts +9 -0
  53. package/dist/extensions/mcp/agent-plugin-loader.d.ts.map +1 -0
  54. package/dist/extensions/mcp/agent-plugin-loader.js +384 -0
  55. package/dist/extensions/mcp/agent-plugin-loader.js.map +1 -0
  56. package/dist/extensions/mcp/app-bridge.bundle.js +67 -0
  57. package/dist/extensions/mcp/commands.d.ts +27 -0
  58. package/dist/extensions/mcp/commands.d.ts.map +1 -0
  59. package/dist/extensions/mcp/commands.js +629 -0
  60. package/dist/extensions/mcp/commands.js.map +1 -0
  61. package/dist/extensions/mcp/config.d.ts +121 -38
  62. package/dist/extensions/mcp/config.d.ts.map +1 -1
  63. package/dist/extensions/mcp/config.js +1030 -70
  64. package/dist/extensions/mcp/config.js.map +1 -1
  65. package/dist/extensions/mcp/consent-manager.d.ts +14 -0
  66. package/dist/extensions/mcp/consent-manager.d.ts.map +1 -0
  67. package/dist/extensions/mcp/consent-manager.js +60 -0
  68. package/dist/extensions/mcp/consent-manager.js.map +1 -0
  69. package/dist/extensions/mcp/direct-tools.d.ts +11 -0
  70. package/dist/extensions/mcp/direct-tools.d.ts.map +1 -0
  71. package/dist/extensions/mcp/direct-tools.js +562 -0
  72. package/dist/extensions/mcp/direct-tools.js.map +1 -0
  73. package/dist/extensions/mcp/elicitation-handler.d.ts +18 -0
  74. package/dist/extensions/mcp/elicitation-handler.d.ts.map +1 -0
  75. package/dist/extensions/mcp/elicitation-handler.js +320 -0
  76. package/dist/extensions/mcp/elicitation-handler.js.map +1 -0
  77. package/dist/extensions/mcp/error-signal.d.ts +16 -0
  78. package/dist/extensions/mcp/error-signal.d.ts.map +1 -0
  79. package/dist/extensions/mcp/error-signal.js +22 -0
  80. package/dist/extensions/mcp/error-signal.js.map +1 -0
  81. package/dist/extensions/mcp/errors.d.ts +104 -0
  82. package/dist/extensions/mcp/errors.d.ts.map +1 -0
  83. package/dist/extensions/mcp/errors.js +171 -0
  84. package/dist/extensions/mcp/errors.js.map +1 -0
  85. package/dist/extensions/mcp/glimpse-ui.d.ts +10 -0
  86. package/dist/extensions/mcp/glimpse-ui.d.ts.map +1 -0
  87. package/dist/extensions/mcp/glimpse-ui.js +67 -0
  88. package/dist/extensions/mcp/glimpse-ui.js.map +1 -0
  89. package/dist/extensions/mcp/host-html-template.d.ts +17 -0
  90. package/dist/extensions/mcp/host-html-template.d.ts.map +1 -0
  91. package/dist/extensions/mcp/host-html-template.js +442 -0
  92. package/dist/extensions/mcp/host-html-template.js.map +1 -0
  93. package/dist/extensions/mcp/index.d.ts +20 -15
  94. package/dist/extensions/mcp/index.d.ts.map +1 -1
  95. package/dist/extensions/mcp/index.js +1064 -82
  96. package/dist/extensions/mcp/index.js.map +1 -1
  97. package/dist/extensions/mcp/init.d.ts +28 -0
  98. package/dist/extensions/mcp/init.d.ts.map +1 -0
  99. package/dist/extensions/mcp/init.js +631 -0
  100. package/dist/extensions/mcp/init.js.map +1 -0
  101. package/dist/extensions/mcp/json-schema-validator.d.ts +3 -0
  102. package/dist/extensions/mcp/json-schema-validator.d.ts.map +1 -0
  103. package/dist/extensions/mcp/json-schema-validator.js +53 -0
  104. package/dist/extensions/mcp/json-schema-validator.js.map +1 -0
  105. package/dist/extensions/mcp/lifecycle.d.ts +56 -0
  106. package/dist/extensions/mcp/lifecycle.d.ts.map +1 -0
  107. package/dist/extensions/mcp/lifecycle.js +395 -0
  108. package/dist/extensions/mcp/lifecycle.js.map +1 -0
  109. package/dist/extensions/mcp/logger.d.ts +52 -0
  110. package/dist/extensions/mcp/logger.d.ts.map +1 -0
  111. package/dist/extensions/mcp/logger.js +134 -0
  112. package/dist/extensions/mcp/logger.js.map +1 -0
  113. package/dist/extensions/mcp/mcp-auth-flow.d.ts +117 -0
  114. package/dist/extensions/mcp/mcp-auth-flow.d.ts.map +1 -0
  115. package/dist/extensions/mcp/mcp-auth-flow.js +869 -0
  116. package/dist/extensions/mcp/mcp-auth-flow.js.map +1 -0
  117. package/dist/extensions/mcp/mcp-auth.d.ts +162 -0
  118. package/dist/extensions/mcp/mcp-auth.d.ts.map +1 -0
  119. package/dist/extensions/mcp/mcp-auth.js +897 -0
  120. package/dist/extensions/mcp/mcp-auth.js.map +1 -0
  121. package/dist/extensions/mcp/mcp-bearer-store.d.ts +25 -0
  122. package/dist/extensions/mcp/mcp-bearer-store.d.ts.map +1 -0
  123. package/dist/extensions/mcp/mcp-bearer-store.js +350 -0
  124. package/dist/extensions/mcp/mcp-bearer-store.js.map +1 -0
  125. package/dist/extensions/mcp/mcp-callback-server.d.ts +54 -0
  126. package/dist/extensions/mcp/mcp-callback-server.d.ts.map +1 -0
  127. package/dist/extensions/mcp/mcp-callback-server.js +454 -0
  128. package/dist/extensions/mcp/mcp-callback-server.js.map +1 -0
  129. package/dist/extensions/mcp/mcp-code.d.ts +48 -0
  130. package/dist/extensions/mcp/mcp-code.d.ts.map +1 -0
  131. package/dist/extensions/mcp/mcp-code.js +358 -0
  132. package/dist/extensions/mcp/mcp-code.js.map +1 -0
  133. package/dist/extensions/mcp/mcp-keyring-helper.cjs +89 -0
  134. package/dist/extensions/mcp/mcp-oauth-provider.d.ts +135 -0
  135. package/dist/extensions/mcp/mcp-oauth-provider.d.ts.map +1 -0
  136. package/dist/extensions/mcp/mcp-oauth-provider.js +491 -0
  137. package/dist/extensions/mcp/mcp-oauth-provider.js.map +1 -0
  138. package/dist/extensions/mcp/mcp-output-guard.d.ts +59 -0
  139. package/dist/extensions/mcp/mcp-output-guard.d.ts.map +1 -0
  140. package/dist/extensions/mcp/mcp-output-guard.js +343 -0
  141. package/dist/extensions/mcp/mcp-output-guard.js.map +1 -0
  142. package/dist/extensions/mcp/mcp-panel.d.ts +71 -0
  143. package/dist/extensions/mcp/mcp-panel.d.ts.map +1 -0
  144. package/dist/extensions/mcp/mcp-panel.js +973 -0
  145. package/dist/extensions/mcp/mcp-panel.js.map +1 -0
  146. package/dist/extensions/mcp/mcp-probe.d.ts +7 -0
  147. package/dist/extensions/mcp/mcp-probe.d.ts.map +1 -0
  148. package/dist/extensions/mcp/mcp-probe.js +155 -0
  149. package/dist/extensions/mcp/mcp-probe.js.map +1 -0
  150. package/dist/extensions/mcp/mcp-script-worker.mjs +130 -0
  151. package/dist/extensions/mcp/mcp-setup-panel.d.ts +85 -0
  152. package/dist/extensions/mcp/mcp-setup-panel.d.ts.map +1 -0
  153. package/dist/extensions/mcp/mcp-setup-panel.js +618 -0
  154. package/dist/extensions/mcp/mcp-setup-panel.js.map +1 -0
  155. package/dist/extensions/mcp/mcp-status.d.ts +12 -0
  156. package/dist/extensions/mcp/mcp-status.d.ts.map +1 -0
  157. package/dist/extensions/mcp/mcp-status.js +98 -0
  158. package/dist/extensions/mcp/mcp-status.js.map +1 -0
  159. package/dist/extensions/mcp/mcp-trace.d.ts +95 -0
  160. package/dist/extensions/mcp/mcp-trace.d.ts.map +1 -0
  161. package/dist/extensions/mcp/mcp-trace.js +252 -0
  162. package/dist/extensions/mcp/mcp-trace.js.map +1 -0
  163. package/dist/extensions/mcp/metadata-cache.d.ts +20 -0
  164. package/dist/extensions/mcp/metadata-cache.d.ts.map +1 -0
  165. package/dist/extensions/mcp/metadata-cache.js +318 -0
  166. package/dist/extensions/mcp/metadata-cache.js.map +1 -0
  167. package/dist/extensions/mcp/npx-resolver.d.ts +7 -0
  168. package/dist/extensions/mcp/npx-resolver.d.ts.map +1 -0
  169. package/dist/extensions/mcp/npx-resolver.js +505 -0
  170. package/dist/extensions/mcp/npx-resolver.js.map +1 -0
  171. package/dist/extensions/mcp/oauth.d.ts +21 -0
  172. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  173. package/dist/extensions/mcp/oauth.js +15 -0
  174. package/dist/extensions/mcp/oauth.js.map +1 -0
  175. package/dist/extensions/mcp/onboarding-state.d.ts +13 -0
  176. package/dist/extensions/mcp/onboarding-state.d.ts.map +1 -0
  177. package/dist/extensions/mcp/onboarding-state.js +65 -0
  178. package/dist/extensions/mcp/onboarding-state.js.map +1 -0
  179. package/dist/extensions/mcp/package-mcp-loader.d.ts +3 -0
  180. package/dist/extensions/mcp/package-mcp-loader.d.ts.map +1 -0
  181. package/dist/extensions/mcp/package-mcp-loader.js +170 -0
  182. package/dist/extensions/mcp/package-mcp-loader.js.map +1 -0
  183. package/dist/extensions/mcp/panel-keys.d.ts +21 -0
  184. package/dist/extensions/mcp/panel-keys.d.ts.map +1 -0
  185. package/dist/extensions/mcp/panel-keys.js +29 -0
  186. package/dist/extensions/mcp/panel-keys.js.map +1 -0
  187. package/dist/extensions/mcp/prompts.d.ts +63 -0
  188. package/dist/extensions/mcp/prompts.d.ts.map +1 -0
  189. package/dist/extensions/mcp/prompts.js +297 -0
  190. package/dist/extensions/mcp/prompts.js.map +1 -0
  191. package/dist/extensions/mcp/proxy-modes.d.ts +15 -0
  192. package/dist/extensions/mcp/proxy-modes.d.ts.map +1 -0
  193. package/dist/extensions/mcp/proxy-modes.js +1421 -0
  194. package/dist/extensions/mcp/proxy-modes.js.map +1 -0
  195. package/dist/extensions/mcp/request-headers-command.d.ts +11 -0
  196. package/dist/extensions/mcp/request-headers-command.d.ts.map +1 -0
  197. package/dist/extensions/mcp/request-headers-command.js +334 -0
  198. package/dist/extensions/mcp/request-headers-command.js.map +1 -0
  199. package/dist/extensions/mcp/resource-tools.d.ts +2 -0
  200. package/dist/extensions/mcp/resource-tools.d.ts.map +1 -0
  201. package/dist/extensions/mcp/resource-tools.js +15 -0
  202. package/dist/extensions/mcp/resource-tools.js.map +1 -0
  203. package/dist/extensions/mcp/runtime-owner.d.ts +14 -0
  204. package/dist/extensions/mcp/runtime-owner.d.ts.map +1 -0
  205. package/dist/extensions/mcp/runtime-owner.js +84 -0
  206. package/dist/extensions/mcp/runtime-owner.js.map +1 -0
  207. package/dist/extensions/mcp/sampling-handler.d.ts +18 -0
  208. package/dist/extensions/mcp/sampling-handler.d.ts.map +1 -0
  209. package/dist/extensions/mcp/sampling-handler.js +229 -0
  210. package/dist/extensions/mcp/sampling-handler.js.map +1 -0
  211. package/dist/extensions/mcp/search-ranking.d.ts +25 -0
  212. package/dist/extensions/mcp/search-ranking.d.ts.map +1 -0
  213. package/dist/extensions/mcp/search-ranking.js +234 -0
  214. package/dist/extensions/mcp/search-ranking.js.map +1 -0
  215. package/dist/extensions/mcp/server-manager.d.ts +116 -0
  216. package/dist/extensions/mcp/server-manager.d.ts.map +1 -0
  217. package/dist/extensions/mcp/server-manager.js +1052 -0
  218. package/dist/extensions/mcp/server-manager.js.map +1 -0
  219. package/dist/extensions/mcp/session-recovery.d.ts +27 -0
  220. package/dist/extensions/mcp/session-recovery.d.ts.map +1 -0
  221. package/dist/extensions/mcp/session-recovery.js +140 -0
  222. package/dist/extensions/mcp/session-recovery.js.map +1 -0
  223. package/dist/extensions/mcp/skills/mcp-scripting/SKILL.md +38 -0
  224. package/dist/extensions/mcp/state.d.ts +62 -0
  225. package/dist/extensions/mcp/state.d.ts.map +1 -0
  226. package/dist/extensions/mcp/state.js +2 -0
  227. package/dist/extensions/mcp/state.js.map +1 -0
  228. package/dist/extensions/mcp/tool-approval.d.ts +11 -0
  229. package/dist/extensions/mcp/tool-approval.d.ts.map +1 -0
  230. package/dist/extensions/mcp/tool-approval.js +156 -0
  231. package/dist/extensions/mcp/tool-approval.js.map +1 -0
  232. package/dist/extensions/mcp/tool-metadata.d.ts +11 -0
  233. package/dist/extensions/mcp/tool-metadata.d.ts.map +1 -0
  234. package/dist/extensions/mcp/tool-metadata.js +264 -0
  235. package/dist/extensions/mcp/tool-metadata.js.map +1 -0
  236. package/dist/extensions/mcp/tool-registrar.d.ts +21 -0
  237. package/dist/extensions/mcp/tool-registrar.d.ts.map +1 -0
  238. package/dist/extensions/mcp/tool-registrar.js +229 -0
  239. package/dist/extensions/mcp/tool-registrar.js.map +1 -0
  240. package/dist/extensions/mcp/tool-result-renderer.d.ts +83 -0
  241. package/dist/extensions/mcp/tool-result-renderer.d.ts.map +1 -0
  242. package/dist/extensions/mcp/tool-result-renderer.js +345 -0
  243. package/dist/extensions/mcp/tool-result-renderer.js.map +1 -0
  244. package/dist/extensions/mcp/ts-shape.d.ts +3 -0
  245. package/dist/extensions/mcp/ts-shape.d.ts.map +1 -0
  246. package/dist/extensions/mcp/ts-shape.js +160 -0
  247. package/dist/extensions/mcp/ts-shape.js.map +1 -0
  248. package/dist/extensions/mcp/types.d.ts +521 -0
  249. package/dist/extensions/mcp/types.d.ts.map +1 -0
  250. package/dist/extensions/mcp/types.js +294 -0
  251. package/dist/extensions/mcp/types.js.map +1 -0
  252. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts +7 -0
  253. package/dist/extensions/mcp/ui-app-bridge-helpers.d.ts.map +1 -0
  254. package/dist/extensions/mcp/ui-app-bridge-helpers.js +37 -0
  255. package/dist/extensions/mcp/ui-app-bridge-helpers.js.map +1 -0
  256. package/dist/extensions/mcp/ui-resource-handler.d.ts +18 -0
  257. package/dist/extensions/mcp/ui-resource-handler.d.ts.map +1 -0
  258. package/dist/extensions/mcp/ui-resource-handler.js +210 -0
  259. package/dist/extensions/mcp/ui-resource-handler.js.map +1 -0
  260. package/dist/extensions/mcp/ui-server.d.ts +52 -0
  261. package/dist/extensions/mcp/ui-server.d.ts.map +1 -0
  262. package/dist/extensions/mcp/ui-server.js +740 -0
  263. package/dist/extensions/mcp/ui-server.js.map +1 -0
  264. package/dist/extensions/mcp/ui-session.d.ts +40 -0
  265. package/dist/extensions/mcp/ui-session.d.ts.map +1 -0
  266. package/dist/extensions/mcp/ui-session.js +477 -0
  267. package/dist/extensions/mcp/ui-session.js.map +1 -0
  268. package/dist/extensions/mcp/ui-stream-types.d.ts +105 -0
  269. package/dist/extensions/mcp/ui-stream-types.d.ts.map +1 -0
  270. package/dist/extensions/mcp/ui-stream-types.js +61 -0
  271. package/dist/extensions/mcp/ui-stream-types.js.map +1 -0
  272. package/dist/extensions/mcp/ui-tool-visibility.d.ts +5 -0
  273. package/dist/extensions/mcp/ui-tool-visibility.d.ts.map +1 -0
  274. package/dist/extensions/mcp/ui-tool-visibility.js +27 -0
  275. package/dist/extensions/mcp/ui-tool-visibility.js.map +1 -0
  276. package/dist/extensions/mcp/unix-socket-transport.d.ts +15 -0
  277. package/dist/extensions/mcp/unix-socket-transport.d.ts.map +1 -0
  278. package/dist/extensions/mcp/unix-socket-transport.js +85 -0
  279. package/dist/extensions/mcp/unix-socket-transport.js.map +1 -0
  280. package/dist/extensions/mcp/utils.d.ts +32 -0
  281. package/dist/extensions/mcp/utils.d.ts.map +1 -0
  282. package/dist/extensions/mcp/utils.js +336 -0
  283. package/dist/extensions/mcp/utils.js.map +1 -0
  284. package/dist/extensions/subagent/index.d.ts +61 -1
  285. package/dist/extensions/subagent/index.d.ts.map +1 -1
  286. package/dist/extensions/subagent/index.js +177 -4
  287. package/dist/extensions/subagent/index.js.map +1 -1
  288. package/dist/extensions/web-access.d.ts.map +1 -1
  289. package/dist/extensions/web-access.js +1 -1
  290. package/dist/extensions/web-access.js.map +1 -1
  291. package/dist/index.d.ts +2 -0
  292. package/dist/index.d.ts.map +1 -1
  293. package/dist/index.js +20057 -1947
  294. package/dist/index.js.map +1 -1
  295. package/dist/mcp-keyring-helper.cjs +89 -0
  296. package/dist/mcp-script-worker.mjs +130 -0
  297. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  298. package/dist/modes/interactive/components/model-selector.js +1 -1
  299. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  300. package/dist/modes/interactive/components/response-separator.d.ts +1 -1
  301. package/dist/modes/interactive/components/response-separator.d.ts.map +1 -1
  302. package/dist/modes/interactive/components/response-separator.js +1 -1
  303. package/dist/modes/interactive/components/response-separator.js.map +1 -1
  304. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  305. package/dist/modes/interactive/interactive-mode.js +7 -5
  306. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  307. package/dist/rpc-entry.js +20263 -2158
  308. package/dist/skills/mcp-scripting/SKILL.md +38 -0
  309. package/dist/vendor/ai.js +280 -205
  310. package/docs/mcp.md +178 -0
  311. package/docs/pi-subagents.md +75 -0
  312. package/docs/quickstart.md +1 -1
  313. package/docs/usage.md +2 -1
  314. package/examples/extensions/pi-subagents-worker-policy.ts +86 -0
  315. package/npm-shrinkwrap.json +763 -6
  316. package/package.json +15 -4
  317. package/dist/extensions/mcp/client.d.ts +0 -86
  318. package/dist/extensions/mcp/client.d.ts.map +0 -1
  319. package/dist/extensions/mcp/client.js +0 -275
  320. package/dist/extensions/mcp/client.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-bearer-store.js","sourceRoot":"","sources":["../../../src/extensions/mcp/mcp-bearer-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\n\ntype KeyringEntry = {\n\tgetPassword(): string | null;\n\tsetPassword(password: string): void;\n\tdeleteCredential(): boolean;\n};\n\ntype KeyringEntryConstructor = new (service: string, account: string) => KeyringEntry;\ntype KeyringModule = { Entry: KeyringEntryConstructor };\ntype KeyringRequire = ((id: string) => unknown) & { resolve(id: string): string };\n\ntype BearerSecretStore = {\n\tread(account: string): string | undefined;\n\twrite(account: string, payload: string): void;\n\tremove(account: string): void;\n};\n\ninterface StoredBearerTokenRecord {\n\ttoken: string;\n\tserverUrl: string;\n}\n\ninterface BearerChunkManifest {\n\t__nexusMcpBearerChunked: 1;\n\tchunkCount: number;\n\tchunkDigest: string;\n}\n\nconst require = createRequire(import.meta.url);\nconst BEARER_SECRET_SERVICE = \"nexus-mcp.bearer\";\nconst TEST_AUTH_STORE_ENV = \"NEXUS_MCP_TEST_AUTH_STORE\";\nconst BEARER_SECRET_CHUNK_SIZE = 1000;\nconst BEARER_SECRET_VALUE_LIMIT = 1280;\nconst MAX_BEARER_SECRET_CHUNKS = 128;\n\nlet KeyringEntryClass: KeyringEntryConstructor | undefined;\nconst memoryBearerEntries = new Map<string, string>();\nlet testBearerSecretStoreReadCount = 0;\n\nexport class BearerCredentialStoreError extends Error {\n\treadonly code = \"BEARER_CREDENTIAL_STORE_UNAVAILABLE\";\n\treadonly operation: \"read\" | \"write\" | \"remove\";\n\n\t// No parameter properties: cli.js loads this module under plain Node\n\t// type stripping, which rejects non-erasable TypeScript syntax.\n\tconstructor(message: string, operation: \"read\" | \"write\" | \"remove\", cause: unknown) {\n\t\tsuper(message, { cause });\n\t\tthis.name = \"BearerCredentialStoreError\";\n\t\tthis.operation = operation;\n\t}\n}\n\nexport type BearerCredentialStatus =\n\t| { status: \"present\" }\n\t| { status: \"missing\" }\n\t| { status: \"url-mismatch\" }\n\t| { status: \"unavailable\"; message: string };\n\nconst memoryBearerSecretStore: BearerSecretStore = {\n\tread(account) {\n\t\ttestBearerSecretStoreReadCount++;\n\t\treturn memoryBearerEntries.get(account);\n\t},\n\twrite(account, payload) {\n\t\tmemoryBearerEntries.set(account, payload);\n\t},\n\tremove(account) {\n\t\tmemoryBearerEntries.delete(account);\n\t},\n};\n\nconst sizeLimitedBearerSecretStore: BearerSecretStore = {\n\tread(account) {\n\t\ttestBearerSecretStoreReadCount++;\n\t\treturn memoryBearerEntries.get(account);\n\t},\n\twrite(account, payload) {\n\t\tif (payload.length > BEARER_SECRET_VALUE_LIMIT) {\n\t\t\tthrow new Error(\n\t\t\t\t`Value of 'password encoded as UTF-16' is longer than the platform limit of ${BEARER_SECRET_VALUE_LIMIT * 2} chars`,\n\t\t\t);\n\t\t}\n\t\tmemoryBearerEntries.set(account, payload);\n\t},\n\tremove(account) {\n\t\tmemoryBearerEntries.delete(account);\n\t},\n};\n\nconst unavailableBearerSecretStore: BearerSecretStore = {\n\tread() {\n\t\ttestBearerSecretStoreReadCount++;\n\t\tthrow new Error(\"simulated secure credential store unavailable\");\n\t},\n\twrite() {\n\t\tthrow new Error(\"simulated secure credential store unavailable\");\n\t},\n\tremove() {\n\t\tthrow new Error(\"simulated secure credential store unavailable\");\n\t},\n};\n\nconst keyringBearerSecretStore: BearerSecretStore = {\n\tread(account) {\n\t\treturn getKeyringEntry(account).getPassword() ?? undefined;\n\t},\n\twrite(account, payload) {\n\t\tgetKeyringEntry(account).setPassword(payload);\n\t},\n\tremove(account) {\n\t\tgetKeyringEntry(account).deleteCredential();\n\t},\n};\n\nfunction getBearerSecretStore(): BearerSecretStore {\n\tif (process.env[TEST_AUTH_STORE_ENV] === \"memory\") return memoryBearerSecretStore;\n\tif (process.env[TEST_AUTH_STORE_ENV] === \"sizelimited\") return sizeLimitedBearerSecretStore;\n\tif (process.env[TEST_AUTH_STORE_ENV] === \"unavailable\") return unavailableBearerSecretStore;\n\treturn keyringBearerSecretStore;\n}\n\nfunction getKeyringEntry(account: string): KeyringEntry {\n\ttry {\n\t\tKeyringEntryClass ??= loadKeyringEntryClass();\n\t\treturn new KeyringEntryClass(BEARER_SECRET_SERVICE, account);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t\"Bearer token secure credential storage is unavailable. Configure the OS credential store and retry.\",\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nfunction loadKeyringEntryClass(\n\tkeyringRequire: KeyringRequire = require,\n\tplatform: NodeJS.Platform = process.platform,\n\tarch: NodeJS.Architecture = process.arch,\n): KeyringEntryConstructor {\n\ttry {\n\t\treturn (keyringRequire(\"@napi-rs/keyring\") as KeyringModule).Entry;\n\t} catch (loaderError) {\n\t\ttry {\n\t\t\treturn loadKeyringNativeBindingFallback(keyringRequire, platform, arch).Entry;\n\t\t} catch (fallbackError) {\n\t\t\tconst message = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to load @napi-rs/keyring; absolute-path native binding fallback also failed: ${message}`,\n\t\t\t\t{ cause: loaderError },\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction loadKeyringNativeBindingFallback(\n\tkeyringRequire: KeyringRequire,\n\tplatform: NodeJS.Platform,\n\tarch: NodeJS.Architecture,\n): KeyringModule {\n\tconst targets = getKeyringNativeBindingSuffixes(platform, arch).map((suffix) => ({\n\t\tpackageName: `@napi-rs/keyring-${suffix}`,\n\t\tbindingFile: `keyring.${suffix}.node`,\n\t}));\n\tlet lastError: unknown;\n\tfor (const target of targets) {\n\t\ttry {\n\t\t\tconst packageJsonPath = keyringRequire.resolve(`${target.packageName}/package.json`);\n\t\t\treturn keyringRequire(join(dirname(packageJsonPath), target.bindingFile)) as KeyringModule;\n\t\t} catch (error) {\n\t\t\tlastError = error;\n\t\t}\n\t}\n\tthrow lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\nfunction getKeyringNativeBindingSuffixes(platform: NodeJS.Platform, arch: NodeJS.Architecture): string[] {\n\tif (platform === \"darwin\") {\n\t\tif (arch === \"arm64\") return [\"darwin-arm64\"];\n\t\tif (arch === \"x64\") return [\"darwin-x64\"];\n\t}\n\tif (platform === \"win32\") {\n\t\tif (arch === \"arm64\") return [\"win32-arm64-msvc\"];\n\t\tif (arch === \"x64\") return [\"win32-x64-msvc\"];\n\t\tif (arch === \"ia32\") return [\"win32-ia32-msvc\"];\n\t}\n\tif (platform === \"linux\") {\n\t\tif (arch === \"arm64\") return [\"linux-arm64-gnu\", \"linux-arm64-musl\"];\n\t\tif (arch === \"arm\") return [\"linux-arm-gnueabihf\"];\n\t\tif (arch === \"riscv64\") return [\"linux-riscv64-gnu\"];\n\t\tif (arch === \"x64\") return [\"linux-x64-gnu\", \"linux-x64-musl\"];\n\t}\n\tif (platform === \"freebsd\" && arch === \"x64\") return [\"freebsd-x64\"];\n\treturn [];\n}\n\nfunction getBearerAccount(serverName: string): string {\n\tif (typeof serverName !== \"string\") {\n\t\tthrow new Error(`Invalid MCP server name: ${JSON.stringify(serverName)}`);\n\t}\n\treturn `sha256-${createHash(\"sha256\").update(serverName, \"utf8\").digest(\"hex\")}`;\n}\n\nfunction parseBearerPayload(serverName: string, payload: string): StoredBearerTokenRecord {\n\tconst parsed = parseStoredBearerJson(serverName, payload);\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Stored bearer token record for ${serverName} has invalid shape`);\n\t}\n\tconst record = parsed as Partial<StoredBearerTokenRecord>;\n\tif (typeof record.token !== \"string\" || typeof record.serverUrl !== \"string\") {\n\t\tthrow new Error(`Stored bearer token record for ${serverName} has invalid shape`);\n\t}\n\treturn { token: record.token, serverUrl: record.serverUrl };\n}\n\nfunction parseStoredBearerJson(serverName: string, payload: string): unknown {\n\ttry {\n\t\treturn JSON.parse(payload) as unknown;\n\t} catch {\n\t\tthrow new Error(`Failed to parse stored bearer token record for ${serverName}`);\n\t}\n}\n\nfunction isBearerChunkManifest(value: unknown): value is BearerChunkManifest {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst manifest = value as Partial<BearerChunkManifest>;\n\treturn (\n\t\tmanifest.__nexusMcpBearerChunked === 1 &&\n\t\ttypeof manifest.chunkCount === \"number\" &&\n\t\tNumber.isInteger(manifest.chunkCount) &&\n\t\tmanifest.chunkCount > 0 &&\n\t\tmanifest.chunkCount <= MAX_BEARER_SECRET_CHUNKS &&\n\t\ttypeof manifest.chunkDigest === \"string\" &&\n\t\t/^[a-f0-9]{16}$/.test(manifest.chunkDigest)\n\t);\n}\n\nfunction readManifest(serverName: string, payload: string): BearerChunkManifest | undefined {\n\tconst parsed = parseStoredBearerJson(serverName, payload);\n\treturn isBearerChunkManifest(parsed) ? parsed : undefined;\n}\n\nfunction chunkAccount(account: string, manifest: BearerChunkManifest, index: number): string {\n\treturn `${account}.chunk.${manifest.chunkDigest}.${index}`;\n}\n\nfunction chunkAccounts(account: string, manifest: BearerChunkManifest): string[] {\n\treturn Array.from({ length: manifest.chunkCount }, (_, index) => chunkAccount(account, manifest, index));\n}\n\nfunction createManifest(payload: string): BearerChunkManifest {\n\treturn {\n\t\t__nexusMcpBearerChunked: 1,\n\t\tchunkCount: Math.ceil(payload.length / BEARER_SECRET_CHUNK_SIZE),\n\t\tchunkDigest: createHash(\"sha256\").update(payload, \"utf8\").digest(\"hex\").slice(0, 16),\n\t};\n}\n\nfunction readExistingManifest(\n\tstore: BearerSecretStore,\n\tserverName: string,\n\taccount: string,\n): BearerChunkManifest | undefined {\n\ttry {\n\t\tconst payload = store.read(account);\n\t\treturn payload === undefined ? undefined : readManifest(serverName, payload);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction removeChunks(store: BearerSecretStore, account: string, manifest: BearerChunkManifest | undefined): void {\n\tif (!manifest) return;\n\tfor (const accountName of chunkAccounts(account, manifest)) store.remove(accountName);\n}\n\nfunction tryRemoveChunks(store: BearerSecretStore, account: string, manifest: BearerChunkManifest | undefined): void {\n\ttry {\n\t\tremoveChunks(store, account, manifest);\n\t} catch {\n\t\t// Stale chunk cleanup must not hide a successful credential write.\n\t}\n}\n\nfunction readBearerRecordFromStore(store: BearerSecretStore, serverName: string): StoredBearerTokenRecord | undefined {\n\tconst account = getBearerAccount(serverName);\n\tlet payload: string | undefined;\n\ttry {\n\t\tpayload = store.read(account);\n\t} catch (error) {\n\t\tthrow new BearerCredentialStoreError(\n\t\t\t`Failed to read bearer token for ${serverName} from the OS secure credential store`,\n\t\t\t\"read\",\n\t\t\terror,\n\t\t);\n\t}\n\tif (payload === undefined) return undefined;\n\ttry {\n\t\tconst manifest = readManifest(serverName, payload);\n\t\tconst recordPayload = manifest\n\t\t\t? chunkAccounts(account, manifest)\n\t\t\t\t\t.map((chunkName) => {\n\t\t\t\t\t\tconst chunk = store.read(chunkName);\n\t\t\t\t\t\tif (chunk === undefined) throw new Error(`Missing bearer token chunk for ${serverName}`);\n\t\t\t\t\t\treturn chunk;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\")\n\t\t\t: payload;\n\t\tif (manifest) {\n\t\t\tconst digest = createHash(\"sha256\").update(recordPayload, \"utf8\").digest(\"hex\").slice(0, 16);\n\t\t\tif (digest !== manifest.chunkDigest) throw new Error(`Bearer token chunk digest mismatch for ${serverName}`);\n\t\t}\n\t\treturn parseBearerPayload(serverName, recordPayload);\n\t} catch (error) {\n\t\tthrow new BearerCredentialStoreError(\n\t\t\t`Failed to read bearer token for ${serverName} from the OS secure credential store`,\n\t\t\t\"read\",\n\t\t\terror,\n\t\t);\n\t}\n}\n\nfunction writeBearerRecordToStore(store: BearerSecretStore, serverName: string, record: StoredBearerTokenRecord): void {\n\tconst account = getBearerAccount(serverName);\n\tconst payload = JSON.stringify(record);\n\tconst previousManifest = readExistingManifest(store, serverName, account);\n\tconst manifest = payload.length > BEARER_SECRET_CHUNK_SIZE ? createManifest(payload) : undefined;\n\ttry {\n\t\tif (manifest) {\n\t\t\tfor (let index = 0; index < manifest.chunkCount; index++) {\n\t\t\t\tstore.write(\n\t\t\t\t\tchunkAccount(account, manifest, index),\n\t\t\t\t\tpayload.slice(index * BEARER_SECRET_CHUNK_SIZE, (index + 1) * BEARER_SECRET_CHUNK_SIZE),\n\t\t\t\t);\n\t\t\t}\n\t\t\tstore.write(account, JSON.stringify(manifest));\n\t\t} else {\n\t\t\tstore.write(account, payload);\n\t\t}\n\t\tif (previousManifest?.chunkDigest !== manifest?.chunkDigest) {\n\t\t\ttryRemoveChunks(store, account, previousManifest);\n\t\t}\n\t} catch (error) {\n\t\t// An identical payload reuses the previous manifest's digest-keyed chunk\n\t\t// accounts. Removing them on a failed rewrite would destroy the still\n\t\t// installed previous credential, so clean up only digest-distinct chunks.\n\t\tif (previousManifest?.chunkDigest !== manifest?.chunkDigest) {\n\t\t\ttryRemoveChunks(store, account, manifest);\n\t\t}\n\t\tthrow new BearerCredentialStoreError(\n\t\t\t`Failed to write bearer token for ${serverName} to the OS secure credential store`,\n\t\t\t\"write\",\n\t\t\terror,\n\t\t);\n\t}\n}\n\nfunction removeBearerRecordFromStore(store: BearerSecretStore, serverName: string): void {\n\tconst account = getBearerAccount(serverName);\n\ttry {\n\t\tconst payload = store.read(account);\n\t\tconst manifest = payload === undefined ? undefined : readManifest(serverName, payload);\n\t\tremoveChunks(store, account, manifest);\n\t\tstore.remove(account);\n\t} catch (error) {\n\t\tthrow new BearerCredentialStoreError(\n\t\t\t`Failed to remove bearer token for ${serverName} from the OS secure credential store`,\n\t\t\t\"remove\",\n\t\t\terror,\n\t\t);\n\t}\n}\n\nexport function getBearerTokenForUrl(serverName: string, serverUrl: string): string | undefined {\n\tconst record = readBearerRecordFromStore(getBearerSecretStore(), serverName);\n\tif (!record) return undefined;\n\treturn record.serverUrl === serverUrl ? record.token : undefined;\n}\n\nexport function saveBearerTokenForUrl(serverName: string, token: string, serverUrl: string): void {\n\twriteBearerRecordToStore(getBearerSecretStore(), serverName, { token, serverUrl });\n}\n\nexport function removeBearerToken(serverName: string): void {\n\tremoveBearerRecordFromStore(getBearerSecretStore(), serverName);\n}\n\nexport function inspectBearerTokenForUrl(serverName: string, serverUrl: string): BearerCredentialStatus {\n\ttry {\n\t\tconst record = readBearerRecordFromStore(getBearerSecretStore(), serverName);\n\t\tif (!record) return { status: \"missing\" };\n\t\tif (record.serverUrl !== serverUrl) return { status: \"url-mismatch\" };\n\t\treturn { status: \"present\" };\n\t} catch (error) {\n\t\tif (!(error instanceof BearerCredentialStoreError)) throw error;\n\t\treturn {\n\t\t\tstatus: \"unavailable\",\n\t\t\tmessage:\n\t\t\t\t\"Bearer token secure credential store unavailable. Configure or unlock the OS credential store and retry.\",\n\t\t};\n\t}\n}\n\nexport function resetTestBearerTokenStore(): void {\n\tmemoryBearerEntries.clear();\n\ttestBearerSecretStoreReadCount = 0;\n}\n\nexport function getTestBearerTokenStoreEntries(): [string, string][] {\n\treturn [...memoryBearerEntries.entries()];\n}\n\nexport function removeTestBearerTokenStoreEntry(account: string): void {\n\tmemoryBearerEntries.delete(account);\n}\n\nexport function setTestBearerTokenStoreEntry(account: string, payload: string): void {\n\tmemoryBearerEntries.set(account, payload);\n}\n\nexport function getTestBearerTokenStoreReadCount(): number {\n\treturn testBearerSecretStoreReadCount;\n}\n"]}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * MCP OAuth Callback Server
3
+ *
4
+ * HTTP server that handles OAuth callbacks from the authorization server.
5
+ * Uses Node.js http module for compatibility.
6
+ */
7
+ /** Result of a successful OAuth callback */
8
+ export interface OAuthCallbackResult {
9
+ code: string;
10
+ /** RFC 9207 `iss` authorization response parameter, when provided */
11
+ iss?: string;
12
+ }
13
+ interface EnsureCallbackServerOptions {
14
+ strictPort?: boolean;
15
+ port?: number;
16
+ callbackHost?: string;
17
+ callbackPath?: string;
18
+ oauthState?: string;
19
+ reserveState?: boolean;
20
+ }
21
+ /**
22
+ * Ensure the callback server is running.
23
+ * If strictPort is true, requires binding on the configured callback port.
24
+ * If strictPort is false, asks the OS for an available local port.
25
+ */
26
+ export declare function ensureCallbackServer(options?: EnsureCallbackServerOptions): Promise<void>;
27
+ export declare function reserveCallbackServer(oauthState: string): void;
28
+ export declare function releaseCallbackServer(oauthState: string): void;
29
+ /**
30
+ * Wait for a callback with the given OAuth state.
31
+ * Returns a promise that resolves with the authorization code and, when the
32
+ * authorization server sends one, the RFC 9207 `iss` parameter.
33
+ */
34
+ export declare function waitForCallback(oauthState: string): Promise<OAuthCallbackResult>;
35
+ /**
36
+ * Cancel a pending authorization by state.
37
+ */
38
+ export declare function cancelPendingCallback(oauthState: string): void;
39
+ /**
40
+ * Stop the callback server and reject all pending authorizations.
41
+ */
42
+ export declare function stopCallbackServer(): Promise<void>;
43
+ /** Stop the callback server only when no bind or authorization owns it. */
44
+ export declare function stopCallbackServerIfIdle(): Promise<void>;
45
+ /**
46
+ * Check if the callback server is running.
47
+ */
48
+ export declare function isCallbackServerRunning(): boolean;
49
+ /**
50
+ * Get the number of pending authorizations.
51
+ */
52
+ export declare function getPendingAuthCount(): number;
53
+ export {};
54
+ //# sourceMappingURL=mcp-callback-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-callback-server.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/mcp-callback-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoJH,4CAA4C;AAC5C,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAwBD,UAAU,2BAA2B;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAgGD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,2BAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BnG;AAsGD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAG9D;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAG9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmBhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAS9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4ClD;AAED,2EAA2E;AAC3E,wBAAgB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUxD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C","sourcesContent":["/**\n * MCP OAuth Callback Server\n *\n * HTTP server that handles OAuth callbacks from the authorization server.\n * Uses Node.js http module for compatibility.\n */\n\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"http\";\nimport { getAppName } from \"./agent-dir.ts\";\nimport {\n\tDEFAULT_OAUTH_CALLBACK_PATH,\n\tgetConfiguredOAuthCallbackPort,\n\tgetOAuthCallbackPath,\n\tgetOAuthCallbackPort,\n\tsetOAuthCallbackPath,\n\tsetOAuthCallbackPort,\n} from \"./mcp-oauth-provider.ts\";\n\n// HTML templates for callback responses.\n//\n// These pages are served from localhost during OAuth and are the last thing a\n// user sees before returning to their terminal, so they are self-contained: no\n// webfonts, no external assets, nothing that needs the network. They also name\n// the host rather than hardcoding \"Nexus\", so a distribution that rebrands nexus\n// (arc, tau, …) does not send its users back to an app they are not running.\n\n/** Shared chrome: system fonts, a centred card, and light/dark support. */\nconst PAGE_STYLE = `\n :root { color-scheme: light dark; }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif;\n background: #0f1117;\n color: #e6e8ee;\n }\n .card {\n width: 100%;\n max-width: 26rem;\n padding: 2.5rem 2rem;\n text-align: center;\n background: #161922;\n border: 1px solid #242938;\n border-radius: 14px;\n box-shadow: 0 1px 2px rgba(0,0,0,.3), 0 12px 32px rgba(0,0,0,.25);\n }\n .badge {\n width: 3rem; height: 3rem;\n margin: 0 auto 1.25rem;\n display: grid; place-items: center;\n border-radius: 50%;\n }\n .badge svg { width: 1.5rem; height: 1.5rem; display: block; }\n .ok { background: rgba(74,222,128,.12); color: #4ade80; }\n .bad { background: rgba(248,113,113,.12); color: #f87171; }\n h1 { margin: 0 0 .5rem; font-size: 1.15rem; font-weight: 600; letter-spacing: -0.01em; }\n p { margin: 0; color: #9aa1b1; }\n .app { color: #e6e8ee; font-weight: 500; }\n .hint { margin-top: 1.25rem; font-size: .8125rem; color: #6b7280; }\n code {\n display: block;\n margin-top: 1.25rem;\n padding: .75rem .875rem;\n text-align: left;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n color: #fca5a5;\n background: rgba(248,113,113,.08);\n border: 1px solid rgba(248,113,113,.2);\n border-radius: 8px;\n overflow-wrap: anywhere;\n }\n @media (prefers-color-scheme: light) {\n body { background: #f6f7f9; color: #121620; }\n .card { background: #fff; border-color: #e4e7ee; }\n p { color: #5b6474; }\n .app { color: #121620; }\n .hint { color: #8b93a3; }\n }`;\n\nconst CHECK_ICON =\n\t'<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M20 6 9 17l-5-5\"/></svg>';\n\nconst CROSS_ICON =\n\t'<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M18 6 6 18M6 6l12 12\"/></svg>';\n\nfunction page(options: {\n\ttitle: string;\n\theading: string;\n\tbody: string;\n\ticon: string;\n\ttone: \"ok\" | \"bad\";\n\textra?: string;\n\tautoClose?: boolean;\n}): string {\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${options.title}</title>\n <style>${PAGE_STYLE}\n </style>\n</head>\n<body>\n <main class=\"card\">\n <div class=\"badge ${options.tone}\">${options.icon}</div>\n <h1>${options.heading}</h1>\n <p>${options.body}</p>\n ${options.extra ?? \"\"}\n </main>\n${options.autoClose ? \" <script>setTimeout(() => window.close(), 2000);</script>\\n\" : \"\"}</body>\n</html>`;\n}\n\nfunction escapeHtml(value: string): string {\n\treturn value\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#39;\");\n}\n\n/** Built per request so authorization pages always use the Nexus product name. */\nfunction htmlSuccess(): string {\n\tconst app = escapeHtml(getAppName());\n\treturn page({\n\t\ttitle: `${app} — Authorization Successful`,\n\t\theading: \"Authorization Successful\",\n\t\tbody: `You can close this window and return to <span class=\"app\">${app}</span>.`,\n\t\ticon: CHECK_ICON,\n\t\ttone: \"ok\",\n\t\tautoClose: true,\n\t});\n}\n\nfunction htmlError(error: string): string {\n\tconst app = escapeHtml(getAppName());\n\treturn page({\n\t\ttitle: `${app} — Authorization Failed`,\n\t\theading: \"Authorization Failed\",\n\t\tbody: `Something went wrong during authorization. You can close this window and try again from <span class=\"app\">${app}</span>.`,\n\t\ticon: CROSS_ICON,\n\t\ttone: \"bad\",\n\t\textra: `<code>${escapeHtml(error)}</code>`,\n\t});\n}\n\n/** Result of a successful OAuth callback */\nexport interface OAuthCallbackResult {\n\tcode: string;\n\t/** RFC 9207 `iss` authorization response parameter, when provided */\n\tiss?: string;\n}\n\n/** Pending authorization request */\ninterface PendingAuth {\n\tresolve: (result: OAuthCallbackResult) => void;\n\treject: (error: Error) => void;\n\ttimeout: ReturnType<typeof setTimeout>;\n}\n\ntype EarlyAuthResult = { status: \"resolved\"; result: OAuthCallbackResult } | { status: \"rejected\"; error: Error };\n\n/** Server singleton state */\nlet server: Server | undefined;\nlet bindingPromise: Promise<void> | undefined;\nlet stoppingPromise: Promise<void> | undefined;\nlet restartableStoppingPromise: Promise<void> | undefined;\nlet callbackGeneration = 0;\nconst pendingAuths = new Map<string, PendingAuth>();\nconst reservedAuthStates = new Set<string>();\nconst earlyAuthResults = new Map<string, EarlyAuthResult>();\n\n/** Timeout for callback completion (5 minutes) */\nconst CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;\n\ninterface EnsureCallbackServerOptions {\n\tstrictPort?: boolean;\n\tport?: number;\n\tcallbackHost?: string;\n\tcallbackPath?: string;\n\toauthState?: string;\n\treserveState?: boolean;\n}\n\nconst DEFAULT_OAUTH_CALLBACK_HOST = \"localhost\";\nlet callbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST;\n\n/**\n * Handle incoming HTTP requests to the callback server.\n */\nfunction handleRequest(req: IncomingMessage, res: ServerResponse): void {\n\tconst url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n\n\t// Only handle the callback path\n\tif (url.pathname !== getOAuthCallbackPath()) {\n\t\tres.writeHead(404, { \"Content-Type\": \"text/plain\" });\n\t\tres.end(\"Not found\");\n\t\treturn;\n\t}\n\n\tconst code = url.searchParams.get(\"code\");\n\tconst iss = url.searchParams.get(\"iss\");\n\tconst state = url.searchParams.get(\"state\");\n\tconst error = url.searchParams.get(\"error\");\n\tconst errorDescription = url.searchParams.get(\"error_description\");\n\n\t// Enforce state parameter presence for CSRF protection\n\tif (!state) {\n\t\tconst errorMsg = \"Missing required state parameter - potential CSRF attack\";\n\t\tres.writeHead(400, { \"Content-Type\": \"text/html\" });\n\t\tres.end(htmlError(errorMsg));\n\t\treturn;\n\t}\n\n\tconst pending = pendingAuths.get(state);\n\tconst isReserved = reservedAuthStates.has(state);\n\n\t// Handle OAuth errors only for a state that belongs to an active flow.\n\tif (error) {\n\t\tif (!pending && !isReserved) {\n\t\t\tconst errorMsg = \"Invalid or expired state parameter - potential CSRF attack\";\n\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html\" });\n\t\t\tres.end(htmlError(errorMsg));\n\t\t\treturn;\n\t\t}\n\n\t\tconst errorMsg = errorDescription || error;\n\t\t// Send HTTP response first before rejecting promise\n\t\tres.writeHead(200, { \"Content-Type\": \"text/html\" });\n\t\tres.end(htmlError(errorMsg));\n\t\tif (pending) {\n\t\t\treservedAuthStates.delete(state);\n\t\t\tclearTimeout(pending.timeout);\n\t\t\tpendingAuths.delete(state);\n\t\t\t// Reject after the response is sent so callers can attach their handler.\n\t\t\tsetTimeout(() => pending.reject(new Error(errorMsg)), 0);\n\t\t} else {\n\t\t\treservedAuthStates.delete(state);\n\t\t\tearlyAuthResults.set(state, { status: \"rejected\", error: new Error(errorMsg) });\n\t\t}\n\t\treturn;\n\t}\n\n\t// Validate state parameter\n\tif (!pending && !isReserved) {\n\t\tconst errorMsg = \"Invalid or expired state parameter - potential CSRF attack\";\n\t\tres.writeHead(400, { \"Content-Type\": \"text/html\" });\n\t\tres.end(htmlError(errorMsg));\n\t\treturn;\n\t}\n\n\t// Require authorization code\n\tif (!code) {\n\t\tres.writeHead(400, { \"Content-Type\": \"text/html\" });\n\t\tres.end(htmlError(\"No authorization code provided\"));\n\t\treturn;\n\t}\n\n\tif (!pending) {\n\t\treservedAuthStates.delete(state);\n\t\tearlyAuthResults.set(state, {\n\t\t\tstatus: \"resolved\",\n\t\t\tresult: { code, ...(iss !== null ? { iss } : {}) },\n\t\t});\n\t\tres.writeHead(200, { \"Content-Type\": \"text/html\" });\n\t\tres.end(htmlSuccess());\n\t\treturn;\n\t}\n\n\t// Clear timeout and resolve the pending promise\n\tclearTimeout(pending.timeout);\n\tpendingAuths.delete(state);\n\tpending.resolve({ code, ...(iss !== null ? { iss } : {}) });\n\n\tres.writeHead(200, { \"Content-Type\": \"text/html\" });\n\tres.end(htmlSuccess());\n}\n\n/**\n * Ensure the callback server is running.\n * If strictPort is true, requires binding on the configured callback port.\n * If strictPort is false, asks the OS for an available local port.\n */\nexport async function ensureCallbackServer(options: EnsureCallbackServerOptions = {}): Promise<void> {\n\tconst generation = callbackGeneration;\n\tif (stoppingPromise) {\n\t\tif (!restartableStoppingPromise) {\n\t\t\tthrow new Error(\"OAuth callback server stopped\");\n\t\t}\n\t\tawait restartableStoppingPromise;\n\t\tif (generation !== callbackGeneration) {\n\t\t\tthrow new Error(\"OAuth callback server stopped\");\n\t\t}\n\t}\n\twhile (bindingPromise) {\n\t\tawait bindingPromise;\n\t\tif (generation !== callbackGeneration) {\n\t\t\tthrow new Error(\"OAuth callback server stopped\");\n\t\t}\n\t}\n\tif (generation !== callbackGeneration) {\n\t\tthrow new Error(\"OAuth callback server stopped\");\n\t}\n\n\tconst operation = ensureCallbackServerLocked(options);\n\tbindingPromise = operation;\n\ttry {\n\t\tawait operation;\n\t} finally {\n\t\tif (bindingPromise === operation) {\n\t\t\tbindingPromise = undefined;\n\t\t}\n\t}\n}\n\nasync function ensureCallbackServerLocked(options: EnsureCallbackServerOptions = {}): Promise<void> {\n\tconst requiredPort = options.port ?? getConfiguredOAuthCallbackPort();\n\tconst strictPort = options.strictPort === true;\n\tconst requestedHost = options.callbackHost ?? DEFAULT_OAUTH_CALLBACK_HOST;\n\tconst rawRequestedPath = options.callbackPath ?? DEFAULT_OAUTH_CALLBACK_PATH;\n\tconst requestedPath = rawRequestedPath.startsWith(\"/\") ? rawRequestedPath : `/${rawRequestedPath}`;\n\tif (options.reserveState && !options.oauthState) {\n\t\tthrow new Error(\"OAuth callback reservation requires an oauthState\");\n\t}\n\tlet reservedState: string | undefined;\n\n\tconst previousServer = server;\n\tconst needsStrictRebind = Boolean(previousServer && strictPort && getOAuthCallbackPort() !== requiredPort);\n\tconst needsHostSwitch = Boolean(previousServer && callbackServerHost !== requestedHost);\n\tconst needsPathSwitch = Boolean(previousServer && getOAuthCallbackPath() !== requestedPath);\n\n\tif (previousServer) {\n\t\tif (!needsStrictRebind && !needsHostSwitch) {\n\t\t\tif (needsPathSwitch) {\n\t\t\t\tif (pendingAuths.size > 0 || reservedAuthStates.size > 0) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`OAuth callback server is using path ${getOAuthCallbackPath()}, but callback path ${requestedPath} is required and cannot be switched while authorizations are pending`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tsetOAuthCallbackPath(requestedPath);\n\t\t\t}\n\t\t\tif (options.reserveState && options.oauthState) {\n\t\t\t\tearlyAuthResults.delete(options.oauthState);\n\t\t\t\treservedAuthStates.add(options.oauthState);\n\t\t\t\treservedState = options.oauthState;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (pendingAuths.size > 0 || reservedAuthStates.size > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`OAuth callback server is running on ${callbackServerHost}:${getOAuthCallbackPort()}, but strict callback endpoint ${requestedHost}:${requiredPort} is required and cannot be switched while authorizations are pending`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst candidateServer = createServer(handleRequest);\n\tconst listenPort = strictPort ? requiredPort : 0;\n\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tcandidateServer.once(\"error\", (err) => {\n\t\t\t\treject(err);\n\t\t\t});\n\n\t\t\tcandidateServer.listen(listenPort, requestedHost, () => {\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\n\t\tif (strictPort) {\n\t\t\tsetOAuthCallbackPort(requiredPort);\n\t\t} else {\n\t\t\tconst address = candidateServer.address();\n\t\t\tif (!address || typeof address === \"string\" || typeof address.port !== \"number\") {\n\t\t\t\tthrow new Error(\"OAuth callback server did not report an assigned port\");\n\t\t\t}\n\t\t\tsetOAuthCallbackPort(address.port);\n\t\t}\n\n\t\tif (previousServer && (needsStrictRebind || needsHostSwitch)) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tpreviousServer.close(() => resolve());\n\t\t\t});\n\t\t}\n\n\t\tcallbackServerHost = requestedHost;\n\t\tsetOAuthCallbackPath(requestedPath);\n\t\tserver = candidateServer;\n\t\tif (options.reserveState && options.oauthState) {\n\t\t\tearlyAuthResults.delete(options.oauthState);\n\t\t\treservedAuthStates.add(options.oauthState);\n\t\t\treservedState = options.oauthState;\n\t\t}\n\t\tserver.unref();\n\t} catch (error) {\n\t\tif (reservedState) {\n\t\t\treservedAuthStates.delete(reservedState);\n\t\t}\n\t\tconst nodeError = error as NodeJS.ErrnoException;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tcandidateServer.close(() => resolve());\n\t\t});\n\n\t\tif (strictPort && nodeError.code === \"EADDRINUSE\") {\n\t\t\tthrow new Error(\n\t\t\t\t`OAuth callback port ${requiredPort} is already in use. Pre-registered OAuth clients require an exact redirect URI; set MCP_OAUTH_CALLBACK_PORT to your registered port or free port ${requiredPort}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\nexport function reserveCallbackServer(oauthState: string): void {\n\tearlyAuthResults.delete(oauthState);\n\treservedAuthStates.add(oauthState);\n}\n\nexport function releaseCallbackServer(oauthState: string): void {\n\treservedAuthStates.delete(oauthState);\n\tearlyAuthResults.delete(oauthState);\n}\n\n/**\n * Wait for a callback with the given OAuth state.\n * Returns a promise that resolves with the authorization code and, when the\n * authorization server sends one, the RFC 9207 `iss` parameter.\n */\nexport function waitForCallback(oauthState: string): Promise<OAuthCallbackResult> {\n\treservedAuthStates.delete(oauthState);\n\tconst earlyResult = earlyAuthResults.get(oauthState);\n\tif (earlyResult) {\n\t\tearlyAuthResults.delete(oauthState);\n\t\treturn earlyResult.status === \"resolved\"\n\t\t\t? Promise.resolve(earlyResult.result)\n\t\t\t: Promise.reject(earlyResult.error);\n\t}\n\treturn new Promise((resolve, reject) => {\n\t\tconst timeout = setTimeout(() => {\n\t\t\tif (pendingAuths.has(oauthState)) {\n\t\t\t\tpendingAuths.delete(oauthState);\n\t\t\t\treject(new Error(\"OAuth callback timeout - authorization took too long\"));\n\t\t\t}\n\t\t}, CALLBACK_TIMEOUT_MS);\n\n\t\tpendingAuths.set(oauthState, { resolve, reject, timeout });\n\t});\n}\n\n/**\n * Cancel a pending authorization by state.\n */\nexport function cancelPendingCallback(oauthState: string): void {\n\treservedAuthStates.delete(oauthState);\n\tearlyAuthResults.delete(oauthState);\n\tconst pending = pendingAuths.get(oauthState);\n\tif (pending) {\n\t\tclearTimeout(pending.timeout);\n\t\tpendingAuths.delete(oauthState);\n\t\tpending.reject(new Error(\"Authorization cancelled\"));\n\t}\n}\n\n/**\n * Stop the callback server and reject all pending authorizations.\n */\nexport function stopCallbackServer(): Promise<void> {\n\tif (stoppingPromise) {\n\t\trestartableStoppingPromise = undefined;\n\t\tcallbackGeneration += 1;\n\t\treturn stoppingPromise;\n\t}\n\n\tcallbackGeneration += 1;\n\tconst cleanup = (async () => {\n\t\twhile (bindingPromise) {\n\t\t\tawait bindingPromise.catch(() => {});\n\t\t}\n\n\t\tif (server) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tserver!.close(() => {\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t});\n\t\t\tserver = undefined;\n\t\t}\n\n\t\tsetOAuthCallbackPort(getConfiguredOAuthCallbackPort());\n\t\tcallbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST;\n\t\tsetOAuthCallbackPath(DEFAULT_OAUTH_CALLBACK_PATH);\n\n\t\t// Reject all pending auths (defer to allow any pending operations to complete)\n\t\tconst pendingList = Array.from(pendingAuths.entries());\n\t\tpendingAuths.clear();\n\t\treservedAuthStates.clear();\n\t\tearlyAuthResults.clear();\n\t\tsetTimeout(() => {\n\t\t\tfor (const [, pending] of pendingList) {\n\t\t\t\tclearTimeout(pending.timeout);\n\t\t\t\tpending.reject(new Error(\"OAuth callback server stopped\"));\n\t\t\t}\n\t\t}, 0);\n\t})();\n\n\tconst operation = cleanup.finally(() => {\n\t\tif (stoppingPromise === operation) stoppingPromise = undefined;\n\t});\n\tstoppingPromise = operation;\n\treturn operation;\n}\n\n/** Stop the callback server only when no bind or authorization owns it. */\nexport function stopCallbackServerIfIdle(): Promise<void> {\n\tif (stoppingPromise) return stoppingPromise;\n\tif (bindingPromise || !server || pendingAuths.size > 0 || reservedAuthStates.size > 0) {\n\t\treturn Promise.resolve();\n\t}\n\tconst operation = stopCallbackServer().finally(() => {\n\t\tif (restartableStoppingPromise === operation) restartableStoppingPromise = undefined;\n\t});\n\trestartableStoppingPromise = operation;\n\treturn operation;\n}\n\n/**\n * Check if the callback server is running.\n */\nexport function isCallbackServerRunning(): boolean {\n\treturn server !== undefined;\n}\n\n/**\n * Get the number of pending authorizations.\n */\nexport function getPendingAuthCount(): number {\n\treturn pendingAuths.size;\n}\n"]}
@@ -0,0 +1,454 @@
1
+ /**
2
+ * MCP OAuth Callback Server
3
+ *
4
+ * HTTP server that handles OAuth callbacks from the authorization server.
5
+ * Uses Node.js http module for compatibility.
6
+ */
7
+ import { createServer } from "http";
8
+ import { getAppName } from "./agent-dir.js";
9
+ import { DEFAULT_OAUTH_CALLBACK_PATH, getConfiguredOAuthCallbackPort, getOAuthCallbackPath, getOAuthCallbackPort, setOAuthCallbackPath, setOAuthCallbackPort, } from "./mcp-oauth-provider.js";
10
+ // HTML templates for callback responses.
11
+ //
12
+ // These pages are served from localhost during OAuth and are the last thing a
13
+ // user sees before returning to their terminal, so they are self-contained: no
14
+ // webfonts, no external assets, nothing that needs the network. They also name
15
+ // the host rather than hardcoding "Nexus", so a distribution that rebrands nexus
16
+ // (arc, tau, …) does not send its users back to an app they are not running.
17
+ /** Shared chrome: system fonts, a centred card, and light/dark support. */
18
+ const PAGE_STYLE = `
19
+ :root { color-scheme: light dark; }
20
+ * { box-sizing: border-box; }
21
+ body {
22
+ margin: 0;
23
+ min-height: 100vh;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ padding: 24px;
28
+ font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
29
+ background: #0f1117;
30
+ color: #e6e8ee;
31
+ }
32
+ .card {
33
+ width: 100%;
34
+ max-width: 26rem;
35
+ padding: 2.5rem 2rem;
36
+ text-align: center;
37
+ background: #161922;
38
+ border: 1px solid #242938;
39
+ border-radius: 14px;
40
+ box-shadow: 0 1px 2px rgba(0,0,0,.3), 0 12px 32px rgba(0,0,0,.25);
41
+ }
42
+ .badge {
43
+ width: 3rem; height: 3rem;
44
+ margin: 0 auto 1.25rem;
45
+ display: grid; place-items: center;
46
+ border-radius: 50%;
47
+ }
48
+ .badge svg { width: 1.5rem; height: 1.5rem; display: block; }
49
+ .ok { background: rgba(74,222,128,.12); color: #4ade80; }
50
+ .bad { background: rgba(248,113,113,.12); color: #f87171; }
51
+ h1 { margin: 0 0 .5rem; font-size: 1.15rem; font-weight: 600; letter-spacing: -0.01em; }
52
+ p { margin: 0; color: #9aa1b1; }
53
+ .app { color: #e6e8ee; font-weight: 500; }
54
+ .hint { margin-top: 1.25rem; font-size: .8125rem; color: #6b7280; }
55
+ code {
56
+ display: block;
57
+ margin-top: 1.25rem;
58
+ padding: .75rem .875rem;
59
+ text-align: left;
60
+ font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
61
+ color: #fca5a5;
62
+ background: rgba(248,113,113,.08);
63
+ border: 1px solid rgba(248,113,113,.2);
64
+ border-radius: 8px;
65
+ overflow-wrap: anywhere;
66
+ }
67
+ @media (prefers-color-scheme: light) {
68
+ body { background: #f6f7f9; color: #121620; }
69
+ .card { background: #fff; border-color: #e4e7ee; }
70
+ p { color: #5b6474; }
71
+ .app { color: #121620; }
72
+ .hint { color: #8b93a3; }
73
+ }`;
74
+ const CHECK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>';
75
+ const CROSS_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>';
76
+ function page(options) {
77
+ return `<!DOCTYPE html>
78
+ <html lang="en">
79
+ <head>
80
+ <meta charset="utf-8">
81
+ <meta name="viewport" content="width=device-width, initial-scale=1">
82
+ <title>${options.title}</title>
83
+ <style>${PAGE_STYLE}
84
+ </style>
85
+ </head>
86
+ <body>
87
+ <main class="card">
88
+ <div class="badge ${options.tone}">${options.icon}</div>
89
+ <h1>${options.heading}</h1>
90
+ <p>${options.body}</p>
91
+ ${options.extra ?? ""}
92
+ </main>
93
+ ${options.autoClose ? " <script>setTimeout(() => window.close(), 2000);</script>\n" : ""}</body>
94
+ </html>`;
95
+ }
96
+ function escapeHtml(value) {
97
+ return value
98
+ .replace(/&/g, "&amp;")
99
+ .replace(/</g, "&lt;")
100
+ .replace(/>/g, "&gt;")
101
+ .replace(/"/g, "&quot;")
102
+ .replace(/'/g, "&#39;");
103
+ }
104
+ /** Built per request so authorization pages always use the Nexus product name. */
105
+ function htmlSuccess() {
106
+ const app = escapeHtml(getAppName());
107
+ return page({
108
+ title: `${app} — Authorization Successful`,
109
+ heading: "Authorization Successful",
110
+ body: `You can close this window and return to <span class="app">${app}</span>.`,
111
+ icon: CHECK_ICON,
112
+ tone: "ok",
113
+ autoClose: true,
114
+ });
115
+ }
116
+ function htmlError(error) {
117
+ const app = escapeHtml(getAppName());
118
+ return page({
119
+ title: `${app} — Authorization Failed`,
120
+ heading: "Authorization Failed",
121
+ body: `Something went wrong during authorization. You can close this window and try again from <span class="app">${app}</span>.`,
122
+ icon: CROSS_ICON,
123
+ tone: "bad",
124
+ extra: `<code>${escapeHtml(error)}</code>`,
125
+ });
126
+ }
127
+ /** Server singleton state */
128
+ let server;
129
+ let bindingPromise;
130
+ let stoppingPromise;
131
+ let restartableStoppingPromise;
132
+ let callbackGeneration = 0;
133
+ const pendingAuths = new Map();
134
+ const reservedAuthStates = new Set();
135
+ const earlyAuthResults = new Map();
136
+ /** Timeout for callback completion (5 minutes) */
137
+ const CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
138
+ const DEFAULT_OAUTH_CALLBACK_HOST = "localhost";
139
+ let callbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST;
140
+ /**
141
+ * Handle incoming HTTP requests to the callback server.
142
+ */
143
+ function handleRequest(req, res) {
144
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
145
+ // Only handle the callback path
146
+ if (url.pathname !== getOAuthCallbackPath()) {
147
+ res.writeHead(404, { "Content-Type": "text/plain" });
148
+ res.end("Not found");
149
+ return;
150
+ }
151
+ const code = url.searchParams.get("code");
152
+ const iss = url.searchParams.get("iss");
153
+ const state = url.searchParams.get("state");
154
+ const error = url.searchParams.get("error");
155
+ const errorDescription = url.searchParams.get("error_description");
156
+ // Enforce state parameter presence for CSRF protection
157
+ if (!state) {
158
+ const errorMsg = "Missing required state parameter - potential CSRF attack";
159
+ res.writeHead(400, { "Content-Type": "text/html" });
160
+ res.end(htmlError(errorMsg));
161
+ return;
162
+ }
163
+ const pending = pendingAuths.get(state);
164
+ const isReserved = reservedAuthStates.has(state);
165
+ // Handle OAuth errors only for a state that belongs to an active flow.
166
+ if (error) {
167
+ if (!pending && !isReserved) {
168
+ const errorMsg = "Invalid or expired state parameter - potential CSRF attack";
169
+ res.writeHead(400, { "Content-Type": "text/html" });
170
+ res.end(htmlError(errorMsg));
171
+ return;
172
+ }
173
+ const errorMsg = errorDescription || error;
174
+ // Send HTTP response first before rejecting promise
175
+ res.writeHead(200, { "Content-Type": "text/html" });
176
+ res.end(htmlError(errorMsg));
177
+ if (pending) {
178
+ reservedAuthStates.delete(state);
179
+ clearTimeout(pending.timeout);
180
+ pendingAuths.delete(state);
181
+ // Reject after the response is sent so callers can attach their handler.
182
+ setTimeout(() => pending.reject(new Error(errorMsg)), 0);
183
+ }
184
+ else {
185
+ reservedAuthStates.delete(state);
186
+ earlyAuthResults.set(state, { status: "rejected", error: new Error(errorMsg) });
187
+ }
188
+ return;
189
+ }
190
+ // Validate state parameter
191
+ if (!pending && !isReserved) {
192
+ const errorMsg = "Invalid or expired state parameter - potential CSRF attack";
193
+ res.writeHead(400, { "Content-Type": "text/html" });
194
+ res.end(htmlError(errorMsg));
195
+ return;
196
+ }
197
+ // Require authorization code
198
+ if (!code) {
199
+ res.writeHead(400, { "Content-Type": "text/html" });
200
+ res.end(htmlError("No authorization code provided"));
201
+ return;
202
+ }
203
+ if (!pending) {
204
+ reservedAuthStates.delete(state);
205
+ earlyAuthResults.set(state, {
206
+ status: "resolved",
207
+ result: { code, ...(iss !== null ? { iss } : {}) },
208
+ });
209
+ res.writeHead(200, { "Content-Type": "text/html" });
210
+ res.end(htmlSuccess());
211
+ return;
212
+ }
213
+ // Clear timeout and resolve the pending promise
214
+ clearTimeout(pending.timeout);
215
+ pendingAuths.delete(state);
216
+ pending.resolve({ code, ...(iss !== null ? { iss } : {}) });
217
+ res.writeHead(200, { "Content-Type": "text/html" });
218
+ res.end(htmlSuccess());
219
+ }
220
+ /**
221
+ * Ensure the callback server is running.
222
+ * If strictPort is true, requires binding on the configured callback port.
223
+ * If strictPort is false, asks the OS for an available local port.
224
+ */
225
+ export async function ensureCallbackServer(options = {}) {
226
+ const generation = callbackGeneration;
227
+ if (stoppingPromise) {
228
+ if (!restartableStoppingPromise) {
229
+ throw new Error("OAuth callback server stopped");
230
+ }
231
+ await restartableStoppingPromise;
232
+ if (generation !== callbackGeneration) {
233
+ throw new Error("OAuth callback server stopped");
234
+ }
235
+ }
236
+ while (bindingPromise) {
237
+ await bindingPromise;
238
+ if (generation !== callbackGeneration) {
239
+ throw new Error("OAuth callback server stopped");
240
+ }
241
+ }
242
+ if (generation !== callbackGeneration) {
243
+ throw new Error("OAuth callback server stopped");
244
+ }
245
+ const operation = ensureCallbackServerLocked(options);
246
+ bindingPromise = operation;
247
+ try {
248
+ await operation;
249
+ }
250
+ finally {
251
+ if (bindingPromise === operation) {
252
+ bindingPromise = undefined;
253
+ }
254
+ }
255
+ }
256
+ async function ensureCallbackServerLocked(options = {}) {
257
+ const requiredPort = options.port ?? getConfiguredOAuthCallbackPort();
258
+ const strictPort = options.strictPort === true;
259
+ const requestedHost = options.callbackHost ?? DEFAULT_OAUTH_CALLBACK_HOST;
260
+ const rawRequestedPath = options.callbackPath ?? DEFAULT_OAUTH_CALLBACK_PATH;
261
+ const requestedPath = rawRequestedPath.startsWith("/") ? rawRequestedPath : `/${rawRequestedPath}`;
262
+ if (options.reserveState && !options.oauthState) {
263
+ throw new Error("OAuth callback reservation requires an oauthState");
264
+ }
265
+ let reservedState;
266
+ const previousServer = server;
267
+ const needsStrictRebind = Boolean(previousServer && strictPort && getOAuthCallbackPort() !== requiredPort);
268
+ const needsHostSwitch = Boolean(previousServer && callbackServerHost !== requestedHost);
269
+ const needsPathSwitch = Boolean(previousServer && getOAuthCallbackPath() !== requestedPath);
270
+ if (previousServer) {
271
+ if (!needsStrictRebind && !needsHostSwitch) {
272
+ if (needsPathSwitch) {
273
+ if (pendingAuths.size > 0 || reservedAuthStates.size > 0) {
274
+ throw new Error(`OAuth callback server is using path ${getOAuthCallbackPath()}, but callback path ${requestedPath} is required and cannot be switched while authorizations are pending`);
275
+ }
276
+ setOAuthCallbackPath(requestedPath);
277
+ }
278
+ if (options.reserveState && options.oauthState) {
279
+ earlyAuthResults.delete(options.oauthState);
280
+ reservedAuthStates.add(options.oauthState);
281
+ reservedState = options.oauthState;
282
+ }
283
+ return;
284
+ }
285
+ if (pendingAuths.size > 0 || reservedAuthStates.size > 0) {
286
+ throw new Error(`OAuth callback server is running on ${callbackServerHost}:${getOAuthCallbackPort()}, but strict callback endpoint ${requestedHost}:${requiredPort} is required and cannot be switched while authorizations are pending`);
287
+ }
288
+ }
289
+ const candidateServer = createServer(handleRequest);
290
+ const listenPort = strictPort ? requiredPort : 0;
291
+ try {
292
+ await new Promise((resolve, reject) => {
293
+ candidateServer.once("error", (err) => {
294
+ reject(err);
295
+ });
296
+ candidateServer.listen(listenPort, requestedHost, () => {
297
+ resolve();
298
+ });
299
+ });
300
+ if (strictPort) {
301
+ setOAuthCallbackPort(requiredPort);
302
+ }
303
+ else {
304
+ const address = candidateServer.address();
305
+ if (!address || typeof address === "string" || typeof address.port !== "number") {
306
+ throw new Error("OAuth callback server did not report an assigned port");
307
+ }
308
+ setOAuthCallbackPort(address.port);
309
+ }
310
+ if (previousServer && (needsStrictRebind || needsHostSwitch)) {
311
+ await new Promise((resolve) => {
312
+ previousServer.close(() => resolve());
313
+ });
314
+ }
315
+ callbackServerHost = requestedHost;
316
+ setOAuthCallbackPath(requestedPath);
317
+ server = candidateServer;
318
+ if (options.reserveState && options.oauthState) {
319
+ earlyAuthResults.delete(options.oauthState);
320
+ reservedAuthStates.add(options.oauthState);
321
+ reservedState = options.oauthState;
322
+ }
323
+ server.unref();
324
+ }
325
+ catch (error) {
326
+ if (reservedState) {
327
+ reservedAuthStates.delete(reservedState);
328
+ }
329
+ const nodeError = error;
330
+ await new Promise((resolve) => {
331
+ candidateServer.close(() => resolve());
332
+ });
333
+ if (strictPort && nodeError.code === "EADDRINUSE") {
334
+ throw new Error(`OAuth callback port ${requiredPort} is already in use. Pre-registered OAuth clients require an exact redirect URI; set MCP_OAUTH_CALLBACK_PORT to your registered port or free port ${requiredPort}`, { cause: error });
335
+ }
336
+ throw error;
337
+ }
338
+ }
339
+ export function reserveCallbackServer(oauthState) {
340
+ earlyAuthResults.delete(oauthState);
341
+ reservedAuthStates.add(oauthState);
342
+ }
343
+ export function releaseCallbackServer(oauthState) {
344
+ reservedAuthStates.delete(oauthState);
345
+ earlyAuthResults.delete(oauthState);
346
+ }
347
+ /**
348
+ * Wait for a callback with the given OAuth state.
349
+ * Returns a promise that resolves with the authorization code and, when the
350
+ * authorization server sends one, the RFC 9207 `iss` parameter.
351
+ */
352
+ export function waitForCallback(oauthState) {
353
+ reservedAuthStates.delete(oauthState);
354
+ const earlyResult = earlyAuthResults.get(oauthState);
355
+ if (earlyResult) {
356
+ earlyAuthResults.delete(oauthState);
357
+ return earlyResult.status === "resolved"
358
+ ? Promise.resolve(earlyResult.result)
359
+ : Promise.reject(earlyResult.error);
360
+ }
361
+ return new Promise((resolve, reject) => {
362
+ const timeout = setTimeout(() => {
363
+ if (pendingAuths.has(oauthState)) {
364
+ pendingAuths.delete(oauthState);
365
+ reject(new Error("OAuth callback timeout - authorization took too long"));
366
+ }
367
+ }, CALLBACK_TIMEOUT_MS);
368
+ pendingAuths.set(oauthState, { resolve, reject, timeout });
369
+ });
370
+ }
371
+ /**
372
+ * Cancel a pending authorization by state.
373
+ */
374
+ export function cancelPendingCallback(oauthState) {
375
+ reservedAuthStates.delete(oauthState);
376
+ earlyAuthResults.delete(oauthState);
377
+ const pending = pendingAuths.get(oauthState);
378
+ if (pending) {
379
+ clearTimeout(pending.timeout);
380
+ pendingAuths.delete(oauthState);
381
+ pending.reject(new Error("Authorization cancelled"));
382
+ }
383
+ }
384
+ /**
385
+ * Stop the callback server and reject all pending authorizations.
386
+ */
387
+ export function stopCallbackServer() {
388
+ if (stoppingPromise) {
389
+ restartableStoppingPromise = undefined;
390
+ callbackGeneration += 1;
391
+ return stoppingPromise;
392
+ }
393
+ callbackGeneration += 1;
394
+ const cleanup = (async () => {
395
+ while (bindingPromise) {
396
+ await bindingPromise.catch(() => { });
397
+ }
398
+ if (server) {
399
+ await new Promise((resolve) => {
400
+ server.close(() => {
401
+ resolve();
402
+ });
403
+ });
404
+ server = undefined;
405
+ }
406
+ setOAuthCallbackPort(getConfiguredOAuthCallbackPort());
407
+ callbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST;
408
+ setOAuthCallbackPath(DEFAULT_OAUTH_CALLBACK_PATH);
409
+ // Reject all pending auths (defer to allow any pending operations to complete)
410
+ const pendingList = Array.from(pendingAuths.entries());
411
+ pendingAuths.clear();
412
+ reservedAuthStates.clear();
413
+ earlyAuthResults.clear();
414
+ setTimeout(() => {
415
+ for (const [, pending] of pendingList) {
416
+ clearTimeout(pending.timeout);
417
+ pending.reject(new Error("OAuth callback server stopped"));
418
+ }
419
+ }, 0);
420
+ })();
421
+ const operation = cleanup.finally(() => {
422
+ if (stoppingPromise === operation)
423
+ stoppingPromise = undefined;
424
+ });
425
+ stoppingPromise = operation;
426
+ return operation;
427
+ }
428
+ /** Stop the callback server only when no bind or authorization owns it. */
429
+ export function stopCallbackServerIfIdle() {
430
+ if (stoppingPromise)
431
+ return stoppingPromise;
432
+ if (bindingPromise || !server || pendingAuths.size > 0 || reservedAuthStates.size > 0) {
433
+ return Promise.resolve();
434
+ }
435
+ const operation = stopCallbackServer().finally(() => {
436
+ if (restartableStoppingPromise === operation)
437
+ restartableStoppingPromise = undefined;
438
+ });
439
+ restartableStoppingPromise = operation;
440
+ return operation;
441
+ }
442
+ /**
443
+ * Check if the callback server is running.
444
+ */
445
+ export function isCallbackServerRunning() {
446
+ return server !== undefined;
447
+ }
448
+ /**
449
+ * Get the number of pending authorizations.
450
+ */
451
+ export function getPendingAuthCount() {
452
+ return pendingAuths.size;
453
+ }
454
+ //# sourceMappingURL=mcp-callback-server.js.map