@ashx-j/lunr 0.2.25 → 0.2.27
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 +31 -1
- package/LICENSE +22 -0
- package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -1
- package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts +11 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +6 -10
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +1 -0
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-computer-use.d.ts +3 -0
- package/dist/builtin-extensions/lunr-computer-use.d.ts.map +1 -0
- package/dist/builtin-extensions/lunr-computer-use.js +179 -0
- package/dist/builtin-extensions/lunr-computer-use.js.map +1 -0
- package/dist/builtin-extensions/lunr-cron.d.ts +4 -5
- package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-cron.js +94 -108
- package/dist/builtin-extensions/lunr-cron.js.map +1 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.js +3 -1
- package/dist/builtin-extensions/lunr-local-providers/local-servers.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js +2 -2
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.js +2 -2
- package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.js +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/bemol-extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js +1 -15
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.d.ts +6 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.js +187 -132
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-client.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.d.ts +8 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.js +142 -112
- package/dist/builtin-extensions/pi-lsp-extension/src/lsp-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.d.ts +12 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.js +14 -7
- package/dist/builtin-extensions/pi-lsp-extension/src/tools/code-rewrite.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.d.ts +11 -3
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.js +67 -41
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/rewrite-engine.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.d.ts +4 -2
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.js +3 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/tree-sitter/search-engine.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.d.ts +2 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/commands.js +6 -6
- package/dist/builtin-extensions/pi-mcp-adapter/commands.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.d.ts +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/config.js +11 -5
- package/dist/builtin-extensions/pi-mcp-adapter/config.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +2 -2
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.js +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/host-html-template.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.js +48 -40
- package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.js +3 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.d.ts +12 -40
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js +166 -235
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.d.ts +5 -0
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.js +43 -13
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.d.ts +14 -3
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.js +73 -21
- package/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.js +4 -4
- package/dist/builtin-extensions/pi-mcp-adapter/proxy-modes.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js +2 -2
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/state.d.ts +2 -0
- package/dist/builtin-extensions/pi-mcp-adapter/state.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/state.js.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.js +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/index.js.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/models.d.ts +11 -5
- package/dist/builtin-extensions/pi-ollama-cloud/models.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-ollama-cloud/models.js +12 -32
- package/dist/builtin-extensions/pi-ollama-cloud/models.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/index.js +5 -3
- package/dist/builtin-extensions/pi-prompt-template-model/index.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts +2 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +21 -12
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +7 -24
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +39 -77
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -4
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +8 -5
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +15 -31
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +7 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +21 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +11 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +121 -25
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +25 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js +5 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/chain-outputs.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +7 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js +60 -32
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.js +15 -5
- package/dist/builtin-extensions/pi-subagents/src/shared/utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +4 -3
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +22 -11
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
- package/dist/builtin-extensions/pi-tps.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-tps.js +20 -17
- package/dist/builtin-extensions/pi-tps.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/activity.d.ts +1 -0
- package/dist/builtin-extensions/pi-web-access/activity.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/activity.js +27 -5
- package/dist/builtin-extensions/pi-web-access/activity.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/bounded-body.d.ts +3 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.js +43 -0
- package/dist/builtin-extensions/pi-web-access/bounded-body.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/content-page.d.ts +24 -0
- package/dist/builtin-extensions/pi-web-access/content-page.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/content-page.js +57 -0
- package/dist/builtin-extensions/pi-web-access/content-page.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/extract.js +7 -2
- package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.d.ts +0 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.js +147 -36
- package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +48 -73
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +12 -4
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js +35 -12
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/storage.d.ts +9 -6
- package/dist/builtin-extensions/pi-web-access/storage.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/storage.js +36 -24
- package/dist/builtin-extensions/pi-web-access/storage.js.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.d.ts +1 -1
- package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
- package/dist/builtin-extensions/simple-pi-memory.js +1 -1
- package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
- package/dist/cli/install-cli.d.ts.map +1 -1
- package/dist/cli/install-cli.js +38 -30
- package/dist/cli/install-cli.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +13 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +75 -11
- package/dist/core/agent-session-runtime.js.map +1 -1
- 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 +40 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +309 -76
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/browser/runtime.d.ts +2 -0
- package/dist/core/browser/runtime.d.ts.map +1 -1
- package/dist/core/browser/runtime.js +80 -45
- package/dist/core/browser/runtime.js.map +1 -1
- package/dist/core/browser/setup.d.ts.map +1 -1
- package/dist/core/browser/setup.js +12 -1
- package/dist/core/browser/setup.js.map +1 -1
- package/dist/core/computer-use/adapter.d.ts +28 -0
- package/dist/core/computer-use/adapter.d.ts.map +1 -0
- package/dist/core/computer-use/adapter.js +138 -0
- package/dist/core/computer-use/adapter.js.map +1 -0
- package/dist/core/computer-use/image.d.ts +27 -0
- package/dist/core/computer-use/image.d.ts.map +1 -0
- package/dist/core/computer-use/image.js +84 -0
- package/dist/core/computer-use/image.js.map +1 -0
- package/dist/core/computer-use/lease.d.ts +18 -0
- package/dist/core/computer-use/lease.d.ts.map +1 -0
- package/dist/core/computer-use/lease.js +129 -0
- package/dist/core/computer-use/lease.js.map +1 -0
- package/dist/core/computer-use/macos-runtime.d.ts +14 -0
- package/dist/core/computer-use/macos-runtime.d.ts.map +1 -0
- package/dist/core/computer-use/macos-runtime.js +148 -0
- package/dist/core/computer-use/macos-runtime.js.map +1 -0
- package/dist/core/computer-use/policy.d.ts +19 -0
- package/dist/core/computer-use/policy.d.ts.map +1 -0
- package/dist/core/computer-use/policy.js +67 -0
- package/dist/core/computer-use/policy.js.map +1 -0
- package/dist/core/computer-use/release.generated.d.ts +31 -0
- package/dist/core/computer-use/release.generated.d.ts.map +1 -0
- package/dist/core/computer-use/release.generated.js +36 -0
- package/dist/core/computer-use/release.generated.js.map +1 -0
- package/dist/core/computer-use/runtime.d.ts +13 -0
- package/dist/core/computer-use/runtime.d.ts.map +1 -0
- package/dist/core/computer-use/runtime.js +158 -0
- package/dist/core/computer-use/runtime.js.map +1 -0
- package/dist/core/computer-use/schemas.d.ts +100 -0
- package/dist/core/computer-use/schemas.d.ts.map +1 -0
- package/dist/core/computer-use/schemas.js +96 -0
- package/dist/core/computer-use/schemas.js.map +1 -0
- package/dist/core/computer-use/windows-desktop.d.ts +3 -0
- package/dist/core/computer-use/windows-desktop.d.ts.map +1 -0
- package/dist/core/computer-use/windows-desktop.js +48 -0
- package/dist/core/computer-use/windows-desktop.js.map +1 -0
- package/dist/core/computer-use/workflow.d.ts +38 -0
- package/dist/core/computer-use/workflow.d.ts.map +1 -0
- package/dist/core/computer-use/workflow.js +900 -0
- package/dist/core/computer-use/workflow.js.map +1 -0
- package/dist/core/cron/jobs.d.ts +26 -8
- package/dist/core/cron/jobs.d.ts.map +1 -1
- package/dist/core/cron/jobs.js +357 -232
- package/dist/core/cron/jobs.js.map +1 -1
- package/dist/core/cron/origin-context.d.ts +1 -0
- package/dist/core/cron/origin-context.d.ts.map +1 -1
- package/dist/core/cron/origin-context.js.map +1 -1
- package/dist/core/cron/scheduler.d.ts +22 -17
- package/dist/core/cron/scheduler.d.ts.map +1 -1
- package/dist/core/cron/scheduler.js +153 -73
- package/dist/core/cron/scheduler.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 +4 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +8 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +4 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +22 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/large-subagent-launch.d.ts +1 -1
- package/dist/core/large-subagent-launch.d.ts.map +1 -1
- package/dist/core/large-subagent-launch.js +7 -7
- package/dist/core/large-subagent-launch.js.map +1 -1
- package/dist/core/model-registry.d.ts +2 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +5 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts +4 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +40 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions.d.ts +4 -4
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +25 -38
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts +5 -13
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +135 -116
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/prompt-resource-bridge.d.ts +12 -0
- package/dist/core/prompt-resource-bridge.d.ts.map +1 -0
- package/dist/core/prompt-resource-bridge.js +9 -0
- package/dist/core/prompt-resource-bridge.js.map +1 -0
- package/dist/core/protected-targets.d.ts +6 -0
- package/dist/core/protected-targets.d.ts.map +1 -0
- package/dist/core/protected-targets.js +45 -0
- package/dist/core/protected-targets.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rollback.d.ts +19 -3
- package/dist/core/rollback.d.ts.map +1 -1
- package/dist/core/rollback.js +172 -56
- package/dist/core/rollback.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +3 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +14 -1
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +95 -32
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-ownership.d.ts.map +1 -1
- package/dist/core/session-ownership.js +8 -3
- package/dist/core/session-ownership.js.map +1 -1
- package/dist/core/session-retention.d.ts.map +1 -1
- package/dist/core/session-retention.js +18 -7
- package/dist/core/session-retention.js.map +1 -1
- package/dist/core/session-startup-settings.d.ts +10 -0
- package/dist/core/session-startup-settings.d.ts.map +1 -0
- package/dist/core/session-startup-settings.js +70 -0
- package/dist/core/session-startup-settings.js.map +1 -0
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +19 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-event-transport.d.ts +3 -0
- package/dist/core/subagent-event-transport.d.ts.map +1 -0
- package/dist/core/subagent-event-transport.js +61 -0
- package/dist/core/subagent-event-transport.js.map +1 -0
- package/dist/core/subscriptions.d.ts +16 -7
- package/dist/core/subscriptions.d.ts.map +1 -1
- package/dist/core/subscriptions.js +96 -55
- package/dist/core/subscriptions.js.map +1 -1
- package/dist/core/trust-manager.d.ts +2 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +6 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/update-check.d.ts.map +1 -1
- package/dist/core/update-check.js.map +1 -1
- package/dist/core/usage-adapters/kimi-coding.d.ts +2 -2
- package/dist/core/usage-adapters/kimi-coding.d.ts.map +1 -1
- package/dist/core/usage-adapters/kimi-coding.js +2 -2
- package/dist/core/usage-adapters/kimi-coding.js.map +1 -1
- package/dist/core/usage-adapters/openai-codex.d.ts +3 -2
- package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
- package/dist/core/usage-adapters/openai-codex.js +3 -3
- package/dist/core/usage-adapters/openai-codex.js.map +1 -1
- package/dist/core/usage-adapters/xai.d.ts +2 -2
- package/dist/core/usage-adapters/xai.d.ts.map +1 -1
- package/dist/core/usage-adapters/xai.js +3 -3
- package/dist/core/usage-adapters/xai.js.map +1 -1
- package/dist/core/usage-adapters/zai.d.ts +2 -2
- package/dist/core/usage-adapters/zai.d.ts.map +1 -1
- package/dist/core/usage-adapters/zai.js +2 -2
- package/dist/core/usage-adapters/zai.js.map +1 -1
- package/dist/core/usage-service.d.ts +9 -2
- package/dist/core/usage-service.d.ts.map +1 -1
- package/dist/core/usage-service.js +95 -50
- package/dist/core/usage-service.js.map +1 -1
- package/dist/gateway/adapters/discord.d.ts.map +1 -1
- package/dist/gateway/adapters/discord.js +2 -2
- package/dist/gateway/adapters/discord.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +9 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +91 -37
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/approval.d.ts.map +1 -1
- package/dist/gateway/approval.js +3 -3
- package/dist/gateway/approval.js.map +1 -1
- package/dist/gateway/authz.d.ts +4 -4
- package/dist/gateway/authz.d.ts.map +1 -1
- package/dist/gateway/authz.js +8 -12
- package/dist/gateway/authz.js.map +1 -1
- package/dist/gateway/buttons.d.ts +8 -1
- package/dist/gateway/buttons.d.ts.map +1 -1
- package/dist/gateway/buttons.js +76 -18
- package/dist/gateway/buttons.js.map +1 -1
- package/dist/gateway/commands.d.ts +1 -0
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +12 -10
- package/dist/gateway/commands.js.map +1 -1
- package/dist/gateway/cron.d.ts +12 -11
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +85 -62
- package/dist/gateway/cron.js.map +1 -1
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +5 -4
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/mobile-commands.d.ts +1 -0
- package/dist/gateway/mobile-commands.d.ts.map +1 -1
- package/dist/gateway/mobile-commands.js +64 -22
- package/dist/gateway/mobile-commands.js.map +1 -1
- package/dist/gateway/presenter.d.ts +12 -2
- package/dist/gateway/presenter.d.ts.map +1 -1
- package/dist/gateway/presenter.js +74 -39
- package/dist/gateway/presenter.js.map +1 -1
- package/dist/gateway/router.d.ts +2 -2
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js +22 -9
- package/dist/gateway/router.js.map +1 -1
- package/dist/gateway/service.d.ts +2 -0
- package/dist/gateway/service.d.ts.map +1 -1
- package/dist/gateway/service.js +153 -0
- package/dist/gateway/service.js.map +1 -1
- package/dist/gateway/setup.d.ts.map +1 -1
- package/dist/gateway/setup.js +6 -4
- package/dist/gateway/setup.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +86 -33
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +6 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -1
- package/dist/modes/interactive/components/copyable-text.js +3 -2
- package/dist/modes/interactive/components/copyable-text.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +20 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +104 -109
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/smooth-streaming.d.ts.map +1 -1
- package/dist/modes/interactive/smooth-streaming.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +9 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/node-runtime/adapter-247RTYLS.js +16 -0
- package/dist/node-runtime/agent-session-services-KDMSPQDY.js +53 -0
- package/dist/node-runtime/{brave-UWDA3I22.js → brave-2AFFAXNN.js} +1 -1
- package/dist/node-runtime/{builtin-extensions-ZLAX7TUH.js → builtin-extensions-OX6KELNX.js} +9 -7
- package/dist/node-runtime/{chunk-QH6YL7VK.js → chunk-252ZVPPF.js} +3 -3
- package/dist/node-runtime/{chunk-PCEW76PM.js → chunk-2OIPYKLZ.js} +6 -6
- package/dist/node-runtime/{chunk-XBWPBZBN.js → chunk-2SWW7KMW.js} +1 -1
- package/dist/node-runtime/{chunk-UQUCFAJ3.js → chunk-2VIW3IMF.js} +40 -7
- package/dist/node-runtime/{chunk-UOEDI7RP.js → chunk-4KNKQGHM.js} +2 -2
- package/dist/node-runtime/{chunk-FQMM2EZ2.js → chunk-64XTQNLA.js} +29 -7
- package/dist/node-runtime/{chunk-NRKGMJYU.js → chunk-6O3IW3IA.js} +2 -2
- package/dist/node-runtime/{chunk-5ZQXRPMC.js → chunk-6ZZHGUSA.js} +2 -2
- package/dist/node-runtime/chunk-A2WO6WIN.js +1197 -0
- package/dist/node-runtime/{chunk-ZXSGTGJ6.js → chunk-APVM5NEU.js} +169 -148
- package/dist/node-runtime/{chunk-RC7DMV45.js → chunk-AYHH7YSD.js} +205 -144
- package/dist/node-runtime/{chunk-LWYIVUGV.js → chunk-B2IBAXNX.js} +48 -31
- package/dist/node-runtime/{chunk-M3LZLQW2.js → chunk-BDRGN3L2.js} +1 -0
- package/dist/node-runtime/{chunk-GJ2RDBRL.js → chunk-BYC6RKCN.js} +4 -2
- package/dist/node-runtime/{chunk-KWIYUUZK.js → chunk-C3P6Q3B2.js} +469 -283
- package/dist/node-runtime/{chunk-YCUZEGJG.js → chunk-DQSCFU7R.js} +17 -8
- package/dist/node-runtime/chunk-EBLAZVSA.js +4170 -0
- package/dist/node-runtime/{chunk-2KIPT4HJ.js → chunk-EPR2F3GU.js} +68 -20
- package/dist/node-runtime/{chunk-CSFI6YXL.js → chunk-ES6PBSIE.js} +1 -1
- package/dist/node-runtime/{chunk-IF24A3FH.js → chunk-EVM653DD.js} +4 -4
- package/dist/node-runtime/{chunk-HTFRRDSF.js → chunk-F2SMQ6ES.js} +3 -2
- package/dist/node-runtime/chunk-F2V2F4ZG.js +114 -0
- package/dist/node-runtime/chunk-FE3WZI7F.js +290 -0
- package/dist/node-runtime/{chunk-GYIXXQAO.js → chunk-FIRA54AC.js} +2 -5
- package/dist/node-runtime/{chunk-6VYZ5UFP.js → chunk-FLGEEH27.js} +1 -1
- package/dist/node-runtime/{chunk-5EFIU3OM.js → chunk-FTKEZL27.js} +1 -1
- package/dist/node-runtime/chunk-FY4A63RK.js +73 -0
- package/dist/node-runtime/chunk-FYIFPFXE.js +98 -0
- package/dist/node-runtime/{chunk-HMBGROQK.js → chunk-GLDXBBL6.js} +3 -3
- package/dist/node-runtime/{chunk-KWA4OC2J.js → chunk-H6YBCWKG.js} +1 -1
- package/dist/node-runtime/{chunk-2MI5OPMN.js → chunk-HNNHHJAB.js} +68 -50
- package/dist/node-runtime/{chunk-6XL67VVY.js → chunk-HUD2RFJW.js} +17 -2
- package/dist/node-runtime/{chunk-I54LGHWM.js → chunk-I2H5QMWW.js} +3 -3
- package/dist/node-runtime/chunk-IAZSK7KK.js +108 -0
- package/dist/node-runtime/{chunk-2HHLJWGD.js → chunk-IHHTWSXN.js} +9 -9
- package/dist/node-runtime/{chunk-DAPBPCBP.js → chunk-IPP5BIV5.js} +25 -3
- package/dist/node-runtime/{chunk-QFWG2RVL.js → chunk-IXG6F4NT.js} +11 -0
- package/dist/node-runtime/{chunk-RDDAZOMU.js → chunk-JL4HYQXK.js} +1 -1
- package/dist/node-runtime/{chunk-CDVHZOOK.js → chunk-JQYNHAKX.js} +1 -1
- package/dist/node-runtime/{chunk-WF7PGWRZ.js → chunk-JWEVT363.js} +37 -28
- package/dist/node-runtime/{chunk-2HMIRK7W.js → chunk-LHV3V67B.js} +5 -5
- package/dist/node-runtime/{chunk-UAEOTO52.js → chunk-MNQXDFPV.js} +6 -2
- package/dist/node-runtime/{chunk-IJIFHRTB.js → chunk-MQPKUHRN.js} +165 -85
- package/dist/node-runtime/{chunk-MPKSOJBT.js → chunk-NHATCSOI.js} +4 -7
- package/dist/node-runtime/{chunk-RMQZU2YU.js → chunk-NNNR3QIY.js} +1 -1
- package/dist/node-runtime/{chunk-RWTKOC3B.js → chunk-QBTJG3UM.js} +1 -1
- package/dist/node-runtime/{chunk-E4D3IGP2.js → chunk-QNVMKNNN.js} +20 -17
- package/dist/node-runtime/{chunk-GS42T6MX.js → chunk-QW3AAHWN.js} +1 -1
- package/dist/node-runtime/{chunk-7S3T6YEA.js → chunk-R4WSB2MQ.js} +5 -5
- package/dist/node-runtime/{chunk-B4HP6ZWM.js → chunk-RHCGYWO7.js} +1 -1
- package/dist/node-runtime/{chunk-3XPLBUEM.js → chunk-RLGY2QIL.js} +49 -59
- package/dist/node-runtime/{chunk-KKUTQQV7.js → chunk-RYRGL7P4.js} +1 -1
- package/dist/node-runtime/{chunk-AD6VXAO7.js → chunk-TCT6PCUR.js} +47 -115
- package/dist/node-runtime/chunk-U5F4IC7R.js +53 -0
- package/dist/node-runtime/{chunk-OCVIXVTZ.js → chunk-UBWW2PID.js} +13 -2
- package/dist/node-runtime/{chunk-HFVZUPFJ.js → chunk-UNUZICC4.js} +3 -3
- package/dist/node-runtime/{chunk-LQP3RB67.js → chunk-UYRKUKFE.js} +1 -1
- package/dist/node-runtime/{chunk-DSIKTUPW.js → chunk-VSUEAI7O.js} +2993 -3820
- package/dist/node-runtime/{chunk-NAY6UUQZ.js → chunk-WDIVLMOH.js} +1 -1
- package/dist/node-runtime/{chunk-E24EO34J.js → chunk-WPXUR3HE.js} +1 -1
- package/dist/node-runtime/{chunk-SLVOAQOY.js → chunk-WXYNALHD.js} +113 -1
- package/dist/node-runtime/{chunk-KJ6DWS3K.js → chunk-XEOCUEUJ.js} +121 -60
- package/dist/node-runtime/chunk-YD3IZAZ7.js +47 -0
- package/dist/node-runtime/chunk-YSB6URMT.js +41 -0
- package/dist/node-runtime/{chunk-VQFSUJJG.js → chunk-ZDJUR45D.js} +430 -129
- package/dist/node-runtime/{chunk-YDO2F2IA.js → chunk-ZEVFBFNF.js} +95 -142
- package/dist/node-runtime/chunk-ZIQUS5QO.js +180 -0
- package/dist/node-runtime/cli-runtime.js +4 -4
- package/dist/node-runtime/{command-6WDOYKS6.js → command-3HMSY6W2.js} +5 -5
- package/dist/node-runtime/{commands-NZLSOHPE.js → commands-D6A6H4TS.js} +11 -16
- package/dist/node-runtime/commands-OCSSEEWJ.js +37 -0
- package/dist/node-runtime/{config-QDD5PUE2.js → config-CU7M7BTK.js} +1 -1
- package/dist/node-runtime/{config-D4QUPAHX.js → config-DS7XLMEM.js} +2 -2
- package/dist/node-runtime/{direct-tool-executor-77GW4F5P.js → direct-tool-executor-2QJXVQD2.js} +8 -10
- package/dist/node-runtime/{exa-LL64QZR2.js → exa-6VBZNPGE.js} +1 -1
- package/dist/node-runtime/{export-html-VM4J2MNR.js → export-html-BRWF5AHI.js} +4 -4
- package/dist/node-runtime/{extension-input-E7BJZ35H.js → extension-input-VBBMX7YV.js} +5 -5
- package/dist/node-runtime/{extension-selector-WU42XDTU.js → extension-selector-T5AOG5XB.js} +5 -5
- package/dist/node-runtime/{extract-EQJE7FZZ.js → extract-BFX2N35A.js} +3 -3
- package/dist/node-runtime/{gateway-INAYBF4Q.js → gateway-6623C2U3.js} +61 -53
- package/dist/node-runtime/{gemini-search-35OCRFLN.js → gemini-search-C66QHDT6.js} +2 -2
- package/dist/node-runtime/{gemini-url-context-UQY3PHHW.js → gemini-url-context-T7DEK73R.js} +3 -3
- package/dist/node-runtime/{github-extract-F64RZOEA.js → github-extract-HOGE3D6F.js} +107 -38
- package/dist/node-runtime/{goal-NJEE5CTU.js → goal-AIHEDUYA.js} +5 -5
- package/dist/node-runtime/index.js +54 -48
- package/dist/node-runtime/{init-HS6NQXSK.js → init-JBQJIPYI.js} +3 -4
- package/dist/node-runtime/{install-cli-KL4UDDAD.js → install-cli-INGHIVBY.js} +30 -25
- package/dist/node-runtime/interactive-mode-FM5DNUSW.js +74 -0
- package/dist/node-runtime/{interactive-view-NGFAMHPW.js → interactive-view-K33PM4OS.js} +8 -8
- package/dist/node-runtime/{lsp-manager-3ASUSO4T.js → lsp-manager-S554V5HR.js} +240 -155
- package/dist/node-runtime/{lunr-browser-IR7TL3J7.js → lunr-browser-H4FDOR3C.js} +7 -7
- package/dist/node-runtime/lunr-computer-use-VDP2QNRQ.js +158 -0
- package/dist/node-runtime/{lunr-cron-LWIZJM2N.js → lunr-cron-LKVA5CZZ.js} +94 -79
- package/dist/node-runtime/main.js +42 -39
- package/dist/node-runtime/{mobile-commands-J7OJEKFO.js → mobile-commands-XT3NQXLD.js} +13 -12
- package/dist/node-runtime/{model-runtime-OO5HFLWE.js → model-runtime-MZ2JMDV4.js} +4 -4
- package/dist/node-runtime/{openai-search-B3MSNCQA.js → openai-search-K72LJDYN.js} +1 -1
- package/dist/node-runtime/{package-manager-cli-VYZM5WHN.js → package-manager-cli-CYM262SI.js} +20 -19
- package/dist/node-runtime/{parallel-AI2MNSCU.js → parallel-X724NCNU.js} +1 -1
- package/dist/node-runtime/{perplexity-QVJW3I35.js → perplexity-RDHQHVMK.js} +2 -2
- package/dist/node-runtime/{pi-intercom-QM53RLTS.js → pi-intercom-NHHEPBMI.js} +2 -2
- package/dist/node-runtime/{pi-mcp-adapter-5UKBZP44.js → pi-mcp-adapter-PP3GQJQ2.js} +98 -94
- package/dist/node-runtime/{pi-ollama-cloud-2F3Y2QNM.js → pi-ollama-cloud-4MNWIMFN.js} +11 -24
- package/dist/node-runtime/{pi-prompt-template-model-QWTCGLJU.js → pi-prompt-template-model-FTGELLS5.js} +32 -36
- package/dist/node-runtime/{pi-subagents-DNY7EAIG.js → pi-subagents-LT3CTO4E.js} +114 -116
- package/dist/node-runtime/{pi-web-access-WTGMNZ32.js → pi-web-access-Z3LP246C.js} +144 -108
- package/dist/node-runtime/{print-mode-XSFM26EL.js → print-mode-2XHN5SUA.js} +4 -3
- package/dist/node-runtime/{process-registry-4FAKZQOL.js → process-registry-Q4QWIU33.js} +3 -3
- package/dist/node-runtime/{proxy-modes-LGEUYD7R.js → proxy-modes-VEGC6QG5.js} +9 -13
- package/dist/node-runtime/rpc-entry.js +42 -39
- package/dist/node-runtime/{rpc-mode-O3XV4SID.js → rpc-mode-32DHJPEJ.js} +4 -4
- package/dist/node-runtime/{runtime-4VA6JKNF.js → runtime-EDUUGAQD.js} +56 -46
- package/dist/node-runtime/runtime-UGXM4NPQ.js +21 -0
- package/dist/node-runtime/{runtime-bridges-VRDDR73P.js → runtime-bridges-DNKMNJCF.js} +8 -7
- package/dist/node-runtime/{service-MDQIPQ26.js → service-IHLGFLBT.js} +6 -4
- package/dist/node-runtime/{session-handoff-GWARVEWT.js → session-handoff-LNSPDTKY.js} +4 -4
- package/dist/node-runtime/{session-manager-JB5J6XBN.js → session-manager-YIFIAVGC.js} +3 -3
- package/dist/node-runtime/{session-selector-GIM4DHQ2.js → session-selector-I73U3EIO.js} +7 -7
- package/dist/node-runtime/{settings-manager-J4SPQPDJ.js → settings-manager-P2TKGYTR.js} +6 -5
- package/dist/node-runtime/{setup-JBKOLJ6F.js → setup-H7CCELIL.js} +15 -1
- package/dist/node-runtime/{setup-CQ2NLVK5.js → setup-OLQ4GXWS.js} +22 -21
- package/dist/node-runtime/{src-IVPNZ2BX.js → src-6RV4PXKJ.js} +64 -36
- package/dist/node-runtime/{subagent-executor-KZZQGAKV.js → subagent-executor-Q5F7DBVM.js} +141 -62
- package/dist/node-runtime/{tavily-WEZFVFP7.js → tavily-KZBFYQB6.js} +1 -1
- package/dist/node-runtime/{theme-UOO5RVFN.js → theme-YLVZKKZD.js} +2 -2
- package/dist/node-runtime/{trust-manager-MMISNCYO.js → trust-manager-ZCU76D23.js} +2 -2
- package/dist/node-runtime/{update-cli-GTFJC7XK.js → update-cli-F3XXJANQ.js} +7 -6
- package/dist/node-runtime/{usage-service-LFB2SWYV.js → usage-service-CPAGBED5.js} +1 -1
- package/dist/node-runtime/{video-extract-OOZHR7SU.js → video-extract-UPKYIBW3.js} +3 -3
- package/dist/node-runtime/workflow-ICDI4N3J.js +767 -0
- package/dist/node-runtime/{youtube-extract-FNPAUNHU.js → youtube-extract-77NT7FWH.js} +4 -4
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js +25 -10
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts +2 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js +12 -0
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/paths.d.ts +4 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +33 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/sanitize-terminal-text.d.ts +7 -0
- package/dist/utils/sanitize-terminal-text.d.ts.map +1 -0
- package/dist/utils/sanitize-terminal-text.js +67 -0
- package/dist/utils/sanitize-terminal-text.js.map +1 -0
- package/docs/browser.md +1 -1
- package/docs/computer-use.md +362 -0
- package/docs/custom-provider.md +3 -3
- package/docs/extensions.md +8 -4
- package/docs/features.md +22 -12
- package/docs/keybindings.md +1 -1
- package/docs/models.md +5 -5
- package/docs/packages.md +1 -1
- package/docs/providers.md +2 -2
- package/docs/rpc.md +7 -7
- package/docs/security.md +10 -5
- package/docs/sessions.md +2 -2
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +7 -7
- package/docs/themes.md +1 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/auto-commit-on-exit.ts +1 -1
- package/examples/extensions/bash-spawn-hook.ts +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +1 -1
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-compaction.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
- 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 +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/git-merge-and-resolve.ts +2 -2
- package/examples/extensions/gondolin/index.ts +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +2 -2
- package/examples/extensions/input-transform.ts +2 -2
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/kimi-deferred-tools.ts +1 -1
- package/examples/extensions/mac-system-theme.ts +1 -1
- package/examples/extensions/minimal-mode.ts +1 -1
- package/examples/extensions/modal-editor.ts +1 -1
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/notify.ts +3 -3
- package/examples/extensions/overlay-qa-tests.ts +1 -1
- package/examples/extensions/overlay-test.ts +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/preset.ts +3 -3
- package/examples/extensions/project-trust.ts +4 -4
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/index.ts +7 -7
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/shutdown-command.ts +5 -5
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/subagent/README.md +3 -3
- package/examples/extensions/subagent/index.ts +2 -2
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/working-indicator.ts +1 -1
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/06-extensions.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +1 -1
- package/install-lock/package-lock.json +3841 -0
- package/install-lock/package.json +18 -0
- package/native/computer-use/LICENSE.md +21 -0
- package/npm-shrinkwrap.json +3858 -0
- package/package.json +15 -9
- package/dist/modes/interactive/components/exit-card.d.ts +0 -22
- package/dist/modes/interactive/components/exit-card.d.ts.map +0 -1
- package/dist/modes/interactive/components/exit-card.js +0 -69
- package/dist/modes/interactive/components/exit-card.js.map +0 -1
- package/dist/node-runtime/agent-session-services-YXXFCP5J.js +0 -49
- package/dist/node-runtime/chunk-4HXHDDCF.js +0 -16
- package/dist/node-runtime/chunk-4TLO4PO2.js +0 -3427
- package/dist/node-runtime/chunk-AUXVGBO4.js +0 -19
- package/dist/node-runtime/chunk-OVX6X377.js +0 -50
- package/dist/node-runtime/chunk-QTU6AKNJ.js +0 -773
- package/dist/node-runtime/chunk-TORR5XBV.js +0 -356
- package/dist/node-runtime/commands-QC6VUZJQ.js +0 -36
- package/dist/node-runtime/interactive-mode-Z5M7WYYZ.js +0 -72
- package/dist/node-runtime/mcp-auth-flow-QIXHW6QN.js +0 -32
|
@@ -0,0 +1,4170 @@
|
|
|
1
|
+
import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
AjvJsonSchemaValidator,
|
|
4
|
+
CallToolResultSchema,
|
|
5
|
+
Client,
|
|
6
|
+
ContentBlockSchema,
|
|
7
|
+
CreateMessageRequestSchema,
|
|
8
|
+
ElicitRequestSchema,
|
|
9
|
+
ElicitationCompleteNotificationSchema,
|
|
10
|
+
EmbeddedResourceSchema,
|
|
11
|
+
ErrorCode,
|
|
12
|
+
ImplementationSchema,
|
|
13
|
+
JSONRPCMessageSchema,
|
|
14
|
+
LATEST_PROTOCOL_VERSION,
|
|
15
|
+
McpError,
|
|
16
|
+
RequestIdSchema,
|
|
17
|
+
ResourceLinkSchema,
|
|
18
|
+
StdioClientTransport,
|
|
19
|
+
ToolSchema,
|
|
20
|
+
UrlElicitationRequiredError,
|
|
21
|
+
isInitializedNotification,
|
|
22
|
+
isJSONRPCRequest,
|
|
23
|
+
isJSONRPCResultResponse
|
|
24
|
+
} from "./chunk-VSUEAI7O.js";
|
|
25
|
+
import {
|
|
26
|
+
abortable,
|
|
27
|
+
computeServerHash,
|
|
28
|
+
extractToolUiStreamMode,
|
|
29
|
+
getAgentPath,
|
|
30
|
+
getMetadataCachePath,
|
|
31
|
+
getMissingConfiguredDirectToolServers,
|
|
32
|
+
interpolateEnvRecord,
|
|
33
|
+
isServerCacheValid,
|
|
34
|
+
loadMcpConfig,
|
|
35
|
+
loadMetadataCache,
|
|
36
|
+
openUrl,
|
|
37
|
+
parallelLimit,
|
|
38
|
+
reconstructToolMetadata,
|
|
39
|
+
resolveBearerToken,
|
|
40
|
+
resolveConfigPath,
|
|
41
|
+
saveMetadataCache,
|
|
42
|
+
serializeResources,
|
|
43
|
+
serializeTools,
|
|
44
|
+
throwIfAborted,
|
|
45
|
+
truncateAtWord
|
|
46
|
+
} from "./chunk-B2IBAXNX.js";
|
|
47
|
+
import {
|
|
48
|
+
formatToolName,
|
|
49
|
+
isToolExcluded,
|
|
50
|
+
resourceNameToToolName,
|
|
51
|
+
serverStreamResultPatchNotificationSchema
|
|
52
|
+
} from "./chunk-ARC4KOTI.js";
|
|
53
|
+
import {
|
|
54
|
+
NEVER,
|
|
55
|
+
ZodIssueCode,
|
|
56
|
+
any,
|
|
57
|
+
array,
|
|
58
|
+
boolean,
|
|
59
|
+
coerce_exports,
|
|
60
|
+
external_exports,
|
|
61
|
+
literal,
|
|
62
|
+
looseObject,
|
|
63
|
+
number,
|
|
64
|
+
object,
|
|
65
|
+
string,
|
|
66
|
+
url
|
|
67
|
+
} from "./chunk-BI3DHYCN.js";
|
|
68
|
+
import {
|
|
69
|
+
__commonJS,
|
|
70
|
+
__require,
|
|
71
|
+
__toESM
|
|
72
|
+
} from "./chunk-BRJX2PRC.js";
|
|
73
|
+
|
|
74
|
+
// node_modules/content-type/index.js
|
|
75
|
+
var require_content_type = __commonJS({
|
|
76
|
+
"node_modules/content-type/index.js"(exports) {
|
|
77
|
+
"use strict";
|
|
78
|
+
var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g, TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/, TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/, QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g, QUOTE_REGEXP = /([\\"])/g, TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
79
|
+
exports.format = format;
|
|
80
|
+
exports.parse = parse;
|
|
81
|
+
function format(obj) {
|
|
82
|
+
if (!obj || typeof obj != "object")
|
|
83
|
+
throw new TypeError("argument obj is required");
|
|
84
|
+
var parameters = obj.parameters, type = obj.type;
|
|
85
|
+
if (!type || !TYPE_REGEXP.test(type))
|
|
86
|
+
throw new TypeError("invalid type");
|
|
87
|
+
var string2 = type;
|
|
88
|
+
if (parameters && typeof parameters == "object")
|
|
89
|
+
for (var param, params = Object.keys(parameters).sort(), i2 = 0; i2 < params.length; i2++) {
|
|
90
|
+
if (param = params[i2], !TOKEN_REGEXP.test(param))
|
|
91
|
+
throw new TypeError("invalid parameter name");
|
|
92
|
+
string2 += "; " + param + "=" + qstring(parameters[param]);
|
|
93
|
+
}
|
|
94
|
+
return string2;
|
|
95
|
+
}
|
|
96
|
+
function parse(string2) {
|
|
97
|
+
if (!string2)
|
|
98
|
+
throw new TypeError("argument string is required");
|
|
99
|
+
var header = typeof string2 == "object" ? getcontenttype(string2) : string2;
|
|
100
|
+
if (typeof header != "string")
|
|
101
|
+
throw new TypeError("argument string is required to be a string");
|
|
102
|
+
var index = header.indexOf(";"), type = index !== -1 ? header.slice(0, index).trim() : header.trim();
|
|
103
|
+
if (!TYPE_REGEXP.test(type))
|
|
104
|
+
throw new TypeError("invalid media type");
|
|
105
|
+
var obj = new ContentType(type.toLowerCase());
|
|
106
|
+
if (index !== -1) {
|
|
107
|
+
var key, match, value;
|
|
108
|
+
for (PARAM_REGEXP.lastIndex = index; match = PARAM_REGEXP.exec(header); ) {
|
|
109
|
+
if (match.index !== index)
|
|
110
|
+
throw new TypeError("invalid parameter format");
|
|
111
|
+
index += match[0].length, key = match[1].toLowerCase(), value = match[2], value.charCodeAt(0) === 34 && (value = value.slice(1, -1), value.indexOf("\\") !== -1 && (value = value.replace(QESC_REGEXP, "$1"))), obj.parameters[key] = value;
|
|
112
|
+
}
|
|
113
|
+
if (index !== header.length)
|
|
114
|
+
throw new TypeError("invalid parameter format");
|
|
115
|
+
}
|
|
116
|
+
return obj;
|
|
117
|
+
}
|
|
118
|
+
function getcontenttype(obj) {
|
|
119
|
+
var header;
|
|
120
|
+
if (typeof obj.getHeader == "function" ? header = obj.getHeader("content-type") : typeof obj.headers == "object" && (header = obj.headers && obj.headers["content-type"]), typeof header != "string")
|
|
121
|
+
throw new TypeError("content-type header is missing from object");
|
|
122
|
+
return header;
|
|
123
|
+
}
|
|
124
|
+
function qstring(val) {
|
|
125
|
+
var str = String(val);
|
|
126
|
+
if (TOKEN_REGEXP.test(str))
|
|
127
|
+
return str;
|
|
128
|
+
if (str.length > 0 && !TEXT_REGEXP.test(str))
|
|
129
|
+
throw new TypeError("invalid parameter value");
|
|
130
|
+
return '"' + str.replace(QUOTE_REGEXP, "\\$1") + '"';
|
|
131
|
+
}
|
|
132
|
+
function ContentType(type) {
|
|
133
|
+
this.parameters = /* @__PURE__ */ Object.create(null), this.type = type;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// node_modules/pkce-challenge/dist/index.node.js
|
|
139
|
+
var crypto2;
|
|
140
|
+
crypto2 = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
|
|
141
|
+
globalThis.crypto ?? // Node.js >18
|
|
142
|
+
import("node:crypto").then((m) => m.webcrypto);
|
|
143
|
+
async function getRandomValues(size) {
|
|
144
|
+
return (await crypto2).getRandomValues(new Uint8Array(size));
|
|
145
|
+
}
|
|
146
|
+
async function random(size) {
|
|
147
|
+
let mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length, result = "";
|
|
148
|
+
for (; result.length < size; ) {
|
|
149
|
+
let randomBytes = await getRandomValues(size - result.length);
|
|
150
|
+
for (let randomByte of randomBytes)
|
|
151
|
+
randomByte < evenDistCutoff && (result += mask[randomByte % mask.length]);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
async function generateVerifier(length) {
|
|
156
|
+
return await random(length);
|
|
157
|
+
}
|
|
158
|
+
async function generateChallenge(code_verifier) {
|
|
159
|
+
let buffer = await (await crypto2).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
160
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
161
|
+
}
|
|
162
|
+
async function pkceChallenge(length) {
|
|
163
|
+
if (length || (length = 43), length < 43 || length > 128)
|
|
164
|
+
throw `Expected a length between 43 and 128. Received ${length}.`;
|
|
165
|
+
let verifier = await generateVerifier(length), challenge = await generateChallenge(verifier);
|
|
166
|
+
return {
|
|
167
|
+
code_verifier: verifier,
|
|
168
|
+
code_challenge: challenge
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
173
|
+
var SafeUrlSchema = url().superRefine((val, ctx) => {
|
|
174
|
+
if (!URL.canParse(val))
|
|
175
|
+
return ctx.addIssue({
|
|
176
|
+
code: ZodIssueCode.custom,
|
|
177
|
+
message: "URL must be parseable",
|
|
178
|
+
fatal: !0
|
|
179
|
+
}), NEVER;
|
|
180
|
+
}).refine((url2) => {
|
|
181
|
+
let u2 = new URL(url2);
|
|
182
|
+
return u2.protocol !== "javascript:" && u2.protocol !== "data:" && u2.protocol !== "vbscript:";
|
|
183
|
+
}, { message: "URL cannot use javascript:, data:, or vbscript: scheme" }), OAuthProtectedResourceMetadataSchema = looseObject({
|
|
184
|
+
resource: string().url(),
|
|
185
|
+
authorization_servers: array(SafeUrlSchema).optional(),
|
|
186
|
+
jwks_uri: string().url().optional(),
|
|
187
|
+
scopes_supported: array(string()).optional(),
|
|
188
|
+
bearer_methods_supported: array(string()).optional(),
|
|
189
|
+
resource_signing_alg_values_supported: array(string()).optional(),
|
|
190
|
+
resource_name: string().optional(),
|
|
191
|
+
resource_documentation: string().optional(),
|
|
192
|
+
resource_policy_uri: string().url().optional(),
|
|
193
|
+
resource_tos_uri: string().url().optional(),
|
|
194
|
+
tls_client_certificate_bound_access_tokens: boolean().optional(),
|
|
195
|
+
authorization_details_types_supported: array(string()).optional(),
|
|
196
|
+
dpop_signing_alg_values_supported: array(string()).optional(),
|
|
197
|
+
dpop_bound_access_tokens_required: boolean().optional()
|
|
198
|
+
}), OAuthMetadataSchema = looseObject({
|
|
199
|
+
issuer: string(),
|
|
200
|
+
authorization_endpoint: SafeUrlSchema,
|
|
201
|
+
token_endpoint: SafeUrlSchema,
|
|
202
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
203
|
+
scopes_supported: array(string()).optional(),
|
|
204
|
+
response_types_supported: array(string()),
|
|
205
|
+
response_modes_supported: array(string()).optional(),
|
|
206
|
+
grant_types_supported: array(string()).optional(),
|
|
207
|
+
token_endpoint_auth_methods_supported: array(string()).optional(),
|
|
208
|
+
token_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
|
|
209
|
+
service_documentation: SafeUrlSchema.optional(),
|
|
210
|
+
revocation_endpoint: SafeUrlSchema.optional(),
|
|
211
|
+
revocation_endpoint_auth_methods_supported: array(string()).optional(),
|
|
212
|
+
revocation_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
|
|
213
|
+
introspection_endpoint: string().optional(),
|
|
214
|
+
introspection_endpoint_auth_methods_supported: array(string()).optional(),
|
|
215
|
+
introspection_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
|
|
216
|
+
code_challenge_methods_supported: array(string()).optional(),
|
|
217
|
+
client_id_metadata_document_supported: boolean().optional()
|
|
218
|
+
}), OpenIdProviderMetadataSchema = looseObject({
|
|
219
|
+
issuer: string(),
|
|
220
|
+
authorization_endpoint: SafeUrlSchema,
|
|
221
|
+
token_endpoint: SafeUrlSchema,
|
|
222
|
+
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
223
|
+
jwks_uri: SafeUrlSchema,
|
|
224
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
225
|
+
scopes_supported: array(string()).optional(),
|
|
226
|
+
response_types_supported: array(string()),
|
|
227
|
+
response_modes_supported: array(string()).optional(),
|
|
228
|
+
grant_types_supported: array(string()).optional(),
|
|
229
|
+
acr_values_supported: array(string()).optional(),
|
|
230
|
+
subject_types_supported: array(string()),
|
|
231
|
+
id_token_signing_alg_values_supported: array(string()),
|
|
232
|
+
id_token_encryption_alg_values_supported: array(string()).optional(),
|
|
233
|
+
id_token_encryption_enc_values_supported: array(string()).optional(),
|
|
234
|
+
userinfo_signing_alg_values_supported: array(string()).optional(),
|
|
235
|
+
userinfo_encryption_alg_values_supported: array(string()).optional(),
|
|
236
|
+
userinfo_encryption_enc_values_supported: array(string()).optional(),
|
|
237
|
+
request_object_signing_alg_values_supported: array(string()).optional(),
|
|
238
|
+
request_object_encryption_alg_values_supported: array(string()).optional(),
|
|
239
|
+
request_object_encryption_enc_values_supported: array(string()).optional(),
|
|
240
|
+
token_endpoint_auth_methods_supported: array(string()).optional(),
|
|
241
|
+
token_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
|
|
242
|
+
display_values_supported: array(string()).optional(),
|
|
243
|
+
claim_types_supported: array(string()).optional(),
|
|
244
|
+
claims_supported: array(string()).optional(),
|
|
245
|
+
service_documentation: string().optional(),
|
|
246
|
+
claims_locales_supported: array(string()).optional(),
|
|
247
|
+
ui_locales_supported: array(string()).optional(),
|
|
248
|
+
claims_parameter_supported: boolean().optional(),
|
|
249
|
+
request_parameter_supported: boolean().optional(),
|
|
250
|
+
request_uri_parameter_supported: boolean().optional(),
|
|
251
|
+
require_request_uri_registration: boolean().optional(),
|
|
252
|
+
op_policy_uri: SafeUrlSchema.optional(),
|
|
253
|
+
op_tos_uri: SafeUrlSchema.optional(),
|
|
254
|
+
client_id_metadata_document_supported: boolean().optional()
|
|
255
|
+
}), OpenIdProviderDiscoveryMetadataSchema = object({
|
|
256
|
+
...OpenIdProviderMetadataSchema.shape,
|
|
257
|
+
...OAuthMetadataSchema.pick({
|
|
258
|
+
code_challenge_methods_supported: !0
|
|
259
|
+
}).shape
|
|
260
|
+
}), OAuthTokensSchema = object({
|
|
261
|
+
access_token: string(),
|
|
262
|
+
id_token: string().optional(),
|
|
263
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
264
|
+
token_type: string(),
|
|
265
|
+
expires_in: coerce_exports.number().optional(),
|
|
266
|
+
scope: string().optional(),
|
|
267
|
+
refresh_token: string().optional()
|
|
268
|
+
}).strip(), OAuthErrorResponseSchema = object({
|
|
269
|
+
error: string(),
|
|
270
|
+
error_description: string().optional(),
|
|
271
|
+
error_uri: string().optional()
|
|
272
|
+
}), OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => {
|
|
273
|
+
})), OAuthClientMetadataSchema = object({
|
|
274
|
+
redirect_uris: array(SafeUrlSchema),
|
|
275
|
+
token_endpoint_auth_method: string().optional(),
|
|
276
|
+
grant_types: array(string()).optional(),
|
|
277
|
+
response_types: array(string()).optional(),
|
|
278
|
+
client_name: string().optional(),
|
|
279
|
+
client_uri: SafeUrlSchema.optional(),
|
|
280
|
+
logo_uri: OptionalSafeUrlSchema,
|
|
281
|
+
scope: string().optional(),
|
|
282
|
+
contacts: array(string()).optional(),
|
|
283
|
+
tos_uri: OptionalSafeUrlSchema,
|
|
284
|
+
policy_uri: string().optional(),
|
|
285
|
+
jwks_uri: SafeUrlSchema.optional(),
|
|
286
|
+
jwks: any().optional(),
|
|
287
|
+
software_id: string().optional(),
|
|
288
|
+
software_version: string().optional(),
|
|
289
|
+
software_statement: string().optional()
|
|
290
|
+
}).strip(), OAuthClientInformationSchema = object({
|
|
291
|
+
client_id: string(),
|
|
292
|
+
client_secret: string().optional(),
|
|
293
|
+
client_id_issued_at: number().optional(),
|
|
294
|
+
client_secret_expires_at: number().optional()
|
|
295
|
+
}).strip(), OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema), OAuthClientRegistrationErrorSchema = object({
|
|
296
|
+
error: string(),
|
|
297
|
+
error_description: string().optional()
|
|
298
|
+
}).strip(), OAuthTokenRevocationRequestSchema = object({
|
|
299
|
+
token: string(),
|
|
300
|
+
token_type_hint: string().optional()
|
|
301
|
+
}).strip();
|
|
302
|
+
|
|
303
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
|
|
304
|
+
function resourceUrlFromServerUrl(url2) {
|
|
305
|
+
let resourceURL = typeof url2 == "string" ? new URL(url2) : new URL(url2.href);
|
|
306
|
+
return resourceURL.hash = "", resourceURL;
|
|
307
|
+
}
|
|
308
|
+
function checkResourceAllowed({ requestedResource, configuredResource }) {
|
|
309
|
+
let requested = typeof requestedResource == "string" ? new URL(requestedResource) : new URL(requestedResource.href), configured = typeof configuredResource == "string" ? new URL(configuredResource) : new URL(configuredResource.href);
|
|
310
|
+
if (requested.origin !== configured.origin || requested.pathname.length < configured.pathname.length)
|
|
311
|
+
return !1;
|
|
312
|
+
let requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/", configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
|
|
313
|
+
return requestedPath.startsWith(configuredPath);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
317
|
+
var OAuthError = class extends Error {
|
|
318
|
+
constructor(message, errorUri) {
|
|
319
|
+
super(message), this.errorUri = errorUri, this.name = this.constructor.name;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Converts the error to a standard OAuth error response object
|
|
323
|
+
*/
|
|
324
|
+
toResponseObject() {
|
|
325
|
+
let response = {
|
|
326
|
+
error: this.errorCode,
|
|
327
|
+
error_description: this.message
|
|
328
|
+
};
|
|
329
|
+
return this.errorUri && (response.error_uri = this.errorUri), response;
|
|
330
|
+
}
|
|
331
|
+
get errorCode() {
|
|
332
|
+
return this.constructor.errorCode;
|
|
333
|
+
}
|
|
334
|
+
}, InvalidRequestError = class extends OAuthError {
|
|
335
|
+
};
|
|
336
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
337
|
+
var InvalidClientError = class extends OAuthError {
|
|
338
|
+
};
|
|
339
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
340
|
+
var InvalidGrantError = class extends OAuthError {
|
|
341
|
+
};
|
|
342
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
343
|
+
var UnauthorizedClientError = class extends OAuthError {
|
|
344
|
+
};
|
|
345
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
346
|
+
var UnsupportedGrantTypeError = class extends OAuthError {
|
|
347
|
+
};
|
|
348
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
349
|
+
var InvalidScopeError = class extends OAuthError {
|
|
350
|
+
};
|
|
351
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
352
|
+
var AccessDeniedError = class extends OAuthError {
|
|
353
|
+
};
|
|
354
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
355
|
+
var ServerError = class extends OAuthError {
|
|
356
|
+
};
|
|
357
|
+
ServerError.errorCode = "server_error";
|
|
358
|
+
var TemporarilyUnavailableError = class extends OAuthError {
|
|
359
|
+
};
|
|
360
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
361
|
+
var UnsupportedResponseTypeError = class extends OAuthError {
|
|
362
|
+
};
|
|
363
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
364
|
+
var UnsupportedTokenTypeError = class extends OAuthError {
|
|
365
|
+
};
|
|
366
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
367
|
+
var InvalidTokenError = class extends OAuthError {
|
|
368
|
+
};
|
|
369
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
370
|
+
var MethodNotAllowedError = class extends OAuthError {
|
|
371
|
+
};
|
|
372
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
373
|
+
var TooManyRequestsError = class extends OAuthError {
|
|
374
|
+
};
|
|
375
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
376
|
+
var InvalidClientMetadataError = class extends OAuthError {
|
|
377
|
+
};
|
|
378
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
379
|
+
var InsufficientScopeError = class extends OAuthError {
|
|
380
|
+
};
|
|
381
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
382
|
+
var InvalidTargetError = class extends OAuthError {
|
|
383
|
+
};
|
|
384
|
+
InvalidTargetError.errorCode = "invalid_target";
|
|
385
|
+
var OAUTH_ERRORS = {
|
|
386
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
387
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
388
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
389
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
390
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
391
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
392
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
393
|
+
[ServerError.errorCode]: ServerError,
|
|
394
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
395
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
396
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
397
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
398
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
399
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
400
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
401
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError,
|
|
402
|
+
[InvalidTargetError.errorCode]: InvalidTargetError
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
406
|
+
var UnauthorizedError = class extends Error {
|
|
407
|
+
constructor(message) {
|
|
408
|
+
super(message ?? "Unauthorized");
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
function isClientAuthMethod(method) {
|
|
412
|
+
return ["client_secret_basic", "client_secret_post", "none"].includes(method);
|
|
413
|
+
}
|
|
414
|
+
var AUTHORIZATION_CODE_RESPONSE_TYPE = "code", AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
|
|
415
|
+
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
|
416
|
+
let hasClientSecret = clientInformation.client_secret !== void 0;
|
|
417
|
+
return "token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method)) ? clientInformation.token_endpoint_auth_method : supportedMethods.length === 0 ? hasClientSecret ? "client_secret_basic" : "none" : hasClientSecret && supportedMethods.includes("client_secret_basic") ? "client_secret_basic" : hasClientSecret && supportedMethods.includes("client_secret_post") ? "client_secret_post" : supportedMethods.includes("none") ? "none" : hasClientSecret ? "client_secret_post" : "none";
|
|
418
|
+
}
|
|
419
|
+
function applyClientAuthentication(method, clientInformation, headers, params) {
|
|
420
|
+
let { client_id, client_secret } = clientInformation;
|
|
421
|
+
switch (method) {
|
|
422
|
+
case "client_secret_basic":
|
|
423
|
+
applyBasicAuth(client_id, client_secret, headers);
|
|
424
|
+
return;
|
|
425
|
+
case "client_secret_post":
|
|
426
|
+
applyPostAuth(client_id, client_secret, params);
|
|
427
|
+
return;
|
|
428
|
+
case "none":
|
|
429
|
+
applyPublicAuth(client_id, params);
|
|
430
|
+
return;
|
|
431
|
+
default:
|
|
432
|
+
throw new Error(`Unsupported client authentication method: ${method}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function applyBasicAuth(clientId, clientSecret, headers) {
|
|
436
|
+
if (!clientSecret)
|
|
437
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
438
|
+
let credentials = btoa(`${clientId}:${clientSecret}`);
|
|
439
|
+
headers.set("Authorization", `Basic ${credentials}`);
|
|
440
|
+
}
|
|
441
|
+
function applyPostAuth(clientId, clientSecret, params) {
|
|
442
|
+
params.set("client_id", clientId), clientSecret && params.set("client_secret", clientSecret);
|
|
443
|
+
}
|
|
444
|
+
function applyPublicAuth(clientId, params) {
|
|
445
|
+
params.set("client_id", clientId);
|
|
446
|
+
}
|
|
447
|
+
async function parseErrorResponse(input) {
|
|
448
|
+
let statusCode = input instanceof Response ? input.status : void 0, body = input instanceof Response ? await input.text() : input;
|
|
449
|
+
try {
|
|
450
|
+
let result = OAuthErrorResponseSchema.parse(JSON.parse(body)), { error, error_description, error_uri } = result, errorClass = OAUTH_ERRORS[error] || ServerError;
|
|
451
|
+
return new errorClass(error_description || "", error_uri);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
let errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error}. Raw body: ${body}`;
|
|
454
|
+
return new ServerError(errorMessage);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
async function auth(provider, options) {
|
|
458
|
+
try {
|
|
459
|
+
return await authInternal(provider, options);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError)
|
|
462
|
+
return await provider.invalidateCredentials?.("all"), await authInternal(provider, options);
|
|
463
|
+
if (error instanceof InvalidGrantError)
|
|
464
|
+
return await provider.invalidateCredentials?.("tokens"), await authInternal(provider, options);
|
|
465
|
+
throw error;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
|
469
|
+
let cachedState = await provider.discoveryState?.(), resourceMetadata, authorizationServerUrl, metadata, effectiveResourceMetadataUrl = resourceMetadataUrl;
|
|
470
|
+
if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl && (effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl)), cachedState?.authorizationServerUrl) {
|
|
471
|
+
if (authorizationServerUrl = cachedState.authorizationServerUrl, resourceMetadata = cachedState.resourceMetadata, metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn }), !resourceMetadata)
|
|
472
|
+
try {
|
|
473
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
476
|
+
(metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) && await provider.saveDiscoveryState?.({
|
|
477
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
478
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
479
|
+
resourceMetadata,
|
|
480
|
+
authorizationServerMetadata: metadata
|
|
481
|
+
});
|
|
482
|
+
} else {
|
|
483
|
+
let serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
|
|
484
|
+
authorizationServerUrl = serverInfo.authorizationServerUrl, metadata = serverInfo.authorizationServerMetadata, resourceMetadata = serverInfo.resourceMetadata, await provider.saveDiscoveryState?.({
|
|
485
|
+
authorizationServerUrl: String(authorizationServerUrl),
|
|
486
|
+
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
|
487
|
+
resourceMetadata,
|
|
488
|
+
authorizationServerMetadata: metadata
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
let resource = await selectResourceURL(serverUrl, provider, resourceMetadata), resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope, clientInformation = await Promise.resolve(provider.clientInformation());
|
|
492
|
+
if (!clientInformation) {
|
|
493
|
+
if (authorizationCode !== void 0)
|
|
494
|
+
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
|
|
495
|
+
let supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === !0, clientMetadataUrl = provider.clientMetadataUrl;
|
|
496
|
+
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl))
|
|
497
|
+
throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
|
498
|
+
if (supportsUrlBasedClientId && clientMetadataUrl)
|
|
499
|
+
clientInformation = {
|
|
500
|
+
client_id: clientMetadataUrl
|
|
501
|
+
}, await provider.saveClientInformation?.(clientInformation);
|
|
502
|
+
else {
|
|
503
|
+
if (!provider.saveClientInformation)
|
|
504
|
+
throw new Error("OAuth client information must be saveable for dynamic registration");
|
|
505
|
+
let fullInformation = await registerClient(authorizationServerUrl, {
|
|
506
|
+
metadata,
|
|
507
|
+
clientMetadata: provider.clientMetadata,
|
|
508
|
+
scope: resolvedScope,
|
|
509
|
+
fetchFn
|
|
510
|
+
});
|
|
511
|
+
await provider.saveClientInformation(fullInformation), clientInformation = fullInformation;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
let nonInteractiveFlow = !provider.redirectUrl;
|
|
515
|
+
if (authorizationCode !== void 0 || nonInteractiveFlow) {
|
|
516
|
+
let tokens2 = await fetchToken(provider, authorizationServerUrl, {
|
|
517
|
+
metadata,
|
|
518
|
+
resource,
|
|
519
|
+
authorizationCode,
|
|
520
|
+
fetchFn
|
|
521
|
+
});
|
|
522
|
+
return await provider.saveTokens(tokens2), "AUTHORIZED";
|
|
523
|
+
}
|
|
524
|
+
let tokens = await provider.tokens();
|
|
525
|
+
if (tokens?.refresh_token)
|
|
526
|
+
try {
|
|
527
|
+
let newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
528
|
+
metadata,
|
|
529
|
+
clientInformation,
|
|
530
|
+
refreshToken: tokens.refresh_token,
|
|
531
|
+
resource,
|
|
532
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
533
|
+
fetchFn
|
|
534
|
+
});
|
|
535
|
+
return await provider.saveTokens(newTokens), "AUTHORIZED";
|
|
536
|
+
} catch (error) {
|
|
537
|
+
if (!(!(error instanceof OAuthError) || error instanceof ServerError))
|
|
538
|
+
throw error;
|
|
539
|
+
}
|
|
540
|
+
let state = provider.state ? await provider.state() : void 0, { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
|
541
|
+
metadata,
|
|
542
|
+
clientInformation,
|
|
543
|
+
state,
|
|
544
|
+
redirectUrl: provider.redirectUrl,
|
|
545
|
+
scope: resolvedScope,
|
|
546
|
+
resource
|
|
547
|
+
});
|
|
548
|
+
return await provider.saveCodeVerifier(codeVerifier), await provider.redirectToAuthorization(authorizationUrl), "REDIRECT";
|
|
549
|
+
}
|
|
550
|
+
function isHttpsUrl(value) {
|
|
551
|
+
if (!value)
|
|
552
|
+
return !1;
|
|
553
|
+
try {
|
|
554
|
+
let url2 = new URL(value);
|
|
555
|
+
return url2.protocol === "https:" && url2.pathname !== "/";
|
|
556
|
+
} catch {
|
|
557
|
+
return !1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
561
|
+
let defaultResource = resourceUrlFromServerUrl(serverUrl);
|
|
562
|
+
if (provider.validateResourceURL)
|
|
563
|
+
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
|
564
|
+
if (resourceMetadata) {
|
|
565
|
+
if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource }))
|
|
566
|
+
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
|
567
|
+
return new URL(resourceMetadata.resource);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function extractWWWAuthenticateParams(res) {
|
|
571
|
+
let authenticateHeader = res.headers.get("WWW-Authenticate");
|
|
572
|
+
if (!authenticateHeader)
|
|
573
|
+
return {};
|
|
574
|
+
let [type, scheme] = authenticateHeader.split(" ");
|
|
575
|
+
if (type.toLowerCase() !== "bearer" || !scheme)
|
|
576
|
+
return {};
|
|
577
|
+
let resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0, resourceMetadataUrl;
|
|
578
|
+
if (resourceMetadataMatch)
|
|
579
|
+
try {
|
|
580
|
+
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
let scope = extractFieldFromWwwAuth(res, "scope") || void 0, error = extractFieldFromWwwAuth(res, "error") || void 0;
|
|
584
|
+
return {
|
|
585
|
+
resourceMetadataUrl,
|
|
586
|
+
scope,
|
|
587
|
+
error
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function extractFieldFromWwwAuth(response, fieldName) {
|
|
591
|
+
let wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
592
|
+
if (!wwwAuthHeader)
|
|
593
|
+
return null;
|
|
594
|
+
let pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`), match = wwwAuthHeader.match(pattern);
|
|
595
|
+
return match ? match[1] || match[2] : null;
|
|
596
|
+
}
|
|
597
|
+
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
|
598
|
+
let response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
|
|
599
|
+
protocolVersion: opts?.protocolVersion,
|
|
600
|
+
metadataUrl: opts?.resourceMetadataUrl
|
|
601
|
+
});
|
|
602
|
+
if (!response || response.status === 404)
|
|
603
|
+
throw await response?.body?.cancel(), new Error("Resource server does not implement OAuth 2.0 Protected Resource Metadata.");
|
|
604
|
+
if (!response.ok)
|
|
605
|
+
throw await response.body?.cancel(), new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
|
|
606
|
+
return OAuthProtectedResourceMetadataSchema.parse(await response.json());
|
|
607
|
+
}
|
|
608
|
+
async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
|
|
609
|
+
try {
|
|
610
|
+
return await fetchFn(url2, { headers });
|
|
611
|
+
} catch (error) {
|
|
612
|
+
if (error instanceof TypeError)
|
|
613
|
+
return headers ? fetchWithCorsRetry(url2, void 0, fetchFn) : void 0;
|
|
614
|
+
throw error;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
618
|
+
return pathname.endsWith("/") && (pathname = pathname.slice(0, -1)), options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
|
619
|
+
}
|
|
620
|
+
async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
|
|
621
|
+
return await fetchWithCorsRetry(url2, {
|
|
622
|
+
"MCP-Protocol-Version": protocolVersion
|
|
623
|
+
}, fetchFn);
|
|
624
|
+
}
|
|
625
|
+
function shouldAttemptFallback(response, pathname) {
|
|
626
|
+
return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
|
|
627
|
+
}
|
|
628
|
+
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
|
629
|
+
let issuer = new URL(serverUrl), protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION, url2;
|
|
630
|
+
if (opts?.metadataUrl)
|
|
631
|
+
url2 = new URL(opts.metadataUrl);
|
|
632
|
+
else {
|
|
633
|
+
let wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
|
634
|
+
url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer), url2.search = issuer.search;
|
|
635
|
+
}
|
|
636
|
+
let response = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
|
|
637
|
+
if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
|
|
638
|
+
let rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
|
639
|
+
response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
|
640
|
+
}
|
|
641
|
+
return response;
|
|
642
|
+
}
|
|
643
|
+
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
644
|
+
let url2 = typeof authorizationServerUrl == "string" ? new URL(authorizationServerUrl) : authorizationServerUrl, hasPath = url2.pathname !== "/", urlsToTry = [];
|
|
645
|
+
if (!hasPath)
|
|
646
|
+
return urlsToTry.push({
|
|
647
|
+
url: new URL("/.well-known/oauth-authorization-server", url2.origin),
|
|
648
|
+
type: "oauth"
|
|
649
|
+
}), urlsToTry.push({
|
|
650
|
+
url: new URL("/.well-known/openid-configuration", url2.origin),
|
|
651
|
+
type: "oidc"
|
|
652
|
+
}), urlsToTry;
|
|
653
|
+
let pathname = url2.pathname;
|
|
654
|
+
return pathname.endsWith("/") && (pathname = pathname.slice(0, -1)), urlsToTry.push({
|
|
655
|
+
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
|
|
656
|
+
type: "oauth"
|
|
657
|
+
}), urlsToTry.push({
|
|
658
|
+
url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
|
|
659
|
+
type: "oidc"
|
|
660
|
+
}), urlsToTry.push({
|
|
661
|
+
url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
|
|
662
|
+
type: "oidc"
|
|
663
|
+
}), urlsToTry;
|
|
664
|
+
}
|
|
665
|
+
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
|
|
666
|
+
let headers = {
|
|
667
|
+
"MCP-Protocol-Version": protocolVersion,
|
|
668
|
+
Accept: "application/json"
|
|
669
|
+
}, urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
670
|
+
for (let { url: endpointUrl, type } of urlsToTry) {
|
|
671
|
+
let response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
672
|
+
if (response) {
|
|
673
|
+
if (!response.ok) {
|
|
674
|
+
if (await response.body?.cancel(), response.status >= 400 && response.status < 500)
|
|
675
|
+
continue;
|
|
676
|
+
throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
|
|
677
|
+
}
|
|
678
|
+
return type === "oauth" ? OAuthMetadataSchema.parse(await response.json()) : OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
async function discoverOAuthServerInfo(serverUrl, opts) {
|
|
683
|
+
let resourceMetadata, authorizationServerUrl;
|
|
684
|
+
try {
|
|
685
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn), resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0 && (authorizationServerUrl = resourceMetadata.authorization_servers[0]);
|
|
686
|
+
} catch {
|
|
687
|
+
}
|
|
688
|
+
authorizationServerUrl || (authorizationServerUrl = String(new URL("/", serverUrl)));
|
|
689
|
+
let authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
|
|
690
|
+
return {
|
|
691
|
+
authorizationServerUrl,
|
|
692
|
+
authorizationServerMetadata,
|
|
693
|
+
resourceMetadata
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
|
|
697
|
+
let authorizationUrl;
|
|
698
|
+
if (metadata) {
|
|
699
|
+
if (authorizationUrl = new URL(metadata.authorization_endpoint), !metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE))
|
|
700
|
+
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
|
701
|
+
if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD))
|
|
702
|
+
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
|
703
|
+
} else
|
|
704
|
+
authorizationUrl = new URL("/authorize", authorizationServerUrl);
|
|
705
|
+
let challenge = await pkceChallenge(), codeVerifier = challenge.code_verifier, codeChallenge = challenge.code_challenge;
|
|
706
|
+
return authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE), authorizationUrl.searchParams.set("client_id", clientInformation.client_id), authorizationUrl.searchParams.set("code_challenge", codeChallenge), authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD), authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl)), state && authorizationUrl.searchParams.set("state", state), scope && authorizationUrl.searchParams.set("scope", scope), scope?.includes("offline_access") && authorizationUrl.searchParams.append("prompt", "consent"), resource && authorizationUrl.searchParams.set("resource", resource.href), { authorizationUrl, codeVerifier };
|
|
707
|
+
}
|
|
708
|
+
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
|
709
|
+
return new URLSearchParams({
|
|
710
|
+
grant_type: "authorization_code",
|
|
711
|
+
code: authorizationCode,
|
|
712
|
+
code_verifier: codeVerifier,
|
|
713
|
+
redirect_uri: String(redirectUri)
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
|
717
|
+
let tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl), headers = new Headers({
|
|
718
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
719
|
+
Accept: "application/json"
|
|
720
|
+
});
|
|
721
|
+
if (resource && tokenRequestParams.set("resource", resource.href), addClientAuthentication)
|
|
722
|
+
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
|
723
|
+
else if (clientInformation) {
|
|
724
|
+
let supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [], authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
|
725
|
+
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
|
726
|
+
}
|
|
727
|
+
let response = await (fetchFn ?? fetch)(tokenUrl, {
|
|
728
|
+
method: "POST",
|
|
729
|
+
headers,
|
|
730
|
+
body: tokenRequestParams
|
|
731
|
+
});
|
|
732
|
+
if (!response.ok)
|
|
733
|
+
throw await parseErrorResponse(response);
|
|
734
|
+
return OAuthTokensSchema.parse(await response.json());
|
|
735
|
+
}
|
|
736
|
+
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
737
|
+
let tokenRequestParams = new URLSearchParams({
|
|
738
|
+
grant_type: "refresh_token",
|
|
739
|
+
refresh_token: refreshToken
|
|
740
|
+
}), tokens = await executeTokenRequest(authorizationServerUrl, {
|
|
741
|
+
metadata,
|
|
742
|
+
tokenRequestParams,
|
|
743
|
+
clientInformation,
|
|
744
|
+
addClientAuthentication,
|
|
745
|
+
resource,
|
|
746
|
+
fetchFn
|
|
747
|
+
});
|
|
748
|
+
return { refresh_token: refreshToken, ...tokens };
|
|
749
|
+
}
|
|
750
|
+
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
|
751
|
+
let scope = provider.clientMetadata.scope, tokenRequestParams;
|
|
752
|
+
if (provider.prepareTokenRequest && (tokenRequestParams = await provider.prepareTokenRequest(scope)), !tokenRequestParams) {
|
|
753
|
+
if (!authorizationCode)
|
|
754
|
+
throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
|
|
755
|
+
if (!provider.redirectUrl)
|
|
756
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
757
|
+
let codeVerifier = await provider.codeVerifier();
|
|
758
|
+
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
|
759
|
+
}
|
|
760
|
+
let clientInformation = await provider.clientInformation();
|
|
761
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
762
|
+
metadata,
|
|
763
|
+
tokenRequestParams,
|
|
764
|
+
clientInformation: clientInformation ?? void 0,
|
|
765
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
766
|
+
resource,
|
|
767
|
+
fetchFn
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
|
|
771
|
+
let registrationUrl;
|
|
772
|
+
if (metadata) {
|
|
773
|
+
if (!metadata.registration_endpoint)
|
|
774
|
+
throw new Error("Incompatible auth server: does not support dynamic client registration");
|
|
775
|
+
registrationUrl = new URL(metadata.registration_endpoint);
|
|
776
|
+
} else
|
|
777
|
+
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
778
|
+
let response = await (fetchFn ?? fetch)(registrationUrl, {
|
|
779
|
+
method: "POST",
|
|
780
|
+
headers: {
|
|
781
|
+
"Content-Type": "application/json"
|
|
782
|
+
},
|
|
783
|
+
body: JSON.stringify({
|
|
784
|
+
...clientMetadata,
|
|
785
|
+
...scope !== void 0 ? { scope } : {}
|
|
786
|
+
})
|
|
787
|
+
});
|
|
788
|
+
if (!response.ok)
|
|
789
|
+
throw await parseErrorResponse(response);
|
|
790
|
+
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
|
|
794
|
+
var import_content_type = __toESM(require_content_type(), 1);
|
|
795
|
+
function mediaTypeEssence(header) {
|
|
796
|
+
if (header)
|
|
797
|
+
try {
|
|
798
|
+
return import_content_type.default.parse(header).type;
|
|
799
|
+
} catch {
|
|
800
|
+
let essence = (header.split(";", 1)[0] ?? "").trim().toLowerCase();
|
|
801
|
+
return essence === "" || header.slice(essence.length).includes(",") ? void 0 : essence;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
|
|
806
|
+
function normalizeHeaders(headers) {
|
|
807
|
+
return headers ? headers instanceof Headers ? Object.fromEntries(headers.entries()) : Array.isArray(headers) ? Object.fromEntries(headers) : { ...headers } : {};
|
|
808
|
+
}
|
|
809
|
+
function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
810
|
+
return baseInit ? async (url2, init) => {
|
|
811
|
+
let mergedInit = {
|
|
812
|
+
...baseInit,
|
|
813
|
+
...init,
|
|
814
|
+
// Headers need special handling - merge instead of replace
|
|
815
|
+
headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
|
|
816
|
+
};
|
|
817
|
+
return baseFetch(url2, mergedInit);
|
|
818
|
+
} : baseFetch;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
822
|
+
var ParseError = class extends Error {
|
|
823
|
+
constructor(message, options) {
|
|
824
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
825
|
+
}
|
|
826
|
+
}, LF = 10, CR = 13, SPACE = 32;
|
|
827
|
+
function noop(_arg) {
|
|
828
|
+
}
|
|
829
|
+
function createParser(config) {
|
|
830
|
+
if (typeof config == "function")
|
|
831
|
+
throw new TypeError(
|
|
832
|
+
"`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?"
|
|
833
|
+
);
|
|
834
|
+
let { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [], pendingFragmentsLength = 0, isFirstChunk = !0, id, data = "", dataLines = 0, eventType, terminated = !1;
|
|
835
|
+
function feed(chunk) {
|
|
836
|
+
if (terminated)
|
|
837
|
+
throw new Error(
|
|
838
|
+
"Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing."
|
|
839
|
+
);
|
|
840
|
+
if (isFirstChunk && (isFirstChunk = !1, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
|
|
841
|
+
let trailing2 = processLines(chunk);
|
|
842
|
+
trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (chunk.indexOf(`
|
|
846
|
+
`) === -1 && chunk.indexOf("\r") === -1) {
|
|
847
|
+
pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
pendingFragments.push(chunk);
|
|
851
|
+
let input = pendingFragments.join("");
|
|
852
|
+
pendingFragments.length = 0, pendingFragmentsLength = 0;
|
|
853
|
+
let trailing = processLines(input);
|
|
854
|
+
trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
|
|
855
|
+
}
|
|
856
|
+
function checkBufferSize() {
|
|
857
|
+
maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = !0, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(
|
|
858
|
+
new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, {
|
|
859
|
+
type: "max-buffer-size-exceeded"
|
|
860
|
+
})
|
|
861
|
+
)));
|
|
862
|
+
}
|
|
863
|
+
function processLines(chunk) {
|
|
864
|
+
let searchIndex = 0;
|
|
865
|
+
if (chunk.indexOf("\r") === -1) {
|
|
866
|
+
let lfIndex = chunk.indexOf(`
|
|
867
|
+
`, searchIndex);
|
|
868
|
+
for (; lfIndex !== -1; ) {
|
|
869
|
+
if (searchIndex === lfIndex) {
|
|
870
|
+
dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
871
|
+
`, searchIndex);
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
let firstCharCode = chunk.charCodeAt(searchIndex);
|
|
875
|
+
if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
|
|
876
|
+
let valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
|
|
877
|
+
if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
|
|
878
|
+
onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
|
|
879
|
+
`, searchIndex);
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
data = dataLines === 0 ? value : `${data}
|
|
883
|
+
${value}`, dataLines++;
|
|
884
|
+
} else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
|
|
885
|
+
chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
|
|
886
|
+
lfIndex
|
|
887
|
+
) || void 0 : parseLine(chunk, searchIndex, lfIndex);
|
|
888
|
+
searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
|
|
889
|
+
`, searchIndex);
|
|
890
|
+
}
|
|
891
|
+
return chunk.slice(searchIndex);
|
|
892
|
+
}
|
|
893
|
+
for (; searchIndex < chunk.length; ) {
|
|
894
|
+
let crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
895
|
+
`, searchIndex), lineEnd = -1;
|
|
896
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
|
|
897
|
+
break;
|
|
898
|
+
parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
|
|
899
|
+
}
|
|
900
|
+
return chunk.slice(searchIndex);
|
|
901
|
+
}
|
|
902
|
+
function parseLine(chunk, start, end) {
|
|
903
|
+
if (start === end) {
|
|
904
|
+
dispatchEvent();
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
let firstCharCode = chunk.charCodeAt(start);
|
|
908
|
+
if (isDataPrefix(chunk, start, firstCharCode)) {
|
|
909
|
+
let valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
|
|
910
|
+
data = dataLines === 0 ? value2 : `${data}
|
|
911
|
+
${value2}`, dataLines++;
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
if (isEventPrefix(chunk, start, firstCharCode)) {
|
|
915
|
+
eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
|
|
919
|
+
let value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
|
|
920
|
+
id = value2.includes("\0") ? void 0 : value2;
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (firstCharCode === 58) {
|
|
924
|
+
if (onComment) {
|
|
925
|
+
let line2 = chunk.slice(start, end);
|
|
926
|
+
onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
|
|
927
|
+
}
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
let line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
|
|
931
|
+
if (fieldSeparatorIndex === -1) {
|
|
932
|
+
processField(line, "", line);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
let field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
936
|
+
processField(field, value, line);
|
|
937
|
+
}
|
|
938
|
+
function processField(field, value, line) {
|
|
939
|
+
switch (field) {
|
|
940
|
+
case "event":
|
|
941
|
+
eventType = value || void 0;
|
|
942
|
+
break;
|
|
943
|
+
case "data":
|
|
944
|
+
data = dataLines === 0 ? value : `${data}
|
|
945
|
+
${value}`, dataLines++;
|
|
946
|
+
break;
|
|
947
|
+
case "id":
|
|
948
|
+
id = value.includes("\0") ? void 0 : value;
|
|
949
|
+
break;
|
|
950
|
+
case "retry":
|
|
951
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
952
|
+
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
953
|
+
type: "invalid-retry",
|
|
954
|
+
value,
|
|
955
|
+
line
|
|
956
|
+
})
|
|
957
|
+
);
|
|
958
|
+
break;
|
|
959
|
+
default:
|
|
960
|
+
onError(
|
|
961
|
+
new ParseError(
|
|
962
|
+
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
963
|
+
{ type: "unknown-field", field, value, line }
|
|
964
|
+
)
|
|
965
|
+
);
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
function dispatchEvent() {
|
|
970
|
+
dataLines > 0 && onEvent({
|
|
971
|
+
id,
|
|
972
|
+
event: eventType,
|
|
973
|
+
data
|
|
974
|
+
}), id = void 0, data = "", dataLines = 0, eventType = void 0;
|
|
975
|
+
}
|
|
976
|
+
function reset(options = {}) {
|
|
977
|
+
if (options.consume && pendingFragments.length > 0) {
|
|
978
|
+
let incompleteLine = pendingFragments.join("");
|
|
979
|
+
parseLine(incompleteLine, 0, incompleteLine.length);
|
|
980
|
+
}
|
|
981
|
+
isFirstChunk = !0, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = !1;
|
|
982
|
+
}
|
|
983
|
+
return { feed, reset };
|
|
984
|
+
}
|
|
985
|
+
function isDataPrefix(chunk, i2, firstCharCode) {
|
|
986
|
+
return firstCharCode === 100 && chunk.charCodeAt(i2 + 1) === 97 && chunk.charCodeAt(i2 + 2) === 116 && chunk.charCodeAt(i2 + 3) === 97 && chunk.charCodeAt(i2 + 4) === 58;
|
|
987
|
+
}
|
|
988
|
+
function isEventPrefix(chunk, i2, firstCharCode) {
|
|
989
|
+
return firstCharCode === 101 && chunk.charCodeAt(i2 + 1) === 118 && chunk.charCodeAt(i2 + 2) === 101 && chunk.charCodeAt(i2 + 3) === 110 && chunk.charCodeAt(i2 + 4) === 116 && chunk.charCodeAt(i2 + 5) === 58;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// node_modules/eventsource-parser/dist/stream.js
|
|
993
|
+
var EventSourceParserStream = class extends TransformStream {
|
|
994
|
+
constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
|
|
995
|
+
let parser;
|
|
996
|
+
super({
|
|
997
|
+
start(controller) {
|
|
998
|
+
parser = createParser({
|
|
999
|
+
onEvent: (event) => {
|
|
1000
|
+
controller.enqueue(event);
|
|
1001
|
+
},
|
|
1002
|
+
onError(error) {
|
|
1003
|
+
typeof onError == "function" && onError(error), (onError === "terminate" || error.type === "max-buffer-size-exceeded") && controller.error(error);
|
|
1004
|
+
},
|
|
1005
|
+
onRetry,
|
|
1006
|
+
onComment,
|
|
1007
|
+
maxBufferSize
|
|
1008
|
+
});
|
|
1009
|
+
},
|
|
1010
|
+
transform(chunk) {
|
|
1011
|
+
parser.feed(chunk);
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
|
|
1018
|
+
var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
1019
|
+
initialReconnectionDelay: 1e3,
|
|
1020
|
+
maxReconnectionDelay: 3e4,
|
|
1021
|
+
reconnectionDelayGrowFactor: 1.5,
|
|
1022
|
+
maxRetries: 2
|
|
1023
|
+
}, StreamableHTTPError = class extends Error {
|
|
1024
|
+
constructor(code, message) {
|
|
1025
|
+
super(`Streamable HTTP error: ${message}`), this.code = code;
|
|
1026
|
+
}
|
|
1027
|
+
}, StreamableHTTPClientTransport = class {
|
|
1028
|
+
constructor(url2, opts) {
|
|
1029
|
+
this._hasCompletedAuthFlow = !1, this._url = url2, this._resourceMetadataUrl = void 0, this._scope = void 0, this._requestInit = opts?.requestInit, this._authProvider = opts?.authProvider, this._fetch = opts?.fetch, this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit), this._sessionId = opts?.sessionId, this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
|
|
1030
|
+
}
|
|
1031
|
+
async _authThenStart() {
|
|
1032
|
+
if (!this._authProvider)
|
|
1033
|
+
throw new UnauthorizedError("No auth provider");
|
|
1034
|
+
let result;
|
|
1035
|
+
try {
|
|
1036
|
+
result = await auth(this._authProvider, {
|
|
1037
|
+
serverUrl: this._url,
|
|
1038
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
1039
|
+
scope: this._scope,
|
|
1040
|
+
fetchFn: this._fetchWithInit
|
|
1041
|
+
});
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
throw this.onerror?.(error), error;
|
|
1044
|
+
}
|
|
1045
|
+
if (result !== "AUTHORIZED")
|
|
1046
|
+
throw new UnauthorizedError();
|
|
1047
|
+
return await this._startOrAuthSse({ resumptionToken: void 0 });
|
|
1048
|
+
}
|
|
1049
|
+
async _commonHeaders() {
|
|
1050
|
+
let headers = {};
|
|
1051
|
+
if (this._authProvider) {
|
|
1052
|
+
let tokens = await this._authProvider.tokens();
|
|
1053
|
+
tokens && (headers.Authorization = `Bearer ${tokens.access_token}`);
|
|
1054
|
+
}
|
|
1055
|
+
this._sessionId && (headers["mcp-session-id"] = this._sessionId), this._protocolVersion && (headers["mcp-protocol-version"] = this._protocolVersion);
|
|
1056
|
+
let extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
1057
|
+
return new Headers({
|
|
1058
|
+
...headers,
|
|
1059
|
+
...extraHeaders
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
async _startOrAuthSse(options) {
|
|
1063
|
+
let { resumptionToken } = options;
|
|
1064
|
+
try {
|
|
1065
|
+
let headers = await this._commonHeaders();
|
|
1066
|
+
headers.set("Accept", "text/event-stream"), resumptionToken && headers.set("last-event-id", resumptionToken);
|
|
1067
|
+
let response = await (this._fetch ?? fetch)(this._url, {
|
|
1068
|
+
method: "GET",
|
|
1069
|
+
headers,
|
|
1070
|
+
signal: this._abortController?.signal
|
|
1071
|
+
});
|
|
1072
|
+
if (!response.ok) {
|
|
1073
|
+
if (await response.body?.cancel(), response.status === 401 && this._authProvider)
|
|
1074
|
+
return await this._authThenStart();
|
|
1075
|
+
if (response.status === 405)
|
|
1076
|
+
return;
|
|
1077
|
+
throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
|
|
1078
|
+
}
|
|
1079
|
+
this._handleSseStream(response.body, options, !0);
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
throw this.onerror?.(error), error;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Calculates the next reconnection delay using backoff algorithm
|
|
1086
|
+
*
|
|
1087
|
+
* @param attempt Current reconnection attempt count for the specific stream
|
|
1088
|
+
* @returns Time to wait in milliseconds before next reconnection attempt
|
|
1089
|
+
*/
|
|
1090
|
+
_getNextReconnectionDelay(attempt) {
|
|
1091
|
+
if (this._serverRetryMs !== void 0)
|
|
1092
|
+
return this._serverRetryMs;
|
|
1093
|
+
let initialDelay = this._reconnectionOptions.initialReconnectionDelay, growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor, maxDelay = this._reconnectionOptions.maxReconnectionDelay;
|
|
1094
|
+
return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Schedule a reconnection attempt using server-provided retry interval or backoff
|
|
1098
|
+
*
|
|
1099
|
+
* @param lastEventId The ID of the last received event for resumability
|
|
1100
|
+
* @param attemptCount Current reconnection attempt count for this specific stream
|
|
1101
|
+
*/
|
|
1102
|
+
_scheduleReconnection(options, attemptCount = 0) {
|
|
1103
|
+
let maxRetries = this._reconnectionOptions.maxRetries;
|
|
1104
|
+
if (attemptCount >= maxRetries) {
|
|
1105
|
+
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
let delay = this._getNextReconnectionDelay(attemptCount);
|
|
1109
|
+
this._reconnectionTimeout = setTimeout(() => {
|
|
1110
|
+
this._startOrAuthSse(options).catch((error) => {
|
|
1111
|
+
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error instanceof Error ? error.message : String(error)}`)), this._scheduleReconnection(options, attemptCount + 1);
|
|
1112
|
+
});
|
|
1113
|
+
}, delay);
|
|
1114
|
+
}
|
|
1115
|
+
_handleSseStream(stream, options, isReconnectable) {
|
|
1116
|
+
if (!stream)
|
|
1117
|
+
return;
|
|
1118
|
+
let { onresumptiontoken, replayMessageId } = options, lastEventId, hasPrimingEvent = !1, receivedResponse = !1;
|
|
1119
|
+
(async () => {
|
|
1120
|
+
try {
|
|
1121
|
+
let reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({
|
|
1122
|
+
onRetry: (retryMs) => {
|
|
1123
|
+
this._serverRetryMs = retryMs;
|
|
1124
|
+
}
|
|
1125
|
+
})).getReader();
|
|
1126
|
+
for (; ; ) {
|
|
1127
|
+
let { value: event, done } = await reader.read();
|
|
1128
|
+
if (done)
|
|
1129
|
+
break;
|
|
1130
|
+
if (event.id && (lastEventId = event.id, hasPrimingEvent = !0, onresumptiontoken?.(event.id)), !!event.data && (!event.event || event.event === "message"))
|
|
1131
|
+
try {
|
|
1132
|
+
let message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
|
|
1133
|
+
isJSONRPCResultResponse(message) && (receivedResponse = !0, replayMessageId !== void 0 && (message.id = replayMessageId)), this.onmessage?.(message);
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
this.onerror?.(error);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
(isReconnectable || hasPrimingEvent) && !receivedResponse && this._abortController && !this._abortController.signal.aborted && this._scheduleReconnection({
|
|
1139
|
+
resumptionToken: lastEventId,
|
|
1140
|
+
onresumptiontoken,
|
|
1141
|
+
replayMessageId
|
|
1142
|
+
}, 0);
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
if (this.onerror?.(new Error(`SSE stream disconnected: ${error}`)), (isReconnectable || hasPrimingEvent) && !receivedResponse && this._abortController && !this._abortController.signal.aborted)
|
|
1145
|
+
try {
|
|
1146
|
+
this._scheduleReconnection({
|
|
1147
|
+
resumptionToken: lastEventId,
|
|
1148
|
+
onresumptiontoken,
|
|
1149
|
+
replayMessageId
|
|
1150
|
+
}, 0);
|
|
1151
|
+
} catch (error2) {
|
|
1152
|
+
this.onerror?.(new Error(`Failed to reconnect: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
})();
|
|
1156
|
+
}
|
|
1157
|
+
async start() {
|
|
1158
|
+
if (this._abortController)
|
|
1159
|
+
throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
1160
|
+
this._abortController = new AbortController();
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
|
|
1164
|
+
*/
|
|
1165
|
+
async finishAuth(authorizationCode) {
|
|
1166
|
+
if (!this._authProvider)
|
|
1167
|
+
throw new UnauthorizedError("No auth provider");
|
|
1168
|
+
if (await auth(this._authProvider, {
|
|
1169
|
+
serverUrl: this._url,
|
|
1170
|
+
authorizationCode,
|
|
1171
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
1172
|
+
scope: this._scope,
|
|
1173
|
+
fetchFn: this._fetchWithInit
|
|
1174
|
+
}) !== "AUTHORIZED")
|
|
1175
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
1176
|
+
}
|
|
1177
|
+
async close() {
|
|
1178
|
+
this._reconnectionTimeout && (clearTimeout(this._reconnectionTimeout), this._reconnectionTimeout = void 0), this._abortController?.abort(), this.onclose?.();
|
|
1179
|
+
}
|
|
1180
|
+
async send(message, options) {
|
|
1181
|
+
try {
|
|
1182
|
+
let { resumptionToken, onresumptiontoken } = options || {};
|
|
1183
|
+
if (resumptionToken) {
|
|
1184
|
+
this._startOrAuthSse({ resumptionToken, replayMessageId: isJSONRPCRequest(message) ? message.id : void 0 }).catch((err) => this.onerror?.(err));
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
let headers = await this._commonHeaders();
|
|
1188
|
+
headers.set("content-type", "application/json"), headers.set("accept", "application/json, text/event-stream");
|
|
1189
|
+
let init = {
|
|
1190
|
+
...this._requestInit,
|
|
1191
|
+
method: "POST",
|
|
1192
|
+
headers,
|
|
1193
|
+
body: JSON.stringify(message),
|
|
1194
|
+
signal: this._abortController?.signal
|
|
1195
|
+
}, response = await (this._fetch ?? fetch)(this._url, init), sessionId = response.headers.get("mcp-session-id");
|
|
1196
|
+
if (sessionId && (this._sessionId = sessionId), !response.ok) {
|
|
1197
|
+
let text = await response.text().catch(() => null);
|
|
1198
|
+
if (response.status === 401 && this._authProvider) {
|
|
1199
|
+
if (this._hasCompletedAuthFlow)
|
|
1200
|
+
throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
|
|
1201
|
+
let { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
1202
|
+
if (this._resourceMetadataUrl = resourceMetadataUrl, this._scope = scope, await auth(this._authProvider, {
|
|
1203
|
+
serverUrl: this._url,
|
|
1204
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
1205
|
+
scope: this._scope,
|
|
1206
|
+
fetchFn: this._fetchWithInit
|
|
1207
|
+
}) !== "AUTHORIZED")
|
|
1208
|
+
throw new UnauthorizedError();
|
|
1209
|
+
return this._hasCompletedAuthFlow = !0, this.send(message);
|
|
1210
|
+
}
|
|
1211
|
+
if (response.status === 403 && this._authProvider) {
|
|
1212
|
+
let { resourceMetadataUrl, scope, error } = extractWWWAuthenticateParams(response);
|
|
1213
|
+
if (error === "insufficient_scope") {
|
|
1214
|
+
let wwwAuthHeader = response.headers.get("WWW-Authenticate");
|
|
1215
|
+
if (this._lastUpscopingHeader === wwwAuthHeader)
|
|
1216
|
+
throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
|
|
1217
|
+
if (scope && (this._scope = scope), resourceMetadataUrl && (this._resourceMetadataUrl = resourceMetadataUrl), this._lastUpscopingHeader = wwwAuthHeader ?? void 0, await auth(this._authProvider, {
|
|
1218
|
+
serverUrl: this._url,
|
|
1219
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
1220
|
+
scope: this._scope,
|
|
1221
|
+
fetchFn: this._fetch
|
|
1222
|
+
}) !== "AUTHORIZED")
|
|
1223
|
+
throw new UnauthorizedError();
|
|
1224
|
+
return this.send(message);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);
|
|
1228
|
+
}
|
|
1229
|
+
if (this._hasCompletedAuthFlow = !1, this._lastUpscopingHeader = void 0, response.status === 202) {
|
|
1230
|
+
await response.body?.cancel(), isInitializedNotification(message) && this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
let hasRequests = (Array.isArray(message) ? message : [message]).filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0, contentType2 = response.headers.get("content-type"), responseMediaType = mediaTypeEssence(contentType2);
|
|
1234
|
+
if (hasRequests)
|
|
1235
|
+
if (responseMediaType === "text/event-stream")
|
|
1236
|
+
this._handleSseStream(response.body, { onresumptiontoken }, !1);
|
|
1237
|
+
else if (responseMediaType === "application/json") {
|
|
1238
|
+
let data = await response.json(), responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
|
|
1239
|
+
for (let msg of responseMessages)
|
|
1240
|
+
this.onmessage?.(msg);
|
|
1241
|
+
} else
|
|
1242
|
+
throw await response.body?.cancel(), new StreamableHTTPError(-1, `Unexpected content type: ${contentType2}`);
|
|
1243
|
+
else
|
|
1244
|
+
await response.body?.cancel();
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
throw this.onerror?.(error), error;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
get sessionId() {
|
|
1250
|
+
return this._sessionId;
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Terminates the current session by sending a DELETE request to the server.
|
|
1254
|
+
*
|
|
1255
|
+
* Clients that no longer need a particular session
|
|
1256
|
+
* (e.g., because the user is leaving the client application) SHOULD send an
|
|
1257
|
+
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
|
|
1258
|
+
* terminate the session.
|
|
1259
|
+
*
|
|
1260
|
+
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
|
|
1261
|
+
* the server does not allow clients to terminate sessions.
|
|
1262
|
+
*/
|
|
1263
|
+
async terminateSession() {
|
|
1264
|
+
if (this._sessionId)
|
|
1265
|
+
try {
|
|
1266
|
+
let headers = await this._commonHeaders(), init = {
|
|
1267
|
+
...this._requestInit,
|
|
1268
|
+
method: "DELETE",
|
|
1269
|
+
headers,
|
|
1270
|
+
signal: this._abortController?.signal
|
|
1271
|
+
}, response = await (this._fetch ?? fetch)(this._url, init);
|
|
1272
|
+
if (await response.body?.cancel(), !response.ok && response.status !== 405)
|
|
1273
|
+
throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
|
|
1274
|
+
this._sessionId = void 0;
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
throw this.onerror?.(error), error;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
setProtocolVersion(version) {
|
|
1280
|
+
this._protocolVersion = version;
|
|
1281
|
+
}
|
|
1282
|
+
get protocolVersion() {
|
|
1283
|
+
return this._protocolVersion;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Resume an SSE stream from a previous event ID.
|
|
1287
|
+
* Opens a GET SSE connection with Last-Event-ID header to replay missed events.
|
|
1288
|
+
*
|
|
1289
|
+
* @param lastEventId The event ID to resume from
|
|
1290
|
+
* @param options Optional callback to receive new resumption tokens
|
|
1291
|
+
*/
|
|
1292
|
+
async resumeStream(lastEventId, options) {
|
|
1293
|
+
await this._startOrAuthSse({
|
|
1294
|
+
resumptionToken: lastEventId,
|
|
1295
|
+
onresumptiontoken: options?.onresumptiontoken
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js
|
|
1301
|
+
import open from "open";
|
|
1302
|
+
|
|
1303
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/mcp-auth.js
|
|
1304
|
+
import { createHash } from "crypto";
|
|
1305
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from "fs";
|
|
1306
|
+
import { join } from "path";
|
|
1307
|
+
function getAuthBaseDir() {
|
|
1308
|
+
let override = process.env.MCP_OAUTH_DIR?.trim();
|
|
1309
|
+
return override || getAgentPath("mcp-oauth");
|
|
1310
|
+
}
|
|
1311
|
+
function getServerDir(serverName) {
|
|
1312
|
+
if (typeof serverName != "string")
|
|
1313
|
+
throw new Error(`Invalid MCP server name: ${JSON.stringify(serverName)}`);
|
|
1314
|
+
let storageKey = createHash("sha256").update(serverName, "utf8").digest("hex");
|
|
1315
|
+
return join(getAuthBaseDir(), `sha256-${storageKey}`);
|
|
1316
|
+
}
|
|
1317
|
+
function getAuthEntryFilePath(serverName) {
|
|
1318
|
+
return join(getServerDir(serverName), "tokens.json");
|
|
1319
|
+
}
|
|
1320
|
+
function ensureServerDir(serverName) {
|
|
1321
|
+
let dir = getServerDir(serverName);
|
|
1322
|
+
existsSync(dir) || mkdirSync(dir, { recursive: !0, mode: 448 });
|
|
1323
|
+
}
|
|
1324
|
+
function readAuthEntry(serverName) {
|
|
1325
|
+
let filePath = getAuthEntryFilePath(serverName);
|
|
1326
|
+
try {
|
|
1327
|
+
if (!existsSync(filePath))
|
|
1328
|
+
return;
|
|
1329
|
+
let data = readFileSync(filePath, "utf-8");
|
|
1330
|
+
return JSON.parse(data);
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
console.error(`Failed to read auth entry for ${serverName}:`, error);
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
function writeAuthEntry(serverName, entry) {
|
|
1337
|
+
ensureServerDir(serverName);
|
|
1338
|
+
let filePath = getAuthEntryFilePath(serverName);
|
|
1339
|
+
writeFileSync(filePath, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
1340
|
+
}
|
|
1341
|
+
function getAuthEntry(serverName) {
|
|
1342
|
+
return readAuthEntry(serverName);
|
|
1343
|
+
}
|
|
1344
|
+
function getAuthForUrl(serverName, serverUrl) {
|
|
1345
|
+
let entry = getAuthEntry(serverName);
|
|
1346
|
+
if (entry && entry.serverUrl && entry.serverUrl === serverUrl)
|
|
1347
|
+
return entry;
|
|
1348
|
+
}
|
|
1349
|
+
function saveAuthEntry(serverName, entry, serverUrl) {
|
|
1350
|
+
serverUrl && (entry.serverUrl = serverUrl), writeAuthEntry(serverName, entry);
|
|
1351
|
+
}
|
|
1352
|
+
function removeAuthEntry(serverName) {
|
|
1353
|
+
try {
|
|
1354
|
+
let filePath = getAuthEntryFilePath(serverName);
|
|
1355
|
+
existsSync(filePath) && writeFileSync(filePath, "{}", { mode: 384 });
|
|
1356
|
+
let dir = getServerDir(serverName);
|
|
1357
|
+
if (existsSync(dir))
|
|
1358
|
+
try {
|
|
1359
|
+
rmSync(dir, { recursive: !0 });
|
|
1360
|
+
} catch {
|
|
1361
|
+
}
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
console.error(`Failed to remove auth entry for ${serverName}:`, error);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
function updateTokens(serverName, tokens, serverUrl) {
|
|
1367
|
+
let entry = getAuthEntry(serverName) ?? {};
|
|
1368
|
+
serverUrl && entry.serverUrl !== serverUrl && (delete entry.clientInfo, delete entry.codeVerifier, delete entry.oauthState), entry.tokens = tokens, saveAuthEntry(serverName, entry, serverUrl);
|
|
1369
|
+
}
|
|
1370
|
+
function updateClientInfo(serverName, clientInfo, serverUrl) {
|
|
1371
|
+
let entry = getAuthEntry(serverName) ?? {};
|
|
1372
|
+
serverUrl && entry.serverUrl !== serverUrl && (delete entry.tokens, delete entry.codeVerifier, delete entry.oauthState), entry.clientInfo = clientInfo, saveAuthEntry(serverName, entry, serverUrl);
|
|
1373
|
+
}
|
|
1374
|
+
function updateCodeVerifier(serverName, codeVerifier, serverUrl) {
|
|
1375
|
+
let entry = getAuthEntry(serverName) ?? {};
|
|
1376
|
+
serverUrl && entry.serverUrl !== serverUrl && (delete entry.tokens, delete entry.clientInfo, delete entry.oauthState), entry.codeVerifier = codeVerifier, saveAuthEntry(serverName, entry, serverUrl);
|
|
1377
|
+
}
|
|
1378
|
+
function updateOAuthState(serverName, state, serverUrl) {
|
|
1379
|
+
let entry = getAuthEntry(serverName) ?? {};
|
|
1380
|
+
serverUrl && entry.serverUrl !== serverUrl && (delete entry.tokens, delete entry.clientInfo, delete entry.codeVerifier), entry.oauthState = state, saveAuthEntry(serverName, entry, serverUrl);
|
|
1381
|
+
}
|
|
1382
|
+
function clearAllCredentials(serverName) {
|
|
1383
|
+
removeAuthEntry(serverName);
|
|
1384
|
+
}
|
|
1385
|
+
function clearClientInfo(serverName) {
|
|
1386
|
+
let entry = getAuthEntry(serverName);
|
|
1387
|
+
entry && (delete entry.clientInfo, saveAuthEntry(serverName, entry));
|
|
1388
|
+
}
|
|
1389
|
+
function clearTokens(serverName) {
|
|
1390
|
+
let entry = getAuthEntry(serverName);
|
|
1391
|
+
entry && (delete entry.tokens, saveAuthEntry(serverName, entry));
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/mcp-oauth-provider.js
|
|
1395
|
+
var DEFAULT_OAUTH_CALLBACK_PORT = 19876, DEFAULT_OAUTH_CALLBACK_PATH = "/callback", configuredOAuthCallbackPort = DEFAULT_OAUTH_CALLBACK_PORT;
|
|
1396
|
+
if (process.env.MCP_OAUTH_CALLBACK_PORT) {
|
|
1397
|
+
let parsedPort = Number.parseInt(process.env.MCP_OAUTH_CALLBACK_PORT, 10);
|
|
1398
|
+
Number.isInteger(parsedPort) && parsedPort > 0 && parsedPort <= 65535 && (configuredOAuthCallbackPort = parsedPort);
|
|
1399
|
+
}
|
|
1400
|
+
var oauthCallbackPort = configuredOAuthCallbackPort, oauthCallbackPath = DEFAULT_OAUTH_CALLBACK_PATH;
|
|
1401
|
+
function getConfiguredOAuthCallbackPort() {
|
|
1402
|
+
return configuredOAuthCallbackPort;
|
|
1403
|
+
}
|
|
1404
|
+
function getOAuthCallbackPort() {
|
|
1405
|
+
return oauthCallbackPort;
|
|
1406
|
+
}
|
|
1407
|
+
function setOAuthCallbackPort(port) {
|
|
1408
|
+
oauthCallbackPort = port;
|
|
1409
|
+
}
|
|
1410
|
+
function getOAuthCallbackPath() {
|
|
1411
|
+
return oauthCallbackPath;
|
|
1412
|
+
}
|
|
1413
|
+
function setOAuthCallbackPath(path) {
|
|
1414
|
+
oauthCallbackPath = path.startsWith("/") ? path : `/${path}`;
|
|
1415
|
+
}
|
|
1416
|
+
var McpOAuthProvider = class {
|
|
1417
|
+
serverName;
|
|
1418
|
+
serverUrl;
|
|
1419
|
+
config;
|
|
1420
|
+
callbacks;
|
|
1421
|
+
flowState;
|
|
1422
|
+
redirectUrlSnapshot;
|
|
1423
|
+
flowClientInfo;
|
|
1424
|
+
flowClientInfoLoaded = !1;
|
|
1425
|
+
constructor(serverName, serverUrl, config, callbacks, flowState) {
|
|
1426
|
+
if (this.serverName = serverName, this.serverUrl = serverUrl, this.config = config, this.callbacks = callbacks, this.flowState = flowState, flowState) {
|
|
1427
|
+
let info = flowState.clientInfo;
|
|
1428
|
+
this.flowClientInfo = info?.clientSecretExpiresAt && info.clientSecretExpiresAt < Date.now() / 1e3 ? void 0 : info, this.flowClientInfoLoaded = !0;
|
|
1429
|
+
}
|
|
1430
|
+
this.redirectUrlSnapshot = config.grantType === "client_credentials" ? void 0 : config.redirectUri ?? `http://localhost:${getOAuthCallbackPort()}${getOAuthCallbackPath()}`;
|
|
1431
|
+
}
|
|
1432
|
+
get usesClientCredentials() {
|
|
1433
|
+
return this.config.grantType === "client_credentials";
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* The redirect URL for OAuth callbacks.
|
|
1437
|
+
* This must match the redirect_uri in client metadata.
|
|
1438
|
+
*/
|
|
1439
|
+
get redirectUrl() {
|
|
1440
|
+
return this.redirectUrlSnapshot;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Client metadata for dynamic registration.
|
|
1444
|
+
* Describes this client to the OAuth authorization server.
|
|
1445
|
+
*/
|
|
1446
|
+
get clientMetadata() {
|
|
1447
|
+
if (this.usesClientCredentials)
|
|
1448
|
+
return {
|
|
1449
|
+
client_name: this.config.clientName ?? "lunR",
|
|
1450
|
+
...this.config.clientUri ? { client_uri: this.config.clientUri } : {},
|
|
1451
|
+
redirect_uris: [],
|
|
1452
|
+
grant_types: ["client_credentials"],
|
|
1453
|
+
token_endpoint_auth_method: this.config.clientSecret ? "client_secret_post" : "none"
|
|
1454
|
+
};
|
|
1455
|
+
let redirectUrl = this.redirectUrl;
|
|
1456
|
+
if (!redirectUrl)
|
|
1457
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
1458
|
+
return {
|
|
1459
|
+
redirect_uris: [redirectUrl],
|
|
1460
|
+
client_name: this.config.clientName ?? "lunR",
|
|
1461
|
+
...this.config.clientUri ? { client_uri: this.config.clientUri } : {},
|
|
1462
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
1463
|
+
response_types: ["code"],
|
|
1464
|
+
token_endpoint_auth_method: this.config.clientSecret ? "client_secret_post" : "none",
|
|
1465
|
+
...this.config.scope !== void 0 ? { scope: this.config.scope } : {}
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Get client information (for pre-registered or dynamically registered clients).
|
|
1470
|
+
* Returns undefined if no client info exists or if the server URL has changed.
|
|
1471
|
+
*/
|
|
1472
|
+
async clientInformation() {
|
|
1473
|
+
if (this.config.clientId)
|
|
1474
|
+
return {
|
|
1475
|
+
client_id: this.config.clientId,
|
|
1476
|
+
client_secret: this.config.clientSecret
|
|
1477
|
+
};
|
|
1478
|
+
if (!this.flowState || !this.flowClientInfoLoaded) {
|
|
1479
|
+
let entry = await getAuthForUrl(this.serverName, this.serverUrl);
|
|
1480
|
+
throwIfAborted(this.flowState?.signal);
|
|
1481
|
+
let info = entry?.clientInfo;
|
|
1482
|
+
this.flowClientInfo = info?.clientSecretExpiresAt && info.clientSecretExpiresAt < Date.now() / 1e3 ? void 0 : info, this.flowClientInfoLoaded = !0;
|
|
1483
|
+
}
|
|
1484
|
+
if (this.flowClientInfo)
|
|
1485
|
+
return {
|
|
1486
|
+
client_id: this.flowClientInfo.clientId,
|
|
1487
|
+
client_secret: this.flowClientInfo.clientSecret
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Save client information from dynamic registration.
|
|
1492
|
+
*/
|
|
1493
|
+
async saveClientInformation(info) {
|
|
1494
|
+
throwIfAborted(this.flowState?.signal);
|
|
1495
|
+
let redirectUris = info.redirect_uris ?? (this.redirectUrl ? [this.redirectUrl] : void 0), clientInfo = {
|
|
1496
|
+
clientId: info.client_id,
|
|
1497
|
+
clientSecret: info.client_secret,
|
|
1498
|
+
clientIdIssuedAt: info.client_id_issued_at,
|
|
1499
|
+
clientSecretExpiresAt: info.client_secret_expires_at,
|
|
1500
|
+
redirectUris
|
|
1501
|
+
};
|
|
1502
|
+
this.flowState && (this.flowClientInfo = clientInfo, this.flowClientInfoLoaded = !0), updateClientInfo(this.serverName, clientInfo, this.serverUrl);
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Get stored OAuth tokens.
|
|
1506
|
+
* Returns undefined if no tokens exist or if the server URL has changed.
|
|
1507
|
+
*/
|
|
1508
|
+
async tokens() {
|
|
1509
|
+
let entry = await getAuthForUrl(this.serverName, this.serverUrl);
|
|
1510
|
+
if (entry?.tokens)
|
|
1511
|
+
return {
|
|
1512
|
+
access_token: entry.tokens.accessToken,
|
|
1513
|
+
token_type: "Bearer",
|
|
1514
|
+
refresh_token: entry.tokens.refreshToken,
|
|
1515
|
+
expires_in: entry.tokens.expiresAt ? Math.max(0, Math.floor(entry.tokens.expiresAt - Date.now() / 1e3)) : void 0,
|
|
1516
|
+
scope: entry.tokens.scope
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Save OAuth tokens.
|
|
1521
|
+
*/
|
|
1522
|
+
async saveTokens(tokens) {
|
|
1523
|
+
throwIfAborted(this.flowState?.signal);
|
|
1524
|
+
let storedTokens = {
|
|
1525
|
+
accessToken: tokens.access_token,
|
|
1526
|
+
refreshToken: tokens.refresh_token,
|
|
1527
|
+
expiresAt: tokens.expires_in ? Date.now() / 1e3 + tokens.expires_in : void 0,
|
|
1528
|
+
scope: tokens.scope
|
|
1529
|
+
};
|
|
1530
|
+
this.flowState && this.flowClientInfo && updateClientInfo(this.serverName, this.flowClientInfo, this.serverUrl), updateTokens(this.serverName, storedTokens, this.serverUrl);
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Redirect the user to the authorization URL.
|
|
1534
|
+
* This opens the browser for the user to authenticate.
|
|
1535
|
+
*
|
|
1536
|
+
* Throws UnauthorizedError when called without owned or legacy flow state.
|
|
1537
|
+
* That path is reached when the SDK
|
|
1538
|
+
* falls through from a failed refresh into a fresh authorization_code
|
|
1539
|
+
* flow, which library hosts cannot complete in-process.
|
|
1540
|
+
*/
|
|
1541
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
1542
|
+
if (this.usesClientCredentials)
|
|
1543
|
+
throw new Error("redirectToAuthorization is not used for client_credentials flow");
|
|
1544
|
+
if (throwIfAborted(this.flowState?.signal), this.flowState) {
|
|
1545
|
+
await this.callbacks.onRedirect(authorizationUrl);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
if (!(await getAuthForUrl(this.serverName, this.serverUrl))?.oauthState)
|
|
1549
|
+
throw new UnauthorizedError(`Re-authentication required for MCP server: ${this.serverName}`);
|
|
1550
|
+
await this.callbacks.onRedirect(authorizationUrl);
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Save the PKCE code verifier.
|
|
1554
|
+
*/
|
|
1555
|
+
async saveCodeVerifier(codeVerifier) {
|
|
1556
|
+
if (throwIfAborted(this.flowState?.signal), this.flowState) {
|
|
1557
|
+
this.flowState.codeVerifier = codeVerifier;
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
updateCodeVerifier(this.serverName, codeVerifier, this.serverUrl);
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Get the stored PKCE code verifier.
|
|
1564
|
+
* @throws Error if no code verifier is stored
|
|
1565
|
+
*/
|
|
1566
|
+
async codeVerifier() {
|
|
1567
|
+
if (throwIfAborted(this.flowState?.signal), this.flowState) {
|
|
1568
|
+
if (!this.flowState.codeVerifier)
|
|
1569
|
+
throw new Error(`No code verifier saved for MCP server: ${this.serverName}`);
|
|
1570
|
+
return this.flowState.codeVerifier;
|
|
1571
|
+
}
|
|
1572
|
+
if (this.usesClientCredentials)
|
|
1573
|
+
throw new Error("codeVerifier is not used for client_credentials flow");
|
|
1574
|
+
let entry = await getAuthForUrl(this.serverName, this.serverUrl);
|
|
1575
|
+
if (!entry?.codeVerifier)
|
|
1576
|
+
throw new Error(`No code verifier saved for MCP server: ${this.serverName}`);
|
|
1577
|
+
return entry.codeVerifier;
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Save the OAuth state parameter for CSRF protection.
|
|
1581
|
+
*/
|
|
1582
|
+
async saveState(state) {
|
|
1583
|
+
if (throwIfAborted(this.flowState?.signal), this.flowState) {
|
|
1584
|
+
this.flowState.oauthState = state;
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
updateOAuthState(this.serverName, state, this.serverUrl);
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Get the stored OAuth state parameter.
|
|
1591
|
+
* @throws UnauthorizedError if no flow is in progress (see redirectToAuthorization)
|
|
1592
|
+
*/
|
|
1593
|
+
async state() {
|
|
1594
|
+
if (throwIfAborted(this.flowState?.signal), this.flowState)
|
|
1595
|
+
return this.flowState.oauthState;
|
|
1596
|
+
if (this.usesClientCredentials)
|
|
1597
|
+
throw new Error("state is not used for client_credentials flow");
|
|
1598
|
+
let entry = await getAuthForUrl(this.serverName, this.serverUrl);
|
|
1599
|
+
if (!entry?.oauthState)
|
|
1600
|
+
throw new UnauthorizedError(`Re-authentication required for MCP server: ${this.serverName}`);
|
|
1601
|
+
return entry.oauthState;
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Invalidate credentials when authentication fails.
|
|
1605
|
+
* Clears tokens, client info, or all credentials based on the type.
|
|
1606
|
+
*/
|
|
1607
|
+
async invalidateCredentials(type) {
|
|
1608
|
+
switch (throwIfAborted(this.flowState?.signal), this.flowState && type !== "tokens" && (this.flowClientInfo = void 0, this.flowClientInfoLoaded = !0), type) {
|
|
1609
|
+
case "all":
|
|
1610
|
+
clearAllCredentials(this.serverName);
|
|
1611
|
+
break;
|
|
1612
|
+
case "client":
|
|
1613
|
+
clearClientInfo(this.serverName);
|
|
1614
|
+
break;
|
|
1615
|
+
case "tokens":
|
|
1616
|
+
clearTokens(this.serverName);
|
|
1617
|
+
break;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Adds configured authorization-code scope without replacing the SDK's
|
|
1622
|
+
* default token endpoint authentication behavior.
|
|
1623
|
+
*/
|
|
1624
|
+
addClientAuthentication = async (headers, params, _url2, metadata) => {
|
|
1625
|
+
params.get("grant_type") === "authorization_code" && !params.has("scope") && this.config.scope && params.set("scope", this.config.scope);
|
|
1626
|
+
let clientInfo = await this.clientInformation();
|
|
1627
|
+
if (!clientInfo)
|
|
1628
|
+
return;
|
|
1629
|
+
let supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [], hasClientSecret = clientInfo.client_secret !== void 0, authMethod;
|
|
1630
|
+
if (supportedMethods.length === 0 ? authMethod = hasClientSecret ? "client_secret_post" : "none" : hasClientSecret && supportedMethods.includes("client_secret_basic") ? authMethod = "client_secret_basic" : hasClientSecret && supportedMethods.includes("client_secret_post") ? authMethod = "client_secret_post" : supportedMethods.includes("none") ? authMethod = "none" : authMethod = hasClientSecret ? "client_secret_post" : "none", authMethod === "client_secret_basic") {
|
|
1631
|
+
if (!clientInfo.client_secret)
|
|
1632
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
1633
|
+
headers.set("Authorization", `Basic ${Buffer.from(`${clientInfo.client_id}:${clientInfo.client_secret}`).toString("base64")}`);
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
params.has("client_id") || params.set("client_id", clientInfo.client_id), authMethod === "client_secret_post" && clientInfo.client_secret && !params.has("client_secret") && params.set("client_secret", clientInfo.client_secret);
|
|
1637
|
+
};
|
|
1638
|
+
prepareTokenRequest(scope) {
|
|
1639
|
+
if (!this.usesClientCredentials)
|
|
1640
|
+
return;
|
|
1641
|
+
let params = new URLSearchParams({ grant_type: "client_credentials" }), requestedScope = scope ?? this.config.scope;
|
|
1642
|
+
return requestedScope && params.set("scope", requestedScope), params;
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/mcp-callback-server.js
|
|
1647
|
+
import { createServer } from "http";
|
|
1648
|
+
var HTML_SUCCESS = `<!DOCTYPE html>
|
|
1649
|
+
<html>
|
|
1650
|
+
<head>
|
|
1651
|
+
<title>lunR - Authorization Successful</title>
|
|
1652
|
+
<style>
|
|
1653
|
+
body { font-family: system-ui, -apple-system, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e; color: #eee; }
|
|
1654
|
+
.container { text-align: center; padding: 2rem; }
|
|
1655
|
+
h1 { color: #4ade80; margin-bottom: 1rem; }
|
|
1656
|
+
p { color: #aaa; }
|
|
1657
|
+
</style>
|
|
1658
|
+
</head>
|
|
1659
|
+
<body>
|
|
1660
|
+
<div class="container">
|
|
1661
|
+
<h1>Authorization Successful</h1>
|
|
1662
|
+
<p>You can close this window and return to lunR.</p>
|
|
1663
|
+
</div>
|
|
1664
|
+
<script>setTimeout(() => window.close(), 2000);</script>
|
|
1665
|
+
</body>
|
|
1666
|
+
</html>`;
|
|
1667
|
+
function escapeHtml(value) {
|
|
1668
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1669
|
+
}
|
|
1670
|
+
var HTML_ERROR = (error) => `<!DOCTYPE html>
|
|
1671
|
+
<html>
|
|
1672
|
+
<head>
|
|
1673
|
+
<title>lunR - Authorization Failed</title>
|
|
1674
|
+
<style>
|
|
1675
|
+
body { font-family: system-ui, -apple-system, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e; color: #eee; }
|
|
1676
|
+
.container { text-align: center; padding: 2rem; }
|
|
1677
|
+
h1 { color: #f87171; margin-bottom: 1rem; }
|
|
1678
|
+
p { color: #aaa; }
|
|
1679
|
+
.error { color: #fca5a5; font-family: monospace; margin-top: 1rem; padding: 1rem; background: rgba(248,113,113,0.1); border-radius: 0.5rem; }
|
|
1680
|
+
</style>
|
|
1681
|
+
</head>
|
|
1682
|
+
<body>
|
|
1683
|
+
<div class="container">
|
|
1684
|
+
<h1>Authorization Failed</h1>
|
|
1685
|
+
<p>An error occurred during authorization.</p>
|
|
1686
|
+
<div class="error">${escapeHtml(error)}</div>
|
|
1687
|
+
</div>
|
|
1688
|
+
</body>
|
|
1689
|
+
</html>`, server, bindingPromise, pendingAuths = /* @__PURE__ */ new Map(), reservedAuthStates = /* @__PURE__ */ new Set(), callbackOwners = /* @__PURE__ */ new Set(), CALLBACK_TIMEOUT_MS = 300 * 1e3, DEFAULT_OAUTH_CALLBACK_HOST = "localhost", callbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST;
|
|
1690
|
+
function handleRequest(req, res) {
|
|
1691
|
+
let url2 = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
1692
|
+
if (url2.pathname !== getOAuthCallbackPath()) {
|
|
1693
|
+
res.writeHead(404, { "Content-Type": "text/plain" }), res.end("Not found");
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
let code = url2.searchParams.get("code"), state = url2.searchParams.get("state"), error = url2.searchParams.get("error"), errorDescription = url2.searchParams.get("error_description");
|
|
1697
|
+
if (!state) {
|
|
1698
|
+
let errorMsg = "Missing required state parameter - potential CSRF attack";
|
|
1699
|
+
res.writeHead(400, { "Content-Type": "text/html" }), res.end(HTML_ERROR(errorMsg));
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
let pending = pendingAuths.get(state), isReserved = reservedAuthStates.has(state);
|
|
1703
|
+
if (error) {
|
|
1704
|
+
if (!pending && !isReserved) {
|
|
1705
|
+
let errorMsg2 = "Invalid or expired state parameter - potential CSRF attack";
|
|
1706
|
+
res.writeHead(400, { "Content-Type": "text/html" }), res.end(HTML_ERROR(errorMsg2));
|
|
1707
|
+
return;
|
|
1708
|
+
}
|
|
1709
|
+
let errorMsg = errorDescription || error;
|
|
1710
|
+
res.writeHead(200, { "Content-Type": "text/html" }), res.end(HTML_ERROR(errorMsg)), reservedAuthStates.delete(state), pending && (clearTimeout(pending.timeout), pendingAuths.delete(state), setTimeout(() => pending.reject(new Error(errorMsg)), 0));
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
if (!pending) {
|
|
1714
|
+
let errorMsg = "Invalid or expired state parameter - potential CSRF attack";
|
|
1715
|
+
res.writeHead(400, { "Content-Type": "text/html" }), res.end(HTML_ERROR(errorMsg));
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
if (!code) {
|
|
1719
|
+
res.writeHead(400, { "Content-Type": "text/html" }), res.end(HTML_ERROR("No authorization code provided"));
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
clearTimeout(pending.timeout), pendingAuths.delete(state), pending.resolve(code), res.writeHead(200, { "Content-Type": "text/html" }), res.end(HTML_SUCCESS);
|
|
1723
|
+
}
|
|
1724
|
+
async function withCallbackLock(action) {
|
|
1725
|
+
for (; bindingPromise; )
|
|
1726
|
+
await bindingPromise.catch(() => {
|
|
1727
|
+
});
|
|
1728
|
+
let operation = action();
|
|
1729
|
+
bindingPromise = operation;
|
|
1730
|
+
try {
|
|
1731
|
+
await operation;
|
|
1732
|
+
} finally {
|
|
1733
|
+
bindingPromise === operation && (bindingPromise = void 0);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
function acquireCallbackServerOwner() {
|
|
1737
|
+
let owner = /* @__PURE__ */ Symbol("MCP OAuth owner");
|
|
1738
|
+
return callbackOwners.add(owner), owner;
|
|
1739
|
+
}
|
|
1740
|
+
async function releaseCallbackServerOwner(owner) {
|
|
1741
|
+
await withCallbackLock(async () => {
|
|
1742
|
+
callbackOwners.delete(owner), callbackOwners.size === 0 && await stopCallbackServerLocked();
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
async function ensureCallbackServer(options = {}) {
|
|
1746
|
+
await withCallbackLock(async () => {
|
|
1747
|
+
if (throwIfAborted(options.signal), options.owner && !callbackOwners.has(options.owner))
|
|
1748
|
+
throw new Error("MCP OAuth session closed");
|
|
1749
|
+
await ensureCallbackServerLocked(options), throwIfAborted(options.signal);
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
async function ensureCallbackServerLocked(options = {}) {
|
|
1753
|
+
let requiredPort = options.port ?? getConfiguredOAuthCallbackPort(), strictPort = options.strictPort === !0, requestedHost = options.callbackHost ?? DEFAULT_OAUTH_CALLBACK_HOST, rawRequestedPath = options.callbackPath ?? DEFAULT_OAUTH_CALLBACK_PATH, requestedPath = rawRequestedPath.startsWith("/") ? rawRequestedPath : `/${rawRequestedPath}`;
|
|
1754
|
+
if (options.reserveState && !options.oauthState)
|
|
1755
|
+
throw new Error("OAuth callback reservation requires an oauthState");
|
|
1756
|
+
let reservedState, previousServer = server, needsStrictRebind = !!(previousServer && strictPort && getOAuthCallbackPort() !== requiredPort), needsHostSwitch = !!(previousServer && callbackServerHost !== requestedHost), needsPathSwitch = !!(previousServer && getOAuthCallbackPath() !== requestedPath);
|
|
1757
|
+
if (previousServer) {
|
|
1758
|
+
if (!needsStrictRebind && !needsHostSwitch) {
|
|
1759
|
+
if (needsPathSwitch) {
|
|
1760
|
+
if (pendingAuths.size > 0 || reservedAuthStates.size > 0)
|
|
1761
|
+
throw new Error(`OAuth callback server is using path ${getOAuthCallbackPath()}, but callback path ${requestedPath} is required and cannot be switched while authorizations are pending`);
|
|
1762
|
+
setOAuthCallbackPath(requestedPath);
|
|
1763
|
+
}
|
|
1764
|
+
options.reserveState && options.oauthState && !options.signal?.aborted && (reservedAuthStates.add(options.oauthState), reservedState = options.oauthState);
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
if (pendingAuths.size > 0 || reservedAuthStates.size > 0)
|
|
1768
|
+
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`);
|
|
1769
|
+
}
|
|
1770
|
+
let candidateServer = createServer(handleRequest), listenPort = strictPort ? requiredPort : 0;
|
|
1771
|
+
try {
|
|
1772
|
+
if (await new Promise((resolve2, reject) => {
|
|
1773
|
+
candidateServer.once("error", (err) => {
|
|
1774
|
+
reject(err);
|
|
1775
|
+
}), candidateServer.listen(listenPort, requestedHost, () => {
|
|
1776
|
+
resolve2();
|
|
1777
|
+
});
|
|
1778
|
+
}), strictPort)
|
|
1779
|
+
setOAuthCallbackPort(requiredPort);
|
|
1780
|
+
else {
|
|
1781
|
+
let address = candidateServer.address();
|
|
1782
|
+
if (!address || typeof address == "string" || typeof address.port != "number")
|
|
1783
|
+
throw new Error("OAuth callback server did not report an assigned port");
|
|
1784
|
+
setOAuthCallbackPort(address.port);
|
|
1785
|
+
}
|
|
1786
|
+
previousServer && (needsStrictRebind || needsHostSwitch) && await new Promise((resolve2) => {
|
|
1787
|
+
previousServer.close(() => resolve2());
|
|
1788
|
+
}), callbackServerHost = requestedHost, setOAuthCallbackPath(requestedPath), server = candidateServer, options.reserveState && options.oauthState && !options.signal?.aborted && (reservedAuthStates.add(options.oauthState), reservedState = options.oauthState), server.unref();
|
|
1789
|
+
} catch (error) {
|
|
1790
|
+
reservedState && reservedAuthStates.delete(reservedState);
|
|
1791
|
+
let nodeError = error;
|
|
1792
|
+
throw await new Promise((resolve2) => {
|
|
1793
|
+
candidateServer.close(() => resolve2());
|
|
1794
|
+
}), strictPort && nodeError.code === "EADDRINUSE" ? 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 }) : error;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
function releaseCallbackServer(oauthState) {
|
|
1798
|
+
reservedAuthStates.delete(oauthState);
|
|
1799
|
+
}
|
|
1800
|
+
function waitForCallback(oauthState) {
|
|
1801
|
+
return reservedAuthStates.delete(oauthState), new Promise((resolve2, reject) => {
|
|
1802
|
+
let timeout = setTimeout(() => {
|
|
1803
|
+
pendingAuths.has(oauthState) && (pendingAuths.delete(oauthState), reject(new Error("OAuth callback timeout - authorization took too long")));
|
|
1804
|
+
}, CALLBACK_TIMEOUT_MS);
|
|
1805
|
+
pendingAuths.set(oauthState, { resolve: resolve2, reject, timeout });
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
function cancelPendingCallback(oauthState) {
|
|
1809
|
+
reservedAuthStates.delete(oauthState);
|
|
1810
|
+
let pending = pendingAuths.get(oauthState);
|
|
1811
|
+
pending && (clearTimeout(pending.timeout), pendingAuths.delete(oauthState), pending.reject(new Error("Authorization cancelled")));
|
|
1812
|
+
}
|
|
1813
|
+
async function stopCallbackServerLocked() {
|
|
1814
|
+
server && (await new Promise((resolve2) => {
|
|
1815
|
+
server.close(() => {
|
|
1816
|
+
resolve2();
|
|
1817
|
+
});
|
|
1818
|
+
}), server = void 0), setOAuthCallbackPort(getConfiguredOAuthCallbackPort()), callbackServerHost = DEFAULT_OAUTH_CALLBACK_HOST, setOAuthCallbackPath(DEFAULT_OAUTH_CALLBACK_PATH);
|
|
1819
|
+
let pendingList = Array.from(pendingAuths.entries());
|
|
1820
|
+
pendingAuths.clear(), reservedAuthStates.clear(), setTimeout(() => {
|
|
1821
|
+
for (let [, pending] of pendingList)
|
|
1822
|
+
clearTimeout(pending.timeout), pending.reject(new Error("OAuth callback server stopped"));
|
|
1823
|
+
}, 0);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/mcp-auth-flow.js
|
|
1827
|
+
var MANUAL_AUTH_TIMEOUT_MS = 300 * 1e3;
|
|
1828
|
+
function generateState() {
|
|
1829
|
+
return Array.from(crypto.getRandomValues(new Uint8Array(32))).map((b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
1830
|
+
}
|
|
1831
|
+
function extractOAuthConfig(definition) {
|
|
1832
|
+
if (definition.oauth === !1)
|
|
1833
|
+
return {};
|
|
1834
|
+
let config = {};
|
|
1835
|
+
if (definition.oauth?.grantType !== void 0 && (config.grantType = definition.oauth.grantType), definition.oauth?.clientId !== void 0 && (config.clientId = definition.oauth.clientId), definition.oauth?.clientSecret !== void 0 && (config.clientSecret = definition.oauth.clientSecret), definition.oauth?.scope !== void 0 && (config.scope = definition.oauth.scope), definition.oauth?.redirectUri !== void 0) {
|
|
1836
|
+
if (typeof definition.oauth.redirectUri != "string")
|
|
1837
|
+
throw new Error("OAuth redirectUri must be a string");
|
|
1838
|
+
let redirectUri = definition.oauth.redirectUri.trim();
|
|
1839
|
+
if (!redirectUri)
|
|
1840
|
+
throw new Error("OAuth redirectUri must not be empty");
|
|
1841
|
+
config.redirectUri = redirectUri;
|
|
1842
|
+
}
|
|
1843
|
+
if (definition.oauth?.clientName !== void 0) {
|
|
1844
|
+
if (typeof definition.oauth.clientName != "string")
|
|
1845
|
+
throw new Error("OAuth clientName must be a string");
|
|
1846
|
+
let clientName = definition.oauth.clientName.trim();
|
|
1847
|
+
if (!clientName)
|
|
1848
|
+
throw new Error("OAuth clientName must not be empty");
|
|
1849
|
+
config.clientName = clientName;
|
|
1850
|
+
}
|
|
1851
|
+
if (definition.oauth?.clientUri !== void 0) {
|
|
1852
|
+
if (typeof definition.oauth.clientUri != "string")
|
|
1853
|
+
throw new Error("OAuth clientUri must be a string");
|
|
1854
|
+
let clientUri = definition.oauth.clientUri.trim();
|
|
1855
|
+
if (!clientUri)
|
|
1856
|
+
throw new Error("OAuth clientUri must not be empty");
|
|
1857
|
+
config.clientUri = clientUri;
|
|
1858
|
+
}
|
|
1859
|
+
return config;
|
|
1860
|
+
}
|
|
1861
|
+
function parseOAuthRedirectUri(redirectUri) {
|
|
1862
|
+
let url2;
|
|
1863
|
+
try {
|
|
1864
|
+
url2 = new URL(redirectUri);
|
|
1865
|
+
} catch (error) {
|
|
1866
|
+
throw new Error(`Invalid OAuth redirectUri: ${redirectUri}`, { cause: error });
|
|
1867
|
+
}
|
|
1868
|
+
let hostname = url2.hostname.toLowerCase(), isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
|
|
1869
|
+
if (url2.protocol !== "http:" || !isLocalhost)
|
|
1870
|
+
throw new Error("OAuth redirectUri must be an http:// localhost or loopback URI");
|
|
1871
|
+
if (url2.username || url2.password)
|
|
1872
|
+
throw new Error("OAuth redirectUri must not include username or password");
|
|
1873
|
+
if (url2.hash)
|
|
1874
|
+
throw new Error("OAuth redirectUri must not include a fragment");
|
|
1875
|
+
if (!url2.port)
|
|
1876
|
+
throw new Error("OAuth redirectUri must include an explicit numeric port");
|
|
1877
|
+
let port = Number.parseInt(url2.port, 10);
|
|
1878
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535)
|
|
1879
|
+
throw new Error("OAuth redirectUri must include an explicit numeric port");
|
|
1880
|
+
return { port, callbackHost: hostname === "[::1]" ? "::1" : hostname, callbackPath: url2.pathname };
|
|
1881
|
+
}
|
|
1882
|
+
function getSearchParamsFromInput(input) {
|
|
1883
|
+
try {
|
|
1884
|
+
let url2 = new URL(input), params = new URLSearchParams(url2.search);
|
|
1885
|
+
if (url2.hash) {
|
|
1886
|
+
let hash = url2.hash.startsWith("#") ? url2.hash.slice(1) : url2.hash, hashParams = new URLSearchParams(hash);
|
|
1887
|
+
for (let [key, value] of hashParams)
|
|
1888
|
+
params.has(key) || params.set(key, value);
|
|
1889
|
+
}
|
|
1890
|
+
return params;
|
|
1891
|
+
} catch {
|
|
1892
|
+
let query = input.includes("?") ? input.slice(input.indexOf("?") + 1) : input, params = new URLSearchParams(query.startsWith("#") ? query.slice(1) : query);
|
|
1893
|
+
return params.has("code") || params.has("state") || params.has("error") ? params : void 0;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
function parseAuthorizationCodeInput(input, expectedState) {
|
|
1897
|
+
let trimmed = input.trim();
|
|
1898
|
+
if (!trimmed)
|
|
1899
|
+
throw new Error("Authorization code or redirect URL is required");
|
|
1900
|
+
let params = getSearchParamsFromInput(trimmed);
|
|
1901
|
+
if (params) {
|
|
1902
|
+
let error = params.get("error");
|
|
1903
|
+
if (error) {
|
|
1904
|
+
let description = params.get("error_description");
|
|
1905
|
+
throw new Error(description ? `${error}: ${description}` : error);
|
|
1906
|
+
}
|
|
1907
|
+
let state = params.get("state");
|
|
1908
|
+
if (expectedState && !state)
|
|
1909
|
+
throw new Error("OAuth state missing from redirect URL");
|
|
1910
|
+
if (expectedState && state !== expectedState)
|
|
1911
|
+
throw new Error("OAuth state mismatch - potential CSRF attack");
|
|
1912
|
+
let code = params.get("code");
|
|
1913
|
+
if (code)
|
|
1914
|
+
return code;
|
|
1915
|
+
}
|
|
1916
|
+
if (/^[A-Za-z0-9._~+/=-]+$/.test(trimmed))
|
|
1917
|
+
return trimmed;
|
|
1918
|
+
throw new Error("Could not find an OAuth authorization code in the provided input");
|
|
1919
|
+
}
|
|
1920
|
+
function createMcpAuthFlow() {
|
|
1921
|
+
let owner = acquireCallbackServerOwner(), flows = /* @__PURE__ */ new Map(), authenticating = /* @__PURE__ */ new Map(), shutdownPromise, closed = !1;
|
|
1922
|
+
function assertOpen() {
|
|
1923
|
+
if (closed)
|
|
1924
|
+
throw new Error("MCP OAuth session closed");
|
|
1925
|
+
}
|
|
1926
|
+
async function clearPendingAuth(serverName, flow = flows.get(serverName)) {
|
|
1927
|
+
flow && (flow.cleanup || (flow.cleanup = (async () => {
|
|
1928
|
+
flows.get(serverName) === flow && flows.delete(serverName), flow.timer && clearTimeout(flow.timer), flow.controller.abort(new Error("Authorization cancelled")), cancelPendingCallback(flow.state.oauthState), releaseCallbackServer(flow.state.oauthState), await flow.transport?.close().catch(() => {
|
|
1929
|
+
});
|
|
1930
|
+
})()), await flow.cleanup);
|
|
1931
|
+
}
|
|
1932
|
+
async function startAuth(serverName, serverUrl, definition) {
|
|
1933
|
+
assertOpen();
|
|
1934
|
+
let previous = flows.get(serverName);
|
|
1935
|
+
if (previous && await clearPendingAuth(serverName, previous), assertOpen(), flows.has(serverName))
|
|
1936
|
+
throw new Error(`OAuth flow already pending for server: ${serverName}`);
|
|
1937
|
+
let controller = new AbortController(), flow = { controller, state: { oauthState: generateState(), signal: controller.signal } };
|
|
1938
|
+
flows.set(serverName, flow);
|
|
1939
|
+
let signal = controller.signal, fetchFn = (input, init) => fetch(input, {
|
|
1940
|
+
...init,
|
|
1941
|
+
signal: init?.signal ? AbortSignal.any([init.signal, signal]) : signal
|
|
1942
|
+
});
|
|
1943
|
+
try {
|
|
1944
|
+
let config = definition ? extractOAuthConfig(definition) : {}, storedAuth = await getAuthForUrl(serverName, serverUrl);
|
|
1945
|
+
if (throwIfAborted(signal), flow.state.clientInfo = storedAuth?.clientInfo, config.grantType !== "client_credentials") {
|
|
1946
|
+
if (!config.redirectUri && !config.clientId) {
|
|
1947
|
+
let registeredRedirect = storedAuth?.clientInfo?.redirectUris?.[0];
|
|
1948
|
+
registeredRedirect && (config.redirectUri = registeredRedirect);
|
|
1949
|
+
}
|
|
1950
|
+
let redirect = config.redirectUri ? parseOAuthRedirectUri(config.redirectUri) : void 0;
|
|
1951
|
+
await ensureCallbackServer({
|
|
1952
|
+
owner,
|
|
1953
|
+
signal,
|
|
1954
|
+
strictPort: !!(config.clientId || storedAuth?.clientInfo) || config.redirectUri !== void 0,
|
|
1955
|
+
oauthState: flow.state.oauthState,
|
|
1956
|
+
reserveState: !0,
|
|
1957
|
+
...redirect ? { port: redirect.port, callbackHost: redirect.callbackHost, callbackPath: redirect.callbackPath } : {}
|
|
1958
|
+
}), throwIfAborted(signal);
|
|
1959
|
+
}
|
|
1960
|
+
let capturedUrl, authProvider = new McpOAuthProvider(serverName, serverUrl, config, {
|
|
1961
|
+
onRedirect: (url2) => {
|
|
1962
|
+
throwIfAborted(signal), capturedUrl = url2;
|
|
1963
|
+
}
|
|
1964
|
+
}, flow.state), result = await abortable(auth(authProvider, { serverUrl, fetchFn }), signal);
|
|
1965
|
+
if (throwIfAborted(signal), result === "AUTHORIZED")
|
|
1966
|
+
return await clearPendingAuth(serverName, flow), { authorizationUrl: "" };
|
|
1967
|
+
if (config.grantType === "client_credentials" || !capturedUrl)
|
|
1968
|
+
throw new UnauthorizedError("OAuth authorization URL was not provided");
|
|
1969
|
+
return flow.transport = new StreamableHTTPClientTransport(new URL(serverUrl), { authProvider, fetch: fetchFn }), flow.timer = setTimeout(() => {
|
|
1970
|
+
clearPendingAuth(serverName, flow);
|
|
1971
|
+
}, MANUAL_AUTH_TIMEOUT_MS), flow.timer.unref?.(), { authorizationUrl: capturedUrl.toString() };
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
throw await clearPendingAuth(serverName, flow), error;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
async function completeAuthFromInput(serverName, input) {
|
|
1977
|
+
assertOpen();
|
|
1978
|
+
let flow = flows.get(serverName);
|
|
1979
|
+
if (!flow)
|
|
1980
|
+
throw new Error(`No pending OAuth flow for server: ${serverName}`);
|
|
1981
|
+
return completeAuth(serverName, parseAuthorizationCodeInput(input, flow.state.oauthState));
|
|
1982
|
+
}
|
|
1983
|
+
async function completeAuth(serverName, code) {
|
|
1984
|
+
assertOpen();
|
|
1985
|
+
let flow = flows.get(serverName);
|
|
1986
|
+
if (!flow?.transport)
|
|
1987
|
+
throw new Error(`No pending OAuth flow for server: ${serverName}`);
|
|
1988
|
+
try {
|
|
1989
|
+
return await abortable(flow.transport.finishAuth(code), flow.state.signal), throwIfAborted(flow.state.signal), "authenticated";
|
|
1990
|
+
} finally {
|
|
1991
|
+
await clearPendingAuth(serverName, flow);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
async function authenticate(serverName, serverUrl, definition, options = {}) {
|
|
1995
|
+
assertOpen();
|
|
1996
|
+
let pending = authenticating.get(serverName);
|
|
1997
|
+
if (pending)
|
|
1998
|
+
return pending;
|
|
1999
|
+
let operation = (async () => {
|
|
2000
|
+
let { authorizationUrl } = await startAuth(serverName, serverUrl, definition);
|
|
2001
|
+
if (!authorizationUrl)
|
|
2002
|
+
return "authenticated";
|
|
2003
|
+
assertOpen();
|
|
2004
|
+
let flow = flows.get(serverName);
|
|
2005
|
+
if (!flow)
|
|
2006
|
+
throw new Error(`No pending OAuth flow for server: ${serverName}`);
|
|
2007
|
+
let callback = waitForCallback(flow.state.oauthState);
|
|
2008
|
+
callback.catch(() => {
|
|
2009
|
+
});
|
|
2010
|
+
try {
|
|
2011
|
+
options.onAuthorizationUrl ? await abortable(Promise.resolve(options.onAuthorizationUrl(authorizationUrl)), flow.state.signal) : console.log(`MCP Auth: Open this URL to authenticate ${serverName}:
|
|
2012
|
+
${authorizationUrl}`), throwIfAborted(flow.state.signal);
|
|
2013
|
+
try {
|
|
2014
|
+
await abortable(open(authorizationUrl), flow.state.signal);
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
throwIfAborted(flow.state.signal), console.warn(`MCP Auth: Failed to open browser for ${serverName}; waiting for manual callback`, { error });
|
|
2017
|
+
}
|
|
2018
|
+
let code = await callback;
|
|
2019
|
+
return await completeAuth(serverName, code);
|
|
2020
|
+
} catch (error) {
|
|
2021
|
+
throw await clearPendingAuth(serverName, flow), error;
|
|
2022
|
+
}
|
|
2023
|
+
})();
|
|
2024
|
+
authenticating.set(serverName, operation);
|
|
2025
|
+
try {
|
|
2026
|
+
return await operation;
|
|
2027
|
+
} finally {
|
|
2028
|
+
authenticating.get(serverName) === operation && authenticating.delete(serverName);
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
async function removeAuth(serverName) {
|
|
2032
|
+
assertOpen(), await clearPendingAuth(serverName), clearAllCredentials(serverName);
|
|
2033
|
+
}
|
|
2034
|
+
function shutdown() {
|
|
2035
|
+
return shutdownPromise || (closed = !0, shutdownPromise = (async () => {
|
|
2036
|
+
await Promise.all([...flows].map(([name, flow]) => clearPendingAuth(name, flow))), await releaseCallbackServerOwner(owner);
|
|
2037
|
+
})()), shutdownPromise;
|
|
2038
|
+
}
|
|
2039
|
+
return { startAuth, completeAuth, completeAuthFromInput, authenticate, removeAuth, shutdown };
|
|
2040
|
+
}
|
|
2041
|
+
function supportsOAuth(definition) {
|
|
2042
|
+
return !definition.url || definition.auth === !1 || definition.oauth === !1 ? !1 : definition.auth === "oauth" ? !0 : definition.headers && Object.keys(definition.headers).length > 0 ? !1 : definition.auth === void 0;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/init.js
|
|
2046
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
2047
|
+
|
|
2048
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/errors.js
|
|
2049
|
+
var McpUiError = class extends Error {
|
|
2050
|
+
code;
|
|
2051
|
+
context;
|
|
2052
|
+
recoveryHint;
|
|
2053
|
+
cause;
|
|
2054
|
+
constructor(message, options) {
|
|
2055
|
+
super(message), this.name = "McpUiError", this.code = options.code, this.context = options.context ?? {}, this.recoveryHint = options.recoveryHint, this.cause = options.cause, Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
|
|
2056
|
+
}
|
|
2057
|
+
toJSON() {
|
|
2058
|
+
return {
|
|
2059
|
+
name: this.name,
|
|
2060
|
+
code: this.code,
|
|
2061
|
+
message: this.message,
|
|
2062
|
+
context: this.context,
|
|
2063
|
+
recoveryHint: this.recoveryHint,
|
|
2064
|
+
stack: this.stack
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
}, ResourceFetchError = class extends McpUiError {
|
|
2068
|
+
constructor(uri, reason, options) {
|
|
2069
|
+
super(`Failed to fetch UI resource "${uri}": ${reason}`, {
|
|
2070
|
+
code: "RESOURCE_FETCH_ERROR",
|
|
2071
|
+
context: { uri, server: options?.server },
|
|
2072
|
+
recoveryHint: "Check that the MCP server is connected and the resource URI is valid.",
|
|
2073
|
+
cause: options?.cause
|
|
2074
|
+
}), this.name = "ResourceFetchError";
|
|
2075
|
+
}
|
|
2076
|
+
}, ResourceParseError = class extends McpUiError {
|
|
2077
|
+
constructor(uri, reason, options) {
|
|
2078
|
+
super(`Invalid UI resource "${uri}": ${reason}`, {
|
|
2079
|
+
code: "RESOURCE_PARSE_ERROR",
|
|
2080
|
+
context: { uri, server: options?.server, mimeType: options?.mimeType },
|
|
2081
|
+
recoveryHint: "Ensure the resource returns valid HTML with the correct MIME type."
|
|
2082
|
+
}), this.name = "ResourceParseError";
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
var ConsentError = class extends McpUiError {
|
|
2086
|
+
denied;
|
|
2087
|
+
constructor(server2, options) {
|
|
2088
|
+
let message = options.denied ? `Tool calls for "${server2}" were denied for this session` : `Tool call approval required for "${server2}"`;
|
|
2089
|
+
super(message, {
|
|
2090
|
+
code: options.denied ? "CONSENT_DENIED" : "CONSENT_REQUIRED",
|
|
2091
|
+
context: { server: server2 },
|
|
2092
|
+
recoveryHint: options.denied ? "The user denied tool access. Start a new session to try again." : "Prompt the user for consent before calling tools."
|
|
2093
|
+
}), this.name = "ConsentError", this.denied = options.denied ?? !1;
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
var ServerError2 = class extends McpUiError {
|
|
2097
|
+
constructor(reason, options) {
|
|
2098
|
+
super(`UI server error: ${reason}`, {
|
|
2099
|
+
code: "SERVER_ERROR",
|
|
2100
|
+
context: { port: options?.port },
|
|
2101
|
+
recoveryHint: "Check if the port is available. Another process may be using it.",
|
|
2102
|
+
cause: options?.cause
|
|
2103
|
+
}), this.name = "ServerError";
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
function wrapError(error, context) {
|
|
2107
|
+
if (error instanceof McpUiError)
|
|
2108
|
+
return new McpUiError(error.message, {
|
|
2109
|
+
code: error.code,
|
|
2110
|
+
context: { ...error.context, ...context },
|
|
2111
|
+
recoveryHint: error.recoveryHint,
|
|
2112
|
+
cause: error.cause
|
|
2113
|
+
});
|
|
2114
|
+
let cause = error instanceof Error ? error : void 0, message = error instanceof Error ? error.message : String(error);
|
|
2115
|
+
return new McpUiError(message, {
|
|
2116
|
+
code: "UNKNOWN_ERROR",
|
|
2117
|
+
context,
|
|
2118
|
+
cause
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/logger.js
|
|
2123
|
+
var LEVEL_PRIORITY = {
|
|
2124
|
+
debug: 0,
|
|
2125
|
+
info: 1,
|
|
2126
|
+
warn: 2,
|
|
2127
|
+
error: 3
|
|
2128
|
+
}, LEVEL_PREFIX = {
|
|
2129
|
+
debug: "[MCP-UI:DEBUG]",
|
|
2130
|
+
info: "[MCP-UI]",
|
|
2131
|
+
warn: "[MCP-UI:WARN]",
|
|
2132
|
+
error: "[MCP-UI:ERROR]"
|
|
2133
|
+
}, Logger = class {
|
|
2134
|
+
minLevel = "info";
|
|
2135
|
+
handlers = [];
|
|
2136
|
+
defaultContext = {};
|
|
2137
|
+
setLevel(level) {
|
|
2138
|
+
this.minLevel = level;
|
|
2139
|
+
}
|
|
2140
|
+
setDefaultContext(context) {
|
|
2141
|
+
this.defaultContext = context;
|
|
2142
|
+
}
|
|
2143
|
+
addHandler(handler) {
|
|
2144
|
+
this.handlers.push(handler);
|
|
2145
|
+
}
|
|
2146
|
+
clearHandlers() {
|
|
2147
|
+
this.handlers = [];
|
|
2148
|
+
}
|
|
2149
|
+
shouldLog(level) {
|
|
2150
|
+
return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[this.minLevel];
|
|
2151
|
+
}
|
|
2152
|
+
emit(level, message, context, error) {
|
|
2153
|
+
if (!this.shouldLog(level))
|
|
2154
|
+
return;
|
|
2155
|
+
let entry = {
|
|
2156
|
+
level,
|
|
2157
|
+
message,
|
|
2158
|
+
context: { ...this.defaultContext, ...context },
|
|
2159
|
+
error,
|
|
2160
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
2161
|
+
}, prefix = LEVEL_PREFIX[level], contextStr = formatContext(entry.context), fullMessage = contextStr ? `${prefix} ${message} ${contextStr}` : `${prefix} ${message}`;
|
|
2162
|
+
level === "error" ? console.error(fullMessage, error ?? "") : level === "warn" ? console.warn(fullMessage) : level === "debug" ? console.debug(fullMessage) : console.log(fullMessage);
|
|
2163
|
+
for (let handler of this.handlers)
|
|
2164
|
+
try {
|
|
2165
|
+
handler(entry);
|
|
2166
|
+
} catch {
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
debug(message, context) {
|
|
2170
|
+
this.emit("debug", message, context);
|
|
2171
|
+
}
|
|
2172
|
+
info(message, context) {
|
|
2173
|
+
this.emit("info", message, context);
|
|
2174
|
+
}
|
|
2175
|
+
warn(message, context) {
|
|
2176
|
+
this.emit("warn", message, context);
|
|
2177
|
+
}
|
|
2178
|
+
error(message, error, context) {
|
|
2179
|
+
this.emit("error", message, context, error);
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Create a child logger with additional default context.
|
|
2183
|
+
*/
|
|
2184
|
+
child(context) {
|
|
2185
|
+
return new ChildLogger(this, context);
|
|
2186
|
+
}
|
|
2187
|
+
}, ChildLogger = class _ChildLogger {
|
|
2188
|
+
parent;
|
|
2189
|
+
context;
|
|
2190
|
+
constructor(parent, context) {
|
|
2191
|
+
this.parent = parent, this.context = context;
|
|
2192
|
+
}
|
|
2193
|
+
debug(message, context) {
|
|
2194
|
+
this.parent.debug(message, { ...this.context, ...context });
|
|
2195
|
+
}
|
|
2196
|
+
info(message, context) {
|
|
2197
|
+
this.parent.info(message, { ...this.context, ...context });
|
|
2198
|
+
}
|
|
2199
|
+
warn(message, context) {
|
|
2200
|
+
this.parent.warn(message, { ...this.context, ...context });
|
|
2201
|
+
}
|
|
2202
|
+
error(message, error, context) {
|
|
2203
|
+
this.parent.error(message, error, { ...this.context, ...context });
|
|
2204
|
+
}
|
|
2205
|
+
child(context) {
|
|
2206
|
+
return new _ChildLogger(this.parent, { ...this.context, ...context });
|
|
2207
|
+
}
|
|
2208
|
+
};
|
|
2209
|
+
function formatContext(context) {
|
|
2210
|
+
if (!context || Object.keys(context).length === 0)
|
|
2211
|
+
return "";
|
|
2212
|
+
let parts = [];
|
|
2213
|
+
for (let [key, value] of Object.entries(context))
|
|
2214
|
+
value != null && parts.push(`${key}=${typeof value == "string" ? value : JSON.stringify(value)}`);
|
|
2215
|
+
return parts.length > 0 ? `(${parts.join(", ")})` : "";
|
|
2216
|
+
}
|
|
2217
|
+
var logger = new Logger();
|
|
2218
|
+
(process.env.MCP_UI_DEBUG === "1" || process.env.MCP_UI_DEBUG === "true") && logger.setLevel("debug");
|
|
2219
|
+
|
|
2220
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/consent-manager.js
|
|
2221
|
+
var ConsentManager = class {
|
|
2222
|
+
mode;
|
|
2223
|
+
approvedServers = /* @__PURE__ */ new Set();
|
|
2224
|
+
deniedServers = /* @__PURE__ */ new Set();
|
|
2225
|
+
log = logger.child({ component: "ConsentManager" });
|
|
2226
|
+
constructor(mode = "once-per-server") {
|
|
2227
|
+
this.mode = mode, this.log.debug("Initialized", { mode });
|
|
2228
|
+
}
|
|
2229
|
+
requiresPrompt(serverName) {
|
|
2230
|
+
return this.mode === "never" ? !1 : this.deniedServers.has(serverName) || this.mode === "always" ? !0 : !this.approvedServers.has(serverName);
|
|
2231
|
+
}
|
|
2232
|
+
shouldCacheConsent() {
|
|
2233
|
+
return this.mode !== "always";
|
|
2234
|
+
}
|
|
2235
|
+
registerDecision(serverName, approved) {
|
|
2236
|
+
if (this.deniedServers.delete(serverName), this.approvedServers.delete(serverName), approved) {
|
|
2237
|
+
this.approvedServers.add(serverName), this.log.debug("Consent granted", { server: serverName });
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
this.deniedServers.add(serverName), this.log.debug("Consent denied", { server: serverName });
|
|
2241
|
+
}
|
|
2242
|
+
ensureApproved(serverName) {
|
|
2243
|
+
if (this.mode !== "never") {
|
|
2244
|
+
if (this.deniedServers.has(serverName))
|
|
2245
|
+
throw new ConsentError(serverName, { denied: !0 });
|
|
2246
|
+
if (!this.approvedServers.has(serverName))
|
|
2247
|
+
throw new ConsentError(serverName, { requiresApproval: !0 });
|
|
2248
|
+
this.mode === "always" && this.approvedServers.delete(serverName);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
clear(serverName) {
|
|
2252
|
+
if (serverName) {
|
|
2253
|
+
this.approvedServers.delete(serverName), this.deniedServers.delete(serverName), this.log.debug("Cleared consent for server", { server: serverName });
|
|
2254
|
+
return;
|
|
2255
|
+
}
|
|
2256
|
+
this.approvedServers.clear(), this.deniedServers.clear(), this.log.debug("Cleared all consent records");
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
|
|
2260
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/lifecycle.js
|
|
2261
|
+
var McpLifecycleManager = class {
|
|
2262
|
+
manager;
|
|
2263
|
+
keepAliveServers = /* @__PURE__ */ new Map();
|
|
2264
|
+
allServers = /* @__PURE__ */ new Map();
|
|
2265
|
+
serverSettings = /* @__PURE__ */ new Map();
|
|
2266
|
+
globalIdleTimeout = 600 * 1e3;
|
|
2267
|
+
healthCheckInterval;
|
|
2268
|
+
onReconnect;
|
|
2269
|
+
onIdleShutdown;
|
|
2270
|
+
constructor(manager) {
|
|
2271
|
+
this.manager = manager;
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Set callback to be invoked after a successful auto-reconnect.
|
|
2275
|
+
* Use this to update tool metadata when a server reconnects.
|
|
2276
|
+
*/
|
|
2277
|
+
setReconnectCallback(callback) {
|
|
2278
|
+
this.onReconnect = callback;
|
|
2279
|
+
}
|
|
2280
|
+
markKeepAlive(name, definition) {
|
|
2281
|
+
this.keepAliveServers.set(name, definition);
|
|
2282
|
+
}
|
|
2283
|
+
registerServer(name, definition, settings) {
|
|
2284
|
+
this.allServers.set(name, definition), settings?.idleTimeout !== void 0 && this.serverSettings.set(name, settings);
|
|
2285
|
+
}
|
|
2286
|
+
setGlobalIdleTimeout(minutes) {
|
|
2287
|
+
this.globalIdleTimeout = minutes * 60 * 1e3;
|
|
2288
|
+
}
|
|
2289
|
+
setIdleShutdownCallback(callback) {
|
|
2290
|
+
this.onIdleShutdown = callback;
|
|
2291
|
+
}
|
|
2292
|
+
startHealthChecks(intervalMs = 3e4) {
|
|
2293
|
+
this.healthCheckInterval = setInterval(() => {
|
|
2294
|
+
this.checkConnections();
|
|
2295
|
+
}, intervalMs), this.healthCheckInterval.unref();
|
|
2296
|
+
}
|
|
2297
|
+
async checkConnections() {
|
|
2298
|
+
for (let [name, definition] of this.keepAliveServers) {
|
|
2299
|
+
let connection = this.manager.getConnection(name);
|
|
2300
|
+
if (!connection || connection.status !== "connected")
|
|
2301
|
+
try {
|
|
2302
|
+
await this.manager.connect(name, definition), logger.debug(`Reconnected to ${name}`), this.onReconnect?.(name);
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
console.error(`MCP: Failed to reconnect to ${name}:`, error);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
for (let [name] of this.allServers) {
|
|
2308
|
+
if (this.keepAliveServers.has(name))
|
|
2309
|
+
continue;
|
|
2310
|
+
let timeout = this.getIdleTimeout(name);
|
|
2311
|
+
timeout > 0 && this.manager.isIdle(name, timeout) && (await this.manager.close(name), this.onIdleShutdown?.(name));
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
getIdleTimeout(name) {
|
|
2315
|
+
let perServer = this.serverSettings.get(name)?.idleTimeout;
|
|
2316
|
+
return perServer !== void 0 ? perServer * 60 * 1e3 : this.globalIdleTimeout;
|
|
2317
|
+
}
|
|
2318
|
+
async gracefulShutdown() {
|
|
2319
|
+
this.healthCheckInterval && clearInterval(this.healthCheckInterval), await this.manager.closeAll();
|
|
2320
|
+
}
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
// node_modules/eventsource/dist/index.js
|
|
2324
|
+
var ErrorEvent = class extends Event {
|
|
2325
|
+
/**
|
|
2326
|
+
* Constructs a new `ErrorEvent` instance. This is typically not called directly,
|
|
2327
|
+
* but rather emitted by the `EventSource` object when an error occurs.
|
|
2328
|
+
*
|
|
2329
|
+
* @param type - The type of the event (should be "error")
|
|
2330
|
+
* @param errorEventInitDict - Optional properties to include in the error event
|
|
2331
|
+
*/
|
|
2332
|
+
constructor(type, errorEventInitDict) {
|
|
2333
|
+
var _a, _b;
|
|
2334
|
+
super(type), this.code = (_a = errorEventInitDict?.code) != null ? _a : void 0, this.message = (_b = errorEventInitDict?.message) != null ? _b : void 0;
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Node.js "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
2338
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
2339
|
+
* we explicitly include the properties in the `inspect` method.
|
|
2340
|
+
*
|
|
2341
|
+
* This is automatically called by Node.js when you `console.log` an instance of this class.
|
|
2342
|
+
*
|
|
2343
|
+
* @param _depth - The current depth
|
|
2344
|
+
* @param options - The options passed to `util.inspect`
|
|
2345
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
2346
|
+
* @returns A string representation of the error
|
|
2347
|
+
*/
|
|
2348
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")](_depth, options, inspect) {
|
|
2349
|
+
return inspect(inspectableError(this), options);
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* Deno "hides" the `message` and `code` properties of the `ErrorEvent` instance,
|
|
2353
|
+
* when it is `console.log`'ed. This makes it harder to debug errors. To ease debugging,
|
|
2354
|
+
* we explicitly include the properties in the `inspect` method.
|
|
2355
|
+
*
|
|
2356
|
+
* This is automatically called by Deno when you `console.log` an instance of this class.
|
|
2357
|
+
*
|
|
2358
|
+
* @param inspect - The inspect function to use (prevents having to import it from `util`)
|
|
2359
|
+
* @param options - The options passed to `Deno.inspect`
|
|
2360
|
+
* @returns A string representation of the error
|
|
2361
|
+
*/
|
|
2362
|
+
[/* @__PURE__ */ Symbol.for("Deno.customInspect")](inspect, options) {
|
|
2363
|
+
return inspect(inspectableError(this), options);
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
function syntaxError(message) {
|
|
2367
|
+
let DomException = globalThis.DOMException;
|
|
2368
|
+
return typeof DomException == "function" ? new DomException(message, "SyntaxError") : new SyntaxError(message);
|
|
2369
|
+
}
|
|
2370
|
+
function flattenError(err) {
|
|
2371
|
+
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError).join(", ") : "cause" in err && err.cause instanceof Error ? `${err}: ${flattenError(err.cause)}` : err.message : `${err}`;
|
|
2372
|
+
}
|
|
2373
|
+
function inspectableError(err) {
|
|
2374
|
+
return {
|
|
2375
|
+
type: err.type,
|
|
2376
|
+
message: err.message,
|
|
2377
|
+
code: err.code,
|
|
2378
|
+
defaultPrevented: err.defaultPrevented,
|
|
2379
|
+
cancelable: err.cancelable,
|
|
2380
|
+
timeStamp: err.timeStamp
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
var __typeError = (msg) => {
|
|
2384
|
+
throw TypeError(msg);
|
|
2385
|
+
}, __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg), __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)), __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value), __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value), __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method), _readyState, _url, _redirectUrl, _withCredentials, _fetch, _reconnectInterval, _reconnectTimer, _lastEventId, _controller, _parser, _onError, _onMessage, _onOpen, _EventSource_instances, connect_fn, _onFetchResponse, _onFetchError, getRequestOptions_fn, _onEvent, _onRetryChange, failConnection_fn, scheduleReconnect_fn, _reconnect, EventSource = class extends EventTarget {
|
|
2386
|
+
constructor(url2, eventSourceInitDict) {
|
|
2387
|
+
var _a, _b;
|
|
2388
|
+
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response) => {
|
|
2389
|
+
var _a2;
|
|
2390
|
+
__privateGet(this, _parser).reset();
|
|
2391
|
+
let { body, redirected, status, headers } = response;
|
|
2392
|
+
if (status === 204) {
|
|
2393
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
if (redirected ? __privateSet(this, _redirectUrl, new URL(response.url)) : __privateSet(this, _redirectUrl, void 0), status !== 200) {
|
|
2397
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2400
|
+
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
2401
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
2405
|
+
return;
|
|
2406
|
+
__privateSet(this, _readyState, this.OPEN);
|
|
2407
|
+
let openEvent = new Event("open");
|
|
2408
|
+
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
2409
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
let decoder = new TextDecoder(), reader = body.getReader(), open3 = !0;
|
|
2413
|
+
do {
|
|
2414
|
+
let { done, value } = await reader.read();
|
|
2415
|
+
value && __privateGet(this, _parser).feed(decoder.decode(value, { stream: !done })), done && (open3 = !1, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
2416
|
+
} while (open3);
|
|
2417
|
+
}), __privateAdd(this, _onFetchError, (err) => {
|
|
2418
|
+
__privateSet(this, _controller, void 0), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError(err));
|
|
2419
|
+
}), __privateAdd(this, _onEvent, (event) => {
|
|
2420
|
+
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
2421
|
+
let messageEvent = new MessageEvent(event.event || "message", {
|
|
2422
|
+
data: event.data,
|
|
2423
|
+
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url).origin,
|
|
2424
|
+
lastEventId: event.id || ""
|
|
2425
|
+
});
|
|
2426
|
+
__privateGet(this, _onMessage) && (!event.event || event.event === "message") && __privateGet(this, _onMessage).call(this, messageEvent), this.dispatchEvent(messageEvent);
|
|
2427
|
+
}), __privateAdd(this, _onRetryChange, (value) => {
|
|
2428
|
+
__privateSet(this, _reconnectInterval, value);
|
|
2429
|
+
}), __privateAdd(this, _reconnect, () => {
|
|
2430
|
+
__privateSet(this, _reconnectTimer, void 0), __privateGet(this, _readyState) === this.CONNECTING && __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
2431
|
+
});
|
|
2432
|
+
try {
|
|
2433
|
+
if (url2 instanceof URL)
|
|
2434
|
+
__privateSet(this, _url, url2);
|
|
2435
|
+
else if (typeof url2 == "string")
|
|
2436
|
+
__privateSet(this, _url, new URL(url2, getBaseURL()));
|
|
2437
|
+
else
|
|
2438
|
+
throw new Error("Invalid URL");
|
|
2439
|
+
} catch {
|
|
2440
|
+
throw syntaxError("An invalid or illegal string was specified");
|
|
2441
|
+
}
|
|
2442
|
+
__privateSet(this, _parser, createParser({
|
|
2443
|
+
onEvent: __privateGet(this, _onEvent),
|
|
2444
|
+
onRetry: __privateGet(this, _onRetryChange)
|
|
2445
|
+
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3e3), __privateSet(this, _fetch, (_a = eventSourceInitDict?.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict?.withCredentials) != null ? _b : !1), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* Returns the state of this EventSource object's connection. It can have the values described below.
|
|
2449
|
+
*
|
|
2450
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/readyState)
|
|
2451
|
+
*
|
|
2452
|
+
* Note: typed as `number` instead of `0 | 1 | 2` for compatibility with the `EventSource` interface,
|
|
2453
|
+
* defined in the TypeScript `dom` library.
|
|
2454
|
+
*
|
|
2455
|
+
* @public
|
|
2456
|
+
*/
|
|
2457
|
+
get readyState() {
|
|
2458
|
+
return __privateGet(this, _readyState);
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Returns the URL providing the event stream.
|
|
2462
|
+
*
|
|
2463
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/url)
|
|
2464
|
+
*
|
|
2465
|
+
* @public
|
|
2466
|
+
*/
|
|
2467
|
+
get url() {
|
|
2468
|
+
return __privateGet(this, _url).href;
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise.
|
|
2472
|
+
*
|
|
2473
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/withCredentials)
|
|
2474
|
+
*/
|
|
2475
|
+
get withCredentials() {
|
|
2476
|
+
return __privateGet(this, _withCredentials);
|
|
2477
|
+
}
|
|
2478
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/error_event) */
|
|
2479
|
+
get onerror() {
|
|
2480
|
+
return __privateGet(this, _onError);
|
|
2481
|
+
}
|
|
2482
|
+
set onerror(value) {
|
|
2483
|
+
__privateSet(this, _onError, value);
|
|
2484
|
+
}
|
|
2485
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/message_event) */
|
|
2486
|
+
get onmessage() {
|
|
2487
|
+
return __privateGet(this, _onMessage);
|
|
2488
|
+
}
|
|
2489
|
+
set onmessage(value) {
|
|
2490
|
+
__privateSet(this, _onMessage, value);
|
|
2491
|
+
}
|
|
2492
|
+
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/open_event) */
|
|
2493
|
+
get onopen() {
|
|
2494
|
+
return __privateGet(this, _onOpen);
|
|
2495
|
+
}
|
|
2496
|
+
set onopen(value) {
|
|
2497
|
+
__privateSet(this, _onOpen, value);
|
|
2498
|
+
}
|
|
2499
|
+
addEventListener(type, listener, options) {
|
|
2500
|
+
let listen = listener;
|
|
2501
|
+
super.addEventListener(type, listen, options);
|
|
2502
|
+
}
|
|
2503
|
+
removeEventListener(type, listener, options) {
|
|
2504
|
+
let listen = listener;
|
|
2505
|
+
super.removeEventListener(type, listen, options);
|
|
2506
|
+
}
|
|
2507
|
+
/**
|
|
2508
|
+
* Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED.
|
|
2509
|
+
*
|
|
2510
|
+
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventSource/close)
|
|
2511
|
+
*
|
|
2512
|
+
* @public
|
|
2513
|
+
*/
|
|
2514
|
+
close() {
|
|
2515
|
+
__privateGet(this, _reconnectTimer) && clearTimeout(__privateGet(this, _reconnectTimer)), __privateGet(this, _readyState) !== this.CLOSED && (__privateGet(this, _controller) && __privateGet(this, _controller).abort(), __privateSet(this, _readyState, this.CLOSED), __privateSet(this, _controller, void 0));
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
_readyState = /* @__PURE__ */ new WeakMap(), _url = /* @__PURE__ */ new WeakMap(), _redirectUrl = /* @__PURE__ */ new WeakMap(), _withCredentials = /* @__PURE__ */ new WeakMap(), _fetch = /* @__PURE__ */ new WeakMap(), _reconnectInterval = /* @__PURE__ */ new WeakMap(), _reconnectTimer = /* @__PURE__ */ new WeakMap(), _lastEventId = /* @__PURE__ */ new WeakMap(), _controller = /* @__PURE__ */ new WeakMap(), _parser = /* @__PURE__ */ new WeakMap(), _onError = /* @__PURE__ */ new WeakMap(), _onMessage = /* @__PURE__ */ new WeakMap(), _onOpen = /* @__PURE__ */ new WeakMap(), _EventSource_instances = /* @__PURE__ */ new WeakSet(), /**
|
|
2519
|
+
* Connect to the given URL and start receiving events
|
|
2520
|
+
*
|
|
2521
|
+
* @internal
|
|
2522
|
+
*/
|
|
2523
|
+
connect_fn = function() {
|
|
2524
|
+
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController()), __privateGet(this, _fetch)(__privateGet(this, _url), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
2525
|
+
}, _onFetchResponse = /* @__PURE__ */ new WeakMap(), _onFetchError = /* @__PURE__ */ new WeakMap(), /**
|
|
2526
|
+
* Get request options for the `fetch()` request
|
|
2527
|
+
*
|
|
2528
|
+
* @returns The request options
|
|
2529
|
+
* @internal
|
|
2530
|
+
*/
|
|
2531
|
+
getRequestOptions_fn = function() {
|
|
2532
|
+
var _a;
|
|
2533
|
+
let init = {
|
|
2534
|
+
// [spec] Let `corsAttributeState` be `Anonymous`…
|
|
2535
|
+
// [spec] …will have their mode set to "cors"…
|
|
2536
|
+
mode: "cors",
|
|
2537
|
+
redirect: "follow",
|
|
2538
|
+
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : void 0 },
|
|
2539
|
+
cache: "no-store",
|
|
2540
|
+
signal: (_a = __privateGet(this, _controller)) == null ? void 0 : _a.signal
|
|
2541
|
+
};
|
|
2542
|
+
return "window" in globalThis && (init.credentials = this.withCredentials ? "include" : "same-origin"), init;
|
|
2543
|
+
}, _onEvent = /* @__PURE__ */ new WeakMap(), _onRetryChange = /* @__PURE__ */ new WeakMap(), /**
|
|
2544
|
+
* Handles the process referred to in the EventSource specification as "failing a connection".
|
|
2545
|
+
*
|
|
2546
|
+
* @param error - The error causing the connection to fail
|
|
2547
|
+
* @param code - The HTTP status code, if available
|
|
2548
|
+
* @internal
|
|
2549
|
+
*/
|
|
2550
|
+
failConnection_fn = function(message, code) {
|
|
2551
|
+
var _a;
|
|
2552
|
+
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
2553
|
+
let errorEvent = new ErrorEvent("error", { code, message });
|
|
2554
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
2555
|
+
}, /**
|
|
2556
|
+
* Schedules a reconnection attempt against the EventSource endpoint.
|
|
2557
|
+
*
|
|
2558
|
+
* @param message - The error causing the connection to fail
|
|
2559
|
+
* @param code - The HTTP status code, if available
|
|
2560
|
+
* @internal
|
|
2561
|
+
*/
|
|
2562
|
+
scheduleReconnect_fn = function(message, code) {
|
|
2563
|
+
var _a;
|
|
2564
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
2565
|
+
return;
|
|
2566
|
+
__privateSet(this, _readyState, this.CONNECTING);
|
|
2567
|
+
let errorEvent = new ErrorEvent("error", { code, message });
|
|
2568
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
2569
|
+
}, _reconnect = /* @__PURE__ */ new WeakMap(), /**
|
|
2570
|
+
* ReadyState representing an EventSource currently trying to connect
|
|
2571
|
+
*
|
|
2572
|
+
* @public
|
|
2573
|
+
*/
|
|
2574
|
+
EventSource.CONNECTING = 0, /**
|
|
2575
|
+
* ReadyState representing an EventSource connection that is open (eg connected)
|
|
2576
|
+
*
|
|
2577
|
+
* @public
|
|
2578
|
+
*/
|
|
2579
|
+
EventSource.OPEN = 1, /**
|
|
2580
|
+
* ReadyState representing an EventSource connection that is closed (eg disconnected)
|
|
2581
|
+
*
|
|
2582
|
+
* @public
|
|
2583
|
+
*/
|
|
2584
|
+
EventSource.CLOSED = 2;
|
|
2585
|
+
function getBaseURL() {
|
|
2586
|
+
let doc = "document" in globalThis ? globalThis.document : void 0;
|
|
2587
|
+
return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/sse.js
|
|
2591
|
+
var SseError = class extends Error {
|
|
2592
|
+
constructor(code, message, event) {
|
|
2593
|
+
super(`SSE error: ${message}`), this.code = code, this.event = event;
|
|
2594
|
+
}
|
|
2595
|
+
}, SSEClientTransport = class {
|
|
2596
|
+
constructor(url2, opts) {
|
|
2597
|
+
this._url = url2, this._resourceMetadataUrl = void 0, this._scope = void 0, this._eventSourceInit = opts?.eventSourceInit, this._requestInit = opts?.requestInit, this._authProvider = opts?.authProvider, this._fetch = opts?.fetch, this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
|
|
2598
|
+
}
|
|
2599
|
+
async _authThenStart() {
|
|
2600
|
+
if (!this._authProvider)
|
|
2601
|
+
throw new UnauthorizedError("No auth provider");
|
|
2602
|
+
let result;
|
|
2603
|
+
try {
|
|
2604
|
+
result = await auth(this._authProvider, {
|
|
2605
|
+
serverUrl: this._url,
|
|
2606
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2607
|
+
scope: this._scope,
|
|
2608
|
+
fetchFn: this._fetchWithInit
|
|
2609
|
+
});
|
|
2610
|
+
} catch (error) {
|
|
2611
|
+
throw this.onerror?.(error), error;
|
|
2612
|
+
}
|
|
2613
|
+
if (result !== "AUTHORIZED")
|
|
2614
|
+
throw new UnauthorizedError();
|
|
2615
|
+
return await this._startOrAuth();
|
|
2616
|
+
}
|
|
2617
|
+
async _commonHeaders() {
|
|
2618
|
+
let headers = {};
|
|
2619
|
+
if (this._authProvider) {
|
|
2620
|
+
let tokens = await this._authProvider.tokens();
|
|
2621
|
+
tokens && (headers.Authorization = `Bearer ${tokens.access_token}`);
|
|
2622
|
+
}
|
|
2623
|
+
this._protocolVersion && (headers["mcp-protocol-version"] = this._protocolVersion);
|
|
2624
|
+
let extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
2625
|
+
return new Headers({
|
|
2626
|
+
...headers,
|
|
2627
|
+
...extraHeaders
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
_startOrAuth() {
|
|
2631
|
+
let fetchImpl = this?._eventSourceInit?.fetch ?? this._fetch ?? fetch;
|
|
2632
|
+
return new Promise((resolve2, reject) => {
|
|
2633
|
+
this._eventSource = new EventSource(this._url.href, {
|
|
2634
|
+
...this._eventSourceInit,
|
|
2635
|
+
fetch: async (url2, init) => {
|
|
2636
|
+
let headers = await this._commonHeaders();
|
|
2637
|
+
headers.set("Accept", "text/event-stream");
|
|
2638
|
+
let response = await fetchImpl(url2, {
|
|
2639
|
+
...init,
|
|
2640
|
+
headers
|
|
2641
|
+
});
|
|
2642
|
+
if (response.status === 401 && response.headers.has("www-authenticate")) {
|
|
2643
|
+
let { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
2644
|
+
this._resourceMetadataUrl = resourceMetadataUrl, this._scope = scope;
|
|
2645
|
+
}
|
|
2646
|
+
return response;
|
|
2647
|
+
}
|
|
2648
|
+
}), this._abortController = new AbortController(), this._eventSource.onerror = (event) => {
|
|
2649
|
+
if (event.code === 401 && this._authProvider) {
|
|
2650
|
+
this._authThenStart().then(resolve2, reject);
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
let error = new SseError(event.code, event.message, event);
|
|
2654
|
+
reject(error), this.onerror?.(error);
|
|
2655
|
+
}, this._eventSource.onopen = () => {
|
|
2656
|
+
}, this._eventSource.addEventListener("endpoint", (event) => {
|
|
2657
|
+
let messageEvent = event;
|
|
2658
|
+
try {
|
|
2659
|
+
if (this._endpoint = new URL(messageEvent.data, this._url), this._endpoint.origin !== this._url.origin)
|
|
2660
|
+
throw new Error(`Endpoint origin does not match connection origin: ${this._endpoint.origin}`);
|
|
2661
|
+
} catch (error) {
|
|
2662
|
+
reject(error), this.onerror?.(error), this.close();
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2665
|
+
resolve2();
|
|
2666
|
+
}), this._eventSource.onmessage = (event) => {
|
|
2667
|
+
let messageEvent = event, message;
|
|
2668
|
+
try {
|
|
2669
|
+
message = JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
|
|
2670
|
+
} catch (error) {
|
|
2671
|
+
this.onerror?.(error);
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
this.onmessage?.(message);
|
|
2675
|
+
};
|
|
2676
|
+
});
|
|
2677
|
+
}
|
|
2678
|
+
async start() {
|
|
2679
|
+
if (this._eventSource)
|
|
2680
|
+
throw new Error("SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
2681
|
+
return await this._startOrAuth();
|
|
2682
|
+
}
|
|
2683
|
+
/**
|
|
2684
|
+
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
|
|
2685
|
+
*/
|
|
2686
|
+
async finishAuth(authorizationCode) {
|
|
2687
|
+
if (!this._authProvider)
|
|
2688
|
+
throw new UnauthorizedError("No auth provider");
|
|
2689
|
+
if (await auth(this._authProvider, {
|
|
2690
|
+
serverUrl: this._url,
|
|
2691
|
+
authorizationCode,
|
|
2692
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2693
|
+
scope: this._scope,
|
|
2694
|
+
fetchFn: this._fetchWithInit
|
|
2695
|
+
}) !== "AUTHORIZED")
|
|
2696
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
2697
|
+
}
|
|
2698
|
+
async close() {
|
|
2699
|
+
this._abortController?.abort(), this._eventSource?.close(), this.onclose?.();
|
|
2700
|
+
}
|
|
2701
|
+
async send(message) {
|
|
2702
|
+
if (!this._endpoint)
|
|
2703
|
+
throw new Error("Not connected");
|
|
2704
|
+
try {
|
|
2705
|
+
let headers = await this._commonHeaders();
|
|
2706
|
+
headers.set("content-type", "application/json");
|
|
2707
|
+
let init = {
|
|
2708
|
+
...this._requestInit,
|
|
2709
|
+
method: "POST",
|
|
2710
|
+
headers,
|
|
2711
|
+
body: JSON.stringify(message),
|
|
2712
|
+
signal: this._abortController?.signal
|
|
2713
|
+
}, response = await (this._fetch ?? fetch)(this._endpoint, init);
|
|
2714
|
+
if (!response.ok) {
|
|
2715
|
+
let text = await response.text().catch(() => null);
|
|
2716
|
+
if (response.status === 401 && this._authProvider) {
|
|
2717
|
+
let { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
2718
|
+
if (this._resourceMetadataUrl = resourceMetadataUrl, this._scope = scope, await auth(this._authProvider, {
|
|
2719
|
+
serverUrl: this._url,
|
|
2720
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
2721
|
+
scope: this._scope,
|
|
2722
|
+
fetchFn: this._fetchWithInit
|
|
2723
|
+
}) !== "AUTHORIZED")
|
|
2724
|
+
throw new UnauthorizedError();
|
|
2725
|
+
return this.send(message);
|
|
2726
|
+
}
|
|
2727
|
+
throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
|
|
2728
|
+
}
|
|
2729
|
+
await response.body?.cancel();
|
|
2730
|
+
} catch (error) {
|
|
2731
|
+
throw this.onerror?.(error), error;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
setProtocolVersion(version) {
|
|
2735
|
+
this._protocolVersion = version;
|
|
2736
|
+
}
|
|
2737
|
+
};
|
|
2738
|
+
|
|
2739
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/npx-resolver.js
|
|
2740
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync, readdirSync, statSync, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2, openSync, readSync, closeSync } from "node:fs";
|
|
2741
|
+
import { join as join2, dirname, extname, resolve, sep } from "node:path";
|
|
2742
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2743
|
+
var CACHE_VERSION = 1, CACHE_TTL_MS = 1440 * 60 * 1e3;
|
|
2744
|
+
async function resolveNpxBinary(command, args) {
|
|
2745
|
+
let parsed = command === "npx" ? parseNpxArgs(args) : command === "npm" ? parseNpmExecArgs(args) : null;
|
|
2746
|
+
if (!parsed)
|
|
2747
|
+
return null;
|
|
2748
|
+
let cacheKey = JSON.stringify([command, ...args]), cached = loadCache()?.entries?.[cacheKey];
|
|
2749
|
+
if (cached && Date.now() - cached.resolvedAt < CACHE_TTL_MS && existsSync2(cached.resolvedBin))
|
|
2750
|
+
return { binPath: cached.resolvedBin, extraArgs: parsed.extraArgs, isJs: cached.isJs };
|
|
2751
|
+
let resolved = resolveFromNpmCache(parsed.packageSpec, parsed.binName);
|
|
2752
|
+
if (resolved)
|
|
2753
|
+
return saveCacheEntry(cacheKey, resolved), { binPath: resolved.resolvedBin, extraArgs: parsed.extraArgs, isJs: resolved.isJs };
|
|
2754
|
+
await forceNpxCache(parsed.packageSpec);
|
|
2755
|
+
let resolvedAfterInstall = resolveFromNpmCache(parsed.packageSpec, parsed.binName);
|
|
2756
|
+
return resolvedAfterInstall ? (saveCacheEntry(cacheKey, resolvedAfterInstall), { binPath: resolvedAfterInstall.resolvedBin, extraArgs: parsed.extraArgs, isJs: resolvedAfterInstall.isJs }) : null;
|
|
2757
|
+
}
|
|
2758
|
+
function parseNpxArgs(args) {
|
|
2759
|
+
let separatorIndex = args.indexOf("--"), before = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args, after = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [], positionals = [], packageSpec, sawPackageFlag = !1, foundFirstPositional = !1;
|
|
2760
|
+
for (let i2 = 0; i2 < before.length; i2++) {
|
|
2761
|
+
let arg = before[i2];
|
|
2762
|
+
if (foundFirstPositional) {
|
|
2763
|
+
positionals.push(arg);
|
|
2764
|
+
continue;
|
|
2765
|
+
}
|
|
2766
|
+
if (!(arg === "-y" || arg === "--yes")) {
|
|
2767
|
+
if (arg === "-p" || arg === "--package") {
|
|
2768
|
+
let value = before[i2 + 1];
|
|
2769
|
+
if (!value || value.startsWith("-"))
|
|
2770
|
+
return null;
|
|
2771
|
+
packageSpec || (packageSpec = value), sawPackageFlag = !0, i2++;
|
|
2772
|
+
continue;
|
|
2773
|
+
}
|
|
2774
|
+
if (arg.startsWith("--package=")) {
|
|
2775
|
+
let value = arg.slice(10);
|
|
2776
|
+
if (!value)
|
|
2777
|
+
return null;
|
|
2778
|
+
packageSpec || (packageSpec = value), sawPackageFlag = !0;
|
|
2779
|
+
continue;
|
|
2780
|
+
}
|
|
2781
|
+
if (arg.startsWith("-"))
|
|
2782
|
+
return null;
|
|
2783
|
+
positionals.push(arg), foundFirstPositional = !0;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
let separatedAfter = separatorIndex >= 0 && after.length > 0 ? ["--", ...after] : after;
|
|
2787
|
+
if (sawPackageFlag) {
|
|
2788
|
+
let binName = positionals[0];
|
|
2789
|
+
if (!packageSpec || !binName)
|
|
2790
|
+
return null;
|
|
2791
|
+
let extraArgs2 = positionals.slice(1).concat(separatedAfter);
|
|
2792
|
+
return { packageSpec, binName, extraArgs: extraArgs2 };
|
|
2793
|
+
}
|
|
2794
|
+
let packagePositional = positionals[0];
|
|
2795
|
+
if (!packagePositional)
|
|
2796
|
+
return null;
|
|
2797
|
+
let extraArgs = positionals.slice(1).concat(separatedAfter);
|
|
2798
|
+
return { packageSpec: packagePositional, extraArgs };
|
|
2799
|
+
}
|
|
2800
|
+
function parseNpmExecArgs(args) {
|
|
2801
|
+
if (args[0] !== "exec")
|
|
2802
|
+
return null;
|
|
2803
|
+
let execArgs = args.slice(1), separatorIndex = execArgs.indexOf("--");
|
|
2804
|
+
if (separatorIndex < 0)
|
|
2805
|
+
return null;
|
|
2806
|
+
let before = execArgs.slice(0, separatorIndex), after = execArgs.slice(separatorIndex + 1), packageSpec;
|
|
2807
|
+
for (let i2 = 0; i2 < before.length; i2++) {
|
|
2808
|
+
let arg = before[i2];
|
|
2809
|
+
if (!(arg === "-y" || arg === "--yes")) {
|
|
2810
|
+
if (arg === "--package") {
|
|
2811
|
+
let value = before[i2 + 1];
|
|
2812
|
+
if (!value || value.startsWith("-"))
|
|
2813
|
+
return null;
|
|
2814
|
+
packageSpec || (packageSpec = value), i2++;
|
|
2815
|
+
continue;
|
|
2816
|
+
}
|
|
2817
|
+
if (arg.startsWith("--package=")) {
|
|
2818
|
+
let value = arg.slice(10);
|
|
2819
|
+
if (!value)
|
|
2820
|
+
return null;
|
|
2821
|
+
packageSpec || (packageSpec = value);
|
|
2822
|
+
continue;
|
|
2823
|
+
}
|
|
2824
|
+
if (arg.startsWith("-"))
|
|
2825
|
+
return null;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
let binName = after[0];
|
|
2829
|
+
if (!packageSpec || !binName)
|
|
2830
|
+
return null;
|
|
2831
|
+
let extraArgs = after.slice(1);
|
|
2832
|
+
return { packageSpec, binName, extraArgs };
|
|
2833
|
+
}
|
|
2834
|
+
function resolveFromNpmCache(packageSpec, binName) {
|
|
2835
|
+
let cacheDir = getNpmCacheDir();
|
|
2836
|
+
if (!cacheDir)
|
|
2837
|
+
return null;
|
|
2838
|
+
let packageName = extractPackageName(packageSpec);
|
|
2839
|
+
if (!packageName)
|
|
2840
|
+
return null;
|
|
2841
|
+
let packageDir = findCachedPackageDir(cacheDir, packageName);
|
|
2842
|
+
if (!packageDir)
|
|
2843
|
+
return null;
|
|
2844
|
+
let packageJsonPath = join2(packageDir, "package.json");
|
|
2845
|
+
if (!existsSync2(packageJsonPath))
|
|
2846
|
+
return null;
|
|
2847
|
+
let pkg = null;
|
|
2848
|
+
try {
|
|
2849
|
+
pkg = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
2850
|
+
} catch {
|
|
2851
|
+
return null;
|
|
2852
|
+
}
|
|
2853
|
+
let binField = pkg?.bin;
|
|
2854
|
+
if (!binField)
|
|
2855
|
+
return null;
|
|
2856
|
+
let candidates = buildBinCandidates(packageName, binName), chosenBinName, binRel;
|
|
2857
|
+
if (typeof binField == "string")
|
|
2858
|
+
chosenBinName = defaultBinName(packageName), binRel = binField;
|
|
2859
|
+
else {
|
|
2860
|
+
for (let candidate of candidates)
|
|
2861
|
+
if (binField[candidate]) {
|
|
2862
|
+
chosenBinName = candidate, binRel = binField[candidate];
|
|
2863
|
+
break;
|
|
2864
|
+
}
|
|
2865
|
+
if (!binRel) {
|
|
2866
|
+
let firstEntry = Object.entries(binField)[0];
|
|
2867
|
+
firstEntry && (chosenBinName = firstEntry[0], binRel = firstEntry[1]);
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
if (!binRel)
|
|
2871
|
+
return null;
|
|
2872
|
+
let nodeModulesDir = findNodeModulesDir(packageDir), binLink = chosenBinName ? join2(nodeModulesDir, ".bin", chosenBinName) : null, resolvedBin = binLink && existsSync2(binLink) ? safeRealpath(binLink) : "";
|
|
2873
|
+
if (!resolvedBin && (resolvedBin = resolve(packageDir, binRel), !existsSync2(resolvedBin)))
|
|
2874
|
+
return null;
|
|
2875
|
+
let isJs = detectJsBinary(resolvedBin);
|
|
2876
|
+
return {
|
|
2877
|
+
resolvedBin,
|
|
2878
|
+
resolvedAt: Date.now(),
|
|
2879
|
+
packageVersion: pkg?.version,
|
|
2880
|
+
isJs
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
var FORCE_CACHE_TIMEOUT_MS = 3e4;
|
|
2884
|
+
async function forceNpxCache(packageSpec) {
|
|
2885
|
+
try {
|
|
2886
|
+
await new Promise((resolve2, reject) => {
|
|
2887
|
+
let proc = spawn("npm", ["exec", "--yes", "--package", packageSpec, "--", "node", "-e", "1"], { stdio: "ignore" }), timer = setTimeout(() => {
|
|
2888
|
+
proc.kill(), reject(new Error("timeout"));
|
|
2889
|
+
}, FORCE_CACHE_TIMEOUT_MS);
|
|
2890
|
+
timer.unref(), proc.on("close", () => {
|
|
2891
|
+
clearTimeout(timer), resolve2();
|
|
2892
|
+
}), proc.on("error", (err) => {
|
|
2893
|
+
clearTimeout(timer), reject(err);
|
|
2894
|
+
});
|
|
2895
|
+
});
|
|
2896
|
+
} catch {
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
function buildBinCandidates(packageName, explicitBin) {
|
|
2900
|
+
let candidates = [];
|
|
2901
|
+
if (explicitBin && candidates.push(explicitBin), packageName.startsWith("@")) {
|
|
2902
|
+
let namePart = packageName.split("/")[1] ?? "", scopePart = packageName.split("/")[0]?.replace("@", "") ?? "";
|
|
2903
|
+
namePart && candidates.push(namePart), scopePart && namePart && candidates.push(`${scopePart}-${namePart}`);
|
|
2904
|
+
} else
|
|
2905
|
+
candidates.push(packageName);
|
|
2906
|
+
return [...new Set(candidates.filter(Boolean))];
|
|
2907
|
+
}
|
|
2908
|
+
function extractPackageName(spec) {
|
|
2909
|
+
let trimmed = spec.trim();
|
|
2910
|
+
if (!trimmed)
|
|
2911
|
+
return null;
|
|
2912
|
+
if (trimmed.startsWith("@")) {
|
|
2913
|
+
let slashIndex = trimmed.indexOf("/");
|
|
2914
|
+
if (slashIndex < 0)
|
|
2915
|
+
return null;
|
|
2916
|
+
let atIndex2 = trimmed.lastIndexOf("@");
|
|
2917
|
+
return atIndex2 > slashIndex ? trimmed.slice(0, atIndex2) : trimmed;
|
|
2918
|
+
}
|
|
2919
|
+
let atIndex = trimmed.indexOf("@");
|
|
2920
|
+
return atIndex >= 0 ? trimmed.slice(0, atIndex) : trimmed;
|
|
2921
|
+
}
|
|
2922
|
+
function defaultBinName(packageName) {
|
|
2923
|
+
return packageName.startsWith("@") ? packageName.split("/")[1] ?? packageName.replace("@", "").replace("/", "-") : packageName;
|
|
2924
|
+
}
|
|
2925
|
+
function findCachedPackageDir(cacheDir, packageName) {
|
|
2926
|
+
let npxDir = join2(cacheDir, "_npx");
|
|
2927
|
+
if (!existsSync2(npxDir))
|
|
2928
|
+
return null;
|
|
2929
|
+
let packagePathParts = packageName.startsWith("@") ? packageName.split("/") : [packageName], candidates = readdirSync(npxDir, { withFileTypes: !0 }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
2930
|
+
let full = join2(npxDir, entry.name), mtime = safeStatMtime(full);
|
|
2931
|
+
return { name: entry.name, mtime };
|
|
2932
|
+
}).sort((a2, b2) => b2.mtime - a2.mtime);
|
|
2933
|
+
for (let entry of candidates) {
|
|
2934
|
+
let pkgDir = join2(npxDir, entry.name, "node_modules", ...packagePathParts);
|
|
2935
|
+
if (existsSync2(join2(pkgDir, "package.json")))
|
|
2936
|
+
return pkgDir;
|
|
2937
|
+
}
|
|
2938
|
+
return null;
|
|
2939
|
+
}
|
|
2940
|
+
function findNodeModulesDir(packageDir) {
|
|
2941
|
+
let parts = packageDir.split(sep), idx = parts.lastIndexOf("node_modules");
|
|
2942
|
+
return idx >= 0 ? parts.slice(0, idx + 1).join(sep) : join2(packageDir, "..");
|
|
2943
|
+
}
|
|
2944
|
+
function detectJsBinary(binPath) {
|
|
2945
|
+
let ext = extname(binPath).toLowerCase();
|
|
2946
|
+
if (ext === ".js" || ext === ".mjs" || ext === ".cjs")
|
|
2947
|
+
return !0;
|
|
2948
|
+
try {
|
|
2949
|
+
let fd = openSync(binPath, "r");
|
|
2950
|
+
try {
|
|
2951
|
+
let buf = Buffer.alloc(256);
|
|
2952
|
+
readSync(fd, buf, 0, 256, 0);
|
|
2953
|
+
let firstLine = buf.toString("utf-8").split(`
|
|
2954
|
+
`)[0] ?? "";
|
|
2955
|
+
return firstLine.startsWith("#!") && firstLine.includes("node");
|
|
2956
|
+
} finally {
|
|
2957
|
+
closeSync(fd);
|
|
2958
|
+
}
|
|
2959
|
+
} catch {
|
|
2960
|
+
return !1;
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
var npmCacheDirCached;
|
|
2964
|
+
function getNpmCacheDir() {
|
|
2965
|
+
if (npmCacheDirCached !== void 0)
|
|
2966
|
+
return npmCacheDirCached;
|
|
2967
|
+
if (process.env.NPM_CONFIG_CACHE)
|
|
2968
|
+
return npmCacheDirCached = process.env.NPM_CONFIG_CACHE, npmCacheDirCached;
|
|
2969
|
+
try {
|
|
2970
|
+
let result = spawnSync("npm", ["config", "get", "cache"], { encoding: "utf-8" });
|
|
2971
|
+
if (result.status === 0)
|
|
2972
|
+
return npmCacheDirCached = String(result.stdout).trim() || null, npmCacheDirCached;
|
|
2973
|
+
} catch {
|
|
2974
|
+
return npmCacheDirCached = null, null;
|
|
2975
|
+
}
|
|
2976
|
+
return npmCacheDirCached = null, null;
|
|
2977
|
+
}
|
|
2978
|
+
function getNpxCachePath() {
|
|
2979
|
+
return getAgentPath("mcp-npx-cache.json");
|
|
2980
|
+
}
|
|
2981
|
+
function loadCache() {
|
|
2982
|
+
let cachePath = getNpxCachePath();
|
|
2983
|
+
if (!existsSync2(cachePath))
|
|
2984
|
+
return null;
|
|
2985
|
+
try {
|
|
2986
|
+
let raw = JSON.parse(readFileSync2(cachePath, "utf-8"));
|
|
2987
|
+
return !raw || typeof raw != "object" || raw.version !== CACHE_VERSION || !raw.entries || typeof raw.entries != "object" ? null : raw;
|
|
2988
|
+
} catch {
|
|
2989
|
+
return null;
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
function saveCacheEntry(key, entry) {
|
|
2993
|
+
let cachePath = getNpxCachePath(), dir = dirname(cachePath);
|
|
2994
|
+
mkdirSync2(dir, { recursive: !0 });
|
|
2995
|
+
let merged = { version: CACHE_VERSION, entries: {} };
|
|
2996
|
+
try {
|
|
2997
|
+
if (existsSync2(cachePath)) {
|
|
2998
|
+
let existing = JSON.parse(readFileSync2(cachePath, "utf-8"));
|
|
2999
|
+
existing && existing.version === CACHE_VERSION && existing.entries && (merged.entries = { ...existing.entries });
|
|
3000
|
+
}
|
|
3001
|
+
} catch {
|
|
3002
|
+
}
|
|
3003
|
+
merged.entries[key] = entry;
|
|
3004
|
+
let tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
3005
|
+
writeFileSync2(tmpPath, JSON.stringify(merged, null, 2), "utf-8"), renameSync(tmpPath, cachePath);
|
|
3006
|
+
}
|
|
3007
|
+
function safeRealpath(path) {
|
|
3008
|
+
try {
|
|
3009
|
+
return realpathSync(path);
|
|
3010
|
+
} catch {
|
|
3011
|
+
return "";
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
function safeStatMtime(path) {
|
|
3015
|
+
try {
|
|
3016
|
+
return statSync(path).mtimeMs;
|
|
3017
|
+
} catch {
|
|
3018
|
+
return 0;
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/sampling-handler.js
|
|
3023
|
+
import { complete } from "@ashx-j/lunr-ai/compat";
|
|
3024
|
+
function registerSamplingHandler(client, options) {
|
|
3025
|
+
client.setRequestHandler(CreateMessageRequestSchema, (request) => handleSamplingRequest(options, request));
|
|
3026
|
+
}
|
|
3027
|
+
async function handleSamplingRequest(options, request) {
|
|
3028
|
+
let params = request.params;
|
|
3029
|
+
if ("task" in params && params.task)
|
|
3030
|
+
throw new Error("MCP sampling tasks are not supported");
|
|
3031
|
+
if (params.includeContext && params.includeContext !== "none")
|
|
3032
|
+
throw new Error("MCP sampling context inclusion is not supported");
|
|
3033
|
+
if (params.tools?.length)
|
|
3034
|
+
throw new Error("MCP sampling tool use is not supported");
|
|
3035
|
+
if (params.toolChoice)
|
|
3036
|
+
throw new Error("MCP sampling tool choice is not supported");
|
|
3037
|
+
if (params.stopSequences?.length)
|
|
3038
|
+
throw new Error("MCP sampling stop sequences are not supported");
|
|
3039
|
+
let messages = params.messages.map(convertSamplingMessage), { model, apiKey, headers } = await resolveSamplingModel(options, params.modelPreferences);
|
|
3040
|
+
await confirmSampling(options, "Approve MCP sampling request", formatRequestApproval(options.serverName, `${model.provider}/${model.id}`, params.systemPrompt, messages));
|
|
3041
|
+
let result = await complete(model, {
|
|
3042
|
+
systemPrompt: params.systemPrompt,
|
|
3043
|
+
messages
|
|
3044
|
+
}, {
|
|
3045
|
+
apiKey,
|
|
3046
|
+
headers,
|
|
3047
|
+
maxTokens: params.maxTokens,
|
|
3048
|
+
temperature: params.temperature,
|
|
3049
|
+
metadata: params.metadata,
|
|
3050
|
+
signal: options.getSignal()
|
|
3051
|
+
}), converted = convertAssistantResult(result);
|
|
3052
|
+
return await confirmSampling(options, "Return MCP sampling response", formatResponseApproval(options.serverName, converted)), converted;
|
|
3053
|
+
}
|
|
3054
|
+
function formatRequestApproval(serverName, modelName, systemPrompt, messages) {
|
|
3055
|
+
let lines = [`${serverName} wants to sample ${messages.length} message${messages.length === 1 ? "" : "s"} with ${modelName}.`];
|
|
3056
|
+
systemPrompt && lines.push(`System: ${truncateAtWord(systemPrompt, 400)}`);
|
|
3057
|
+
for (let [index, message] of messages.entries())
|
|
3058
|
+
lines.push(`${index + 1}. ${message.role}: ${truncateAtWord(messageText(message), 400)}`);
|
|
3059
|
+
return lines.join(`
|
|
3060
|
+
|
|
3061
|
+
`);
|
|
3062
|
+
}
|
|
3063
|
+
function formatResponseApproval(serverName, response) {
|
|
3064
|
+
let text = response.content.type === "text" ? response.content.text : `[${response.content.type} content]`;
|
|
3065
|
+
return `${serverName} will receive this response from ${response.model}:
|
|
3066
|
+
|
|
3067
|
+
${truncateAtWord(text, 1e3)}`;
|
|
3068
|
+
}
|
|
3069
|
+
function messageText(message) {
|
|
3070
|
+
return typeof message.content == "string" ? message.content : message.content.map((block) => block.type === "text" ? block.text : block.type === "image" ? `[image: ${block.mimeType}]` : block.type === "thinking" ? "[thinking]" : block.type === "toolCall" ? `[tool call: ${block.name}]` : "[content]").join(`
|
|
3071
|
+
`);
|
|
3072
|
+
}
|
|
3073
|
+
async function resolveSamplingModel(options, modelPreferences) {
|
|
3074
|
+
let candidates = [], availableModels = options.modelRegistry.getAvailable();
|
|
3075
|
+
for (let hint of modelPreferences?.hints ?? []) {
|
|
3076
|
+
let normalizedHint = hint.name?.trim().toLowerCase();
|
|
3077
|
+
if (normalizedHint)
|
|
3078
|
+
for (let model of availableModels)
|
|
3079
|
+
[`${model.provider}/${model.id}`, model.id, model.name].some((name) => name.toLowerCase().includes(normalizedHint)) && addSamplingCandidate(candidates, model);
|
|
3080
|
+
}
|
|
3081
|
+
let currentModel = options.getCurrentModel();
|
|
3082
|
+
currentModel && addSamplingCandidate(candidates, currentModel);
|
|
3083
|
+
for (let model of availableModels)
|
|
3084
|
+
addSamplingCandidate(candidates, model);
|
|
3085
|
+
let errors = [];
|
|
3086
|
+
for (let model of candidates) {
|
|
3087
|
+
let auth2 = await options.modelRegistry.getApiKeyAndHeaders(model);
|
|
3088
|
+
if (auth2.ok === !1) {
|
|
3089
|
+
errors.push(`${model.provider}/${model.id}: ${auth2.error}`);
|
|
3090
|
+
continue;
|
|
3091
|
+
}
|
|
3092
|
+
return { model, apiKey: auth2.apiKey, headers: auth2.headers };
|
|
3093
|
+
}
|
|
3094
|
+
throw errors.length > 0 ? new Error(`No configured auth for MCP sampling model. ${errors.join("; ")}`) : new Error("No Pi model is available for MCP sampling");
|
|
3095
|
+
}
|
|
3096
|
+
function addSamplingCandidate(candidates, model) {
|
|
3097
|
+
candidates.some((candidate) => candidate.provider === model.provider && candidate.id === model.id) || candidates.push(model);
|
|
3098
|
+
}
|
|
3099
|
+
async function confirmSampling(options, title, message) {
|
|
3100
|
+
if (options.autoApprove)
|
|
3101
|
+
return;
|
|
3102
|
+
if (!options.ui)
|
|
3103
|
+
throw new Error("MCP sampling requires interactive approval. Set settings.samplingAutoApprove to true to allow it without UI.");
|
|
3104
|
+
if (!await options.ui.confirm(title, message))
|
|
3105
|
+
throw new Error("MCP sampling request was declined");
|
|
3106
|
+
}
|
|
3107
|
+
function convertSamplingMessage(message) {
|
|
3108
|
+
let blocks = Array.isArray(message.content) ? message.content : [message.content];
|
|
3109
|
+
return message.role === "user" ? {
|
|
3110
|
+
role: "user",
|
|
3111
|
+
content: blocks.map(convertUserContent),
|
|
3112
|
+
timestamp: Date.now()
|
|
3113
|
+
} : {
|
|
3114
|
+
role: "assistant",
|
|
3115
|
+
content: blocks.map(convertAssistantContent),
|
|
3116
|
+
api: "mcp-sampling",
|
|
3117
|
+
provider: "mcp",
|
|
3118
|
+
model: "sampling-request",
|
|
3119
|
+
usage: zeroUsage(),
|
|
3120
|
+
stopReason: "stop",
|
|
3121
|
+
timestamp: Date.now()
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
function convertUserContent(block) {
|
|
3125
|
+
if (block.type === "text")
|
|
3126
|
+
return { type: "text", text: block.text };
|
|
3127
|
+
throw new Error(`MCP sampling ${block.type} content is not supported`);
|
|
3128
|
+
}
|
|
3129
|
+
function convertAssistantContent(block) {
|
|
3130
|
+
if (block.type === "text")
|
|
3131
|
+
return { type: "text", text: block.text };
|
|
3132
|
+
throw new Error(`MCP sampling assistant ${block.type} content is not supported`);
|
|
3133
|
+
}
|
|
3134
|
+
function convertAssistantResult(message) {
|
|
3135
|
+
if (message.stopReason === "error")
|
|
3136
|
+
throw new Error(message.errorMessage ?? "MCP sampling model call failed");
|
|
3137
|
+
if (message.stopReason === "aborted")
|
|
3138
|
+
throw new Error(message.errorMessage ?? "MCP sampling model call was aborted");
|
|
3139
|
+
let text = message.content.map((block) => {
|
|
3140
|
+
if (block.type === "text")
|
|
3141
|
+
return block.text;
|
|
3142
|
+
if (block.type !== "thinking")
|
|
3143
|
+
throw new Error(`MCP sampling result ${block.type} content is not supported`);
|
|
3144
|
+
}).filter((value) => value !== void 0).join(`
|
|
3145
|
+
|
|
3146
|
+
`).trim();
|
|
3147
|
+
if (!text)
|
|
3148
|
+
throw new Error("MCP sampling result did not contain text content");
|
|
3149
|
+
return {
|
|
3150
|
+
role: "assistant",
|
|
3151
|
+
content: { type: "text", text },
|
|
3152
|
+
model: `${message.provider}/${message.model}`,
|
|
3153
|
+
stopReason: mapStopReason(message.stopReason)
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
function mapStopReason(reason) {
|
|
3157
|
+
return reason === "stop" ? "endTurn" : reason === "length" ? "maxTokens" : reason === "toolUse" ? "toolUse" : reason;
|
|
3158
|
+
}
|
|
3159
|
+
function zeroUsage() {
|
|
3160
|
+
return {
|
|
3161
|
+
input: 0,
|
|
3162
|
+
output: 0,
|
|
3163
|
+
cacheRead: 0,
|
|
3164
|
+
cacheWrite: 0,
|
|
3165
|
+
totalTokens: 0,
|
|
3166
|
+
cost: {
|
|
3167
|
+
input: 0,
|
|
3168
|
+
output: 0,
|
|
3169
|
+
cacheRead: 0,
|
|
3170
|
+
cacheWrite: 0,
|
|
3171
|
+
total: 0
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/elicitation-handler.js
|
|
3177
|
+
import open2 from "open";
|
|
3178
|
+
function registerElicitationHandler(client, options) {
|
|
3179
|
+
client.setRequestHandler(ElicitRequestSchema, (request) => handleElicitationRequest(options, request));
|
|
3180
|
+
}
|
|
3181
|
+
async function handleElicitationRequest(options, request) {
|
|
3182
|
+
return request.params.mode === "url" ? handleUrlElicitation(options, request.params) : handleFormElicitation(options, request.params);
|
|
3183
|
+
}
|
|
3184
|
+
async function handleFormElicitation(options, params) {
|
|
3185
|
+
let decision = await options.ui.select(`MCP Input Request
|
|
3186
|
+
Server: ${options.serverName}
|
|
3187
|
+
|
|
3188
|
+
${params.message}`, ["Continue", "Decline"]);
|
|
3189
|
+
if (decision === void 0)
|
|
3190
|
+
return { action: "cancel" };
|
|
3191
|
+
if (decision === "Decline")
|
|
3192
|
+
return { action: "decline" };
|
|
3193
|
+
let values = {}, properties = Object.entries(params.requestedSchema.properties);
|
|
3194
|
+
for (let [name, schema] of properties) {
|
|
3195
|
+
let value = await collectValidField(options.ui, params, name, schema);
|
|
3196
|
+
if (!("value" in value))
|
|
3197
|
+
return { action: "cancel" };
|
|
3198
|
+
values[name] = value.value;
|
|
3199
|
+
}
|
|
3200
|
+
for (; ; ) {
|
|
3201
|
+
let content = coerceAndValidateFormValues(params, values), action = await options.ui.select(formatReview(options.serverName, properties, content), properties.length > 0 ? ["Submit", "Edit", "Decline"] : ["Submit", "Decline"]);
|
|
3202
|
+
if (action === void 0)
|
|
3203
|
+
return { action: "cancel" };
|
|
3204
|
+
if (action === "Decline")
|
|
3205
|
+
return { action: "decline" };
|
|
3206
|
+
if (action === "Submit")
|
|
3207
|
+
return { action: "accept", content };
|
|
3208
|
+
let labels = properties.map(([name2, schema2]) => `${schema2.title ?? humanizeName(name2)} (${name2})`), selected = await options.ui.select("Choose a field to edit", labels);
|
|
3209
|
+
if (selected === void 0)
|
|
3210
|
+
return { action: "cancel" };
|
|
3211
|
+
let property = properties[labels.indexOf(selected)];
|
|
3212
|
+
if (!property)
|
|
3213
|
+
continue;
|
|
3214
|
+
let [name, schema] = property, value = await collectValidField(options.ui, params, name, schema, values[name]);
|
|
3215
|
+
if (!("value" in value))
|
|
3216
|
+
return { action: "cancel" };
|
|
3217
|
+
values[name] = value.value;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
async function collectValidField(ui, params, name, schema, current) {
|
|
3221
|
+
let required = params.requestedSchema.required?.includes(name) === !0;
|
|
3222
|
+
for (; ; ) {
|
|
3223
|
+
let result = await collectField(ui, params, name, schema, current);
|
|
3224
|
+
if (!("value" in result))
|
|
3225
|
+
return result;
|
|
3226
|
+
try {
|
|
3227
|
+
return coerceAndValidateFormValues({
|
|
3228
|
+
...params,
|
|
3229
|
+
requestedSchema: {
|
|
3230
|
+
type: "object",
|
|
3231
|
+
properties: { [name]: schema },
|
|
3232
|
+
...required ? { required: [name] } : {}
|
|
3233
|
+
}
|
|
3234
|
+
}, { [name]: result.value }), result;
|
|
3235
|
+
} catch (error) {
|
|
3236
|
+
ui.notify(error instanceof Error ? error.message : String(error), "error"), current = result.value;
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
async function collectField(ui, params, name, schema, current) {
|
|
3241
|
+
let required = params.requestedSchema.required?.includes(name) === !0, title = [schema.title ?? humanizeName(name), required ? "(required)" : "", schema.description].filter(Boolean).join(" ");
|
|
3242
|
+
if (schema.type === "string" && ("enum" in schema || "oneOf" in schema)) {
|
|
3243
|
+
let choices = "oneOf" in schema ? schema.oneOf.map((option) => ({ value: option.const, display: formatChoice(option.const, option.title) })) : schema.enum.map((value, index) => ({
|
|
3244
|
+
value,
|
|
3245
|
+
display: formatChoice(value, "enumNames" in schema ? schema.enumNames?.[index] : void 0)
|
|
3246
|
+
})), displays = uniqueLabels(choices.map((choice) => choice.display)), actions2 = [...displays], useDefault = schema.default === void 0 ? void 0 : uniqueAction("Use default", actions2);
|
|
3247
|
+
useDefault && actions2.push(useDefault);
|
|
3248
|
+
let omit = required ? void 0 : uniqueAction("Omit", actions2);
|
|
3249
|
+
omit && actions2.push(omit);
|
|
3250
|
+
let action2 = await ui.select(title, actions2);
|
|
3251
|
+
return action2 === void 0 ? { cancelled: !0 } : action2 === useDefault ? { cancelled: !1, value: schema.default } : action2 === omit ? { cancelled: !1, value: void 0 } : { cancelled: !1, value: choices[displays.indexOf(action2)]?.value };
|
|
3252
|
+
}
|
|
3253
|
+
if (schema.type === "boolean") {
|
|
3254
|
+
let actions2 = ["Yes", "No"];
|
|
3255
|
+
schema.default !== void 0 && actions2.push("Use default"), required || actions2.push("Omit");
|
|
3256
|
+
let action2 = await ui.select(title, actions2);
|
|
3257
|
+
return action2 === void 0 ? { cancelled: !0 } : action2 === "Use default" ? { cancelled: !1, value: schema.default } : action2 === "Omit" ? { cancelled: !1, value: void 0 } : { cancelled: !1, value: action2 === "Yes" };
|
|
3258
|
+
}
|
|
3259
|
+
if (schema.type === "array") {
|
|
3260
|
+
let actions2 = ["Choose values"];
|
|
3261
|
+
schema.default !== void 0 && actions2.push("Use default"), required || actions2.push("Omit");
|
|
3262
|
+
let action2 = await ui.select(title, actions2);
|
|
3263
|
+
if (action2 === void 0)
|
|
3264
|
+
return { cancelled: !0 };
|
|
3265
|
+
if (action2 === "Use default")
|
|
3266
|
+
return { cancelled: !1, value: schema.default };
|
|
3267
|
+
if (action2 === "Omit")
|
|
3268
|
+
return { cancelled: !1, value: void 0 };
|
|
3269
|
+
let choices = extractMultiSelectOptions(schema), selected = new Set(Array.isArray(current) ? current : []);
|
|
3270
|
+
for (; ; ) {
|
|
3271
|
+
let displays = uniqueLabels(choices.map((choice2) => selected.has(choice2.value) ? `\u2713 ${choice2.display}` : choice2.display)), done = uniqueAction("Done", displays), picked = await ui.select(title, [...displays, done]);
|
|
3272
|
+
if (picked === void 0)
|
|
3273
|
+
return { cancelled: !0 };
|
|
3274
|
+
if (picked === done)
|
|
3275
|
+
return { cancelled: !1, value: [...selected] };
|
|
3276
|
+
let choice = choices[displays.indexOf(picked)];
|
|
3277
|
+
choice && (selected.has(choice.value) ? selected.delete(choice.value) : selected.add(choice.value));
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
let actions = ["Enter value"];
|
|
3281
|
+
schema.default !== void 0 && actions.push("Use default"), required || actions.push("Omit");
|
|
3282
|
+
let action = await ui.select(title, actions);
|
|
3283
|
+
if (action === void 0)
|
|
3284
|
+
return { cancelled: !0 };
|
|
3285
|
+
if (action === "Use default")
|
|
3286
|
+
return { cancelled: !1, value: schema.default };
|
|
3287
|
+
if (action === "Omit")
|
|
3288
|
+
return { cancelled: !1, value: void 0 };
|
|
3289
|
+
let entered = await ui.input(title, current === void 0 ? void 0 : String(current));
|
|
3290
|
+
return entered === void 0 ? { cancelled: !0 } : { cancelled: !1, value: entered };
|
|
3291
|
+
}
|
|
3292
|
+
function coerceAndValidateFormValues(params, values) {
|
|
3293
|
+
let output = {}, required = new Set(params.requestedSchema.required ?? []);
|
|
3294
|
+
for (let [name, schema] of Object.entries(params.requestedSchema.properties)) {
|
|
3295
|
+
let value = values[name];
|
|
3296
|
+
if (value === void 0) {
|
|
3297
|
+
if (required.has(name))
|
|
3298
|
+
throw new Error(`Missing required elicitation field: ${name}`);
|
|
3299
|
+
continue;
|
|
3300
|
+
}
|
|
3301
|
+
if (schema.type === "string") {
|
|
3302
|
+
let stringValue = String(value), limits = schema;
|
|
3303
|
+
if (limits.minLength !== void 0 && stringValue.length < limits.minLength)
|
|
3304
|
+
throw new Error(`Elicitation field ${name} is shorter than minimum length ${limits.minLength}`);
|
|
3305
|
+
if (limits.maxLength !== void 0 && stringValue.length > limits.maxLength)
|
|
3306
|
+
throw new Error(`Elicitation field ${name} is longer than maximum length ${limits.maxLength}`);
|
|
3307
|
+
if ("enum" in schema && !schema.enum.includes(stringValue))
|
|
3308
|
+
throw new Error(`Elicitation field ${name} is not an allowed value`);
|
|
3309
|
+
if ("oneOf" in schema && !schema.oneOf.some((option) => option.const === stringValue))
|
|
3310
|
+
throw new Error(`Elicitation field ${name} is not an allowed value`);
|
|
3311
|
+
output[name] = stringValue;
|
|
3312
|
+
continue;
|
|
3313
|
+
}
|
|
3314
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
3315
|
+
if (typeof value == "string" && value.trim() === "")
|
|
3316
|
+
throw new Error(`Elicitation field ${name} must be a number`);
|
|
3317
|
+
let numberValue = typeof value == "number" ? value : Number(value);
|
|
3318
|
+
if (!Number.isFinite(numberValue))
|
|
3319
|
+
throw new Error(`Elicitation field ${name} must be a number`);
|
|
3320
|
+
if (schema.type === "integer" && !Number.isInteger(numberValue))
|
|
3321
|
+
throw new Error(`Elicitation field ${name} must be an integer`);
|
|
3322
|
+
if (schema.minimum !== void 0 && numberValue < schema.minimum)
|
|
3323
|
+
throw new Error(`Elicitation field ${name} is below minimum ${schema.minimum}`);
|
|
3324
|
+
if (schema.maximum !== void 0 && numberValue > schema.maximum)
|
|
3325
|
+
throw new Error(`Elicitation field ${name} is above maximum ${schema.maximum}`);
|
|
3326
|
+
output[name] = numberValue;
|
|
3327
|
+
continue;
|
|
3328
|
+
}
|
|
3329
|
+
if (schema.type === "boolean") {
|
|
3330
|
+
output[name] = typeof value == "boolean" ? value : value === "true";
|
|
3331
|
+
continue;
|
|
3332
|
+
}
|
|
3333
|
+
if (schema.type === "array") {
|
|
3334
|
+
if (!Array.isArray(value))
|
|
3335
|
+
throw new Error(`Elicitation field ${name} must be a list`);
|
|
3336
|
+
let allowed = new Set(extractMultiSelectOptions(schema).map((option) => option.value)), arrayValue = value.map(String);
|
|
3337
|
+
if (schema.minItems !== void 0 && arrayValue.length < schema.minItems)
|
|
3338
|
+
throw new Error(`Elicitation field ${name} has fewer than ${schema.minItems} selections`);
|
|
3339
|
+
if (schema.maxItems !== void 0 && arrayValue.length > schema.maxItems)
|
|
3340
|
+
throw new Error(`Elicitation field ${name} has more than ${schema.maxItems} selections`);
|
|
3341
|
+
if (arrayValue.some((item) => !allowed.has(item)))
|
|
3342
|
+
throw new Error(`Elicitation field ${name} contains an invalid selection`);
|
|
3343
|
+
output[name] = arrayValue;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
let validation = new AjvJsonSchemaValidator().getValidator(params.requestedSchema)(output);
|
|
3347
|
+
if (!validation.valid)
|
|
3348
|
+
throw new Error(`Invalid elicitation response: ${validation.errorMessage}`);
|
|
3349
|
+
return output;
|
|
3350
|
+
}
|
|
3351
|
+
function formatChoice(value, title) {
|
|
3352
|
+
return title && title !== value ? `${title} (${value})` : value;
|
|
3353
|
+
}
|
|
3354
|
+
function uniqueLabels(labels) {
|
|
3355
|
+
let used = /* @__PURE__ */ new Set();
|
|
3356
|
+
return labels.map((label) => {
|
|
3357
|
+
let unique = label;
|
|
3358
|
+
for (; used.has(unique); )
|
|
3359
|
+
unique += "\u2026";
|
|
3360
|
+
return used.add(unique), unique;
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
function uniqueAction(label, choices) {
|
|
3364
|
+
let unique = label;
|
|
3365
|
+
for (; choices.includes(unique); )
|
|
3366
|
+
unique += "\u2026";
|
|
3367
|
+
return unique;
|
|
3368
|
+
}
|
|
3369
|
+
function extractMultiSelectOptions(schema) {
|
|
3370
|
+
let items = schema.items;
|
|
3371
|
+
return items.anyOf ? items.anyOf.map((option) => ({ value: option.const, display: formatChoice(option.const, option.title) })) : (items.enum ?? []).map((value) => ({ value, display: value }));
|
|
3372
|
+
}
|
|
3373
|
+
function formatReview(serverName, properties, content) {
|
|
3374
|
+
let rows = properties.map(([name, schema]) => `${schema.title ?? humanizeName(name)}: ${content[name] === void 0 ? "(omitted)" : String(content[name])}`);
|
|
3375
|
+
return [`Review input for ${serverName}`, "", ...rows].join(`
|
|
3376
|
+
`);
|
|
3377
|
+
}
|
|
3378
|
+
async function handleUrlElicitation(options, params) {
|
|
3379
|
+
if (!options.allowUrl)
|
|
3380
|
+
throw new McpError(ErrorCode.InvalidParams, "URL elicitation is not supported");
|
|
3381
|
+
let parsed;
|
|
3382
|
+
try {
|
|
3383
|
+
parsed = new URL(params.url);
|
|
3384
|
+
} catch {
|
|
3385
|
+
throw new McpError(ErrorCode.InvalidParams, "URL elicitation supplied an invalid URL");
|
|
3386
|
+
}
|
|
3387
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
3388
|
+
throw new McpError(ErrorCode.InvalidParams, "URL elicitation only supports HTTP and HTTPS URLs");
|
|
3389
|
+
let decision = await options.ui.select([
|
|
3390
|
+
"MCP Browser Request",
|
|
3391
|
+
`Server: ${options.serverName}`,
|
|
3392
|
+
"",
|
|
3393
|
+
params.message,
|
|
3394
|
+
"",
|
|
3395
|
+
`Host: ${parsed.host}`,
|
|
3396
|
+
`Full URL: ${params.url}`,
|
|
3397
|
+
"",
|
|
3398
|
+
"Open this URL in your browser?"
|
|
3399
|
+
].join(`
|
|
3400
|
+
`), ["Open", "Decline"]);
|
|
3401
|
+
if (decision === void 0)
|
|
3402
|
+
return { action: "cancel" };
|
|
3403
|
+
if (decision === "Decline")
|
|
3404
|
+
return { action: "decline" };
|
|
3405
|
+
try {
|
|
3406
|
+
await open2(params.url);
|
|
3407
|
+
} catch (error) {
|
|
3408
|
+
return options.ui.notify(`Could not open MCP elicitation URL: ${error instanceof Error ? error.message : String(error)}`, "error"), { action: "cancel" };
|
|
3409
|
+
}
|
|
3410
|
+
return options.onUrlAccepted?.(params.elicitationId), options.ui.notify("Opened browser for MCP elicitation.", "info"), { action: "accept" };
|
|
3411
|
+
}
|
|
3412
|
+
function humanizeName(name) {
|
|
3413
|
+
return name.replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (char) => char.toUpperCase());
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/server-manager.js
|
|
3417
|
+
var McpServerManager = class {
|
|
3418
|
+
defaultCwd;
|
|
3419
|
+
connections = /* @__PURE__ */ new Map();
|
|
3420
|
+
connectPromises = /* @__PURE__ */ new Map();
|
|
3421
|
+
pendingConnections = /* @__PURE__ */ new Map();
|
|
3422
|
+
closing = !1;
|
|
3423
|
+
uiStreamListeners = /* @__PURE__ */ new Map();
|
|
3424
|
+
samplingConfig;
|
|
3425
|
+
elicitationConfig;
|
|
3426
|
+
acceptedUrlElicitations = /* @__PURE__ */ new Map();
|
|
3427
|
+
defaultRequestTimeoutMs;
|
|
3428
|
+
/** Default cwd for stdio servers without an explicit config `cwd`. */
|
|
3429
|
+
constructor(defaultCwd) {
|
|
3430
|
+
this.defaultCwd = defaultCwd;
|
|
3431
|
+
}
|
|
3432
|
+
setSamplingConfig(config) {
|
|
3433
|
+
this.samplingConfig = config;
|
|
3434
|
+
}
|
|
3435
|
+
setElicitationConfig(config) {
|
|
3436
|
+
this.elicitationConfig = config;
|
|
3437
|
+
}
|
|
3438
|
+
setDefaultRequestTimeoutMs(timeoutMs) {
|
|
3439
|
+
this.defaultRequestTimeoutMs = normalizeRequestTimeoutMs(timeoutMs);
|
|
3440
|
+
}
|
|
3441
|
+
getRequestOptions(name, signal) {
|
|
3442
|
+
let connection = this.connections.get(name);
|
|
3443
|
+
return this.buildRequestOptions(connection?.definition, signal);
|
|
3444
|
+
}
|
|
3445
|
+
getResolvedRequestTimeoutMs(definition) {
|
|
3446
|
+
return definition?.requestTimeoutMs !== void 0 ? normalizeRequestTimeoutMs(definition.requestTimeoutMs) : this.defaultRequestTimeoutMs;
|
|
3447
|
+
}
|
|
3448
|
+
buildRequestOptions(definition, signal) {
|
|
3449
|
+
let timeout = this.getResolvedRequestTimeoutMs(definition);
|
|
3450
|
+
if (!(!signal && timeout === void 0))
|
|
3451
|
+
return {
|
|
3452
|
+
...signal ? { signal } : {},
|
|
3453
|
+
...timeout !== void 0 ? { timeout } : {}
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
async connect(name, definition, signal) {
|
|
3457
|
+
if (throwIfAborted(signal), this.closing)
|
|
3458
|
+
throw new Error("MCP server manager is closed");
|
|
3459
|
+
if (this.connectPromises.has(name))
|
|
3460
|
+
return abortable(this.connectPromises.get(name), signal);
|
|
3461
|
+
let existing = this.connections.get(name);
|
|
3462
|
+
if (existing?.status === "connected")
|
|
3463
|
+
return existing.lastUsedAt = Date.now(), existing;
|
|
3464
|
+
let promise = this.createConnection(name, definition, signal).then(async (connection) => {
|
|
3465
|
+
if (this.closing || signal?.aborted)
|
|
3466
|
+
throw await this.disposeConnection(connection), throwIfAborted(signal), new Error("MCP server manager closed during connection");
|
|
3467
|
+
return this.connections.set(name, connection), connection;
|
|
3468
|
+
});
|
|
3469
|
+
this.connectPromises.set(name, promise);
|
|
3470
|
+
try {
|
|
3471
|
+
return await promise;
|
|
3472
|
+
} finally {
|
|
3473
|
+
this.connectPromises.get(name) === promise && this.connectPromises.delete(name);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
async createConnection(name, definition, signal) {
|
|
3477
|
+
throwIfAborted(signal);
|
|
3478
|
+
let client = this.createClient(name), transport;
|
|
3479
|
+
if (definition.command) {
|
|
3480
|
+
let command = definition.command, args = definition.args ?? [];
|
|
3481
|
+
if (command === "npx" || command === "npm") {
|
|
3482
|
+
let resolved = await resolveNpxBinary(command, args);
|
|
3483
|
+
resolved && (command = resolved.isJs ? "node" : resolved.binPath, args = resolved.isJs ? [resolved.binPath, ...resolved.extraArgs] : resolved.extraArgs, logger.debug(`${name} resolved to ${resolved.binPath} (skipping npm parent)`));
|
|
3484
|
+
}
|
|
3485
|
+
transport = new StdioClientTransport({
|
|
3486
|
+
command,
|
|
3487
|
+
args,
|
|
3488
|
+
env: resolveEnv(definition.env),
|
|
3489
|
+
cwd: resolveConfigPath(definition.cwd) ?? this.defaultCwd,
|
|
3490
|
+
stderr: definition.debug ? "inherit" : "ignore"
|
|
3491
|
+
});
|
|
3492
|
+
} else if (definition.url)
|
|
3493
|
+
transport = await this.createHttpTransport(definition, name, signal);
|
|
3494
|
+
else
|
|
3495
|
+
throw new Error(`Server ${name} has no command or url`);
|
|
3496
|
+
let requestOptions = this.buildRequestOptions(definition, signal), pending = { client, transport };
|
|
3497
|
+
this.pendingConnections.set(name, pending);
|
|
3498
|
+
try {
|
|
3499
|
+
await client.connect(transport, requestOptions), this.attachAdapterNotificationHandlers(name, client);
|
|
3500
|
+
let [tools, resources] = await Promise.all([
|
|
3501
|
+
this.fetchAllTools(client, requestOptions),
|
|
3502
|
+
this.fetchAllResources(client, requestOptions)
|
|
3503
|
+
]);
|
|
3504
|
+
return {
|
|
3505
|
+
client,
|
|
3506
|
+
transport,
|
|
3507
|
+
definition,
|
|
3508
|
+
tools,
|
|
3509
|
+
resources,
|
|
3510
|
+
lastUsedAt: Date.now(),
|
|
3511
|
+
inFlight: 0,
|
|
3512
|
+
status: "connected"
|
|
3513
|
+
};
|
|
3514
|
+
} catch (error) {
|
|
3515
|
+
if (error instanceof UnauthorizedError && supportsOAuth(definition))
|
|
3516
|
+
return await client.close().catch(() => {
|
|
3517
|
+
}), await transport.close().catch(() => {
|
|
3518
|
+
}), {
|
|
3519
|
+
client,
|
|
3520
|
+
transport,
|
|
3521
|
+
definition,
|
|
3522
|
+
tools: [],
|
|
3523
|
+
resources: [],
|
|
3524
|
+
lastUsedAt: Date.now(),
|
|
3525
|
+
inFlight: 0,
|
|
3526
|
+
status: "needs-auth"
|
|
3527
|
+
};
|
|
3528
|
+
throw await client.close().catch(() => {
|
|
3529
|
+
}), await transport.close().catch(() => {
|
|
3530
|
+
}), error;
|
|
3531
|
+
} finally {
|
|
3532
|
+
this.pendingConnections.get(name) === pending && this.pendingConnections.delete(name);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
buildClientCapabilities() {
|
|
3536
|
+
return {
|
|
3537
|
+
...this.samplingConfig ? { sampling: {} } : {},
|
|
3538
|
+
...this.elicitationConfig ? {
|
|
3539
|
+
elicitation: {
|
|
3540
|
+
form: {},
|
|
3541
|
+
...this.elicitationConfig.allowUrl ? { url: {} } : {}
|
|
3542
|
+
}
|
|
3543
|
+
} : {}
|
|
3544
|
+
};
|
|
3545
|
+
}
|
|
3546
|
+
createClient(serverName) {
|
|
3547
|
+
let capabilities = this.buildClientCapabilities(), client = new Client({ name: `lunR-mcp-${serverName}`, version: "1.0.0" }, Object.keys(capabilities).length > 0 ? { capabilities } : void 0);
|
|
3548
|
+
return this.samplingConfig && registerSamplingHandler(client, { ...this.samplingConfig, serverName }), this.elicitationConfig && (registerElicitationHandler(client, {
|
|
3549
|
+
...this.elicitationConfig,
|
|
3550
|
+
serverName,
|
|
3551
|
+
onUrlAccepted: (elicitationId) => this.rememberUrlElicitation(serverName, elicitationId)
|
|
3552
|
+
}), this.elicitationConfig.allowUrl && client.setNotificationHandler(ElicitationCompleteNotificationSchema, (notification) => {
|
|
3553
|
+
this.acceptedUrlElicitations.get(serverName)?.delete(notification.params.elicitationId) && this.elicitationConfig?.ui.notify(`MCP browser interaction for ${serverName} completed. You can retry the tool now.`, "info");
|
|
3554
|
+
})), client;
|
|
3555
|
+
}
|
|
3556
|
+
async handleUrlElicitationRequired(serverName, error) {
|
|
3557
|
+
if (!this.elicitationConfig?.allowUrl)
|
|
3558
|
+
return "cancel";
|
|
3559
|
+
for (let params of error.elicitations) {
|
|
3560
|
+
let result = await handleUrlElicitation({
|
|
3561
|
+
...this.elicitationConfig,
|
|
3562
|
+
serverName,
|
|
3563
|
+
onUrlAccepted: (elicitationId) => this.rememberUrlElicitation(serverName, elicitationId)
|
|
3564
|
+
}, params);
|
|
3565
|
+
if (result.action !== "accept")
|
|
3566
|
+
return result.action;
|
|
3567
|
+
}
|
|
3568
|
+
return "accept";
|
|
3569
|
+
}
|
|
3570
|
+
rememberUrlElicitation(serverName, elicitationId) {
|
|
3571
|
+
let accepted = this.acceptedUrlElicitations.get(serverName);
|
|
3572
|
+
accepted || (accepted = /* @__PURE__ */ new Set(), this.acceptedUrlElicitations.set(serverName, accepted)), accepted.add(elicitationId);
|
|
3573
|
+
}
|
|
3574
|
+
async createHttpTransport(definition, serverName, signal) {
|
|
3575
|
+
throwIfAborted(signal);
|
|
3576
|
+
let url2 = new URL(definition.url), headers = resolveHeaders(definition.headers) ?? {};
|
|
3577
|
+
if (definition.auth === "bearer") {
|
|
3578
|
+
let token = resolveBearerToken(definition);
|
|
3579
|
+
token && (headers.Authorization = `Bearer ${token}`);
|
|
3580
|
+
}
|
|
3581
|
+
let requestInit = Object.keys(headers).length > 0 ? { headers } : void 0, authProvider;
|
|
3582
|
+
if (supportsOAuth(definition)) {
|
|
3583
|
+
let oauthConfig = extractOAuthConfig(definition);
|
|
3584
|
+
authProvider = new McpOAuthProvider(serverName, definition.url, oauthConfig, {
|
|
3585
|
+
onRedirect: async (_authUrl) => {
|
|
3586
|
+
}
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
let streamableTransport = new StreamableHTTPClientTransport(url2, {
|
|
3590
|
+
requestInit,
|
|
3591
|
+
authProvider
|
|
3592
|
+
});
|
|
3593
|
+
try {
|
|
3594
|
+
let testClient = new Client({ name: "lunR-mcp-probe", version: "2.1.2" });
|
|
3595
|
+
return await testClient.connect(streamableTransport, this.buildRequestOptions(definition, signal)), await testClient.close().catch(() => {
|
|
3596
|
+
}), await streamableTransport.close().catch(() => {
|
|
3597
|
+
}), new StreamableHTTPClientTransport(url2, { requestInit, authProvider });
|
|
3598
|
+
} catch (error) {
|
|
3599
|
+
if (await streamableTransport.close().catch(() => {
|
|
3600
|
+
}), signal?.aborted && throwIfAborted(signal), error instanceof UnauthorizedError)
|
|
3601
|
+
throw error;
|
|
3602
|
+
return new SSEClientTransport(url2, { requestInit, authProvider });
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
async fetchAllTools(client, requestOptions) {
|
|
3606
|
+
let allTools = [], cursor;
|
|
3607
|
+
do {
|
|
3608
|
+
let result = await client.listTools(cursor ? { cursor } : void 0, requestOptions);
|
|
3609
|
+
allTools.push(...result.tools ?? []), cursor = result.nextCursor;
|
|
3610
|
+
} while (cursor);
|
|
3611
|
+
return allTools;
|
|
3612
|
+
}
|
|
3613
|
+
async fetchAllResources(client, requestOptions) {
|
|
3614
|
+
try {
|
|
3615
|
+
let allResources = [], cursor;
|
|
3616
|
+
do {
|
|
3617
|
+
let result = await client.listResources(cursor ? { cursor } : void 0, requestOptions);
|
|
3618
|
+
allResources.push(...result.resources ?? []), cursor = result.nextCursor;
|
|
3619
|
+
} while (cursor);
|
|
3620
|
+
return allResources;
|
|
3621
|
+
} catch {
|
|
3622
|
+
return requestOptions?.signal?.aborted && throwIfAborted(requestOptions.signal), [];
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
attachAdapterNotificationHandlers(serverName, client) {
|
|
3626
|
+
client.setNotificationHandler(serverStreamResultPatchNotificationSchema, (notification) => {
|
|
3627
|
+
let listener = this.uiStreamListeners.get(notification.params.streamToken);
|
|
3628
|
+
listener && listener(serverName, notification.params);
|
|
3629
|
+
});
|
|
3630
|
+
}
|
|
3631
|
+
registerUiStreamListener(streamToken, listener) {
|
|
3632
|
+
this.uiStreamListeners.set(streamToken, listener);
|
|
3633
|
+
}
|
|
3634
|
+
removeUiStreamListener(streamToken) {
|
|
3635
|
+
this.uiStreamListeners.delete(streamToken);
|
|
3636
|
+
}
|
|
3637
|
+
async readResource(name, uri, signal) {
|
|
3638
|
+
let connection = this.connections.get(name);
|
|
3639
|
+
if (!connection || connection.status !== "connected")
|
|
3640
|
+
throw new Error(`Server "${name}" is not connected`);
|
|
3641
|
+
try {
|
|
3642
|
+
return this.touch(name), this.incrementInFlight(name), await connection.client.readResource({ uri }, this.getRequestOptions(name, signal));
|
|
3643
|
+
} finally {
|
|
3644
|
+
this.decrementInFlight(name), this.touch(name);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
async disposeConnection(connection) {
|
|
3648
|
+
await connection.client.close().catch(() => {
|
|
3649
|
+
}), await connection.transport.close().catch(() => {
|
|
3650
|
+
});
|
|
3651
|
+
}
|
|
3652
|
+
async close(name) {
|
|
3653
|
+
let connection = this.connections.get(name);
|
|
3654
|
+
connection && (connection.status = "closed", this.connections.delete(name), this.acceptedUrlElicitations.delete(name), await this.disposeConnection(connection));
|
|
3655
|
+
}
|
|
3656
|
+
async closeAll() {
|
|
3657
|
+
this.closing = !0;
|
|
3658
|
+
let names = [...this.connections.keys()], pending = [...this.pendingConnections.values()];
|
|
3659
|
+
await Promise.all([
|
|
3660
|
+
...names.map((name) => this.close(name)),
|
|
3661
|
+
...pending.map((connection) => this.disposeConnection(connection))
|
|
3662
|
+
]);
|
|
3663
|
+
}
|
|
3664
|
+
getConnection(name) {
|
|
3665
|
+
return this.connections.get(name);
|
|
3666
|
+
}
|
|
3667
|
+
getAllConnections() {
|
|
3668
|
+
return new Map(this.connections);
|
|
3669
|
+
}
|
|
3670
|
+
touch(name) {
|
|
3671
|
+
let connection = this.connections.get(name);
|
|
3672
|
+
connection && (connection.lastUsedAt = Date.now());
|
|
3673
|
+
}
|
|
3674
|
+
incrementInFlight(name) {
|
|
3675
|
+
let connection = this.connections.get(name);
|
|
3676
|
+
connection && (connection.inFlight = (connection.inFlight ?? 0) + 1);
|
|
3677
|
+
}
|
|
3678
|
+
decrementInFlight(name) {
|
|
3679
|
+
let connection = this.connections.get(name);
|
|
3680
|
+
connection && connection.inFlight && connection.inFlight--;
|
|
3681
|
+
}
|
|
3682
|
+
isIdle(name, timeoutMs) {
|
|
3683
|
+
let connection = this.connections.get(name);
|
|
3684
|
+
return !connection || connection.status !== "connected" || connection.inFlight > 0 ? !1 : Date.now() - connection.lastUsedAt > timeoutMs;
|
|
3685
|
+
}
|
|
3686
|
+
};
|
|
3687
|
+
function resolveEnv(env) {
|
|
3688
|
+
let resolved = {};
|
|
3689
|
+
for (let [key, value] of Object.entries(process.env))
|
|
3690
|
+
value !== void 0 && (resolved[key] = value);
|
|
3691
|
+
if (!env)
|
|
3692
|
+
return resolved;
|
|
3693
|
+
let overrides = interpolateEnvRecord(env);
|
|
3694
|
+
return overrides ? { ...resolved, ...overrides } : resolved;
|
|
3695
|
+
}
|
|
3696
|
+
function resolveHeaders(headers) {
|
|
3697
|
+
return interpolateEnvRecord(headers);
|
|
3698
|
+
}
|
|
3699
|
+
function normalizeRequestTimeoutMs(timeoutMs) {
|
|
3700
|
+
return typeof timeoutMs == "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : void 0;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
// node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
|
|
3704
|
+
var ZQ = ((X) => typeof __require < "u" ? __require : typeof Proxy < "u" ? new Proxy(X, { get: (Y, Z) => (typeof __require < "u" ? __require : Y)[Z] }) : X)(function(X) {
|
|
3705
|
+
if (typeof __require < "u") return __require.apply(this, arguments);
|
|
3706
|
+
throw Error('Dynamic require of "' + X + '" is not supported');
|
|
3707
|
+
});
|
|
3708
|
+
var r = external_exports.union([external_exports.literal("light"), external_exports.literal("dark")]).describe("Color theme preference for the host environment."), B = external_exports.union([external_exports.literal("inline"), external_exports.literal("fullscreen"), external_exports.literal("pip")]).describe("Display mode for UI presentation."), HQ = external_exports.union([external_exports.literal("--color-background-primary"), external_exports.literal("--color-background-secondary"), external_exports.literal("--color-background-tertiary"), external_exports.literal("--color-background-inverse"), external_exports.literal("--color-background-ghost"), external_exports.literal("--color-background-info"), external_exports.literal("--color-background-danger"), external_exports.literal("--color-background-success"), external_exports.literal("--color-background-warning"), external_exports.literal("--color-background-disabled"), external_exports.literal("--color-text-primary"), external_exports.literal("--color-text-secondary"), external_exports.literal("--color-text-tertiary"), external_exports.literal("--color-text-inverse"), external_exports.literal("--color-text-ghost"), external_exports.literal("--color-text-info"), external_exports.literal("--color-text-danger"), external_exports.literal("--color-text-success"), external_exports.literal("--color-text-warning"), external_exports.literal("--color-text-disabled"), external_exports.literal("--color-border-primary"), external_exports.literal("--color-border-secondary"), external_exports.literal("--color-border-tertiary"), external_exports.literal("--color-border-inverse"), external_exports.literal("--color-border-ghost"), external_exports.literal("--color-border-info"), external_exports.literal("--color-border-danger"), external_exports.literal("--color-border-success"), external_exports.literal("--color-border-warning"), external_exports.literal("--color-border-disabled"), external_exports.literal("--color-ring-primary"), external_exports.literal("--color-ring-secondary"), external_exports.literal("--color-ring-inverse"), external_exports.literal("--color-ring-info"), external_exports.literal("--color-ring-danger"), external_exports.literal("--color-ring-success"), external_exports.literal("--color-ring-warning"), external_exports.literal("--font-sans"), external_exports.literal("--font-mono"), external_exports.literal("--font-weight-normal"), external_exports.literal("--font-weight-medium"), external_exports.literal("--font-weight-semibold"), external_exports.literal("--font-weight-bold"), external_exports.literal("--font-text-xs-size"), external_exports.literal("--font-text-sm-size"), external_exports.literal("--font-text-md-size"), external_exports.literal("--font-text-lg-size"), external_exports.literal("--font-heading-xs-size"), external_exports.literal("--font-heading-sm-size"), external_exports.literal("--font-heading-md-size"), external_exports.literal("--font-heading-lg-size"), external_exports.literal("--font-heading-xl-size"), external_exports.literal("--font-heading-2xl-size"), external_exports.literal("--font-heading-3xl-size"), external_exports.literal("--font-text-xs-line-height"), external_exports.literal("--font-text-sm-line-height"), external_exports.literal("--font-text-md-line-height"), external_exports.literal("--font-text-lg-line-height"), external_exports.literal("--font-heading-xs-line-height"), external_exports.literal("--font-heading-sm-line-height"), external_exports.literal("--font-heading-md-line-height"), external_exports.literal("--font-heading-lg-line-height"), external_exports.literal("--font-heading-xl-line-height"), external_exports.literal("--font-heading-2xl-line-height"), external_exports.literal("--font-heading-3xl-line-height"), external_exports.literal("--border-radius-xs"), external_exports.literal("--border-radius-sm"), external_exports.literal("--border-radius-md"), external_exports.literal("--border-radius-lg"), external_exports.literal("--border-radius-xl"), external_exports.literal("--border-radius-full"), external_exports.literal("--border-width-regular"), external_exports.literal("--shadow-hairline"), external_exports.literal("--shadow-sm"), external_exports.literal("--shadow-md"), external_exports.literal("--shadow-lg")]).describe("CSS variable keys available to MCP apps for theming."), RQ = external_exports.record(HQ.describe(`Style variables for theming MCP apps.
|
|
3709
|
+
|
|
3710
|
+
Individual style keys are optional - hosts may provide any subset of these values.
|
|
3711
|
+
Values are strings containing CSS values (colors, sizes, font stacks, etc.).
|
|
3712
|
+
|
|
3713
|
+
Note: This type uses \`Record<K, string | undefined>\` rather than \`Partial<Record<K, string>>\`
|
|
3714
|
+
for compatibility with Zod schema generation. Both are functionally equivalent for validation.`), external_exports.union([external_exports.string(), external_exports.undefined()]).describe(`Style variables for theming MCP apps.
|
|
3715
|
+
|
|
3716
|
+
Individual style keys are optional - hosts may provide any subset of these values.
|
|
3717
|
+
Values are strings containing CSS values (colors, sizes, font stacks, etc.).
|
|
3718
|
+
|
|
3719
|
+
Note: This type uses \`Record<K, string | undefined>\` rather than \`Partial<Record<K, string>>\`
|
|
3720
|
+
for compatibility with Zod schema generation. Both are functionally equivalent for validation.`)).describe(`Style variables for theming MCP apps.
|
|
3721
|
+
|
|
3722
|
+
Individual style keys are optional - hosts may provide any subset of these values.
|
|
3723
|
+
Values are strings containing CSS values (colors, sizes, font stacks, etc.).
|
|
3724
|
+
|
|
3725
|
+
Note: This type uses \`Record<K, string | undefined>\` rather than \`Partial<Record<K, string>>\`
|
|
3726
|
+
for compatibility with Zod schema generation. Both are functionally equivalent for validation.`), L = external_exports.object({ method: external_exports.literal("ui/open-link"), params: external_exports.object({ url: external_exports.string().describe("URL to open in the host's browser") }) }), P = external_exports.object({ isError: external_exports.boolean().optional().describe("True if the host failed to open the URL (e.g., due to security policy).") }).passthrough(), A = external_exports.object({ isError: external_exports.boolean().optional().describe("True if the download failed (e.g., user cancelled or host denied).") }).passthrough(), U = external_exports.object({ isError: external_exports.boolean().optional().describe("True if the host rejected or failed to deliver the message.") }).passthrough(), w = external_exports.object({ method: external_exports.literal("ui/notifications/sandbox-proxy-ready"), params: external_exports.object({}) }), O = external_exports.object({ connectDomains: external_exports.array(external_exports.string()).optional().describe(`Origins for network requests (fetch/XHR/WebSocket).
|
|
3727
|
+
|
|
3728
|
+
- Maps to CSP \`connect-src\` directive
|
|
3729
|
+
- Empty or omitted \u2192 no network connections (secure default)`), resourceDomains: external_exports.array(external_exports.string()).optional().describe("Origins for static resources (images, scripts, stylesheets, fonts, media).\n\n- Maps to CSP `img-src`, `script-src`, `style-src`, `font-src`, `media-src` directives\n- Wildcard subdomains supported: `https://*.example.com`\n- Empty or omitted \u2192 no network resources (secure default)"), frameDomains: external_exports.array(external_exports.string()).optional().describe("Origins for nested iframes.\n\n- Maps to CSP `frame-src` directive\n- Empty or omitted \u2192 no nested iframes allowed (`frame-src 'none'`)"), baseUriDomains: external_exports.array(external_exports.string()).optional().describe("Allowed base URIs for the document.\n\n- Maps to CSP `base-uri` directive\n- Empty or omitted \u2192 only same origin allowed (`base-uri 'self'`)") }), z = external_exports.object({ camera: external_exports.object({}).optional().describe("Request camera access.\n\nMaps to Permission Policy `camera` feature."), microphone: external_exports.object({}).optional().describe("Request microphone access.\n\nMaps to Permission Policy `microphone` feature."), geolocation: external_exports.object({}).optional().describe("Request geolocation access.\n\nMaps to Permission Policy `geolocation` feature."), clipboardWrite: external_exports.object({}).optional().describe("Request clipboard write access.\n\nMaps to Permission Policy `clipboard-write` feature.") }), H = external_exports.object({ method: external_exports.literal("ui/notifications/size-changed"), params: external_exports.object({ width: external_exports.number().optional().describe("New width in pixels."), height: external_exports.number().optional().describe("New height in pixels.") }) }), R = external_exports.object({ method: external_exports.literal("ui/notifications/tool-input"), params: external_exports.object({ arguments: external_exports.record(external_exports.string(), external_exports.unknown().describe("Complete tool call arguments as key-value pairs.")).optional().describe("Complete tool call arguments as key-value pairs.") }) }), T = external_exports.object({ method: external_exports.literal("ui/notifications/tool-input-partial"), params: external_exports.object({ arguments: external_exports.record(external_exports.string(), external_exports.unknown().describe("Partial tool call arguments (incomplete, may change).")).optional().describe("Partial tool call arguments (incomplete, may change).") }) }), M = external_exports.object({ method: external_exports.literal("ui/notifications/tool-cancelled"), params: external_exports.object({ reason: external_exports.string().optional().describe('Optional reason for the cancellation (e.g., "user action", "timeout").') }) }), o = external_exports.object({ fonts: external_exports.string().optional() }), s = external_exports.object({ variables: RQ.optional().describe("CSS variables for theming the app."), css: o.optional().describe("CSS blocks that apps can inject.") }), C = external_exports.object({ method: external_exports.literal("ui/resource-teardown"), params: external_exports.object({}) }), S = external_exports.record(external_exports.string(), external_exports.unknown()), F = external_exports.object({ text: external_exports.object({}).optional().describe("Host supports text content blocks."), image: external_exports.object({}).optional().describe("Host supports image content blocks."), audio: external_exports.object({}).optional().describe("Host supports audio content blocks."), resource: external_exports.object({}).optional().describe("Host supports resource content blocks."), resourceLink: external_exports.object({}).optional().describe("Host supports resource link content blocks."), structuredContent: external_exports.object({}).optional().describe("Host supports structured content.") }), q = external_exports.object({ method: external_exports.literal("ui/notifications/request-teardown"), params: external_exports.object({}).optional() }), t = external_exports.object({ experimental: external_exports.object({}).optional().describe("Experimental features (structure TBD)."), openLinks: external_exports.object({}).optional().describe("Host supports opening external URLs."), downloadFile: external_exports.object({}).optional().describe("Host supports file downloads via ui/download-file."), serverTools: external_exports.object({ listChanged: external_exports.boolean().optional().describe("Host supports tools/list_changed notifications.") }).optional().describe("Host can proxy tool calls to the MCP server."), serverResources: external_exports.object({ listChanged: external_exports.boolean().optional().describe("Host supports resources/list_changed notifications.") }).optional().describe("Host can proxy resource reads to the MCP server."), logging: external_exports.object({}).optional().describe("Host accepts log messages."), sandbox: external_exports.object({ permissions: z.optional().describe("Permissions granted by the host (camera, microphone, geolocation)."), csp: O.optional().describe("CSP domains approved by the host.") }).optional().describe("Sandbox configuration applied by the host."), updateModelContext: F.optional().describe("Host accepts context updates (ui/update-model-context) to be included in the model's context for future turns."), message: F.optional().describe("Host supports receiving content messages (ui/message) from the view."), sampling: external_exports.object({ tools: external_exports.object({}).optional().describe("Host supports tool use via `tools` and `toolChoice` parameters.") }).optional().describe("Host supports LLM sampling (sampling/createMessage) from the view.\nMirrors the MCP `ClientCapabilities.sampling` shape so hosts can pass it through.") }), a = external_exports.object({ experimental: external_exports.object({}).optional().describe("Experimental features (structure TBD)."), tools: external_exports.object({ listChanged: external_exports.boolean().optional().describe("App supports tools/list_changed notifications.") }).optional().describe("App exposes MCP-style tools that the host can call."), availableDisplayModes: external_exports.array(B).optional().describe("Display modes the app supports.") }), y = external_exports.object({ method: external_exports.literal("ui/notifications/initialized"), params: external_exports.object({}).optional() }), TQ = external_exports.object({ csp: O.optional().describe("Content Security Policy configuration for UI resources."), permissions: z.optional().describe("Sandbox permissions requested by the UI resource."), domain: external_exports.string().optional().describe(`Dedicated origin for view sandbox.
|
|
3730
|
+
|
|
3731
|
+
Useful when views need stable, dedicated origins for OAuth callbacks, CORS policies, or API key allowlists.
|
|
3732
|
+
|
|
3733
|
+
**Host-dependent:** The format and validation rules for this field are determined by each host. Servers MUST consult host-specific documentation for the expected domain format. Common patterns include:
|
|
3734
|
+
- Hash-based subdomains (e.g., \`{hash}.claudemcpcontent.com\`)
|
|
3735
|
+
- URL-derived subdomains (e.g., \`www-example-com.oaiusercontent.com\`)
|
|
3736
|
+
|
|
3737
|
+
If omitted, host uses default sandbox origin (typically per-conversation).`), prefersBorder: external_exports.boolean().optional().describe(`Visual boundary preference - true if view prefers a visible border.
|
|
3738
|
+
|
|
3739
|
+
Boolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary.
|
|
3740
|
+
|
|
3741
|
+
- \`true\`: request visible border + background
|
|
3742
|
+
- \`false\`: request no visible border + background
|
|
3743
|
+
- omitted: host decides border`) }), I = external_exports.object({ method: external_exports.literal("ui/request-display-mode"), params: external_exports.object({ mode: B.describe("The display mode being requested.") }) }), g = external_exports.object({ mode: B.describe("The display mode that was actually set. May differ from requested if not supported.") }).passthrough(), e = external_exports.union([external_exports.literal("model"), external_exports.literal("app")]).describe("Tool visibility scope - who can access the tool."), MQ = external_exports.object({ resourceUri: external_exports.string().optional(), visibility: external_exports.array(e).optional().describe(`Who can access this tool. Default: ["model", "app"]
|
|
3744
|
+
- "model": Tool visible to and callable by the agent
|
|
3745
|
+
- "app": Tool callable by the app from this server only`), csp: external_exports.never().optional(), permissions: external_exports.never().optional() }), OX = external_exports.object({ mimeTypes: external_exports.array(external_exports.string()).optional().describe('Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.') }), f = external_exports.object({ method: external_exports.literal("ui/download-file"), params: external_exports.object({ contents: external_exports.array(external_exports.union([EmbeddedResourceSchema, ResourceLinkSchema])).describe("Resource contents to download \u2014 embedded (inline data) or linked (host fetches). Uses standard MCP resource types.") }) }), k = external_exports.object({ method: external_exports.literal("ui/message"), params: external_exports.object({ role: external_exports.literal("user").describe('Message role, currently only "user" is supported.'), content: external_exports.array(ContentBlockSchema).describe("Message content blocks (text, image, etc.).") }) }), CQ = external_exports.object({ method: external_exports.literal("ui/notifications/sandbox-resource-ready"), params: external_exports.object({ html: external_exports.string().describe("HTML content to load into the inner iframe."), sandbox: external_exports.string().optional().describe("Optional override for the inner iframe's sandbox attribute."), csp: O.optional().describe("CSP configuration from resource metadata."), permissions: z.optional().describe("Sandbox permissions from resource metadata.") }) }), v = external_exports.object({ method: external_exports.literal("ui/notifications/tool-result"), params: CallToolResultSchema.describe("Standard MCP tool execution result.") }), x = external_exports.object({ toolInfo: external_exports.object({ id: RequestIdSchema.optional().describe("JSON-RPC id of the tools/call request."), tool: ToolSchema.describe("Tool definition including name, inputSchema, etc.") }).optional().describe("Metadata of the tool call that instantiated this App."), theme: r.optional().describe("Current color theme preference."), styles: s.optional().describe("Style configuration for theming the app."), displayMode: B.optional().describe("How the UI is currently displayed."), availableDisplayModes: external_exports.array(B).optional().describe("Display modes the host supports."), containerDimensions: external_exports.union([external_exports.object({ height: external_exports.number().describe("Fixed container height in pixels.") }), external_exports.object({ maxHeight: external_exports.union([external_exports.number(), external_exports.undefined()]).optional().describe("Maximum container height in pixels.") })]).and(external_exports.union([external_exports.object({ width: external_exports.number().describe("Fixed container width in pixels.") }), external_exports.object({ maxWidth: external_exports.union([external_exports.number(), external_exports.undefined()]).optional().describe("Maximum container width in pixels.") })])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other
|
|
3746
|
+
container holding the app. Specify either width or maxWidth, and either height or maxHeight.`), locale: external_exports.string().optional().describe("User's language and region preference in BCP 47 format."), timeZone: external_exports.string().optional().describe("User's timezone in IANA format."), userAgent: external_exports.string().optional().describe("Host application identifier."), platform: external_exports.union([external_exports.literal("web"), external_exports.literal("desktop"), external_exports.literal("mobile")]).optional().describe("Platform type for responsive design decisions."), deviceCapabilities: external_exports.object({ touch: external_exports.boolean().optional().describe("Whether the device supports touch input."), hover: external_exports.boolean().optional().describe("Whether the device supports hover interactions.") }).optional().describe("Device input capabilities."), safeAreaInsets: external_exports.object({ top: external_exports.number().describe("Top safe area inset in pixels."), right: external_exports.number().describe("Right safe area inset in pixels."), bottom: external_exports.number().describe("Bottom safe area inset in pixels."), left: external_exports.number().describe("Left safe area inset in pixels.") }).optional().describe("Mobile safe area boundaries in pixels.") }).passthrough(), b = external_exports.object({ method: external_exports.literal("ui/notifications/host-context-changed"), params: x.describe("Partial context update containing only changed fields.") }), d = external_exports.object({ method: external_exports.literal("ui/update-model-context"), params: external_exports.object({ content: external_exports.array(ContentBlockSchema).optional().describe("Context content blocks (text, image, etc.)."), structuredContent: external_exports.record(external_exports.string(), external_exports.unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.") }) }), u = external_exports.object({ method: external_exports.literal("ui/initialize"), params: external_exports.object({ appInfo: ImplementationSchema.describe("App identification (name and version)."), appCapabilities: a.describe("Features and capabilities this app provides."), protocolVersion: external_exports.string().describe("Protocol version this app supports.") }) }), h = external_exports.object({ protocolVersion: external_exports.string().describe('Negotiated protocol version string (e.g., "2025-11-21").'), hostInfo: ImplementationSchema.describe("Host application identification and version."), hostCapabilities: t.describe("Features and capabilities provided by the host."), hostContext: x.describe("Rich context about the host environment.") }).passthrough();
|
|
3747
|
+
var i = "ui/resourceUri", pQ = "text/html;profile=mcp-app";
|
|
3748
|
+
function FZ(X) {
|
|
3749
|
+
let Z = X._meta?.ui?.resourceUri;
|
|
3750
|
+
if (Z === void 0 && (Z = X._meta?.[i]), typeof Z == "string" && Z.startsWith("ui://")) return Z;
|
|
3751
|
+
if (Z !== void 0) throw Error(`Invalid UI resource URI: ${JSON.stringify(Z)}`);
|
|
3752
|
+
}
|
|
3753
|
+
function AZ(X) {
|
|
3754
|
+
if (!X) return "";
|
|
3755
|
+
let Y = [];
|
|
3756
|
+
return X.camera && Y.push("camera"), X.microphone && Y.push("microphone"), X.geolocation && Y.push("geolocation"), X.clipboardWrite && Y.push("clipboard-write"), Y.join("; ");
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/tool-metadata.js
|
|
3760
|
+
function buildToolMetadata(tools, resources, definition, serverName, prefix) {
|
|
3761
|
+
let metadata = [], failedTools = [];
|
|
3762
|
+
for (let tool of tools) {
|
|
3763
|
+
if (!tool?.name) {
|
|
3764
|
+
failedTools.push("(unnamed)");
|
|
3765
|
+
continue;
|
|
3766
|
+
}
|
|
3767
|
+
if (isToolExcluded(tool.name, serverName, prefix, definition.excludeTools))
|
|
3768
|
+
continue;
|
|
3769
|
+
let uiResourceUri;
|
|
3770
|
+
try {
|
|
3771
|
+
uiResourceUri = FZ({ _meta: tool._meta });
|
|
3772
|
+
} catch {
|
|
3773
|
+
failedTools.push(tool.name);
|
|
3774
|
+
}
|
|
3775
|
+
metadata.push({
|
|
3776
|
+
name: formatToolName(tool.name, serverName, prefix),
|
|
3777
|
+
originalName: tool.name,
|
|
3778
|
+
description: tool.description ?? "",
|
|
3779
|
+
inputSchema: tool.inputSchema,
|
|
3780
|
+
uiResourceUri,
|
|
3781
|
+
uiStreamMode: extractToolUiStreamMode(tool._meta)
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
if (definition.exposeResources !== !1)
|
|
3785
|
+
for (let resource of resources) {
|
|
3786
|
+
let baseName = `get_${resourceNameToToolName(resource.name)}`;
|
|
3787
|
+
isToolExcluded(baseName, serverName, prefix, definition.excludeTools) || metadata.push({
|
|
3788
|
+
name: formatToolName(baseName, serverName, prefix),
|
|
3789
|
+
originalName: baseName,
|
|
3790
|
+
description: resource.description ?? `Read resource: ${resource.uri}`,
|
|
3791
|
+
resourceUri: resource.uri
|
|
3792
|
+
});
|
|
3793
|
+
}
|
|
3794
|
+
return { metadata, failedTools };
|
|
3795
|
+
}
|
|
3796
|
+
function getToolNames(state, serverName) {
|
|
3797
|
+
return state.toolMetadata.get(serverName)?.map((m) => m.name) ?? [];
|
|
3798
|
+
}
|
|
3799
|
+
function totalToolCount(state) {
|
|
3800
|
+
let count = 0;
|
|
3801
|
+
for (let metadata of state.toolMetadata.values())
|
|
3802
|
+
count += metadata.length;
|
|
3803
|
+
return count;
|
|
3804
|
+
}
|
|
3805
|
+
function findToolByName(metadata, toolName) {
|
|
3806
|
+
if (!metadata)
|
|
3807
|
+
return;
|
|
3808
|
+
let exact = metadata.find((m) => m.name === toolName);
|
|
3809
|
+
if (exact)
|
|
3810
|
+
return exact;
|
|
3811
|
+
let normalized = toolName.replace(/-/g, "_");
|
|
3812
|
+
return metadata.find((m) => m.name.replace(/-/g, "_") === normalized);
|
|
3813
|
+
}
|
|
3814
|
+
function formatSchema(schema, indent = " ") {
|
|
3815
|
+
if (!schema || typeof schema != "object" || Array.isArray(schema))
|
|
3816
|
+
return `${indent}(no schema)`;
|
|
3817
|
+
let s2 = schema;
|
|
3818
|
+
if (s2.type === "object" && s2.properties && typeof s2.properties == "object" && !Array.isArray(s2.properties)) {
|
|
3819
|
+
let props = s2.properties, required = Array.isArray(s2.required) ? s2.required.filter((name) => typeof name == "string") : [];
|
|
3820
|
+
if (Object.keys(props).length === 0)
|
|
3821
|
+
return `${indent}(no parameters)`;
|
|
3822
|
+
let lines2 = [];
|
|
3823
|
+
for (let [name, propSchema] of Object.entries(props))
|
|
3824
|
+
lines2.push(...formatProperty(name, propSchema, required.includes(name), indent));
|
|
3825
|
+
return lines2.join(`
|
|
3826
|
+
`);
|
|
3827
|
+
}
|
|
3828
|
+
let lines = formatNestedSchema(s2, indent);
|
|
3829
|
+
if (lines.length > 0)
|
|
3830
|
+
return lines.join(`
|
|
3831
|
+
`);
|
|
3832
|
+
let typeStr = formatType(s2);
|
|
3833
|
+
return typeStr ? `${indent}(${typeStr})` : `${indent}(complex schema)`;
|
|
3834
|
+
}
|
|
3835
|
+
function formatProperty(name, schema, required, indent) {
|
|
3836
|
+
if (!schema || typeof schema != "object" || Array.isArray(schema))
|
|
3837
|
+
return [`${indent}${name}${required ? " *required*" : ""}`];
|
|
3838
|
+
let s2 = schema, parts = [`${indent}${name}`], typeStr = formatType(s2);
|
|
3839
|
+
return typeStr && parts.push(`(${typeStr})`), required && parts.push("*required*"), appendSchemaAnnotations(parts, s2), [parts.join(" "), ...formatNestedSchema(s2, `${indent} `)];
|
|
3840
|
+
}
|
|
3841
|
+
function formatNestedSchema(schema, indent) {
|
|
3842
|
+
let lines = [];
|
|
3843
|
+
if (Array.isArray(schema.anyOf) && lines.push(...formatVariants("anyOf", schema.anyOf, indent)), Array.isArray(schema.oneOf) && lines.push(...formatVariants("oneOf", schema.oneOf, indent)), schema.items !== void 0 && lines.push(...formatProperty("items", schema.items, !1, indent)), schema.properties && typeof schema.properties == "object" && !Array.isArray(schema.properties)) {
|
|
3844
|
+
let required = Array.isArray(schema.required) ? schema.required.filter((name) => typeof name == "string") : [];
|
|
3845
|
+
for (let [name, propSchema] of Object.entries(schema.properties))
|
|
3846
|
+
lines.push(...formatProperty(name, propSchema, required.includes(name), indent));
|
|
3847
|
+
}
|
|
3848
|
+
return lines;
|
|
3849
|
+
}
|
|
3850
|
+
function formatVariants(keyword, variants, indent) {
|
|
3851
|
+
let lines = [`${indent}${keyword}:`];
|
|
3852
|
+
for (let variant of variants) {
|
|
3853
|
+
if (!variant || typeof variant != "object" || Array.isArray(variant)) {
|
|
3854
|
+
lines.push(`${indent} - ${JSON.stringify(variant)}`);
|
|
3855
|
+
continue;
|
|
3856
|
+
}
|
|
3857
|
+
let s2 = variant, typeStr = formatType(s2) || "schema", parts = [`${indent} - ${typeStr}`];
|
|
3858
|
+
appendSchemaAnnotations(parts, s2), lines.push(parts.join(" ")), lines.push(...formatNestedSchema(s2, `${indent} `));
|
|
3859
|
+
}
|
|
3860
|
+
return lines;
|
|
3861
|
+
}
|
|
3862
|
+
function formatType(schema) {
|
|
3863
|
+
return Object.hasOwn(schema, "const") ? `const ${JSON.stringify(schema.const)}` : Array.isArray(schema.enum) ? `enum: ${schema.enum.map((v2) => JSON.stringify(v2)).join(", ")}` : Array.isArray(schema.type) ? schema.type.map((type) => String(type)).join(" | ") : schema.type ? String(schema.type) : schema.properties && typeof schema.properties == "object" && !Array.isArray(schema.properties) ? "object" : schema.items !== void 0 ? "array" : "";
|
|
3864
|
+
}
|
|
3865
|
+
function appendSchemaAnnotations(parts, schema) {
|
|
3866
|
+
schema.description && typeof schema.description == "string" && parts.push(`- ${schema.description}`);
|
|
3867
|
+
for (let key of ["minLength", "maxLength", "minimum", "maximum", "minItems", "maxItems", "format", "pattern"])
|
|
3868
|
+
schema[key] !== void 0 && parts.push(`[${key}: ${JSON.stringify(schema[key])}]`);
|
|
3869
|
+
schema.default !== void 0 && parts.push(`[default: ${JSON.stringify(schema.default)}]`);
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/ui-resource-handler.js
|
|
3873
|
+
var UiResourceHandler = class {
|
|
3874
|
+
manager;
|
|
3875
|
+
log = logger.child({ component: "UiResourceHandler" });
|
|
3876
|
+
constructor(manager) {
|
|
3877
|
+
this.manager = manager;
|
|
3878
|
+
}
|
|
3879
|
+
async readUiResource(serverName, uri) {
|
|
3880
|
+
let log = this.log.child({ server: serverName, uri });
|
|
3881
|
+
if (!uri.startsWith("ui://"))
|
|
3882
|
+
throw new ResourceParseError(uri, "URI must start with ui://", { server: serverName });
|
|
3883
|
+
log.debug("Fetching UI resource");
|
|
3884
|
+
let result;
|
|
3885
|
+
try {
|
|
3886
|
+
result = await this.manager.readResource(serverName, uri);
|
|
3887
|
+
} catch (error) {
|
|
3888
|
+
if (error instanceof UrlElicitationRequiredError)
|
|
3889
|
+
throw error;
|
|
3890
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
3891
|
+
throw log.error("Failed to read resource", error instanceof Error ? error : void 0), new ResourceFetchError(uri, message, {
|
|
3892
|
+
server: serverName,
|
|
3893
|
+
cause: error instanceof Error ? error : void 0
|
|
3894
|
+
});
|
|
3895
|
+
}
|
|
3896
|
+
let content = selectContent(result, uri), mimeType = content.mimeType;
|
|
3897
|
+
if (mimeType && !isHtmlMimeType(mimeType))
|
|
3898
|
+
throw log.warn("Unsupported MIME type", { mimeType }), new ResourceParseError(uri, `unsupported MIME type "${mimeType}" (expected text/html or ${pQ})`, { server: serverName, mimeType });
|
|
3899
|
+
let html = toHtml(content);
|
|
3900
|
+
if (!html.trim())
|
|
3901
|
+
throw log.warn("Resource content is empty"), new ResourceParseError(uri, "content is empty", { server: serverName });
|
|
3902
|
+
let contentMeta = extractUiMeta(content._meta), listMeta = extractUiMeta(this.getListResourceMeta(serverName, uri));
|
|
3903
|
+
return log.debug("Resource loaded successfully", {
|
|
3904
|
+
contentLength: html.length,
|
|
3905
|
+
hasCsp: !!contentMeta.csp || !!listMeta.csp
|
|
3906
|
+
}), {
|
|
3907
|
+
uri: content.uri ?? uri,
|
|
3908
|
+
html,
|
|
3909
|
+
mimeType: mimeType ?? pQ,
|
|
3910
|
+
meta: {
|
|
3911
|
+
csp: contentMeta.csp ?? listMeta.csp,
|
|
3912
|
+
permissions: contentMeta.permissions ?? listMeta.permissions,
|
|
3913
|
+
domain: contentMeta.domain ?? listMeta.domain,
|
|
3914
|
+
prefersBorder: contentMeta.prefersBorder ?? listMeta.prefersBorder
|
|
3915
|
+
}
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
getListResourceMeta(serverName, uri) {
|
|
3919
|
+
let connection = this.manager.getConnection(serverName);
|
|
3920
|
+
if (!connection?.resources?.length)
|
|
3921
|
+
return;
|
|
3922
|
+
let resource = connection.resources.find((entry) => entry.uri === uri);
|
|
3923
|
+
if (!(!resource || !resource._meta || typeof resource._meta != "object"))
|
|
3924
|
+
return resource._meta;
|
|
3925
|
+
}
|
|
3926
|
+
};
|
|
3927
|
+
function selectContent(result, preferredUri) {
|
|
3928
|
+
let contents = result.contents ?? [];
|
|
3929
|
+
if (contents.length === 0)
|
|
3930
|
+
throw new Error(`No contents returned for UI resource: ${preferredUri}`);
|
|
3931
|
+
let byUri = contents.find((content) => content.uri === preferredUri);
|
|
3932
|
+
if (byUri)
|
|
3933
|
+
return byUri;
|
|
3934
|
+
let byHtmlMime = contents.find((content) => content.mimeType && isHtmlMimeType(content.mimeType));
|
|
3935
|
+
return byHtmlMime || contents[0];
|
|
3936
|
+
}
|
|
3937
|
+
function isHtmlMimeType(mimeType) {
|
|
3938
|
+
let normalized = mimeType.toLowerCase();
|
|
3939
|
+
return normalized.startsWith("text/html") || normalized === pQ.toLowerCase();
|
|
3940
|
+
}
|
|
3941
|
+
function toHtml(content) {
|
|
3942
|
+
if (typeof content.text == "string")
|
|
3943
|
+
return content.text;
|
|
3944
|
+
if (typeof content.blob == "string")
|
|
3945
|
+
return Buffer.from(content.blob, "base64").toString("utf-8");
|
|
3946
|
+
throw new Error(`UI resource ${content.uri ?? "(unknown)"} did not include text or blob content`);
|
|
3947
|
+
}
|
|
3948
|
+
function extractUiMeta(meta) {
|
|
3949
|
+
if (!meta || typeof meta != "object")
|
|
3950
|
+
return {};
|
|
3951
|
+
let ui = meta.ui;
|
|
3952
|
+
if (!ui || typeof ui != "object")
|
|
3953
|
+
return {};
|
|
3954
|
+
let out = {};
|
|
3955
|
+
return ui.csp && typeof ui.csp == "object" && (out.csp = ui.csp), ui.permissions && typeof ui.permissions == "object" && (out.permissions = ui.permissions), typeof ui.domain == "string" && (out.domain = ui.domain), typeof ui.prefersBorder == "boolean" && (out.prefersBorder = ui.prefersBorder), out;
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
// packages/coding-agent/dist/builtin-extensions/pi-mcp-adapter/init.js
|
|
3959
|
+
var FAILURE_BACKOFF_MS = 60 * 1e3;
|
|
3960
|
+
function isTuiMode(ctx) {
|
|
3961
|
+
return ctx.hasUI && ctx.mode === "tui";
|
|
3962
|
+
}
|
|
3963
|
+
async function initializeMcp(pi, ctx, options = {}) {
|
|
3964
|
+
let signal = options.signal ?? ctx.signal;
|
|
3965
|
+
throwIfAborted(signal);
|
|
3966
|
+
let configPath = pi.getFlag("mcp-config"), config = loadMcpConfig(configPath, ctx.cwd, ctx.isProjectTrusted()), manager = new McpServerManager(ctx.cwd);
|
|
3967
|
+
manager.setDefaultRequestTimeoutMs(config.settings?.requestTimeoutMs);
|
|
3968
|
+
let samplingAutoApprove = config.settings?.samplingAutoApprove === !0;
|
|
3969
|
+
config.settings?.sampling !== !1 && (ctx.hasUI || samplingAutoApprove) && manager.setSamplingConfig({
|
|
3970
|
+
autoApprove: samplingAutoApprove,
|
|
3971
|
+
ui: ctx.hasUI ? ctx.ui : void 0,
|
|
3972
|
+
modelRegistry: ctx.modelRegistry,
|
|
3973
|
+
getCurrentModel: () => ctx.model,
|
|
3974
|
+
getSignal: () => ctx.signal
|
|
3975
|
+
}), config.settings?.elicitation !== !1 && ctx.hasUI && manager.setElicitationConfig({
|
|
3976
|
+
ui: ctx.ui,
|
|
3977
|
+
allowUrl: isTuiMode(ctx)
|
|
3978
|
+
});
|
|
3979
|
+
let lifecycle = new McpLifecycleManager(manager), toolMetadata = /* @__PURE__ */ new Map(), failureTracker = /* @__PURE__ */ new Map(), uiResourceHandler = new UiResourceHandler(manager), consentManager = new ConsentManager("once-per-server"), ui = ctx.hasUI ? ctx.ui : void 0, state = {
|
|
3980
|
+
authFlow: createMcpAuthFlow(),
|
|
3981
|
+
manager,
|
|
3982
|
+
lifecycle,
|
|
3983
|
+
toolMetadata,
|
|
3984
|
+
config,
|
|
3985
|
+
failureTracker,
|
|
3986
|
+
uiResourceHandler,
|
|
3987
|
+
consentManager,
|
|
3988
|
+
uiServer: null,
|
|
3989
|
+
completedUiSessions: [],
|
|
3990
|
+
openBrowser: (url2) => openUrl(pi, url2, process.env.BROWSER),
|
|
3991
|
+
ui,
|
|
3992
|
+
sendMessage: (message, options2) => pi.sendMessage(message, options2)
|
|
3993
|
+
};
|
|
3994
|
+
options.onState?.(state);
|
|
3995
|
+
let serverEntries = Object.entries(config.mcpServers);
|
|
3996
|
+
if (serverEntries.length === 0)
|
|
3997
|
+
return state;
|
|
3998
|
+
let idleSetting = typeof config.settings?.idleTimeout == "number" ? config.settings.idleTimeout : 10;
|
|
3999
|
+
lifecycle.setGlobalIdleTimeout(idleSetting);
|
|
4000
|
+
let cachePath = getMetadataCachePath(), cacheFileExists = existsSync3(cachePath), cache = loadMetadataCache(), bootstrapAll = !1;
|
|
4001
|
+
cacheFileExists ? cache || (cache = { version: 1, servers: {} }, saveMetadataCache(cache)) : (bootstrapAll = !0, saveMetadataCache({ version: 1, servers: {} }));
|
|
4002
|
+
let prefix = config.settings?.toolPrefix ?? "server";
|
|
4003
|
+
for (let [name, definition] of serverEntries) {
|
|
4004
|
+
let lifecycleMode = definition.lifecycle ?? "lazy", idleOverride = definition.idleTimeout ?? (lifecycleMode === "eager" ? 0 : void 0);
|
|
4005
|
+
if (lifecycle.registerServer(name, definition, idleOverride !== void 0 ? { idleTimeout: idleOverride } : void 0), lifecycleMode === "keep-alive" && lifecycle.markKeepAlive(name, definition), cache?.servers?.[name] && isServerCacheValid(cache.servers[name], definition)) {
|
|
4006
|
+
let metadata = reconstructToolMetadata(name, cache.servers[name], prefix, definition);
|
|
4007
|
+
toolMetadata.set(name, metadata);
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
let startupServers = bootstrapAll ? serverEntries : serverEntries.filter(([, definition]) => {
|
|
4011
|
+
let mode = definition.lifecycle ?? "lazy";
|
|
4012
|
+
return mode === "keep-alive" || mode === "eager";
|
|
4013
|
+
});
|
|
4014
|
+
ctx.hasUI && startupServers.length > 0 && ctx.ui.setStatus("mcp", `MCP: connecting to ${startupServers.length} servers...`);
|
|
4015
|
+
let results = await parallelLimit(startupServers, 10, async ([name, definition]) => {
|
|
4016
|
+
try {
|
|
4017
|
+
throwIfAborted(signal);
|
|
4018
|
+
let connection = await manager.connect(name, definition, signal);
|
|
4019
|
+
return connection.status === "needs-auth" ? { name, definition, connection: null, error: `OAuth authentication required. Run /mcp-auth ${name}.` } : { name, definition, connection, error: null };
|
|
4020
|
+
} catch (error) {
|
|
4021
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
4022
|
+
return { name, definition, connection: null, error: message };
|
|
4023
|
+
}
|
|
4024
|
+
});
|
|
4025
|
+
throwIfAborted(signal);
|
|
4026
|
+
for (let { name, definition, connection, error } of results) {
|
|
4027
|
+
if (error || !connection) {
|
|
4028
|
+
ctx.hasUI && ctx.ui.notify(`MCP: Failed to connect to ${name}: ${error}`, "error"), console.error(`MCP: Failed to connect to ${name}: ${error}`);
|
|
4029
|
+
continue;
|
|
4030
|
+
}
|
|
4031
|
+
let { metadata, failedTools } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);
|
|
4032
|
+
toolMetadata.set(name, metadata), updateMetadataCache(state, name), failedTools.length > 0 && ctx.hasUI && ctx.ui.notify(`MCP: ${name} - ${failedTools.length} tools skipped`, "warning");
|
|
4033
|
+
}
|
|
4034
|
+
let connectedCount = results.filter((r2) => r2.connection).length, failedCount = results.filter((r2) => r2.error).length;
|
|
4035
|
+
if (ctx.hasUI && connectedCount > 0) {
|
|
4036
|
+
let totalTools = totalToolCount(state), msg = failedCount > 0 ? `MCP: ${connectedCount}/${startupServers.length} servers connected (${totalTools} tools)` : `MCP: ${connectedCount} servers connected (${totalTools} tools)`;
|
|
4037
|
+
ctx.ui.notify(msg, "info");
|
|
4038
|
+
}
|
|
4039
|
+
if (process.env.MCP_DIRECT_TOOLS !== "__none__") {
|
|
4040
|
+
let currentCache = loadMetadataCache(), missingCacheServers = getMissingConfiguredDirectToolServers(config, currentCache);
|
|
4041
|
+
if (missingCacheServers.length > 0) {
|
|
4042
|
+
let bootstrapResults = await parallelLimit(missingCacheServers.filter((name) => !results.some((r2) => r2.name === name && r2.connection)), 10, async (name) => {
|
|
4043
|
+
let definition = config.mcpServers[name];
|
|
4044
|
+
try {
|
|
4045
|
+
throwIfAborted(signal);
|
|
4046
|
+
let connection = await manager.connect(name, definition, signal);
|
|
4047
|
+
if (connection.status === "needs-auth")
|
|
4048
|
+
return { name, ok: !1 };
|
|
4049
|
+
let { metadata } = buildToolMetadata(connection.tools, connection.resources, definition, name, prefix);
|
|
4050
|
+
return toolMetadata.set(name, metadata), updateMetadataCache(state, name), { name, ok: !0 };
|
|
4051
|
+
} catch (error) {
|
|
4052
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
4053
|
+
return logger.debug(`MCP: direct-tools bootstrap failed for ${name}: ${message}`), { name, ok: !1 };
|
|
4054
|
+
}
|
|
4055
|
+
});
|
|
4056
|
+
throwIfAborted(signal);
|
|
4057
|
+
let bootstrapped = bootstrapResults.filter((r2) => r2.ok).map((r2) => r2.name);
|
|
4058
|
+
bootstrapped.length > 0 && ctx.hasUI && ctx.ui.notify(`MCP: direct tools for ${bootstrapped.join(", ")} will be available after restart`, "info");
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
return lifecycle.setReconnectCallback((serverName) => {
|
|
4062
|
+
updateServerMetadata(state, serverName), updateMetadataCache(state, serverName), state.failureTracker.delete(serverName), updateStatusBar(state);
|
|
4063
|
+
}), lifecycle.setIdleShutdownCallback((serverName) => {
|
|
4064
|
+
let idleMinutes = getEffectiveIdleTimeoutMinutes(state, serverName);
|
|
4065
|
+
logger.debug(`${serverName} shut down (idle ${idleMinutes}m)`), updateStatusBar(state);
|
|
4066
|
+
}), lifecycle.startHealthChecks(), state;
|
|
4067
|
+
}
|
|
4068
|
+
function updateServerMetadata(state, serverName) {
|
|
4069
|
+
let connection = state.manager.getConnection(serverName);
|
|
4070
|
+
if (!connection || connection.status !== "connected")
|
|
4071
|
+
return;
|
|
4072
|
+
let definition = state.config.mcpServers[serverName];
|
|
4073
|
+
if (!definition)
|
|
4074
|
+
return;
|
|
4075
|
+
let prefix = state.config.settings?.toolPrefix ?? "server", { metadata } = buildToolMetadata(connection.tools, connection.resources, definition, serverName, prefix);
|
|
4076
|
+
state.toolMetadata.set(serverName, metadata);
|
|
4077
|
+
}
|
|
4078
|
+
function updateMetadataCache(state, serverName) {
|
|
4079
|
+
let connection = state.manager.getConnection(serverName);
|
|
4080
|
+
if (!connection || connection.status !== "connected")
|
|
4081
|
+
return;
|
|
4082
|
+
let definition = state.config.mcpServers[serverName];
|
|
4083
|
+
if (!definition)
|
|
4084
|
+
return;
|
|
4085
|
+
let configHash = computeServerHash(definition), existingEntry = loadMetadataCache()?.servers?.[serverName], tools = serializeTools(connection.tools), resources = definition.exposeResources === !1 ? [] : serializeResources(connection.resources);
|
|
4086
|
+
definition.exposeResources !== !1 && resources.length === 0 && existingEntry?.resources?.length && existingEntry.configHash === configHash && (resources = existingEntry.resources);
|
|
4087
|
+
let entry = {
|
|
4088
|
+
configHash,
|
|
4089
|
+
tools,
|
|
4090
|
+
resources,
|
|
4091
|
+
cachedAt: Date.now()
|
|
4092
|
+
};
|
|
4093
|
+
saveMetadataCache({ version: 1, servers: { [serverName]: entry } });
|
|
4094
|
+
}
|
|
4095
|
+
function flushMetadataCache(state) {
|
|
4096
|
+
for (let [name, connection] of state.manager.getAllConnections())
|
|
4097
|
+
connection.status === "connected" && updateMetadataCache(state, name);
|
|
4098
|
+
}
|
|
4099
|
+
function updateStatusBar(state) {
|
|
4100
|
+
let ui = state.ui;
|
|
4101
|
+
if (!ui)
|
|
4102
|
+
return;
|
|
4103
|
+
let total = Object.keys(state.config.mcpServers).length;
|
|
4104
|
+
if (total === 0) {
|
|
4105
|
+
ui.setStatus("mcp", void 0);
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4108
|
+
let connectedCount = state.manager.getAllConnections().size;
|
|
4109
|
+
ui.setStatus("mcp", ui.theme.fg("accent", `MCP: ${connectedCount}/${total} servers`));
|
|
4110
|
+
}
|
|
4111
|
+
function getFailureAgeSeconds(state, serverName) {
|
|
4112
|
+
let failedAt = state.failureTracker.get(serverName);
|
|
4113
|
+
if (!failedAt)
|
|
4114
|
+
return null;
|
|
4115
|
+
let ageMs = Date.now() - failedAt;
|
|
4116
|
+
return ageMs > FAILURE_BACKOFF_MS ? null : Math.round(ageMs / 1e3);
|
|
4117
|
+
}
|
|
4118
|
+
async function lazyConnect(state, serverName, signal) {
|
|
4119
|
+
let connection = state.manager.getConnection(serverName);
|
|
4120
|
+
if (connection?.status === "needs-auth")
|
|
4121
|
+
return !1;
|
|
4122
|
+
if (connection?.status === "connected")
|
|
4123
|
+
return updateServerMetadata(state, serverName), !0;
|
|
4124
|
+
if (getFailureAgeSeconds(state, serverName) !== null)
|
|
4125
|
+
return !1;
|
|
4126
|
+
let definition = state.config.mcpServers[serverName];
|
|
4127
|
+
if (!definition)
|
|
4128
|
+
return !1;
|
|
4129
|
+
try {
|
|
4130
|
+
return state.ui && state.ui.setStatus("mcp", `MCP: connecting to ${serverName}...`), (await state.manager.connect(serverName, definition, signal)).status === "needs-auth" ? !1 : (state.failureTracker.delete(serverName), updateServerMetadata(state, serverName), updateMetadataCache(state, serverName), updateStatusBar(state), !0);
|
|
4131
|
+
} catch (error) {
|
|
4132
|
+
signal?.aborted && throwIfAborted(signal), state.failureTracker.set(serverName, Date.now());
|
|
4133
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
4134
|
+
return logger.debug(`MCP: lazy connect failed for ${serverName}: ${message}`), updateStatusBar(state), !1;
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
function getEffectiveIdleTimeoutMinutes(state, serverName) {
|
|
4138
|
+
let definition = state.config.mcpServers[serverName];
|
|
4139
|
+
return definition ? typeof definition.idleTimeout == "number" ? definition.idleTimeout : (definition.lifecycle ?? "lazy") === "eager" ? 0 : typeof state.config.settings?.idleTimeout == "number" ? state.config.settings.idleTimeout : 10 : typeof state.config.settings?.idleTimeout == "number" ? state.config.settings.idleTimeout : 10;
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
export {
|
|
4143
|
+
getAuthForUrl,
|
|
4144
|
+
supportsOAuth,
|
|
4145
|
+
ServerError2 as ServerError,
|
|
4146
|
+
wrapError,
|
|
4147
|
+
logger,
|
|
4148
|
+
AZ,
|
|
4149
|
+
buildToolMetadata,
|
|
4150
|
+
getToolNames,
|
|
4151
|
+
findToolByName,
|
|
4152
|
+
formatSchema,
|
|
4153
|
+
isTuiMode,
|
|
4154
|
+
initializeMcp,
|
|
4155
|
+
updateServerMetadata,
|
|
4156
|
+
updateMetadataCache,
|
|
4157
|
+
flushMetadataCache,
|
|
4158
|
+
updateStatusBar,
|
|
4159
|
+
getFailureAgeSeconds,
|
|
4160
|
+
lazyConnect
|
|
4161
|
+
};
|
|
4162
|
+
/*! Bundled license information:
|
|
4163
|
+
|
|
4164
|
+
content-type/index.js:
|
|
4165
|
+
(*!
|
|
4166
|
+
* content-type
|
|
4167
|
+
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
4168
|
+
* MIT Licensed
|
|
4169
|
+
*)
|
|
4170
|
+
*/
|