@gajae-code/coding-agent 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -2
- package/dist/types/append-only-mode.d.ts +1 -1
- package/dist/types/cli/args.d.ts +4 -5
- package/dist/types/cli/daemon-cli.d.ts +12 -1
- package/dist/types/cli/notify-cli.d.ts +21 -1
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +39 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/commands/notify.d.ts +28 -1
- package/dist/types/commands/sdk.d.ts +33 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
- package/dist/types/config/model-profile-activation.d.ts +35 -15
- package/dist/types/config/model-profiles.d.ts +11 -5
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/model-resolver.d.ts +39 -6
- package/dist/types/config/model-selector-value.d.ts +17 -0
- package/dist/types/config/models-config-schema.d.ts +10 -6
- package/dist/types/config/settings-schema.d.ts +133 -6
- package/dist/types/config/settings.d.ts +63 -35
- package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
- package/dist/types/coordinator-mcp/server.d.ts +6 -49
- package/dist/types/daemon/builtin.d.ts +6 -5
- package/dist/types/daemon/control-types.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +12 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
- package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +10 -1
- package/dist/types/extensibility/extensions/runner.d.ts +3 -3
- package/dist/types/extensibility/extensions/types.d.ts +141 -16
- package/dist/types/extensibility/hooks/types.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
- package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
- package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
- package/dist/types/harness-control-plane/operate.d.ts +5 -5
- package/dist/types/harness-control-plane/owner.d.ts +18 -4
- package/dist/types/harness-control-plane/receipts.d.ts +0 -1
- package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
- package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
- package/dist/types/harness-control-plane/types.d.ts +3 -4
- package/dist/types/lsp/index.d.ts +1 -1
- package/dist/types/main.d.ts +32 -38
- package/dist/types/modes/acp/acp-agent.d.ts +224 -53
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
- package/dist/types/modes/acp/acp-mode.d.ts +6 -15
- package/dist/types/modes/acp/permission-mode.d.ts +4 -0
- package/dist/types/modes/acp/startup-options.d.ts +6 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
- package/dist/types/modes/components/model-selector.d.ts +1 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
- package/dist/types/modes/components/settings-selector.d.ts +6 -4
- package/dist/types/modes/components/welcome.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
- package/dist/types/modes/index.d.ts +0 -4
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/runtime-init.d.ts +2 -2
- package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
- package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
- package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
- package/dist/types/modes/types.d.ts +5 -0
- package/dist/types/runtime-mcp/client.d.ts +2 -0
- package/dist/types/runtime-mcp/config.d.ts +5 -1
- package/dist/types/runtime-mcp/manager.d.ts +8 -1
- package/dist/types/runtime-mcp/types.d.ts +4 -0
- package/dist/types/sdk/acp/adapter.d.ts +67 -0
- package/dist/types/sdk/acp/index.d.ts +2 -0
- package/dist/types/sdk/broker/broker.d.ts +53 -0
- package/dist/types/sdk/broker/discovery.d.ts +30 -0
- package/dist/types/sdk/broker/ensure.d.ts +33 -0
- package/dist/types/sdk/broker/identity.d.ts +3 -0
- package/dist/types/sdk/broker/index.d.ts +8 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
- package/dist/types/sdk/broker/runtime.d.ts +33 -0
- package/dist/types/sdk/broker/session-index.d.ts +57 -0
- package/dist/types/sdk/broker/state-version.d.ts +8 -0
- package/dist/types/sdk/broker/transport.d.ts +9 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
- package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
- package/dist/types/sdk/bus/config.d.ts +274 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
- package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
- package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
- package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
- package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
- package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
- package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
- package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
- package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
- package/dist/types/sdk/bus/session-control.d.ts +83 -0
- package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
- package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
- package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
- package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
- package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
- package/dist/types/sdk/cli/index.d.ts +1 -0
- package/dist/types/sdk/cli/session-cli.d.ts +19 -0
- package/dist/types/sdk/client/client.d.ts +1 -0
- package/dist/types/sdk/client/discovery.d.ts +27 -0
- package/dist/types/sdk/client/index.d.ts +2 -0
- package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
- package/dist/types/sdk/host/control/index.d.ts +2 -0
- package/dist/types/sdk/host/control/operations.d.ts +65 -0
- package/dist/types/sdk/host/events.d.ts +35 -0
- package/dist/types/sdk/host/host.d.ts +35 -0
- package/dist/types/sdk/host/index.d.ts +4 -0
- package/dist/types/sdk/host/query/cursor.d.ts +62 -0
- package/dist/types/sdk/host/query/handlers.d.ts +70 -0
- package/dist/types/sdk/host/query/index.d.ts +3 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
- package/dist/types/sdk/host/types.d.ts +32 -0
- package/dist/types/sdk/index.d.ts +6 -0
- package/dist/types/sdk/lifecycle-session.d.ts +14 -0
- package/dist/types/sdk/mcp/index.d.ts +1 -0
- package/dist/types/sdk/mcp/server.d.ts +37 -0
- package/dist/types/sdk/models.d.ts +44 -0
- package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
- package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
- package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
- package/dist/types/sdk/startup-capability.d.ts +50 -0
- package/dist/types/session/agent-session.d.ts +114 -21
- package/dist/types/session/default-model-selection.d.ts +25 -0
- package/dist/types/session/fallback-chain-controller.d.ts +52 -0
- package/dist/types/session/session-manager.d.ts +58 -1
- package/dist/types/setup/credential-auto-import.d.ts +36 -6
- package/dist/types/tools/ask-answer-registry.d.ts +1 -1
- package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
- package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
- package/dist/types/tools/browser/launch.d.ts +22 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
- package/dist/types/tools/browser/profile-posture.d.ts +37 -0
- package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
- package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
- package/dist/types/tools/browser/registry.d.ts +19 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +8 -8
- package/package.json +34 -13
- package/scripts/build-sdk-package-smoke.ts +94 -0
- package/scripts/capture-notifications-settings-showcase.ts +435 -0
- package/scripts/compile-args.ts +4 -2
- package/scripts/g005-daemon-smoke.ts +4 -5
- package/scripts/g011-daemon-path-smoke.ts +5 -5
- package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
- package/scripts/generate-sdk-operation-inventory.ts +867 -0
- package/scripts/generate-telegram-baseline-manifest.ts +128 -0
- package/scripts/manifest-schema.ts +124 -0
- package/scripts/run-test-manifest.ts +153 -0
- package/scripts/run-threat-model-check.ts +157 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
- package/scripts/verify-gjc-sdk-rename.ts +90 -0
- package/src/append-only-mode.ts +1 -1
- package/src/cli/args.ts +43 -12
- package/src/cli/auth-gateway-cli.ts +2 -2
- package/src/cli/config-cli.ts +2 -1
- package/src/cli/daemon-cli.ts +63 -14
- package/src/cli/list-models.ts +1 -1
- package/src/cli/notify-cli.ts +288 -286
- package/src/cli.ts +21 -2
- package/src/commands/daemon.ts +50 -6
- package/src/commands/harness.ts +93 -36
- package/src/commands/launch.ts +5 -2
- package/src/commands/mcp-serve.ts +19 -12
- package/src/commands/notify.ts +36 -3
- package/src/commands/sdk.ts +426 -0
- package/src/commit/agentic/agent.ts +1 -0
- package/src/config/atomic-yaml-patch.ts +423 -0
- package/src/config/model-profile-activation.ts +240 -89
- package/src/config/model-profiles.ts +18 -15
- package/src/config/model-registry.ts +51 -26
- package/src/config/model-resolver.ts +138 -51
- package/src/config/model-selector-value.ts +50 -0
- package/src/config/models-config-schema.ts +14 -21
- package/src/config/settings-schema.ts +128 -10
- package/src/config/settings.ts +1120 -158
- package/src/coordinator-mcp/model-preset.ts +74 -20
- package/src/coordinator-mcp/server.ts +1597 -3052
- package/src/daemon/builtin.ts +8 -5
- package/src/daemon/control-types.ts +1 -1
- package/src/defaults/gjc/skills/team/SKILL.md +4 -4
- package/src/discovery/mcp-json.ts +327 -20
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/compact-handler.ts +3 -3
- package/src/extensibility/extensions/get-commands-handler.ts +2 -2
- package/src/extensibility/extensions/loader.ts +69 -5
- package/src/extensibility/extensions/runner.ts +112 -4
- package/src/extensibility/extensions/types.ts +176 -17
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/gjc-runtime/launch-tmux.ts +170 -86
- package/src/gjc-runtime/psmux-detect.ts +82 -4
- package/src/gjc-runtime/session-state-sidecar.ts +41 -31
- package/src/gjc-runtime/team-runtime.ts +54 -35
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
- package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
- package/src/gjc-runtime/tmux-sessions.ts +19 -13
- package/src/gjc-runtime/ultragoal-guard.ts +53 -6
- package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
- package/src/gjc-runtime/windows-powershell-command.ts +58 -0
- package/src/harness-control-plane/operate.ts +9 -9
- package/src/harness-control-plane/owner.ts +283 -39
- package/src/harness-control-plane/receipts.ts +0 -1
- package/src/harness-control-plane/sdk-transport.ts +395 -0
- package/src/harness-control-plane/session-transport.ts +94 -0
- package/src/harness-control-plane/types.ts +1 -1
- package/src/internal-urls/docs-index.generated.ts +34 -35
- package/src/lsp/client.ts +42 -6
- package/src/lsp/index.ts +2 -2
- package/src/main.ts +299 -204
- package/src/modes/DESIGN.md +258 -0
- package/src/modes/acp/acp-agent.ts +1228 -2612
- package/src/modes/acp/acp-client-bridge.ts +2 -20
- package/src/modes/acp/acp-event-mapper.ts +18 -2
- package/src/modes/acp/acp-mode.ts +8 -36
- package/src/modes/acp/permission-mode.ts +25 -0
- package/src/modes/acp/startup-options.ts +6 -0
- package/src/modes/components/agent-dashboard.ts +37 -17
- package/src/modes/components/model-selector.ts +93 -35
- package/src/modes/components/notifications-settings-editor.ts +1379 -0
- package/src/modes/components/settings-selector.ts +60 -11
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +1 -2
- package/src/modes/controllers/event-controller.ts +11 -16
- package/src/modes/controllers/extension-ui-controller.ts +348 -4
- package/src/modes/controllers/selector-controller.ts +674 -36
- package/src/modes/index.ts +0 -22
- package/src/modes/interactive-mode.ts +59 -20
- package/src/modes/runtime-init.ts +298 -6
- package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
- package/src/modes/shared/agent-wire/event-contract.ts +7 -8
- package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
- package/src/modes/shared/agent-wire/event-observation.ts +16 -7
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
- package/src/modes/types.ts +5 -0
- package/src/runtime-mcp/client.ts +94 -19
- package/src/runtime-mcp/config.ts +27 -15
- package/src/runtime-mcp/manager.ts +343 -105
- package/src/runtime-mcp/oauth-flow.ts +42 -12
- package/src/runtime-mcp/transports/http.ts +49 -19
- package/src/runtime-mcp/transports/stdio.ts +47 -28
- package/src/runtime-mcp/types.ts +10 -0
- package/src/sdk/acp/adapter.ts +418 -0
- package/src/sdk/acp/index.ts +2 -0
- package/src/sdk/broker/broker.ts +642 -0
- package/src/sdk/broker/discovery.ts +94 -0
- package/src/sdk/broker/ensure.ts +249 -0
- package/src/sdk/broker/identity.ts +42 -0
- package/src/sdk/broker/index.ts +8 -0
- package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
- package/src/sdk/broker/internal-source.bunfig.toml +1 -0
- package/src/sdk/broker/lifecycle-ledger.ts +286 -0
- package/src/sdk/broker/lifecycle.ts +2157 -0
- package/src/sdk/broker/process-incarnation.ts +159 -0
- package/src/sdk/broker/runtime.ts +164 -0
- package/src/sdk/broker/session-index.ts +318 -0
- package/src/sdk/broker/state-version.ts +23 -0
- package/src/sdk/broker/transport.ts +125 -0
- package/src/sdk/bus/chat-command-policy.ts +107 -0
- package/src/sdk/bus/chat-daemon-cli.ts +214 -0
- package/src/sdk/bus/chat-daemon-control.ts +713 -0
- package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
- package/src/sdk/bus/chat-effect-journal.ts +353 -0
- package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
- package/src/sdk/bus/config.ts +433 -0
- package/src/sdk/bus/conversation-store.ts +391 -0
- package/src/sdk/bus/discord-conversation.ts +85 -0
- package/src/sdk/bus/discord-daemon.ts +2275 -0
- package/src/sdk/bus/discord-live-provider.ts +521 -0
- package/src/sdk/bus/discord-provider.ts +56 -0
- package/src/{notifications → sdk/bus}/html-format.ts +2 -2
- package/src/sdk/bus/index.ts +3943 -0
- package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
- package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
- package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
- package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
- package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
- package/src/sdk/bus/natives-augment.d.ts +38 -0
- package/src/sdk/bus/notification-orchestration.ts +535 -0
- package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
- package/src/sdk/bus/session-control.ts +333 -0
- package/src/sdk/bus/slack-conversation.ts +74 -0
- package/src/sdk/bus/slack-daemon.ts +2144 -0
- package/src/sdk/bus/slack-live-provider.ts +380 -0
- package/src/sdk/bus/slack-provider.ts +76 -0
- package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
- package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
- package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
- package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
- package/src/sdk/bus/telegram-setup.ts +663 -0
- package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
- package/src/sdk/cli/index.ts +1 -0
- package/src/sdk/cli/session-cli.ts +275 -0
- package/src/sdk/client/client.ts +1 -0
- package/src/sdk/client/discovery.ts +108 -0
- package/src/sdk/client/index.ts +2 -0
- package/src/sdk/host/control/dispatch.ts +367 -0
- package/src/sdk/host/control/index.ts +10 -0
- package/src/sdk/host/control/operations.ts +63 -0
- package/src/sdk/host/events.ts +91 -0
- package/src/sdk/host/host.ts +296 -0
- package/src/sdk/host/index.ts +4 -0
- package/src/sdk/host/query/cursor.ts +189 -0
- package/src/sdk/host/query/handlers.ts +533 -0
- package/src/sdk/host/query/index.ts +3 -0
- package/src/sdk/host/query/revision-store.ts +1126 -0
- package/src/sdk/host/reverse-leases.ts +325 -0
- package/src/sdk/host/types.ts +29 -0
- package/src/sdk/index.ts +13 -0
- package/src/sdk/lifecycle-session.ts +39 -0
- package/src/sdk/mcp/index.ts +1 -0
- package/src/sdk/mcp/server.ts +332 -0
- package/src/sdk/models.ts +168 -0
- package/src/sdk/protocol/adapter-validation.ts +48 -0
- package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
- package/src/sdk/protocol/operation-registry.ts +312 -0
- package/src/{sdk.ts → sdk/session.ts} +339 -212
- package/src/sdk/startup-capability.ts +189 -0
- package/src/session/agent-session.ts +2453 -894
- package/src/session/default-model-selection.ts +93 -0
- package/src/session/fallback-chain-controller.ts +136 -0
- package/src/session/session-manager.ts +438 -11
- package/src/session/session-storage.ts +8 -1
- package/src/setup/credential-auto-import.ts +290 -35
- package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
- package/src/slash-commands/builtin-registry.ts +2 -1
- package/src/task/executor.ts +62 -13
- package/src/tools/ask-answer-registry.ts +1 -1
- package/src/tools/ask.ts +13 -8
- package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
- package/src/tools/browser/benchmark/detector-report.ts +157 -0
- package/src/tools/browser/benchmark/run-suite.ts +39 -0
- package/src/tools/browser/launch.ts +124 -19
- package/src/tools/browser/profile-discovery.ts +63 -0
- package/src/tools/browser/profile-posture.ts +59 -0
- package/src/tools/browser/profile-reuse.ts +102 -0
- package/src/tools/browser/profile-warmup.ts +109 -0
- package/src/tools/browser/registry.ts +87 -11
- package/src/tools/browser/tab-protocol.ts +1 -0
- package/src/tools/browser/tab-supervisor.ts +1 -0
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/browser.ts +6 -0
- package/src/tools/index.ts +8 -8
- package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
- package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
- package/src/tools/telegram-send.ts +2 -2
- package/vendor/insane-search/MANIFEST.json +2 -1
- package/vendor/insane-search/engine/bias_check.py +4 -1
- package/vendor/insane-search/engine/phase0.py +26 -1
- package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
- package/dist/types/modes/bridge/auth.d.ts +0 -12
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
- package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
- package/dist/types/modes/bridge/event-stream.d.ts +0 -8
- package/dist/types/modes/rpc/host-tools.d.ts +0 -1
- package/dist/types/modes/rpc/host-uris.d.ts +0 -1
- package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
- package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
- package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
- package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
- package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
- package/dist/types/notifications/config.d.ts +0 -132
- package/src/harness-control-plane/rpc-adapter.ts +0 -290
- package/src/modes/bridge/auth.ts +0 -41
- package/src/modes/bridge/bridge-client-bridge.ts +0 -47
- package/src/modes/bridge/bridge-mode.ts +0 -675
- package/src/modes/bridge/bridge-ui-context.ts +0 -200
- package/src/modes/bridge/event-stream.ts +0 -70
- package/src/modes/rpc/host-tools.ts +0 -1
- package/src/modes/rpc/host-uris.ts +0 -1
- package/src/modes/rpc/rpc-client.ts +0 -1166
- package/src/modes/rpc/rpc-mode.ts +0 -1029
- package/src/modes/rpc/rpc-socket-security.ts +0 -115
- package/src/modes/rpc/rpc-types.ts +0 -637
- package/src/modes/shared/agent-wire/command-contract.ts +0 -18
- package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
- package/src/modes/shared/agent-wire/command-validation.ts +0 -181
- package/src/modes/shared/agent-wire/handshake.ts +0 -157
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
- package/src/modes/shared/agent-wire/protocol.ts +0 -46
- package/src/modes/shared/agent-wire/responses.ts +0 -17
- package/src/modes/shared/agent-wire/scopes.ts +0 -94
- package/src/modes/shared/agent-wire/session-registry.ts +0 -109
- package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
- package/src/modes/shared/agent-wire/ui-result.ts +0 -48
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
- package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
- package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
- package/src/notifications/config.ts +0 -219
- package/src/notifications/index.ts +0 -1835
- package/src/notifications/telegram-daemon-cli.ts +0 -243
- package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
- /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
- /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
- /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
- /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
- /package/src/{notifications → sdk/bus}/engine.ts +0 -0
- /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
- /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
- /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
- /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
- /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
|
@@ -9,7 +9,7 @@ import * as url from "node:url";
|
|
|
9
9
|
import type { TSchema } from "@gajae-code/ai";
|
|
10
10
|
import { logger } from "@gajae-code/utils";
|
|
11
11
|
import type { SourceMeta } from "../capability/types";
|
|
12
|
-
import
|
|
12
|
+
import * as configValue from "../config/resolve-config-value";
|
|
13
13
|
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
14
14
|
import type { AuthStorage } from "../session/auth-storage";
|
|
15
15
|
import {
|
|
@@ -43,7 +43,7 @@ import type {
|
|
|
43
43
|
MCPServerConnection,
|
|
44
44
|
MCPToolDefinition,
|
|
45
45
|
} from "./types";
|
|
46
|
-
import { MCPNotificationMethods } from "./types";
|
|
46
|
+
import { MCPExpectedFailure, MCPNotificationMethods } from "./types";
|
|
47
47
|
|
|
48
48
|
type ToolLoadResult = {
|
|
49
49
|
connection: MCPServerConnection;
|
|
@@ -56,6 +56,16 @@ type TrackedPromise<T> = {
|
|
|
56
56
|
value?: T;
|
|
57
57
|
reason?: unknown;
|
|
58
58
|
};
|
|
59
|
+
type ConnectionTask = {
|
|
60
|
+
name: string;
|
|
61
|
+
config: MCPServerConfig;
|
|
62
|
+
tracked: TrackedPromise<ToolLoadResult>;
|
|
63
|
+
connectionPromise: Promise<MCPServerConnection>;
|
|
64
|
+
toolsPromise: Promise<ToolLoadResult>;
|
|
65
|
+
connectionAbort: AbortController;
|
|
66
|
+
connectionEpoch: number;
|
|
67
|
+
disconnectEpoch: number;
|
|
68
|
+
};
|
|
59
69
|
|
|
60
70
|
const STARTUP_TIMEOUT_MS = 250;
|
|
61
71
|
const STARTUP_TIMEOUT_GRACE_MS = 500;
|
|
@@ -86,6 +96,24 @@ function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
|
|
|
86
96
|
);
|
|
87
97
|
return tracked;
|
|
88
98
|
}
|
|
99
|
+
const EXPECTED_CONFIG_RESOLUTION_CODES = new Set([
|
|
100
|
+
"EACCES",
|
|
101
|
+
"EISDIR",
|
|
102
|
+
"ELOOP",
|
|
103
|
+
"ENAMETOOLONG",
|
|
104
|
+
"ENOENT",
|
|
105
|
+
"ENOTDIR",
|
|
106
|
+
"EPERM",
|
|
107
|
+
"ESTALE",
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
function isExpectedConfigResolutionFailure(error: unknown): boolean {
|
|
111
|
+
if (error instanceof DOMException && error.name === "AbortError") return true;
|
|
112
|
+
if (!(error instanceof Error)) return false;
|
|
113
|
+
if (error.name === "AbortError") return true;
|
|
114
|
+
const code = "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
115
|
+
return code !== undefined && EXPECTED_CONFIG_RESOLUTION_CODES.has(code);
|
|
116
|
+
}
|
|
89
117
|
|
|
90
118
|
function delay(ms: number, signal?: AbortSignal): Promise<void> {
|
|
91
119
|
if (!signal) return Bun.sleep(ms);
|
|
@@ -151,6 +179,13 @@ export interface MCPDiscoverOptions {
|
|
|
151
179
|
autoloadOnly?: boolean;
|
|
152
180
|
/** Called when starting to connect to servers */
|
|
153
181
|
onConnecting?: (serverNames: string[]) => void;
|
|
182
|
+
/** Load only this explicit MCP config file. */
|
|
183
|
+
configPath?: string;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface MCPManagerOptions {
|
|
187
|
+
/** Restrict this instance to tools from an explicit MCP config. */
|
|
188
|
+
toolsOnly?: boolean;
|
|
154
189
|
}
|
|
155
190
|
|
|
156
191
|
/**
|
|
@@ -198,6 +233,15 @@ export class MCPManager {
|
|
|
198
233
|
#serverConfigs = new Map<string, MCPServerConfig>();
|
|
199
234
|
/** Monotonic epoch incremented on disconnectAll to invalidate stale reconnections. */
|
|
200
235
|
#epoch = 0;
|
|
236
|
+
readonly #toolsOnly: boolean;
|
|
237
|
+
#toolsOnlyConfigLoaded = false;
|
|
238
|
+
|
|
239
|
+
#serverError(message: string): string {
|
|
240
|
+
return this.#toolsOnly ? "MCP server unavailable" : message;
|
|
241
|
+
}
|
|
242
|
+
#assertRawMCPAccessAllowed(): void {
|
|
243
|
+
if (this.#toolsOnly) throw new Error("Tools-only MCP manager does not allow raw MCP access");
|
|
244
|
+
}
|
|
201
245
|
|
|
202
246
|
#isCurrentConnection(
|
|
203
247
|
name: string,
|
|
@@ -217,12 +261,20 @@ export class MCPManager {
|
|
|
217
261
|
constructor(
|
|
218
262
|
private cwd: string,
|
|
219
263
|
private toolCache: MCPToolCache | null = null,
|
|
220
|
-
|
|
264
|
+
options: MCPManagerOptions = {},
|
|
265
|
+
) {
|
|
266
|
+
this.#toolsOnly = options.toolsOnly === true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
isToolsOnly(): boolean {
|
|
270
|
+
return this.#toolsOnly;
|
|
271
|
+
}
|
|
221
272
|
|
|
222
273
|
/**
|
|
223
274
|
* Set a callback to receive all server notifications.
|
|
224
275
|
*/
|
|
225
276
|
setOnNotification(handler: (serverName: string, method: string, params: unknown) => void): void {
|
|
277
|
+
if (this.#toolsOnly) return;
|
|
226
278
|
this.#onNotification = handler;
|
|
227
279
|
}
|
|
228
280
|
|
|
@@ -230,6 +282,7 @@ export class MCPManager {
|
|
|
230
282
|
* Set a callback to fire when any server's tools change.
|
|
231
283
|
*/
|
|
232
284
|
setOnToolsChanged(handler: (tools: CustomTool<TSchema, MCPToolDetails>[]) => void): void {
|
|
285
|
+
if (this.#toolsOnly) return;
|
|
233
286
|
this.#onToolsChanged = handler;
|
|
234
287
|
}
|
|
235
288
|
|
|
@@ -237,6 +290,7 @@ export class MCPManager {
|
|
|
237
290
|
* Set a callback to fire when any server's resources change.
|
|
238
291
|
*/
|
|
239
292
|
setOnResourcesChanged(handler: (serverName: string, uri: string) => void): void {
|
|
293
|
+
if (this.#toolsOnly) return;
|
|
240
294
|
this.#onResourcesChanged = handler;
|
|
241
295
|
}
|
|
242
296
|
|
|
@@ -244,6 +298,7 @@ export class MCPManager {
|
|
|
244
298
|
* Set a callback to fire when any server's prompts change.
|
|
245
299
|
*/
|
|
246
300
|
setOnPromptsChanged(handler: (serverName: string) => void): void {
|
|
301
|
+
if (this.#toolsOnly) return;
|
|
247
302
|
this.#onPromptsChanged = handler;
|
|
248
303
|
// Fire immediately for servers that already have prompts loaded
|
|
249
304
|
for (const [name, connection] of this.#connections) {
|
|
@@ -281,6 +336,7 @@ export class MCPManager {
|
|
|
281
336
|
}
|
|
282
337
|
|
|
283
338
|
setNotificationsEnabled(enabled: boolean): void {
|
|
339
|
+
if (this.#toolsOnly) return;
|
|
284
340
|
const wasEnabled = this.#notificationsEnabled;
|
|
285
341
|
this.#notificationsEnabled = enabled;
|
|
286
342
|
if (enabled === wasEnabled) return;
|
|
@@ -323,13 +379,27 @@ export class MCPManager {
|
|
|
323
379
|
* Returns tools and any connection errors.
|
|
324
380
|
*/
|
|
325
381
|
async discoverAndConnect(options?: MCPDiscoverOptions): Promise<MCPLoadResult> {
|
|
326
|
-
const
|
|
382
|
+
const hasConfigPath = options?.configPath !== undefined;
|
|
383
|
+
if (this.#toolsOnly !== hasConfigPath) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
this.#toolsOnly
|
|
386
|
+
? "Tools-only MCP manager requires an explicit config path"
|
|
387
|
+
: "Explicit MCP config requires a tools-only MCP manager",
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
if (this.#toolsOnly && this.#toolsOnlyConfigLoaded) {
|
|
391
|
+
throw new Error("Tools-only MCP manager already loaded an explicit config");
|
|
392
|
+
}
|
|
393
|
+
if (this.#toolsOnly) this.#toolsOnlyConfigLoaded = true;
|
|
394
|
+
const { configs, exaApiKeys, sources, configurationWarning } = await loadAllMCPConfigs(this.cwd, {
|
|
327
395
|
enableProjectConfig: options?.enableProjectConfig,
|
|
328
396
|
filterExa: options?.filterExa,
|
|
329
397
|
filterBrowser: options?.filterBrowser,
|
|
330
398
|
autoloadOnly: options?.autoloadOnly,
|
|
399
|
+
configPath: options?.configPath,
|
|
331
400
|
});
|
|
332
|
-
const result = await this
|
|
401
|
+
const result = await this.#connectServers(configs, sources, options?.onConnecting);
|
|
402
|
+
if (configurationWarning) result.errors.set("$config", "MCP configuration unavailable");
|
|
333
403
|
result.exaApiKeys = exaApiKeys;
|
|
334
404
|
return result;
|
|
335
405
|
}
|
|
@@ -343,16 +413,15 @@ export class MCPManager {
|
|
|
343
413
|
sources: Record<string, SourceMeta>,
|
|
344
414
|
onConnecting?: (serverNames: string[]) => void,
|
|
345
415
|
): Promise<MCPLoadResult> {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
tracked: TrackedPromise<ToolLoadResult>;
|
|
350
|
-
toolsPromise: Promise<ToolLoadResult>;
|
|
351
|
-
connectionAbort: AbortController;
|
|
352
|
-
connectionEpoch: number;
|
|
353
|
-
disconnectEpoch: number;
|
|
354
|
-
};
|
|
416
|
+
this.#assertRawMCPAccessAllowed();
|
|
417
|
+
return this.#connectServers(configs, sources, onConnecting);
|
|
418
|
+
}
|
|
355
419
|
|
|
420
|
+
async #connectServers(
|
|
421
|
+
configs: Record<string, MCPServerConfig>,
|
|
422
|
+
sources: Record<string, SourceMeta>,
|
|
423
|
+
onConnecting?: (serverNames: string[]) => void,
|
|
424
|
+
): Promise<MCPLoadResult> {
|
|
356
425
|
const errors = new Map<string, string>();
|
|
357
426
|
const connectedServers = new Set<string>();
|
|
358
427
|
const allTools: CustomTool<TSchema, MCPToolDetails>[] = [];
|
|
@@ -372,9 +441,14 @@ export class MCPManager {
|
|
|
372
441
|
}
|
|
373
442
|
}
|
|
374
443
|
|
|
375
|
-
// Skip if already connected
|
|
444
|
+
// Skip if already connected.
|
|
376
445
|
if (this.#connections.has(name)) {
|
|
377
446
|
connectedServers.add(name);
|
|
447
|
+
allTools.push(
|
|
448
|
+
...this.#tools.filter(
|
|
449
|
+
tool => (tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name,
|
|
450
|
+
),
|
|
451
|
+
);
|
|
378
452
|
continue;
|
|
379
453
|
}
|
|
380
454
|
|
|
@@ -389,7 +463,7 @@ export class MCPManager {
|
|
|
389
463
|
// Validate config
|
|
390
464
|
const validationErrors = validateServerConfig(name, config);
|
|
391
465
|
if (validationErrors.length > 0) {
|
|
392
|
-
errors.set(name, validationErrors.join("; "));
|
|
466
|
+
errors.set(name, this.#serverError(validationErrors.join("; ")));
|
|
393
467
|
reportedErrors.add(name);
|
|
394
468
|
continue;
|
|
395
469
|
}
|
|
@@ -406,10 +480,13 @@ export class MCPManager {
|
|
|
406
480
|
const connectionPromise = (async () => {
|
|
407
481
|
const resolvedConfig = await this.#resolveAuthConfig(config);
|
|
408
482
|
return connectToServer(name, resolvedConfig, {
|
|
483
|
+
advertiseRoots: !this.#toolsOnly,
|
|
409
484
|
signal: connectionAbort.signal,
|
|
410
|
-
onNotification:
|
|
411
|
-
|
|
412
|
-
|
|
485
|
+
onNotification: this.#toolsOnly
|
|
486
|
+
? undefined
|
|
487
|
+
: (method, params) => {
|
|
488
|
+
this.#handleServerNotification(name, method, params);
|
|
489
|
+
},
|
|
413
490
|
onRequest: (method, params) => {
|
|
414
491
|
return this.#handleServerRequest(method, params);
|
|
415
492
|
},
|
|
@@ -426,7 +503,8 @@ export class MCPManager {
|
|
|
426
503
|
const stillCurrent =
|
|
427
504
|
this.#epoch === connectionEpoch &&
|
|
428
505
|
(this.#disconnectEpochs.get(name) ?? 0) === disconnectEpoch &&
|
|
429
|
-
this.#serverConfigs.get(name) === config
|
|
506
|
+
this.#serverConfigs.get(name) === config &&
|
|
507
|
+
!connectionAbort.signal.aborted;
|
|
430
508
|
if (stillPending) {
|
|
431
509
|
this.#pendingConnections.delete(name);
|
|
432
510
|
this.#pendingConnectionControllers.delete(name);
|
|
@@ -450,12 +528,14 @@ export class MCPManager {
|
|
|
450
528
|
};
|
|
451
529
|
}
|
|
452
530
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
531
|
+
if (!this.#toolsOnly) {
|
|
532
|
+
// Re-establish connection if the transport closes (server restart,
|
|
533
|
+
// network interruption).
|
|
534
|
+
connection.transport.onClose = () => {
|
|
535
|
+
logger.debug("MCP transport lost, triggering reconnect", { path: `mcp:${name}` });
|
|
536
|
+
void this.reconnectServer(name);
|
|
537
|
+
};
|
|
538
|
+
}
|
|
459
539
|
|
|
460
540
|
return connection;
|
|
461
541
|
},
|
|
@@ -476,10 +556,13 @@ export class MCPManager {
|
|
|
476
556
|
} catch (error) {
|
|
477
557
|
connection.transport.onClose = undefined;
|
|
478
558
|
if (this.#connections.get(name) === connection) this.#connections.delete(name);
|
|
479
|
-
|
|
559
|
+
await connection.transport.close().catch(() => {});
|
|
480
560
|
throw error;
|
|
481
561
|
}
|
|
482
|
-
if (
|
|
562
|
+
if (
|
|
563
|
+
connectionAbort.signal.aborted ||
|
|
564
|
+
!this.#isCurrentConnection(name, config, connectionEpoch, disconnectEpoch, connection)
|
|
565
|
+
) {
|
|
483
566
|
connection.transport.onClose = undefined;
|
|
484
567
|
await connection.transport.close().catch(() => {});
|
|
485
568
|
throw new Error(`Server "${name}" was disconnected during tool loading`);
|
|
@@ -493,6 +576,7 @@ export class MCPManager {
|
|
|
493
576
|
name,
|
|
494
577
|
config,
|
|
495
578
|
tracked,
|
|
579
|
+
connectionPromise,
|
|
496
580
|
toolsPromise,
|
|
497
581
|
connectionAbort,
|
|
498
582
|
connectionEpoch,
|
|
@@ -501,20 +585,25 @@ export class MCPManager {
|
|
|
501
585
|
|
|
502
586
|
void toolsPromise
|
|
503
587
|
.then(async ({ connection, serverTools }) => {
|
|
588
|
+
if (connectionAbort.signal.aborted) return;
|
|
504
589
|
if (this.#pendingToolLoads.get(name) !== toolsPromise) return;
|
|
505
|
-
if (
|
|
590
|
+
if (
|
|
591
|
+
connectionAbort.signal.aborted ||
|
|
592
|
+
!this.#isCurrentConnection(name, config, connectionEpoch, disconnectEpoch, connection)
|
|
593
|
+
)
|
|
594
|
+
return;
|
|
506
595
|
this.#pendingToolLoads.delete(name);
|
|
507
|
-
const reconnect = () => this.reconnectServer(name);
|
|
596
|
+
const reconnect = this.#toolsOnly ? undefined : () => this.reconnectServer(name);
|
|
508
597
|
const customTools = MCPTool.fromTools(connection, serverTools, reconnect);
|
|
509
598
|
this.#replaceServerTools(name, customTools);
|
|
510
|
-
this.#onToolsChanged?.(this.#tools);
|
|
511
|
-
void this.toolCache?.set(name, config, serverTools);
|
|
512
|
-
await this.#loadServerResourcesAndPrompts(name, connection);
|
|
599
|
+
if (!this.#toolsOnly) this.#onToolsChanged?.(this.#tools);
|
|
600
|
+
if (!this.#toolsOnly) void this.toolCache?.set(name, config, serverTools);
|
|
601
|
+
if (!this.#toolsOnly) await this.#loadServerResourcesAndPrompts(name, connection);
|
|
513
602
|
})
|
|
514
603
|
.catch(error => {
|
|
515
604
|
if (this.#pendingToolLoads.get(name) !== toolsPromise) return;
|
|
516
605
|
this.#pendingToolLoads.delete(name);
|
|
517
|
-
if (!allowBackgroundLogging || reportedErrors.has(name)) return;
|
|
606
|
+
if (!allowBackgroundLogging || reportedErrors.has(name) || this.#toolsOnly) return;
|
|
518
607
|
const message = error instanceof Error ? error.message : String(error);
|
|
519
608
|
logger.error("MCP tool load failed", { path: `mcp:${name}`, error: message });
|
|
520
609
|
});
|
|
@@ -522,21 +611,47 @@ export class MCPManager {
|
|
|
522
611
|
|
|
523
612
|
// Notify about servers we're connecting to
|
|
524
613
|
if (connectionTasks.length > 0 && onConnecting) {
|
|
525
|
-
|
|
614
|
+
try {
|
|
615
|
+
onConnecting(connectionTasks.map(task => task.name));
|
|
616
|
+
} catch (error) {
|
|
617
|
+
await this.#cleanupConnectionTasks(connectionTasks);
|
|
618
|
+
throw error;
|
|
619
|
+
}
|
|
526
620
|
}
|
|
527
621
|
|
|
528
622
|
if (connectionTasks.length > 0) {
|
|
529
623
|
const startupTimeoutMs = resolveStartupTimeoutMs(connectionTasks.map(task => task.config));
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
624
|
+
const firstUnexpectedFailure = Promise.withResolvers<{ reason: unknown }>();
|
|
625
|
+
if (this.#toolsOnly) {
|
|
626
|
+
for (const task of connectionTasks) {
|
|
627
|
+
void task.toolsPromise.catch(reason => {
|
|
628
|
+
if (!(reason instanceof MCPExpectedFailure)) firstUnexpectedFailure.resolve({ reason });
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const startupOutcome = await Promise.race([
|
|
633
|
+
Promise.allSettled(connectionTasks.map(task => task.tracked.promise)).then(() => undefined),
|
|
634
|
+
delay(startupTimeoutMs).then(() => undefined),
|
|
635
|
+
firstUnexpectedFailure.promise,
|
|
533
636
|
]);
|
|
637
|
+
const unexpectedTask = connectionTasks.find(
|
|
638
|
+
task =>
|
|
639
|
+
task.tracked.status === "rejected" &&
|
|
640
|
+
this.#toolsOnly &&
|
|
641
|
+
!(task.tracked.reason instanceof MCPExpectedFailure),
|
|
642
|
+
);
|
|
643
|
+
const unexpectedFailure =
|
|
644
|
+
startupOutcome ?? (unexpectedTask ? { reason: unexpectedTask.tracked.reason } : undefined);
|
|
645
|
+
if (unexpectedFailure) {
|
|
646
|
+
await this.#cleanupConnectionTasks(connectionTasks);
|
|
647
|
+
throw unexpectedFailure.reason;
|
|
648
|
+
}
|
|
534
649
|
|
|
535
650
|
const cachedTools = new Map<string, MCPToolDefinition[]>();
|
|
536
651
|
const pendingTasks = connectionTasks.filter(task => task.tracked.status === "pending");
|
|
537
652
|
|
|
538
653
|
if (pendingTasks.length > 0) {
|
|
539
|
-
if (this.toolCache) {
|
|
654
|
+
if (this.toolCache && !this.#toolsOnly) {
|
|
540
655
|
await Promise.all(
|
|
541
656
|
pendingTasks.map(async task => {
|
|
542
657
|
const cached = await this.toolCache?.get(task.name, task.config);
|
|
@@ -551,17 +666,18 @@ export class MCPManager {
|
|
|
551
666
|
if (pendingWithoutCache.length > 0) {
|
|
552
667
|
for (const task of pendingWithoutCache) {
|
|
553
668
|
const message = `MCP server connection timed out during startup: ${task.name}`;
|
|
554
|
-
errors.set(task.name, message);
|
|
669
|
+
errors.set(task.name, this.#serverError(message));
|
|
555
670
|
reportedErrors.add(task.name);
|
|
556
671
|
task.connectionAbort.abort(new Error(message));
|
|
557
672
|
if (this.#pendingConnections.has(task.name)) this.#pendingConnections.delete(task.name);
|
|
558
673
|
if (this.#pendingToolLoads.get(task.name) === task.toolsPromise)
|
|
559
674
|
this.#pendingToolLoads.delete(task.name);
|
|
560
675
|
this.#pendingConnectionControllers.delete(task.name);
|
|
676
|
+
void this.#disconnectServer(task.name).catch(() => {});
|
|
561
677
|
}
|
|
562
|
-
//
|
|
563
|
-
// AbortSignal and keep startup blocked indefinitely
|
|
564
|
-
//
|
|
678
|
+
// Abort and disconnect in the background: a misbehaving stdio/MCP transport can
|
|
679
|
+
// ignore AbortSignal and keep startup blocked indefinitely, but it must not remain
|
|
680
|
+
// registered if it eventually connects.
|
|
565
681
|
}
|
|
566
682
|
}
|
|
567
683
|
|
|
@@ -579,13 +695,21 @@ export class MCPManager {
|
|
|
579
695
|
continue;
|
|
580
696
|
}
|
|
581
697
|
connectedServers.add(name);
|
|
582
|
-
const reconnect = () => this.reconnectServer(name);
|
|
583
|
-
|
|
698
|
+
const reconnect = this.#toolsOnly ? undefined : () => this.reconnectServer(name);
|
|
699
|
+
try {
|
|
700
|
+
allTools.push(...MCPTool.fromTools(connection, serverTools, reconnect));
|
|
701
|
+
} catch (error) {
|
|
702
|
+
await this.#cleanupConnectionTasks(connectionTasks);
|
|
703
|
+
throw error;
|
|
704
|
+
}
|
|
584
705
|
} else if (task.tracked.status === "rejected") {
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
errors.set(name, message);
|
|
706
|
+
const reason = task.tracked.reason;
|
|
707
|
+
const message = reason instanceof Error ? reason.message : String(reason);
|
|
708
|
+
errors.set(name, this.#serverError(message));
|
|
588
709
|
reportedErrors.add(name);
|
|
710
|
+
if (this.#toolsOnly && reason instanceof MCPExpectedFailure) {
|
|
711
|
+
await this.#disconnectServer(name);
|
|
712
|
+
}
|
|
589
713
|
if ((this.#disconnectEpochs.get(name) ?? 0) !== task.disconnectEpoch) {
|
|
590
714
|
shouldPublishToolSnapshot = false;
|
|
591
715
|
}
|
|
@@ -593,10 +717,21 @@ export class MCPManager {
|
|
|
593
717
|
const cached = cachedTools.get(name);
|
|
594
718
|
if (cached) {
|
|
595
719
|
const source = this.#sources.get(name);
|
|
596
|
-
const reconnect = () => this.reconnectServer(name);
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
720
|
+
const reconnect = this.#toolsOnly ? undefined : () => this.reconnectServer(name);
|
|
721
|
+
try {
|
|
722
|
+
allTools.push(
|
|
723
|
+
...DeferredMCPTool.fromTools(
|
|
724
|
+
name,
|
|
725
|
+
cached,
|
|
726
|
+
() => this.#waitForConnection(name),
|
|
727
|
+
source,
|
|
728
|
+
reconnect,
|
|
729
|
+
),
|
|
730
|
+
);
|
|
731
|
+
} catch (error) {
|
|
732
|
+
await this.#cleanupConnectionTasks(connectionTasks);
|
|
733
|
+
throw error;
|
|
734
|
+
}
|
|
600
735
|
}
|
|
601
736
|
}
|
|
602
737
|
}
|
|
@@ -605,13 +740,17 @@ export class MCPManager {
|
|
|
605
740
|
// Stable sort by name so the order is independent of connection completion.
|
|
606
741
|
// See `sortMCPToolsByName` for the cache-stability rationale.
|
|
607
742
|
sortMCPToolsByName(allTools);
|
|
743
|
+
if (this.#toolsOnly && new Set(allTools.map(tool => tool.name)).size !== allTools.length) {
|
|
744
|
+
await this.#cleanupConnectionTasks(connectionTasks);
|
|
745
|
+
throw new Error("MCP tool catalog contains duplicate tool names");
|
|
746
|
+
}
|
|
608
747
|
|
|
609
748
|
// Update cached tools
|
|
610
749
|
if (shouldPublishToolSnapshot) this.#tools = allTools;
|
|
611
750
|
allowBackgroundLogging = true;
|
|
612
751
|
|
|
613
752
|
return {
|
|
614
|
-
tools: allTools,
|
|
753
|
+
tools: [...allTools],
|
|
615
754
|
errors,
|
|
616
755
|
connectedServers: Array.from(connectedServers),
|
|
617
756
|
exaApiKeys: [], // Will be populated by discoverAndConnect
|
|
@@ -619,7 +758,9 @@ export class MCPManager {
|
|
|
619
758
|
}
|
|
620
759
|
|
|
621
760
|
#replaceServerTools(name: string, tools: CustomTool<TSchema, MCPToolDetails>[]): void {
|
|
622
|
-
this.#tools = this.#tools.filter(
|
|
761
|
+
this.#tools = this.#tools.filter(
|
|
762
|
+
tool => !((tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name),
|
|
763
|
+
);
|
|
623
764
|
this.#tools.push(...tools);
|
|
624
765
|
// Stable sort by name so reconnect order does not perturb the array.
|
|
625
766
|
// See `sortMCPToolsByName` for the cache-stability rationale.
|
|
@@ -671,6 +812,9 @@ export class MCPManager {
|
|
|
671
812
|
|
|
672
813
|
/** Handle server-to-client JSON-RPC requests (e.g. ping, roots/list). */
|
|
673
814
|
async #handleServerRequest(method: string, _params: unknown): Promise<unknown> {
|
|
815
|
+
if (this.#toolsOnly && method !== "ping") {
|
|
816
|
+
throw Object.assign(new Error(`Unsupported server request: ${method}`), { code: -32601 });
|
|
817
|
+
}
|
|
674
818
|
switch (method) {
|
|
675
819
|
case "ping":
|
|
676
820
|
return {};
|
|
@@ -696,13 +840,14 @@ export class MCPManager {
|
|
|
696
840
|
* Get all loaded tools.
|
|
697
841
|
*/
|
|
698
842
|
getTools(): CustomTool<TSchema, MCPToolDetails>[] {
|
|
699
|
-
return this.#tools;
|
|
843
|
+
return [...this.#tools];
|
|
700
844
|
}
|
|
701
845
|
|
|
702
846
|
/**
|
|
703
847
|
* Get a specific connection.
|
|
704
848
|
*/
|
|
705
849
|
getConnection(name: string): MCPServerConnection | undefined {
|
|
850
|
+
this.#assertRawMCPAccessAllowed();
|
|
706
851
|
return this.#connections.get(name);
|
|
707
852
|
}
|
|
708
853
|
|
|
@@ -731,6 +876,11 @@ export class MCPManager {
|
|
|
731
876
|
* Wait for a connection to complete (or fail).
|
|
732
877
|
*/
|
|
733
878
|
async waitForConnection(name: string): Promise<MCPServerConnection> {
|
|
879
|
+
this.#assertRawMCPAccessAllowed();
|
|
880
|
+
return this.#waitForConnection(name);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
async #waitForConnection(name: string): Promise<MCPServerConnection> {
|
|
734
884
|
const connection = this.#connections.get(name);
|
|
735
885
|
if (connection) return connection;
|
|
736
886
|
const pending = this.#pendingConnections.get(name);
|
|
@@ -748,6 +898,7 @@ export class MCPManager {
|
|
|
748
898
|
* Resolve auth and shell-command substitutions in config before connecting.
|
|
749
899
|
*/
|
|
750
900
|
async prepareConfig(config: MCPServerConfig): Promise<MCPServerConfig> {
|
|
901
|
+
this.#assertRawMCPAccessAllowed();
|
|
751
902
|
return this.#resolveAuthConfig(config);
|
|
752
903
|
}
|
|
753
904
|
|
|
@@ -771,6 +922,11 @@ export class MCPManager {
|
|
|
771
922
|
* Disconnect from a specific server.
|
|
772
923
|
*/
|
|
773
924
|
async disconnectServer(name: string): Promise<void> {
|
|
925
|
+
this.#assertRawMCPAccessAllowed();
|
|
926
|
+
await this.#disconnectServer(name);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
async #disconnectServer(name: string): Promise<void> {
|
|
774
930
|
const nextEpoch = (this.#disconnectEpochs.get(name) ?? 0) + 1;
|
|
775
931
|
this.#disconnectEpochs.set(name, nextEpoch);
|
|
776
932
|
this.#pendingConnectionControllers.get(name)?.abort(new Error(`MCP server disconnected: ${name}`));
|
|
@@ -791,20 +947,66 @@ export class MCPManager {
|
|
|
791
947
|
}
|
|
792
948
|
this.#subscribedResources.delete(name);
|
|
793
949
|
|
|
950
|
+
let closeError: unknown;
|
|
794
951
|
if (connection) {
|
|
795
952
|
// Detach onClose to prevent spurious reconnect from close()
|
|
796
953
|
connection.transport.onClose = undefined;
|
|
797
|
-
|
|
798
|
-
|
|
954
|
+
try {
|
|
955
|
+
await disconnectServer(connection);
|
|
956
|
+
} catch (error) {
|
|
957
|
+
closeError = error;
|
|
958
|
+
}
|
|
959
|
+
if (this.#connections.get(name) === connection) this.#connections.delete(name);
|
|
799
960
|
}
|
|
800
961
|
|
|
801
962
|
// Remove tools from this server and notify consumers
|
|
802
|
-
const hadTools = this.#tools.some(
|
|
803
|
-
|
|
963
|
+
const hadTools = this.#tools.some(
|
|
964
|
+
tool => (tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name,
|
|
965
|
+
);
|
|
966
|
+
this.#tools = this.#tools.filter(
|
|
967
|
+
tool => !((tool instanceof MCPTool || tool instanceof DeferredMCPTool) && tool.mcpServerName === name),
|
|
968
|
+
);
|
|
804
969
|
if (hadTools) this.#onToolsChanged?.(this.#tools);
|
|
805
970
|
|
|
806
971
|
// Notify prompt consumers so stale commands are cleared
|
|
807
972
|
if (connection?.prompts?.length) this.#onPromptsChanged?.(name);
|
|
973
|
+
if (closeError) throw closeError;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
#abortConnectionTask(task: ConnectionTask): void {
|
|
977
|
+
task.connectionAbort.abort(new Error(`MCP server startup aborted: ${task.name}`));
|
|
978
|
+
if (this.#pendingConnectionControllers.get(task.name) === task.connectionAbort) {
|
|
979
|
+
this.#pendingConnectionControllers.delete(task.name);
|
|
980
|
+
}
|
|
981
|
+
if (this.#pendingConnections.get(task.name) === task.connectionPromise) {
|
|
982
|
+
this.#pendingConnections.delete(task.name);
|
|
983
|
+
}
|
|
984
|
+
if (this.#pendingToolLoads.get(task.name) === task.toolsPromise) {
|
|
985
|
+
this.#pendingToolLoads.delete(task.name);
|
|
986
|
+
}
|
|
987
|
+
if ((this.#disconnectEpochs.get(task.name) ?? 0) === task.disconnectEpoch) {
|
|
988
|
+
this.#disconnectEpochs.set(task.name, task.disconnectEpoch + 1);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
async #terminateConnectionTask(task: ConnectionTask): Promise<void> {
|
|
993
|
+
const connection = await task.connectionPromise.catch(() => undefined);
|
|
994
|
+
if (!connection || this.#connections.get(task.name) !== connection) return;
|
|
995
|
+
|
|
996
|
+
connection.transport.onClose = undefined;
|
|
997
|
+
try {
|
|
998
|
+
await disconnectServer(connection);
|
|
999
|
+
} catch {
|
|
1000
|
+
// Preserve the primary startup failure over best-effort transport cleanup failures.
|
|
1001
|
+
} finally {
|
|
1002
|
+
if (this.#connections.get(task.name) === connection) this.#connections.delete(task.name);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
async #cleanupConnectionTasks(tasks: ConnectionTask[]): Promise<void> {
|
|
1007
|
+
for (const task of tasks) this.#abortConnectionTask(task);
|
|
1008
|
+
await Promise.allSettled(tasks.map(task => this.#terminateConnectionTask(task)));
|
|
1009
|
+
await Promise.allSettled(tasks.map(task => this.#disconnectServer(task.name)));
|
|
808
1010
|
}
|
|
809
1011
|
|
|
810
1012
|
/**
|
|
@@ -848,6 +1050,7 @@ export class MCPManager {
|
|
|
848
1050
|
* Returns the new connection, or null if reconnection failed.
|
|
849
1051
|
*/
|
|
850
1052
|
async reconnectServer(name: string): Promise<MCPServerConnection | null> {
|
|
1053
|
+
if (this.#toolsOnly) return null;
|
|
851
1054
|
const pending = this.#pendingReconnections.get(name);
|
|
852
1055
|
if (pending) return pending;
|
|
853
1056
|
|
|
@@ -1025,6 +1228,7 @@ export class MCPManager {
|
|
|
1025
1228
|
* Shared between initial connection and reconnection.
|
|
1026
1229
|
*/
|
|
1027
1230
|
async #loadServerResourcesAndPrompts(name: string, connection: MCPServerConnection): Promise<void> {
|
|
1231
|
+
if (this.#toolsOnly) return;
|
|
1028
1232
|
if (serverSupportsResources(connection.capabilities)) {
|
|
1029
1233
|
try {
|
|
1030
1234
|
const [resources] = await Promise.all([listResources(connection), listResourceTemplates(connection)]);
|
|
@@ -1053,6 +1257,7 @@ export class MCPManager {
|
|
|
1053
1257
|
* Refresh tools from a specific server.
|
|
1054
1258
|
*/
|
|
1055
1259
|
async refreshServerTools(name: string): Promise<void> {
|
|
1260
|
+
if (this.#toolsOnly) return;
|
|
1056
1261
|
const connection = this.#connections.get(name);
|
|
1057
1262
|
if (!connection) return;
|
|
1058
1263
|
const globalEpoch = this.#epoch;
|
|
@@ -1077,6 +1282,7 @@ export class MCPManager {
|
|
|
1077
1282
|
* Refresh tools from all servers.
|
|
1078
1283
|
*/
|
|
1079
1284
|
async refreshAllTools(): Promise<void> {
|
|
1285
|
+
if (this.#toolsOnly) return;
|
|
1080
1286
|
const promises = Array.from(this.#connections.keys()).map(name => this.refreshServerTools(name));
|
|
1081
1287
|
await Promise.allSettled(promises);
|
|
1082
1288
|
}
|
|
@@ -1085,6 +1291,7 @@ export class MCPManager {
|
|
|
1085
1291
|
* Refresh resources from a specific server.
|
|
1086
1292
|
*/
|
|
1087
1293
|
async refreshServerResources(name: string): Promise<void> {
|
|
1294
|
+
if (this.#toolsOnly) return;
|
|
1088
1295
|
const connection = this.#connections.get(name);
|
|
1089
1296
|
if (!connection || !serverSupportsResources(connection.capabilities)) return;
|
|
1090
1297
|
|
|
@@ -1154,6 +1361,7 @@ export class MCPManager {
|
|
|
1154
1361
|
* Refresh prompts from a specific server.
|
|
1155
1362
|
*/
|
|
1156
1363
|
async refreshServerPrompts(name: string): Promise<void> {
|
|
1364
|
+
if (this.#toolsOnly) return;
|
|
1157
1365
|
const connection = this.#connections.get(name);
|
|
1158
1366
|
if (!connection || !serverSupportsPrompts(connection.capabilities)) return;
|
|
1159
1367
|
|
|
@@ -1167,6 +1375,7 @@ export class MCPManager {
|
|
|
1167
1375
|
* Get resources and templates for a specific server.
|
|
1168
1376
|
*/
|
|
1169
1377
|
getServerResources(name: string): { resources: MCPResource[]; templates: MCPResourceTemplate[] } | undefined {
|
|
1378
|
+
if (this.#toolsOnly) return undefined;
|
|
1170
1379
|
const connection = this.#connections.get(name);
|
|
1171
1380
|
if (!connection) return undefined;
|
|
1172
1381
|
return {
|
|
@@ -1183,6 +1392,7 @@ export class MCPManager {
|
|
|
1183
1392
|
uri: string,
|
|
1184
1393
|
options?: MCPRequestOptions,
|
|
1185
1394
|
): Promise<MCPResourceReadResult | undefined> {
|
|
1395
|
+
if (this.#toolsOnly) return undefined;
|
|
1186
1396
|
const connection = this.#connections.get(name);
|
|
1187
1397
|
if (!connection) return undefined;
|
|
1188
1398
|
return readResource(connection, uri, options);
|
|
@@ -1192,6 +1402,7 @@ export class MCPManager {
|
|
|
1192
1402
|
* Get prompts for a specific server.
|
|
1193
1403
|
*/
|
|
1194
1404
|
getServerPrompts(name: string): MCPPrompt[] | undefined {
|
|
1405
|
+
if (this.#toolsOnly) return undefined;
|
|
1195
1406
|
const connection = this.#connections.get(name);
|
|
1196
1407
|
if (!connection) return undefined;
|
|
1197
1408
|
return connection.prompts ?? [];
|
|
@@ -1206,6 +1417,7 @@ export class MCPManager {
|
|
|
1206
1417
|
args?: Record<string, string>,
|
|
1207
1418
|
options?: MCPRequestOptions,
|
|
1208
1419
|
): Promise<MCPGetPromptResult | undefined> {
|
|
1420
|
+
if (this.#toolsOnly) return undefined;
|
|
1209
1421
|
const connection = this.#connections.get(name);
|
|
1210
1422
|
if (!connection) return undefined;
|
|
1211
1423
|
return getPrompt(connection, promptName, args, options);
|
|
@@ -1215,6 +1427,7 @@ export class MCPManager {
|
|
|
1215
1427
|
* Get all server instructions (for system prompt injection).
|
|
1216
1428
|
*/
|
|
1217
1429
|
getServerInstructions(): Map<string, string> {
|
|
1430
|
+
if (this.#toolsOnly) return new Map();
|
|
1218
1431
|
const instructions = new Map<string, string>();
|
|
1219
1432
|
for (const [name, connection] of this.#connections) {
|
|
1220
1433
|
if (connection.instructions) {
|
|
@@ -1243,61 +1456,85 @@ export class MCPManager {
|
|
|
1243
1456
|
const auth = config.auth;
|
|
1244
1457
|
if (auth?.type === "oauth" && auth.credentialId && this.#authStorage) {
|
|
1245
1458
|
const credentialId = auth.credentialId;
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1459
|
+
let credential = this.#authStorage.get(credentialId);
|
|
1460
|
+
if (credential?.type === "oauth") {
|
|
1461
|
+
// Proactive refresh: 5-minute buffer before expiry
|
|
1462
|
+
// Force refresh: on 401/403 auth errors (revoked tokens, clock skew, missing expires)
|
|
1463
|
+
const REFRESH_BUFFER_MS = 5 * 60_000;
|
|
1464
|
+
const shouldRefresh =
|
|
1465
|
+
forceRefresh || (credential.expires && Date.now() >= credential.expires - REFRESH_BUFFER_MS);
|
|
1466
|
+
let refreshedCredential:
|
|
1467
|
+
| {
|
|
1468
|
+
type: "oauth";
|
|
1469
|
+
access: string;
|
|
1470
|
+
refresh: string;
|
|
1471
|
+
expires: number;
|
|
1472
|
+
}
|
|
1473
|
+
| undefined;
|
|
1474
|
+
if (shouldRefresh && credential.refresh && auth.tokenUrl) {
|
|
1475
|
+
try {
|
|
1476
|
+
const refreshed = await refreshMCPOAuthToken(
|
|
1477
|
+
auth.tokenUrl,
|
|
1478
|
+
credential.refresh,
|
|
1479
|
+
auth.clientId,
|
|
1480
|
+
auth.clientSecret,
|
|
1481
|
+
);
|
|
1482
|
+
refreshedCredential = { type: "oauth", ...refreshed };
|
|
1483
|
+
} catch (error) {
|
|
1484
|
+
if (!(error instanceof MCPExpectedFailure)) throw error;
|
|
1485
|
+
if (this.#toolsOnly) {
|
|
1486
|
+
logger.debug("MCP OAuth refresh failed");
|
|
1487
|
+
} else {
|
|
1488
|
+
logger.warn("MCP OAuth refresh failed, using existing token");
|
|
1270
1489
|
}
|
|
1271
1490
|
}
|
|
1491
|
+
}
|
|
1492
|
+
if (refreshedCredential) {
|
|
1493
|
+
await this.#authStorage.set(credentialId, refreshedCredential);
|
|
1494
|
+
credential = refreshedCredential;
|
|
1495
|
+
}
|
|
1272
1496
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
}
|
|
1497
|
+
if (resolved.type === "http" || resolved.type === "sse") {
|
|
1498
|
+
resolved = {
|
|
1499
|
+
...resolved,
|
|
1500
|
+
headers: {
|
|
1501
|
+
...resolved.headers,
|
|
1502
|
+
Authorization: `Bearer ${credential.access}`,
|
|
1503
|
+
},
|
|
1504
|
+
};
|
|
1505
|
+
} else {
|
|
1506
|
+
resolved = {
|
|
1507
|
+
...resolved,
|
|
1508
|
+
env: {
|
|
1509
|
+
...resolved.env,
|
|
1510
|
+
OAUTH_ACCESS_TOKEN: credential.access,
|
|
1511
|
+
},
|
|
1512
|
+
};
|
|
1290
1513
|
}
|
|
1291
|
-
} catch (error) {
|
|
1292
|
-
logger.warn("Failed to resolve OAuth credential", { credentialId, error });
|
|
1293
1514
|
}
|
|
1294
1515
|
}
|
|
1516
|
+
if (this.#toolsOnly && resolved.type === "stdio") {
|
|
1517
|
+
resolved = { ...resolved, noInheritEnv: true };
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
const resolveValue = async (value: string): Promise<string | undefined> => {
|
|
1521
|
+
try {
|
|
1522
|
+
const resolvedValue = await configValue.resolveConfigValue(value);
|
|
1523
|
+
if (this.#toolsOnly && !resolvedValue) throw new MCPExpectedFailure();
|
|
1524
|
+
return resolvedValue;
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
if (this.#toolsOnly && isExpectedConfigResolutionFailure(error)) {
|
|
1527
|
+
throw new MCPExpectedFailure(error);
|
|
1528
|
+
}
|
|
1529
|
+
throw error;
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1295
1532
|
|
|
1296
1533
|
if (resolved.type !== "http" && resolved.type !== "sse") {
|
|
1297
1534
|
if (resolved.env) {
|
|
1298
1535
|
const nextEnv: Record<string, string> = {};
|
|
1299
1536
|
for (const [key, value] of Object.entries(resolved.env)) {
|
|
1300
|
-
const resolvedValue = await
|
|
1537
|
+
const resolvedValue = await resolveValue(value);
|
|
1301
1538
|
if (resolvedValue) nextEnv[key] = resolvedValue;
|
|
1302
1539
|
}
|
|
1303
1540
|
resolved = { ...resolved, env: nextEnv };
|
|
@@ -1306,7 +1543,7 @@ export class MCPManager {
|
|
|
1306
1543
|
if (resolved.headers) {
|
|
1307
1544
|
const nextHeaders: Record<string, string> = {};
|
|
1308
1545
|
for (const [key, value] of Object.entries(resolved.headers)) {
|
|
1309
|
-
const resolvedValue = await
|
|
1546
|
+
const resolvedValue = await resolveValue(value);
|
|
1310
1547
|
if (resolvedValue) nextHeaders[key] = resolvedValue;
|
|
1311
1548
|
}
|
|
1312
1549
|
resolved = { ...resolved, headers: nextHeaders };
|
|
@@ -1328,7 +1565,8 @@ export async function createMCPManager(
|
|
|
1328
1565
|
manager: MCPManager;
|
|
1329
1566
|
result: MCPLoadResult;
|
|
1330
1567
|
}> {
|
|
1331
|
-
const manager =
|
|
1568
|
+
const manager =
|
|
1569
|
+
options?.configPath !== undefined ? new MCPManager(cwd, null, { toolsOnly: true }) : new MCPManager(cwd);
|
|
1332
1570
|
const result = await manager.discoverAndConnect(options);
|
|
1333
1571
|
return { manager, result };
|
|
1334
1572
|
}
|