@humain/terminal 0.0.2 → 0.0.3-beta.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.
- package/CHANGELOG.md +241 -24
- package/README.md +143 -119
- package/dist/cli/args.d.ts +4 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +37 -39
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts +19 -0
- package/dist/cli/auth-check.d.ts.map +1 -0
- package/dist/cli/auth-check.js +50 -0
- package/dist/cli/auth-check.js.map +1 -0
- package/dist/cli/auth-command.d.ts +24 -0
- package/dist/cli/auth-command.d.ts.map +1 -0
- package/dist/cli/auth-command.js +103 -0
- package/dist/cli/auth-command.js.map +1 -0
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +2 -2
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +5 -15
- package/dist/cli/credential-print.d.ts.map +1 -1
- package/dist/cli/credential-print.js +42 -83
- package/dist/cli/credential-print.js.map +1 -1
- package/dist/cli/experimental/auth.d.ts +16 -0
- package/dist/cli/experimental/auth.d.ts.map +1 -0
- package/dist/cli/experimental/auth.js +13 -0
- package/dist/cli/experimental/auth.js.map +1 -0
- package/dist/cli/experimental/cli.d.ts +6 -0
- package/dist/cli/experimental/cli.d.ts.map +1 -0
- package/dist/cli/experimental/cli.js +5 -0
- package/dist/cli/experimental/cli.js.map +1 -0
- package/dist/cli/experimental/command-options.d.ts +17 -0
- package/dist/cli/experimental/command-options.d.ts.map +1 -0
- package/dist/cli/experimental/command-options.js +35 -0
- package/dist/cli/experimental/command-options.js.map +1 -0
- package/dist/cli/experimental/command.d.ts +63 -0
- package/dist/cli/experimental/command.d.ts.map +1 -0
- package/dist/cli/experimental/command.js +130 -0
- package/dist/cli/experimental/command.js.map +1 -0
- package/dist/cli/experimental/commands/client.d.ts +13 -0
- package/dist/cli/experimental/commands/client.d.ts.map +1 -0
- package/dist/cli/experimental/commands/client.js +25 -0
- package/dist/cli/experimental/commands/client.js.map +1 -0
- package/dist/cli/experimental/commands/pi.d.ts +15 -0
- package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
- package/dist/cli/experimental/commands/pi.js +28 -0
- package/dist/cli/experimental/commands/pi.js.map +1 -0
- package/dist/cli/experimental/commands/server.d.ts +13 -0
- package/dist/cli/experimental/commands/server.d.ts.map +1 -0
- package/dist/cli/experimental/commands/server.js +25 -0
- package/dist/cli/experimental/commands/server.js.map +1 -0
- package/dist/cli/experimental/transport-address.d.ts +10 -0
- package/dist/cli/experimental/transport-address.d.ts.map +1 -0
- package/dist/cli/experimental/transport-address.js +38 -0
- package/dist/cli/experimental/transport-address.js.map +1 -0
- package/dist/cli/list-models.d.ts +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +2 -2
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +2 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/remote-session.d.ts +53 -0
- package/dist/client/remote-session.d.ts.map +1 -0
- package/dist/client/remote-session.js +340 -0
- package/dist/client/remote-session.js.map +1 -0
- package/dist/client/transcript.d.ts +12 -0
- package/dist/client/transcript.d.ts.map +1 -0
- package/dist/client/transcript.js +98 -0
- package/dist/client/transcript.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -10
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +72 -70
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +25 -9
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +237 -39
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +60 -41
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +2 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +27 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/keybindings.d.ts +45 -5
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +29 -5
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +4 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +13 -10
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +4 -3
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +42 -10
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +30 -13
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +233 -73
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.d.ts +12 -7
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +83 -14
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/package-manager.d.ts +6 -3
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +80 -61
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts +8 -0
- package/dist/core/pi-manifest.d.ts.map +1 -0
- package/dist/core/pi-manifest.js +28 -0
- package/dist/core/pi-manifest.js.map +1 -0
- package/dist/core/provider-composer.d.ts +4 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +36 -15
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +73 -67
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +5 -5
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +11 -8
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +3 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +40 -16
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +8 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +5 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +16 -15
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +4 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +11 -7
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +7 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +16 -19
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +4 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +5 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts +4 -0
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +4 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +7 -3
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +4 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +6 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +11 -2
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +21 -7
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/humain/agent-execution-protocol.d.ts +218 -0
- package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
- package/dist/humain/agent-execution-protocol.js +204 -0
- package/dist/humain/agent-execution-protocol.js.map +1 -0
- package/dist/humain/agent-execution-runtime.d.ts +35 -0
- package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
- package/dist/humain/agent-execution-runtime.js +170 -0
- package/dist/humain/agent-execution-runtime.js.map +1 -0
- package/dist/humain/index.d.ts.map +1 -1
- package/dist/humain/index.js +8 -7
- package/dist/humain/index.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
- package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
- package/dist/humain/mcp-adapter/vendor/README.md +733 -0
- package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
- package/dist/humain/mcp-adapter/vendor/agent-dir.ts +60 -0
- package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
- package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
- package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
- package/dist/humain/mcp-adapter/vendor/cli.js +209 -0
- package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
- package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
- package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +604 -0
- package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
- package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
- package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
- package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
- package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +15923 -0
- package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
- package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
- package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
- package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
- package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
- package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
- package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
- package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
- package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
- package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +666 -0
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
- package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +353 -0
- package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
- package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
- package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
- package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
- package/dist/humain/mcp-adapter/vendor/package.json +178 -0
- package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
- package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
- package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
- package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
- package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
- package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +1124 -0
- package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
- package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
- package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
- package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +276 -0
- package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
- package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
- package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
- package/dist/humain/mcp-adapter/vendor/types.ts +859 -0
- package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
- package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
- package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
- package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
- package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
- package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
- package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
- package/dist/humain/mcp-adapter.d.ts +3 -0
- package/dist/humain/mcp-adapter.d.ts.map +1 -0
- package/dist/humain/mcp-adapter.js +5 -0
- package/dist/humain/mcp-adapter.js.map +1 -0
- package/dist/humain/pi-agent-execution-host.d.ts +34 -0
- package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
- package/dist/humain/pi-agent-execution-host.js +77 -0
- package/dist/humain/pi-agent-execution-host.js.map +1 -0
- package/dist/humain/web-access/host.d.ts +4 -0
- package/dist/humain/web-access/host.d.ts.map +1 -0
- package/dist/humain/web-access/host.js +3 -0
- package/dist/humain/web-access/host.js.map +1 -0
- package/dist/humain/web-access/index.d.ts +3 -0
- package/dist/humain/web-access/index.d.ts.map +1 -0
- package/dist/humain/web-access/index.js +5 -0
- package/dist/humain/web-access/index.js.map +1 -0
- package/dist/humain/web-access/vendor/activity.d.ts +34 -0
- package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/activity.js +68 -0
- package/dist/humain/web-access/vendor/activity.js.map +1 -0
- package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
- package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/anysearch.js +167 -0
- package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
- package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
- package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/bocha.js +219 -0
- package/dist/humain/web-access/vendor/bocha.js.map +1 -0
- package/dist/humain/web-access/vendor/brave.d.ts +4 -0
- package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brave.js +194 -0
- package/dist/humain/web-access/vendor/brave.js.map +1 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
- package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
- package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brightdata.js +519 -0
- package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts +10 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/chrome-cookies.js +438 -0
- package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
- package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
- package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/content-find.js +117 -0
- package/dist/humain/web-access/vendor/content-find.js.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.js +151 -0
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-page.d.ts +29 -0
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-page.js +3554 -0
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts +93 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.js +688 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
- package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
- package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
- package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
- package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
- package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
- package/dist/humain/web-access/vendor/exa.d.ts +10 -0
- package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/exa.js +426 -0
- package/dist/humain/web-access/vendor/exa.js.map +1 -0
- package/dist/humain/web-access/vendor/extract.d.ts +46 -0
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/extract.js +1064 -0
- package/dist/humain/web-access/vendor/extract.js.map +1 -0
- package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
- package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/feature-config.js +27 -0
- package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts +25 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/fetch-params.js +57 -0
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
- package/dist/humain/web-access/vendor/firecrawl.d.ts +12 -0
- package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/firecrawl.js +239 -0
- package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
- package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-api.js +230 -0
- package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-search.js +814 -0
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
- package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
- package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
- package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
- package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web.js +385 -0
- package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
- package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
- package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/github-api.js +160 -0
- package/dist/humain/web-access/vendor/github-api.js.map +1 -0
- package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
- package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/github-extract.js +635 -0
- package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/index.d.ts +4 -0
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/index.js +3002 -0
- package/dist/humain/web-access/vendor/index.js.map +1 -0
- package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
- package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/jina-search.js +255 -0
- package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
- package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
- package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/kagi.js +262 -0
- package/dist/humain/web-access/vendor/kagi.js.map +1 -0
- package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
- package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/ollama.js +216 -0
- package/dist/humain/web-access/vendor/ollama.js.map +1 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/openai-search.js +459 -0
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
- package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/page-query.js +79 -0
- package/dist/humain/web-access/vendor/page-query.js.map +1 -0
- package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
- package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/parallel.js +343 -0
- package/dist/humain/web-access/vendor/parallel.js.map +1 -0
- package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
- package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
- package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
- package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/perplexity.js +159 -0
- package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
- package/dist/humain/web-access/vendor/querit.d.ts +10 -0
- package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/querit.js +335 -0
- package/dist/humain/web-access/vendor/querit.js.map +1 -0
- package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
- package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/render-search-error.js +130 -0
- package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
- package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
- package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
- package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
- package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/search1api.js +251 -0
- package/dist/humain/web-access/vendor/search1api.js.map +1 -0
- package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
- package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
- package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
- package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
- package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/searxng.js +238 -0
- package/dist/humain/web-access/vendor/searxng.js.map +1 -0
- package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
- package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpbase.js +211 -0
- package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
- package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
- package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpdive.js +267 -0
- package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
- package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
- package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/source-check.js +205 -0
- package/dist/humain/web-access/vendor/source-check.js.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
- package/dist/humain/web-access/vendor/storage.d.ts +55 -0
- package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/storage.js +485 -0
- package/dist/humain/web-access/vendor/storage.js.map +1 -0
- package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
- package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
- package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
- package/dist/humain/web-access/vendor/summary-review.d.ts +24 -0
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/summary-review.js +341 -0
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
- package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
- package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/tavily.js +194 -0
- package/dist/humain/web-access/vendor/tavily.js.map +1 -0
- package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
- package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/tinyfish.js +331 -0
- package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
- package/dist/humain/web-access/vendor/utils.d.ts +20 -0
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/utils.js +91 -0
- package/dist/humain/web-access/vendor/utils.js.map +1 -0
- package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
- package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/video-extract.js +335 -0
- package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
- package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/xai-search.js +331 -0
- package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
- package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
- package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
- package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +169 -102
- package/dist/main.js.map +1 -1
- package/dist/modes/agent-exec-mode.d.ts +14 -0
- package/dist/modes/agent-exec-mode.d.ts.map +1 -0
- package/dist/modes/agent-exec-mode.js +92 -0
- package/dist/modes/agent-exec-mode.js.map +1 -0
- package/dist/modes/index.d.ts +4 -2
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +2 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +7 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
- package/dist/modes/interactive/components/earendil-announcement.js +40 -0
- package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
- package/dist/modes/interactive/components/markdown-transform.js +19 -0
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
- package/dist/modes/interactive/components/mermaid.d.ts +11 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +75 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +16 -4
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +30 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +3 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +9 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +45 -9
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +581 -211
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -0
- package/dist/modes/interactive/theme/light.json +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +10 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +5 -1
- package/dist/modes/interactive/theme/theme.d.ts +2 -2
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +24 -6
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +28 -0
- package/dist/modes/json-event.d.ts.map +1 -0
- package/dist/modes/json-event.js +12 -0
- package/dist/modes/json-event.js.map +1 -0
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +12 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +12 -5
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +55 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +13 -3
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +15 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +11 -9
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +3 -2
- package/dist/rpc-entry.js.map +1 -1
- package/dist/server/create-harness.d.ts +26 -0
- package/dist/server/create-harness.d.ts.map +1 -0
- package/dist/server/create-harness.js +104 -0
- package/dist/server/create-harness.js.map +1 -0
- package/dist/utils/abort.d.ts +5 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +48 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +22 -2
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/management-http.d.ts +23 -0
- package/dist/utils/management-http.d.ts.map +1 -0
- package/dist/utils/management-http.js +50 -0
- package/dist/utils/management-http.js.map +1 -0
- package/dist/utils/paths.d.ts +3 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +23 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +19 -0
- package/dist/utils/tool-result-images.d.ts.map +1 -0
- package/dist/utils/tool-result-images.js +45 -0
- package/dist/utils/tool-result-images.js.map +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +13 -25
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +4 -0
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +23 -5
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +2 -2
- package/docs/custom-provider.md +7 -5
- package/docs/extensions.md +30 -5
- package/docs/humain-terminal.md +21 -1
- package/docs/json.md +24 -19
- package/docs/keybindings.md +46 -14
- package/docs/models.md +32 -11
- package/docs/providers.md +9 -1
- package/docs/quickstart.md +39 -37
- package/docs/rpc.md +31 -11
- package/docs/sdk.md +21 -2
- package/docs/security.md +21 -21
- package/docs/session-format.md +14 -14
- package/docs/settings.md +4 -1
- package/docs/themes.md +5 -3
- package/docs/usage.md +7 -0
- package/examples/extensions/custom-compaction.ts +3 -18
- package/examples/extensions/custom-provider-anthropic/index.ts +5 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +4 -13
- package/examples/extensions/qna.ts +5 -9
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +9 -20
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +11 -2
- package/examples/sdk/02-custom-model.ts +2 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +2771 -535
- package/package.json +40 -11
- package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
- package/src/humain/mcp-adapter/upstream.json +7 -0
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
- package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
- package/src/humain/web-access/UPSTREAM.md +17 -0
- package/src/humain/web-access/upstream.json +23 -0
- package/src/humain/web-access/vendor/LICENSE +21 -0
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Auth Flow
|
|
3
|
+
*
|
|
4
|
+
* High-level OAuth flow management using the MCP SDK's built-in auth functions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
auth as runSdkAuth,
|
|
9
|
+
extractWWWAuthenticateParams,
|
|
10
|
+
LATEST_PROTOCOL_VERSION,
|
|
11
|
+
UnauthorizedError,
|
|
12
|
+
type AuthOptions,
|
|
13
|
+
} from "@modelcontextprotocol/client"
|
|
14
|
+
import open from "open"
|
|
15
|
+
import { McpOAuthProvider, type McpOAuthConfig } from "./mcp-oauth-provider.ts"
|
|
16
|
+
import {
|
|
17
|
+
ensureCallbackServer,
|
|
18
|
+
waitForCallback,
|
|
19
|
+
cancelPendingCallback,
|
|
20
|
+
stopCallbackServer,
|
|
21
|
+
releaseCallbackServer,
|
|
22
|
+
} from "./mcp-callback-server.ts"
|
|
23
|
+
import {
|
|
24
|
+
getAuthForUrl,
|
|
25
|
+
isTokenExpired,
|
|
26
|
+
hasStoredTokens,
|
|
27
|
+
clearAllCredentials,
|
|
28
|
+
clearClientInfo,
|
|
29
|
+
clearTokens,
|
|
30
|
+
clearCodeVerifier,
|
|
31
|
+
getOAuthState,
|
|
32
|
+
clearOAuthState,
|
|
33
|
+
getAuthBaseDir,
|
|
34
|
+
OAuthCredentialStoreError,
|
|
35
|
+
type AuthStorageOptions,
|
|
36
|
+
type StoredTokens,
|
|
37
|
+
} from "./mcp-auth.ts"
|
|
38
|
+
import { isServerDisabled, type ServerEntry } from "./types.ts"
|
|
39
|
+
import { formatTerminalError, interpolateEnvRecord, interpolateEnvVars } from "./utils.ts"
|
|
40
|
+
import { abortable, throwIfAborted } from "./abort.ts"
|
|
41
|
+
import { combineAbortSignals, isAbortError } from "./runtime-owner.ts"
|
|
42
|
+
|
|
43
|
+
/** Auth status for a server */
|
|
44
|
+
export type AuthStatus = "authenticated" | "expired" | "not_authenticated"
|
|
45
|
+
|
|
46
|
+
export interface McpOAuthRuntime {
|
|
47
|
+
readonly signal: AbortSignal
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface AuthenticateOptions {
|
|
51
|
+
onAuthorizationUrl?: (authorizationUrl: string) => void | Promise<void>
|
|
52
|
+
onAuthorizationInput?: (
|
|
53
|
+
authorizationUrl: string,
|
|
54
|
+
signal: AbortSignal,
|
|
55
|
+
) => Promise<string | undefined>
|
|
56
|
+
authStorageOptions?: AuthStorageOptions
|
|
57
|
+
signal?: AbortSignal
|
|
58
|
+
runtime?: McpOAuthRuntime
|
|
59
|
+
skipIssuerMetadataValidation?: boolean
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type AuthDiscovery = Pick<AuthOptions, "resourceMetadataUrl" | "scope" | "skipIssuerMetadataValidation">
|
|
63
|
+
|
|
64
|
+
function applyOAuthConfig(discovery: AuthDiscovery, config: McpOAuthConfig): AuthDiscovery {
|
|
65
|
+
return {
|
|
66
|
+
...discovery,
|
|
67
|
+
...(config.scope !== undefined ? { scope: config.scope } : {}),
|
|
68
|
+
...(config.skipIssuerMetadataValidation === true ? { skipIssuerMetadataValidation: true } : {}),
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type PendingAuth = {
|
|
73
|
+
serverName: string
|
|
74
|
+
authProvider: McpOAuthProvider
|
|
75
|
+
serverUrl: string
|
|
76
|
+
authorizationUrl: string
|
|
77
|
+
discovery: AuthDiscovery
|
|
78
|
+
authStorageOptions: AuthStorageOptions
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type RuntimeState = {
|
|
82
|
+
controller: AbortController
|
|
83
|
+
generation: number
|
|
84
|
+
pendingAuths: Map<string, PendingAuth>
|
|
85
|
+
pendingAuthStates: Map<string, string>
|
|
86
|
+
pendingAuthCleanupTimers: Map<string, ReturnType<typeof setTimeout>>
|
|
87
|
+
pendingAuthentications: Map<string, Promise<AuthStatus>>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const runtimeStates = new WeakMap<McpOAuthRuntime, RuntimeState>()
|
|
91
|
+
const activeRuntimes = new Set<McpOAuthRuntime>()
|
|
92
|
+
|
|
93
|
+
export function createOAuthRuntime(signal?: AbortSignal): McpOAuthRuntime {
|
|
94
|
+
const controller = new AbortController()
|
|
95
|
+
const runtime = { signal: combineAbortSignals(signal, controller.signal)! } satisfies McpOAuthRuntime
|
|
96
|
+
runtimeStates.set(runtime, {
|
|
97
|
+
controller,
|
|
98
|
+
generation: 0,
|
|
99
|
+
pendingAuths: new Map(),
|
|
100
|
+
pendingAuthStates: new Map(),
|
|
101
|
+
pendingAuthCleanupTimers: new Map(),
|
|
102
|
+
pendingAuthentications: new Map(),
|
|
103
|
+
})
|
|
104
|
+
activeRuntimes.add(runtime)
|
|
105
|
+
return runtime
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let legacyRuntime = createOAuthRuntime()
|
|
109
|
+
activeRuntimes.delete(legacyRuntime)
|
|
110
|
+
|
|
111
|
+
function getRuntime(options?: AuthenticateOptions): McpOAuthRuntime {
|
|
112
|
+
if (options?.runtime) {
|
|
113
|
+
options.runtime.signal.throwIfAborted()
|
|
114
|
+
activeRuntimes.add(options.runtime)
|
|
115
|
+
return options.runtime
|
|
116
|
+
}
|
|
117
|
+
if (legacyRuntime.signal.aborted) legacyRuntime = createOAuthRuntime()
|
|
118
|
+
activeRuntimes.add(legacyRuntime)
|
|
119
|
+
return legacyRuntime
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getRuntimeState(runtime: McpOAuthRuntime): RuntimeState {
|
|
123
|
+
const state = runtimeStates.get(runtime)
|
|
124
|
+
if (!state) throw new Error("Unknown OAuth runtime")
|
|
125
|
+
return state
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getPendingAuthKey(serverName: string, options: AuthStorageOptions): string {
|
|
129
|
+
return `${serverName}|${getAuthBaseDir(options)}`
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function hasPendingAuth(serverName: string, options?: AuthStorageOptions, runtime?: McpOAuthRuntime): boolean {
|
|
133
|
+
const state = getRuntimeState(runtime ?? legacyRuntime)
|
|
134
|
+
if (options) {
|
|
135
|
+
return state.pendingAuths.has(getPendingAuthKey(serverName, options))
|
|
136
|
+
}
|
|
137
|
+
return Array.from(state.pendingAuths.values()).some(pendingAuth => pendingAuth.serverName === serverName)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Timeout for manual auth completion (5 minutes) */
|
|
141
|
+
const MANUAL_AUTH_TIMEOUT_MS = 5 * 60 * 1000
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate a cryptographically secure random state parameter.
|
|
145
|
+
*/
|
|
146
|
+
function generateState(): string {
|
|
147
|
+
return Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
|
148
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
149
|
+
.join("")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Extract OAuth configuration from a ServerEntry.
|
|
154
|
+
*/
|
|
155
|
+
export function extractOAuthConfig(definition: ServerEntry): McpOAuthConfig {
|
|
156
|
+
if (definition.oauth === false) {
|
|
157
|
+
return {}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const config: McpOAuthConfig = {}
|
|
161
|
+
if (definition.oauth?.grantType !== undefined) config.grantType = definition.oauth.grantType
|
|
162
|
+
if (definition.oauth?.clientId !== undefined) {
|
|
163
|
+
if (typeof definition.oauth.clientId !== "string") throw new Error("OAuth clientId must be a string")
|
|
164
|
+
config.clientId = interpolateEnvVars(definition.oauth.clientId)
|
|
165
|
+
}
|
|
166
|
+
if (definition.oauth?.clientSecret !== undefined) {
|
|
167
|
+
if (typeof definition.oauth.clientSecret !== "string") throw new Error("OAuth clientSecret must be a string")
|
|
168
|
+
// Preserve command expressions for the provider; interpolation remains eager for ordinary values.
|
|
169
|
+
config.clientSecret = definition.oauth.clientSecret.startsWith("!")
|
|
170
|
+
? definition.oauth.clientSecret
|
|
171
|
+
: interpolateEnvVars(definition.oauth.clientSecret)
|
|
172
|
+
}
|
|
173
|
+
if (definition.oauth?.scope !== undefined) {
|
|
174
|
+
if (typeof definition.oauth.scope !== "string") throw new Error("OAuth scope must be a string")
|
|
175
|
+
config.scope = interpolateEnvVars(definition.oauth.scope)
|
|
176
|
+
}
|
|
177
|
+
if (definition.oauth?.authorizationParams !== undefined) {
|
|
178
|
+
const params = definition.oauth.authorizationParams
|
|
179
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
180
|
+
throw new Error("OAuth authorizationParams must be an object")
|
|
181
|
+
}
|
|
182
|
+
config.authorizationParams = {}
|
|
183
|
+
for (const [key, value] of Object.entries(params)) {
|
|
184
|
+
if (!key) throw new Error("OAuth authorizationParams keys must not be empty")
|
|
185
|
+
if (typeof value !== "string") throw new Error(`OAuth authorizationParams.${key} must be a string`)
|
|
186
|
+
config.authorizationParams[key] = interpolateEnvVars(value)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (definition.oauth?.redirectUri !== undefined) {
|
|
190
|
+
if (typeof definition.oauth.redirectUri !== "string") {
|
|
191
|
+
throw new Error("OAuth redirectUri must be a string")
|
|
192
|
+
}
|
|
193
|
+
const redirectUri = interpolateEnvVars(definition.oauth.redirectUri).trim()
|
|
194
|
+
if (!redirectUri) {
|
|
195
|
+
throw new Error("OAuth redirectUri must not be empty")
|
|
196
|
+
}
|
|
197
|
+
config.redirectUri = redirectUri
|
|
198
|
+
}
|
|
199
|
+
if (definition.oauth?.clientName !== undefined) {
|
|
200
|
+
if (typeof definition.oauth.clientName !== "string") {
|
|
201
|
+
throw new Error("OAuth clientName must be a string")
|
|
202
|
+
}
|
|
203
|
+
const clientName = interpolateEnvVars(definition.oauth.clientName).trim()
|
|
204
|
+
if (!clientName) {
|
|
205
|
+
throw new Error("OAuth clientName must not be empty")
|
|
206
|
+
}
|
|
207
|
+
config.clientName = clientName
|
|
208
|
+
}
|
|
209
|
+
if (definition.oauth?.clientUri !== undefined) {
|
|
210
|
+
if (typeof definition.oauth.clientUri !== "string") {
|
|
211
|
+
throw new Error("OAuth clientUri must be a string")
|
|
212
|
+
}
|
|
213
|
+
const clientUri = interpolateEnvVars(definition.oauth.clientUri).trim()
|
|
214
|
+
if (!clientUri) {
|
|
215
|
+
throw new Error("OAuth clientUri must not be empty")
|
|
216
|
+
}
|
|
217
|
+
config.clientUri = clientUri
|
|
218
|
+
}
|
|
219
|
+
if (definition.oauth?.logoUri !== undefined) {
|
|
220
|
+
if (typeof definition.oauth.logoUri !== "string") {
|
|
221
|
+
throw new Error("OAuth logoUri must be a string")
|
|
222
|
+
}
|
|
223
|
+
const logoUri = interpolateEnvVars(definition.oauth.logoUri).trim()
|
|
224
|
+
if (!logoUri) {
|
|
225
|
+
throw new Error("OAuth logoUri must not be empty")
|
|
226
|
+
}
|
|
227
|
+
// Consent screens fetch this server-side, so a local path silently renders
|
|
228
|
+
// nothing. Fail here instead, where the message can say why.
|
|
229
|
+
let parsed: URL
|
|
230
|
+
try {
|
|
231
|
+
parsed = new URL(logoUri)
|
|
232
|
+
} catch {
|
|
233
|
+
throw new Error("OAuth logoUri must be an absolute http(s) URL")
|
|
234
|
+
}
|
|
235
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
236
|
+
throw new Error("OAuth logoUri must be an absolute http(s) URL")
|
|
237
|
+
}
|
|
238
|
+
config.logoUri = logoUri
|
|
239
|
+
}
|
|
240
|
+
if (definition.oauth?.skipIssuerMetadataValidation !== undefined) {
|
|
241
|
+
if (typeof definition.oauth.skipIssuerMetadataValidation !== "boolean") {
|
|
242
|
+
throw new Error("OAuth skipIssuerMetadataValidation must be a boolean")
|
|
243
|
+
}
|
|
244
|
+
config.skipIssuerMetadataValidation = definition.oauth.skipIssuerMetadataValidation
|
|
245
|
+
}
|
|
246
|
+
return config
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function probeAuthDiscovery(serverUrl: string, definition?: ServerEntry, signal?: AbortSignal): Promise<AuthDiscovery> {
|
|
250
|
+
// Discovery must not execute config commands or send their source text.
|
|
251
|
+
const discoveryHeaders = definition?.headers
|
|
252
|
+
? Object.fromEntries(Object.entries(definition.headers).filter(([, value]) => !value.startsWith("!") || value.startsWith("!!")))
|
|
253
|
+
: undefined
|
|
254
|
+
const headers = new Headers(interpolateEnvRecord(discoveryHeaders))
|
|
255
|
+
headers.set("content-type", "application/json")
|
|
256
|
+
|
|
257
|
+
const controller = new AbortController()
|
|
258
|
+
const discoverySignal = combineAbortSignals(signal, controller.signal)
|
|
259
|
+
const timer = setTimeout(() => controller.abort(), 5000)
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
headers.set("accept", "application/json, text/event-stream")
|
|
263
|
+
|
|
264
|
+
const response = await fetch(new URL(serverUrl), {
|
|
265
|
+
method: "POST",
|
|
266
|
+
headers,
|
|
267
|
+
body: JSON.stringify({
|
|
268
|
+
jsonrpc: "2.0",
|
|
269
|
+
id: 0,
|
|
270
|
+
method: "initialize",
|
|
271
|
+
params: {
|
|
272
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
273
|
+
capabilities: {},
|
|
274
|
+
clientInfo: { name: "pi-mcp-adapter", version: "2.11.0" },
|
|
275
|
+
},
|
|
276
|
+
}),
|
|
277
|
+
...(discoverySignal ? { signal: discoverySignal } : {}),
|
|
278
|
+
})
|
|
279
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response)
|
|
280
|
+
await response.body?.cancel().catch(() => {})
|
|
281
|
+
return { ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}), ...(scope ? { scope } : {}) }
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (signal?.aborted) throwIfAborted(signal)
|
|
284
|
+
return {}
|
|
285
|
+
} finally {
|
|
286
|
+
clearTimeout(timer)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function parseOAuthRedirectUri(redirectUri: string): { port: number; callbackHost: string; callbackPath: string } {
|
|
291
|
+
let url: URL
|
|
292
|
+
try {
|
|
293
|
+
url = new URL(redirectUri)
|
|
294
|
+
} catch (error) {
|
|
295
|
+
throw new Error(`Invalid OAuth redirectUri: ${redirectUri}`, { cause: error })
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const hostname = url.hostname.toLowerCase()
|
|
299
|
+
const isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1"
|
|
300
|
+
if (url.protocol !== "http:" || !isLocalhost) {
|
|
301
|
+
throw new Error("OAuth redirectUri must be an http:// localhost or loopback URI")
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (url.username || url.password) {
|
|
305
|
+
throw new Error("OAuth redirectUri must not include username or password")
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (url.hash) {
|
|
309
|
+
throw new Error("OAuth redirectUri must not include a fragment")
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!url.port) {
|
|
313
|
+
throw new Error("OAuth redirectUri must include an explicit numeric port")
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const port = Number.parseInt(url.port, 10)
|
|
317
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
318
|
+
throw new Error("OAuth redirectUri must include an explicit numeric port")
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const callbackHost = hostname === "[::1]" ? "::1" : hostname
|
|
322
|
+
return { port, callbackHost, callbackPath: url.pathname }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Start OAuth authentication flow for a server.
|
|
327
|
+
* Returns the authorization URL when browser authorization is required.
|
|
328
|
+
*/
|
|
329
|
+
export async function startAuth(
|
|
330
|
+
serverName: string,
|
|
331
|
+
serverUrl: string,
|
|
332
|
+
definition?: ServerEntry,
|
|
333
|
+
options: AuthenticateOptions = {},
|
|
334
|
+
): Promise<{ authorizationUrl: string }> {
|
|
335
|
+
if (isServerDisabled(definition)) throw new Error(`MCP server "${serverName}" is disabled`)
|
|
336
|
+
const runtime = getRuntime(options)
|
|
337
|
+
const runtimeState = getRuntimeState(runtime)
|
|
338
|
+
const config = definition ? extractOAuthConfig(definition) : {}
|
|
339
|
+
const authStorageOptions = options.authStorageOptions ?? {}
|
|
340
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
341
|
+
const generation = runtimeState.generation
|
|
342
|
+
throwIfAborted(signal)
|
|
343
|
+
|
|
344
|
+
if (config.grantType === "client_credentials") {
|
|
345
|
+
const storedAuth = await getAuthForUrl(serverName, serverUrl, authStorageOptions)
|
|
346
|
+
if (storedAuth?.clientInfo && !storedAuth.tokens && !config.clientId) {
|
|
347
|
+
clearClientInfo(serverName, authStorageOptions)
|
|
348
|
+
clearCodeVerifier(serverName, authStorageOptions)
|
|
349
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const authProvider = new McpOAuthProvider(serverName, serverUrl, config, {
|
|
353
|
+
onRedirect: async () => {
|
|
354
|
+
throw new Error("Browser redirect is not used for client_credentials flow")
|
|
355
|
+
},
|
|
356
|
+
}, authStorageOptions, runtime.signal)
|
|
357
|
+
try {
|
|
358
|
+
const discovery = applyOAuthConfig(await probeAuthDiscovery(serverUrl, definition, signal), config)
|
|
359
|
+
throwIfAborted(signal)
|
|
360
|
+
const result = await abortable(runSdkAuth(authProvider, { serverUrl, ...discovery }), signal)
|
|
361
|
+
throwIfAborted(signal)
|
|
362
|
+
if (result !== "AUTHORIZED") {
|
|
363
|
+
throw new UnauthorizedError("Failed to authorize")
|
|
364
|
+
}
|
|
365
|
+
return { authorizationUrl: "" }
|
|
366
|
+
} finally {
|
|
367
|
+
authProvider.deactivate()
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const existingPendingAuth = runtimeState.pendingAuths.get(getPendingAuthKey(serverName, authStorageOptions))
|
|
372
|
+
if (existingPendingAuth?.serverUrl === serverUrl) {
|
|
373
|
+
return { authorizationUrl: existingPendingAuth.authorizationUrl }
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const redirectCallback = config.redirectUri !== undefined ? parseOAuthRedirectUri(config.redirectUri) : undefined
|
|
377
|
+
const oauthState = generateState()
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
await ensureCallbackServer({
|
|
381
|
+
strictPort: Boolean(config.clientId) || config.redirectUri !== undefined,
|
|
382
|
+
oauthState,
|
|
383
|
+
reserveState: true,
|
|
384
|
+
...(redirectCallback ? { port: redirectCallback.port, callbackHost: redirectCallback.callbackHost, callbackPath: redirectCallback.callbackPath } : {}),
|
|
385
|
+
})
|
|
386
|
+
throwIfAborted(signal)
|
|
387
|
+
} catch (error) {
|
|
388
|
+
releaseCallbackServer(oauthState)
|
|
389
|
+
try {
|
|
390
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
391
|
+
} catch (cleanupError) {
|
|
392
|
+
throw new AggregateError([error, cleanupError], "OAuth startup cleanup failed")
|
|
393
|
+
}
|
|
394
|
+
throw error
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
let capturedUrl: URL | undefined
|
|
398
|
+
const authProvider = new McpOAuthProvider(serverName, serverUrl, config, {
|
|
399
|
+
onRedirect: async (url) => {
|
|
400
|
+
capturedUrl = url
|
|
401
|
+
},
|
|
402
|
+
}, authStorageOptions, runtime.signal, oauthState)
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
const storedAuth = await getAuthForUrl(serverName, serverUrl, authStorageOptions)
|
|
406
|
+
if (storedAuth?.clientInfo && !config.clientId) {
|
|
407
|
+
if (!storedAuth.tokens) {
|
|
408
|
+
clearClientInfo(serverName, authStorageOptions)
|
|
409
|
+
clearCodeVerifier(serverName, authStorageOptions)
|
|
410
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
411
|
+
} else {
|
|
412
|
+
const redirectUris = storedAuth.clientInfo.redirectUris
|
|
413
|
+
if (!Array.isArray(redirectUris) || !redirectUris.includes(authProvider.redirectUrl ?? "")) {
|
|
414
|
+
clearClientInfo(serverName, authStorageOptions)
|
|
415
|
+
clearTokens(serverName, authStorageOptions)
|
|
416
|
+
clearCodeVerifier(serverName, authStorageOptions)
|
|
417
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
throwIfAborted(signal)
|
|
423
|
+
|
|
424
|
+
const discovery = applyOAuthConfig(await probeAuthDiscovery(serverUrl, definition, signal), config)
|
|
425
|
+
throwIfAborted(signal)
|
|
426
|
+
const result = await abortable(runSdkAuth(authProvider, { serverUrl, ...discovery }), signal)
|
|
427
|
+
throwIfAborted(signal)
|
|
428
|
+
if (result === "AUTHORIZED") {
|
|
429
|
+
authProvider.deactivate()
|
|
430
|
+
releaseCallbackServer(oauthState)
|
|
431
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
432
|
+
return { authorizationUrl: "" }
|
|
433
|
+
}
|
|
434
|
+
if (!capturedUrl) {
|
|
435
|
+
throw new UnauthorizedError("OAuth authorization URL was not provided")
|
|
436
|
+
}
|
|
437
|
+
await setPendingAuth(runtime, serverName, { serverName, authProvider, serverUrl, authorizationUrl: capturedUrl.toString(), discovery, authStorageOptions }, oauthState, signal, generation)
|
|
438
|
+
return { authorizationUrl: capturedUrl.toString() }
|
|
439
|
+
} catch (error) {
|
|
440
|
+
authProvider.deactivate()
|
|
441
|
+
try {
|
|
442
|
+
await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
|
|
443
|
+
} catch (cleanupError) {
|
|
444
|
+
throw new AggregateError([error, cleanupError], "OAuth startup cleanup failed")
|
|
445
|
+
}
|
|
446
|
+
throw error
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async function setPendingAuth(
|
|
451
|
+
runtime: McpOAuthRuntime,
|
|
452
|
+
serverName: string,
|
|
453
|
+
pendingAuth: PendingAuth,
|
|
454
|
+
oauthState: string,
|
|
455
|
+
signal?: AbortSignal,
|
|
456
|
+
generation = getRuntimeState(runtime).generation,
|
|
457
|
+
): Promise<void> {
|
|
458
|
+
const state = getRuntimeState(runtime)
|
|
459
|
+
const key = getPendingAuthKey(serverName, pendingAuth.authStorageOptions)
|
|
460
|
+
await clearPendingAuth(runtime, serverName, undefined, pendingAuth.authStorageOptions)
|
|
461
|
+
throwIfAborted(signal)
|
|
462
|
+
if (generation !== state.generation) throw new Error("OAuth runtime stopped")
|
|
463
|
+
state.pendingAuths.set(key, pendingAuth)
|
|
464
|
+
state.pendingAuthStates.set(key, oauthState)
|
|
465
|
+
const cleanupTimer = setTimeout(() => {
|
|
466
|
+
void clearPendingAuth(runtime, serverName, oauthState, pendingAuth.authStorageOptions).catch(error => {
|
|
467
|
+
console.error(`MCP Auth: Timed-out flow cleanup failed: ${formatTerminalError(error)}`)
|
|
468
|
+
})
|
|
469
|
+
}, MANUAL_AUTH_TIMEOUT_MS)
|
|
470
|
+
cleanupTimer.unref?.()
|
|
471
|
+
state.pendingAuthCleanupTimers.set(key, cleanupTimer)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function clearPendingAuth(runtime: McpOAuthRuntime, serverName: string, oauthState?: string, fallbackStorageOptions: AuthStorageOptions = {}): Promise<void> {
|
|
475
|
+
const state = getRuntimeState(runtime)
|
|
476
|
+
const key = getPendingAuthKey(serverName, fallbackStorageOptions)
|
|
477
|
+
const pendingAuth = state.pendingAuths.get(key)
|
|
478
|
+
const authStorageOptions = pendingAuth?.authStorageOptions ?? fallbackStorageOptions
|
|
479
|
+
const pendingState = state.pendingAuthStates.get(key)
|
|
480
|
+
if (oauthState && pendingState && pendingState !== oauthState) return
|
|
481
|
+
|
|
482
|
+
const timer = state.pendingAuthCleanupTimers.get(key)
|
|
483
|
+
if (timer) {
|
|
484
|
+
clearTimeout(timer)
|
|
485
|
+
state.pendingAuthCleanupTimers.delete(key)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
pendingAuth?.authProvider.deactivate()
|
|
489
|
+
state.pendingAuths.delete(key)
|
|
490
|
+
state.pendingAuthStates.delete(key)
|
|
491
|
+
const stateToRelease = pendingState ?? oauthState
|
|
492
|
+
if (stateToRelease) {
|
|
493
|
+
cancelPendingCallback(stateToRelease)
|
|
494
|
+
const storedState = await getOAuthState(serverName, authStorageOptions)
|
|
495
|
+
if (storedState === stateToRelease) {
|
|
496
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function getSearchParamsFromInput(input: string): URLSearchParams | undefined {
|
|
502
|
+
try {
|
|
503
|
+
const url = new URL(input)
|
|
504
|
+
const params = new URLSearchParams(url.search)
|
|
505
|
+
if (url.hash) {
|
|
506
|
+
const hash = url.hash.startsWith("#") ? url.hash.slice(1) : url.hash
|
|
507
|
+
const hashParams = new URLSearchParams(hash)
|
|
508
|
+
for (const [key, value] of hashParams) {
|
|
509
|
+
if (!params.has(key)) params.set(key, value)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return params
|
|
513
|
+
} catch {
|
|
514
|
+
const query = input.includes("?") ? input.slice(input.indexOf("?") + 1) : input
|
|
515
|
+
const params = new URLSearchParams(query.startsWith("#") ? query.slice(1) : query)
|
|
516
|
+
return params.has("code") || params.has("state") || params.has("error") ? params : undefined
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** Authorization code plus the optional RFC 9207 `iss` callback parameter. */
|
|
521
|
+
export interface AuthorizationCodeInput {
|
|
522
|
+
code: string
|
|
523
|
+
iss?: string
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Extract an OAuth authorization code (and the RFC 9207 `iss` parameter, when
|
|
528
|
+
* present) from either a raw code, a query string, or the full localhost
|
|
529
|
+
* redirect URL copied from the browser address bar.
|
|
530
|
+
*/
|
|
531
|
+
export function parseAuthorizationRedirectInput(input: string, expectedState?: string): AuthorizationCodeInput {
|
|
532
|
+
const trimmed = input.trim()
|
|
533
|
+
if (!trimmed) {
|
|
534
|
+
throw new Error("Authorization code or redirect URL is required")
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const params = getSearchParamsFromInput(trimmed)
|
|
538
|
+
if (params) {
|
|
539
|
+
const error = params.get("error")
|
|
540
|
+
if (error) {
|
|
541
|
+
const description = params.get("error_description")
|
|
542
|
+
throw new Error(description ? `${error}: ${description}` : error)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const state = params.get("state")
|
|
546
|
+
if (expectedState && !state) {
|
|
547
|
+
throw new Error("OAuth state missing from redirect URL")
|
|
548
|
+
}
|
|
549
|
+
if (expectedState && state !== expectedState) {
|
|
550
|
+
throw new Error("OAuth state mismatch - potential CSRF attack")
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const code = params.get("code")
|
|
554
|
+
if (code) {
|
|
555
|
+
const iss = params.get("iss")
|
|
556
|
+
return { code, ...(iss !== null ? { iss } : {}) }
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (/^[A-Za-z0-9._~+/=-]+$/.test(trimmed)) {
|
|
561
|
+
return { code: trimmed }
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
throw new Error("Could not find an OAuth authorization code in the provided input")
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Extract an OAuth authorization code from either a raw code, a query string,
|
|
569
|
+
* or the full localhost redirect URL copied from the browser address bar.
|
|
570
|
+
*/
|
|
571
|
+
export function parseAuthorizationCodeInput(input: string, expectedState?: string): string {
|
|
572
|
+
return parseAuthorizationRedirectInput(input, expectedState).code
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
type AuthorizationResponse = {
|
|
576
|
+
input: AuthorizationCodeInput
|
|
577
|
+
source: "callback" | "manual"
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Wait for either the localhost callback or a manually pasted redirect URL.
|
|
582
|
+
* The manual input prompt is dismissed as soon as either path finishes.
|
|
583
|
+
*/
|
|
584
|
+
export async function waitForAuthorizationResponse(
|
|
585
|
+
callbackPromise: Promise<AuthorizationCodeInput>,
|
|
586
|
+
authorizationUrl: string,
|
|
587
|
+
expectedState: string,
|
|
588
|
+
onAuthorizationInput?: AuthenticateOptions["onAuthorizationInput"],
|
|
589
|
+
signal?: AbortSignal,
|
|
590
|
+
): Promise<AuthorizationResponse> {
|
|
591
|
+
if (!onAuthorizationInput) {
|
|
592
|
+
return {
|
|
593
|
+
input: await abortable(callbackPromise, signal),
|
|
594
|
+
source: "callback",
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const inputController = new AbortController()
|
|
599
|
+
try {
|
|
600
|
+
const response = await abortable(Promise.race([
|
|
601
|
+
callbackPromise.then((input) => ({ input, source: "callback" as const })),
|
|
602
|
+
onAuthorizationInput(authorizationUrl, inputController.signal).then((input) => ({
|
|
603
|
+
input,
|
|
604
|
+
source: "manual" as const,
|
|
605
|
+
})),
|
|
606
|
+
]), signal)
|
|
607
|
+
|
|
608
|
+
if (response.source === "callback") return response
|
|
609
|
+
if (!response.input?.trim()) throw new Error("OAuth authentication cancelled")
|
|
610
|
+
if (!getSearchParamsFromInput(response.input.trim())) {
|
|
611
|
+
throw new Error("Paste the full OAuth callback URL, including its code and state parameters")
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
input: parseAuthorizationRedirectInput(response.input, expectedState),
|
|
615
|
+
source: "manual",
|
|
616
|
+
}
|
|
617
|
+
} finally {
|
|
618
|
+
inputController.abort()
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Complete OAuth authentication from manual user input.
|
|
624
|
+
*/
|
|
625
|
+
export async function completeAuthFromInput(
|
|
626
|
+
serverName: string,
|
|
627
|
+
input: string,
|
|
628
|
+
options: AuthenticateOptions = {},
|
|
629
|
+
): Promise<AuthStatus> {
|
|
630
|
+
const runtime = getRuntime(options)
|
|
631
|
+
const runtimeState = getRuntimeState(runtime)
|
|
632
|
+
const fallbackAuthStorageOptions = options.authStorageOptions ?? {}
|
|
633
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
634
|
+
throwIfAborted(signal)
|
|
635
|
+
const key = getPendingAuthKey(serverName, fallbackAuthStorageOptions)
|
|
636
|
+
const oauthState = runtimeState.pendingAuthStates.get(key)
|
|
637
|
+
throwIfAborted(signal)
|
|
638
|
+
const parsed = parseAuthorizationRedirectInput(input, oauthState)
|
|
639
|
+
return completeAuth(serverName, parsed, options)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Complete OAuth authentication with the authorization code.
|
|
644
|
+
*/
|
|
645
|
+
export async function completeAuth(
|
|
646
|
+
serverName: string,
|
|
647
|
+
authorizationCode: string | AuthorizationCodeInput,
|
|
648
|
+
options: AuthenticateOptions = {},
|
|
649
|
+
): Promise<AuthStatus> {
|
|
650
|
+
const runtime = getRuntime(options)
|
|
651
|
+
const runtimeState = getRuntimeState(runtime)
|
|
652
|
+
const { code, iss } = typeof authorizationCode === "string"
|
|
653
|
+
? { code: authorizationCode, iss: undefined }
|
|
654
|
+
: authorizationCode
|
|
655
|
+
const fallbackAuthStorageOptions = options.authStorageOptions ?? {}
|
|
656
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
657
|
+
throwIfAborted(signal)
|
|
658
|
+
const key = getPendingAuthKey(serverName, fallbackAuthStorageOptions)
|
|
659
|
+
const pendingAuth = runtimeState.pendingAuths.get(key)
|
|
660
|
+
const authStorageOptions = pendingAuth?.authStorageOptions ?? fallbackAuthStorageOptions
|
|
661
|
+
if (!pendingAuth) {
|
|
662
|
+
throw new Error(`No pending OAuth flow for server: ${serverName}`)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const oauthState = runtimeState.pendingAuthStates.get(key)
|
|
666
|
+
throwIfAborted(signal)
|
|
667
|
+
|
|
668
|
+
let keepPendingForRetry = false
|
|
669
|
+
let caughtError: unknown
|
|
670
|
+
try {
|
|
671
|
+
const discoveryState = await pendingAuth.authProvider.discoveryState()
|
|
672
|
+
const metadata = discoveryState?.authorizationServerMetadata
|
|
673
|
+
const expectedIssuer = metadata?.issuer ?? discoveryState?.authorizationServerUrl
|
|
674
|
+
const requiresIssuer = (metadata as { authorization_response_iss_parameter_supported?: unknown } | undefined)
|
|
675
|
+
?.authorization_response_iss_parameter_supported === true
|
|
676
|
+
if (expectedIssuer !== undefined && iss === undefined && requiresIssuer) {
|
|
677
|
+
keepPendingForRetry = true
|
|
678
|
+
throw new Error(
|
|
679
|
+
`The authorization server for ${serverName} requires the RFC 9207 "iss" parameter. ` +
|
|
680
|
+
"Paste the full redirect URL from the browser address bar (not just the authorization code).",
|
|
681
|
+
)
|
|
682
|
+
}
|
|
683
|
+
if (expectedIssuer !== undefined && iss !== undefined && iss !== expectedIssuer) {
|
|
684
|
+
throw new Error(`The OAuth authorization response issuer does not match the discovered issuer for ${serverName}.`)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const result = await abortable(runSdkAuth(pendingAuth.authProvider, {
|
|
688
|
+
serverUrl: pendingAuth.serverUrl,
|
|
689
|
+
authorizationCode: code,
|
|
690
|
+
...(iss !== undefined ? { iss } : {}),
|
|
691
|
+
...pendingAuth.discovery,
|
|
692
|
+
}), signal)
|
|
693
|
+
throwIfAborted(signal)
|
|
694
|
+
if (result !== "AUTHORIZED") {
|
|
695
|
+
throw new UnauthorizedError("Failed to authorize")
|
|
696
|
+
}
|
|
697
|
+
return "authenticated"
|
|
698
|
+
} catch (error) {
|
|
699
|
+
caughtError = error
|
|
700
|
+
throw error
|
|
701
|
+
} finally {
|
|
702
|
+
if (!keepPendingForRetry) {
|
|
703
|
+
try {
|
|
704
|
+
await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
|
|
705
|
+
} catch (cleanupError) {
|
|
706
|
+
if (caughtError !== undefined) {
|
|
707
|
+
throw new AggregateError([caughtError, cleanupError], "OAuth completion cleanup failed")
|
|
708
|
+
}
|
|
709
|
+
throw cleanupError
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Perform the complete OAuth authentication flow for a server.
|
|
717
|
+
*
|
|
718
|
+
* @param serverName - The name of the MCP server
|
|
719
|
+
* @param serverUrl - The URL of the MCP server
|
|
720
|
+
* @param definition - The server definition (optional)
|
|
721
|
+
* @returns The final auth status
|
|
722
|
+
*/
|
|
723
|
+
export async function authenticate(
|
|
724
|
+
serverName: string,
|
|
725
|
+
serverUrl: string,
|
|
726
|
+
definition?: ServerEntry,
|
|
727
|
+
options: AuthenticateOptions = {},
|
|
728
|
+
): Promise<AuthStatus> {
|
|
729
|
+
if (isServerDisabled(definition)) throw new Error(`MCP server "${serverName}" is disabled`)
|
|
730
|
+
const runtime = getRuntime(options)
|
|
731
|
+
const runtimeState = getRuntimeState(runtime)
|
|
732
|
+
const authStorageOptions = options.authStorageOptions ?? {}
|
|
733
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
734
|
+
throwIfAborted(signal)
|
|
735
|
+
const authKey = `${serverName}|${serverUrl}|${getAuthBaseDir(authStorageOptions)}`
|
|
736
|
+
const inFlight = runtimeState.pendingAuthentications.get(authKey)
|
|
737
|
+
if (inFlight) {
|
|
738
|
+
return inFlight
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const operation = (async (): Promise<AuthStatus> => {
|
|
742
|
+
const { authorizationUrl } = await startAuth(serverName, serverUrl, definition, {
|
|
743
|
+
...options,
|
|
744
|
+
...(signal ? { signal } : {}),
|
|
745
|
+
runtime,
|
|
746
|
+
})
|
|
747
|
+
|
|
748
|
+
if (!authorizationUrl) {
|
|
749
|
+
return "authenticated"
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
let oauthState: string | undefined
|
|
753
|
+
try {
|
|
754
|
+
// Get the state that was already generated and stored in startAuth().
|
|
755
|
+
// Keep this lookup and its abort check inside the cleanup boundary because
|
|
756
|
+
// startAuth has already reserved callback state at this point.
|
|
757
|
+
oauthState = runtimeState.pendingAuthStates.get(getPendingAuthKey(serverName, authStorageOptions))
|
|
758
|
+
throwIfAborted(signal)
|
|
759
|
+
if (!oauthState) {
|
|
760
|
+
throw new Error("OAuth state not found - this should not happen")
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Register the callback BEFORE opening the browser.
|
|
764
|
+
const callbackPromise = waitForCallback(oauthState)
|
|
765
|
+
void callbackPromise.catch(() => {})
|
|
766
|
+
|
|
767
|
+
// Open browser. Always surface the URL first so remote/headless users can copy it
|
|
768
|
+
// even when the OS browser handoff is unavailable or invisible.
|
|
769
|
+
if (options.onAuthorizationUrl) {
|
|
770
|
+
await abortable(Promise.resolve(options.onAuthorizationUrl(authorizationUrl)), signal)
|
|
771
|
+
} else {
|
|
772
|
+
console.log(`MCP Auth: Open this URL to authenticate ${serverName}:\n${authorizationUrl}`)
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
await abortable(open(authorizationUrl), signal)
|
|
776
|
+
} catch (error) {
|
|
777
|
+
if (isAbortError(error, signal)) throw error
|
|
778
|
+
console.warn(`MCP Auth: Failed to open browser for ${serverName}; waiting for manual callback`, { error })
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const authorizationResponse = await waitForAuthorizationResponse(
|
|
782
|
+
callbackPromise,
|
|
783
|
+
authorizationUrl,
|
|
784
|
+
oauthState,
|
|
785
|
+
options.onAuthorizationInput,
|
|
786
|
+
signal,
|
|
787
|
+
)
|
|
788
|
+
if (authorizationResponse.source === "manual") {
|
|
789
|
+
cancelPendingCallback(oauthState)
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// The callback server accepted only the flow-local reserved state. Manual
|
|
793
|
+
// input is checked against the same state before token exchange.
|
|
794
|
+
throwIfAborted(signal)
|
|
795
|
+
|
|
796
|
+
return await completeAuth(serverName, authorizationResponse.input, {
|
|
797
|
+
...options,
|
|
798
|
+
...(signal ? { signal } : {}),
|
|
799
|
+
runtime,
|
|
800
|
+
})
|
|
801
|
+
} catch (error) {
|
|
802
|
+
if (oauthState) cancelPendingCallback(oauthState)
|
|
803
|
+
try {
|
|
804
|
+
await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
|
|
805
|
+
} catch (cleanupError) {
|
|
806
|
+
throw new AggregateError([error, cleanupError], "OAuth cancellation cleanup failed")
|
|
807
|
+
}
|
|
808
|
+
throw error
|
|
809
|
+
}
|
|
810
|
+
})()
|
|
811
|
+
|
|
812
|
+
runtimeState.pendingAuthentications.set(authKey, operation)
|
|
813
|
+
|
|
814
|
+
try {
|
|
815
|
+
return await operation
|
|
816
|
+
} finally {
|
|
817
|
+
if (runtimeState.pendingAuthentications.get(authKey) === operation) {
|
|
818
|
+
runtimeState.pendingAuthentications.delete(authKey)
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Get a valid access token for a server, refreshing if necessary.
|
|
825
|
+
*
|
|
826
|
+
* @param serverName - The name of the MCP server
|
|
827
|
+
* @param serverUrl - The URL of the MCP server
|
|
828
|
+
* @returns The valid tokens or null if not authenticated
|
|
829
|
+
*/
|
|
830
|
+
export async function getValidToken(
|
|
831
|
+
serverName: string,
|
|
832
|
+
serverUrl: string,
|
|
833
|
+
options: AuthenticateOptions = {},
|
|
834
|
+
): Promise<StoredTokens | null> {
|
|
835
|
+
const runtime = getRuntime(options)
|
|
836
|
+
const authStorageOptions = options.authStorageOptions ?? {}
|
|
837
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
838
|
+
throwIfAborted(signal)
|
|
839
|
+
const entry = await getAuthForUrl(serverName, serverUrl, authStorageOptions)
|
|
840
|
+
throwIfAborted(signal)
|
|
841
|
+
if (!entry?.tokens) {
|
|
842
|
+
return null
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const expired = await isTokenExpired(serverName, authStorageOptions)
|
|
846
|
+
if (expired === false) {
|
|
847
|
+
return entry.tokens
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (expired === true && entry.tokens.refreshToken) {
|
|
851
|
+
console.log(`MCP Auth: Token expired for ${serverName}, attempting refresh`)
|
|
852
|
+
|
|
853
|
+
try {
|
|
854
|
+
const authProvider = new McpOAuthProvider(serverName, serverUrl, {}, {
|
|
855
|
+
onRedirect: async () => {},
|
|
856
|
+
}, authStorageOptions, runtime.signal)
|
|
857
|
+
|
|
858
|
+
try {
|
|
859
|
+
const clientInfo = await authProvider.clientInformation()
|
|
860
|
+
throwIfAborted(signal)
|
|
861
|
+
if (!clientInfo) {
|
|
862
|
+
console.log(`MCP Auth: No client info for refresh for ${serverName}`)
|
|
863
|
+
return null
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const discovery = await probeAuthDiscovery(serverUrl, undefined, signal)
|
|
867
|
+
throwIfAborted(signal)
|
|
868
|
+
const result = await abortable(runSdkAuth(authProvider, {
|
|
869
|
+
serverUrl,
|
|
870
|
+
...discovery,
|
|
871
|
+
...(options.skipIssuerMetadataValidation === true ? { skipIssuerMetadataValidation: true } : {}),
|
|
872
|
+
}), signal)
|
|
873
|
+
throwIfAborted(signal)
|
|
874
|
+
if (result !== "AUTHORIZED") {
|
|
875
|
+
return null
|
|
876
|
+
}
|
|
877
|
+
const refreshed = await getAuthForUrl(serverName, serverUrl, authStorageOptions)
|
|
878
|
+
throwIfAborted(signal)
|
|
879
|
+
return refreshed?.tokens ?? null
|
|
880
|
+
} finally {
|
|
881
|
+
authProvider.deactivate()
|
|
882
|
+
}
|
|
883
|
+
} catch (error) {
|
|
884
|
+
if (isAbortError(error, signal) || error instanceof OAuthCredentialStoreError) throw error
|
|
885
|
+
console.error(`MCP Auth: Token refresh failed for ${serverName}`, { error })
|
|
886
|
+
return null
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// No expiration info or no refresh token, assume valid
|
|
891
|
+
return entry.tokens
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Check the authentication status for a server.
|
|
896
|
+
*
|
|
897
|
+
* @param serverName - The name of the MCP server
|
|
898
|
+
* @returns The current auth status
|
|
899
|
+
*/
|
|
900
|
+
export async function getAuthStatus(serverName: string, options: AuthenticateOptions = {}): Promise<AuthStatus> {
|
|
901
|
+
getRuntime(options)
|
|
902
|
+
const authStorageOptions = options.authStorageOptions ?? {}
|
|
903
|
+
const hasTokens = await hasStoredTokens(serverName, authStorageOptions)
|
|
904
|
+
if (!hasTokens) return "not_authenticated"
|
|
905
|
+
|
|
906
|
+
const expired = await isTokenExpired(serverName, authStorageOptions)
|
|
907
|
+
return expired ? "expired" : "authenticated"
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Remove all OAuth credentials for a server.
|
|
912
|
+
*
|
|
913
|
+
* @param serverName - The name of the MCP server
|
|
914
|
+
*/
|
|
915
|
+
export async function removeAuth(serverName: string, options: AuthenticateOptions = {}): Promise<void> {
|
|
916
|
+
const runtime = getRuntime(options)
|
|
917
|
+
const signal = combineAbortSignals(runtime.signal, options.signal)
|
|
918
|
+
throwIfAborted(signal)
|
|
919
|
+
const authStorageOptions = options.authStorageOptions ?? {}
|
|
920
|
+
const oauthState = await getOAuthState(serverName, authStorageOptions)
|
|
921
|
+
throwIfAborted(signal)
|
|
922
|
+
if (oauthState) {
|
|
923
|
+
cancelPendingCallback(oauthState)
|
|
924
|
+
}
|
|
925
|
+
await clearPendingAuth(runtime, serverName, oauthState, authStorageOptions)
|
|
926
|
+
throwIfAborted(signal)
|
|
927
|
+
clearAllCredentials(serverName, authStorageOptions)
|
|
928
|
+
await clearOAuthState(serverName, authStorageOptions)
|
|
929
|
+
throwIfAborted(signal)
|
|
930
|
+
console.log(`MCP Auth: Removed credentials for ${serverName}`)
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Check if OAuth is supported for a server configuration.
|
|
935
|
+
* OAuth is supported for HTTP servers unless explicitly disabled.
|
|
936
|
+
*
|
|
937
|
+
* @param definition - The server definition
|
|
938
|
+
* @returns True if OAuth is supported
|
|
939
|
+
*/
|
|
940
|
+
export function supportsOAuth(definition: ServerEntry): boolean {
|
|
941
|
+
// OAuth requires a URL
|
|
942
|
+
if (!definition.url) return false
|
|
943
|
+
|
|
944
|
+
// Explicitly disabled via auth: false or oauth: false
|
|
945
|
+
if (definition.auth === false) return false
|
|
946
|
+
if (definition.oauth === false) return false
|
|
947
|
+
if (definition.auth === "oauth") return true
|
|
948
|
+
|
|
949
|
+
// Configured custom headers take precedence over implicit OAuth auto-detection.
|
|
950
|
+
if (definition.headers && Object.keys(definition.headers).length > 0) return false
|
|
951
|
+
|
|
952
|
+
// OAuth is enabled when auth is not specified (auto-detect)
|
|
953
|
+
return definition.auth === undefined
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Initialize the OAuth system on startup.
|
|
958
|
+
* OAuth callback binding is lazy and starts from startAuth() only.
|
|
959
|
+
*/
|
|
960
|
+
export async function initializeOAuth(
|
|
961
|
+
runtimeOrSignal?: McpOAuthRuntime | AbortSignal,
|
|
962
|
+
): Promise<McpOAuthRuntime> {
|
|
963
|
+
if (runtimeOrSignal && "signal" in runtimeOrSignal) {
|
|
964
|
+
runtimeOrSignal.signal.throwIfAborted()
|
|
965
|
+
activeRuntimes.add(runtimeOrSignal)
|
|
966
|
+
return runtimeOrSignal
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
await shutdownOAuth(legacyRuntime)
|
|
970
|
+
legacyRuntime = createOAuthRuntime(runtimeOrSignal as AbortSignal | undefined)
|
|
971
|
+
return legacyRuntime
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Shutdown one OAuth runtime. The callback server remains process-shared while
|
|
976
|
+
* another runtime has pending/reserved callback state or is still active.
|
|
977
|
+
*/
|
|
978
|
+
export async function shutdownOAuth(runtime: McpOAuthRuntime = legacyRuntime): Promise<void> {
|
|
979
|
+
const state = getRuntimeState(runtime)
|
|
980
|
+
if (state.controller.signal.aborted) return
|
|
981
|
+
state.generation += 1
|
|
982
|
+
state.controller.abort(new Error("OAuth runtime stopped"))
|
|
983
|
+
for (const callbackState of Array.from(state.pendingAuthStates.values())) cancelPendingCallback(callbackState)
|
|
984
|
+
for (const pendingAuth of Array.from(state.pendingAuths.values())) {
|
|
985
|
+
await clearPendingAuth(runtime, pendingAuth.serverName, undefined, pendingAuth.authStorageOptions)
|
|
986
|
+
}
|
|
987
|
+
state.pendingAuthentications.clear()
|
|
988
|
+
activeRuntimes.delete(runtime)
|
|
989
|
+
|
|
990
|
+
if (activeRuntimes.size === 0) {
|
|
991
|
+
await stopCallbackServer()
|
|
992
|
+
}
|
|
993
|
+
}
|