@defai.digital/ax-cli 4.4.7 → 4.4.11
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/bin/ax-cli +1 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +158 -9
- package/dist/index.js.map +1 -1
- package/dist/setup.d.ts +27 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +591 -0
- package/dist/setup.js.map +1 -0
- package/package.json +43 -135
- package/LICENSE +0 -22
- package/README.md +0 -420
- package/config-defaults/messages.yaml +0 -75
- package/config-defaults/models.yaml +0 -57
- package/config-defaults/prompts.yaml +0 -948
- package/config-defaults/settings.yaml +0 -157
- package/dist/agent/agent-executor.d.ts +0 -61
- package/dist/agent/agent-executor.js +0 -194
- package/dist/agent/agent-executor.js.map +0 -1
- package/dist/agent/agent-router.d.ts +0 -68
- package/dist/agent/agent-router.js +0 -242
- package/dist/agent/agent-router.js.map +0 -1
- package/dist/agent/context-manager.d.ts +0 -122
- package/dist/agent/context-manager.js +0 -406
- package/dist/agent/context-manager.js.map +0 -1
- package/dist/agent/core/index.d.ts +0 -8
- package/dist/agent/core/index.js +0 -9
- package/dist/agent/core/index.js.map +0 -1
- package/dist/agent/core/types.d.ts +0 -92
- package/dist/agent/core/types.js +0 -11
- package/dist/agent/core/types.js.map +0 -1
- package/dist/agent/dependency-resolver.d.ts +0 -90
- package/dist/agent/dependency-resolver.js +0 -366
- package/dist/agent/dependency-resolver.js.map +0 -1
- package/dist/agent/execution/index.d.ts +0 -9
- package/dist/agent/execution/index.js +0 -9
- package/dist/agent/execution/index.js.map +0 -1
- package/dist/agent/execution/tool-executor.d.ts +0 -93
- package/dist/agent/execution/tool-executor.js +0 -552
- package/dist/agent/execution/tool-executor.js.map +0 -1
- package/dist/agent/index.d.ts +0 -14
- package/dist/agent/index.js +0 -145
- package/dist/agent/index.js.map +0 -1
- package/dist/agent/llm-agent.d.ts +0 -368
- package/dist/agent/llm-agent.js +0 -1931
- package/dist/agent/llm-agent.js.map +0 -1
- package/dist/agent/loop-detector.d.ts +0 -72
- package/dist/agent/loop-detector.js +0 -335
- package/dist/agent/loop-detector.js.map +0 -1
- package/dist/agent/parallel-tools.d.ts +0 -69
- package/dist/agent/parallel-tools.js +0 -188
- package/dist/agent/parallel-tools.js.map +0 -1
- package/dist/agent/planning/index.d.ts +0 -9
- package/dist/agent/planning/index.js +0 -9
- package/dist/agent/planning/index.js.map +0 -1
- package/dist/agent/planning/plan-executor.d.ts +0 -79
- package/dist/agent/planning/plan-executor.js +0 -240
- package/dist/agent/planning/plan-executor.js.map +0 -1
- package/dist/agent/progress-tracker.d.ts +0 -94
- package/dist/agent/progress-tracker.js +0 -225
- package/dist/agent/progress-tracker.js.map +0 -1
- package/dist/agent/specialized/analysis-agent.d.ts +0 -11
- package/dist/agent/specialized/analysis-agent.js +0 -24
- package/dist/agent/specialized/analysis-agent.js.map +0 -1
- package/dist/agent/specialized/debug-agent.d.ts +0 -11
- package/dist/agent/specialized/debug-agent.js +0 -46
- package/dist/agent/specialized/debug-agent.js.map +0 -1
- package/dist/agent/specialized/documentation-agent.d.ts +0 -11
- package/dist/agent/specialized/documentation-agent.js +0 -24
- package/dist/agent/specialized/documentation-agent.js.map +0 -1
- package/dist/agent/specialized/index.d.ts +0 -11
- package/dist/agent/specialized/index.js +0 -12
- package/dist/agent/specialized/index.js.map +0 -1
- package/dist/agent/specialized/performance-agent.d.ts +0 -11
- package/dist/agent/specialized/performance-agent.js +0 -24
- package/dist/agent/specialized/performance-agent.js.map +0 -1
- package/dist/agent/specialized/refactoring-agent.d.ts +0 -11
- package/dist/agent/specialized/refactoring-agent.js +0 -24
- package/dist/agent/specialized/refactoring-agent.js.map +0 -1
- package/dist/agent/specialized/testing-agent.d.ts +0 -11
- package/dist/agent/specialized/testing-agent.js +0 -24
- package/dist/agent/specialized/testing-agent.js.map +0 -1
- package/dist/agent/status-reporter.d.ts +0 -114
- package/dist/agent/status-reporter.js +0 -335
- package/dist/agent/status-reporter.js.map +0 -1
- package/dist/agent/streaming/index.d.ts +0 -9
- package/dist/agent/streaming/index.js +0 -9
- package/dist/agent/streaming/index.js.map +0 -1
- package/dist/agent/streaming/stream-handler.d.ts +0 -62
- package/dist/agent/streaming/stream-handler.js +0 -217
- package/dist/agent/streaming/stream-handler.js.map +0 -1
- package/dist/agent/subagent-orchestrator.d.ts +0 -166
- package/dist/agent/subagent-orchestrator.js +0 -487
- package/dist/agent/subagent-orchestrator.js.map +0 -1
- package/dist/agent/subagent-types.d.ts +0 -261
- package/dist/agent/subagent-types.js +0 -257
- package/dist/agent/subagent-types.js.map +0 -1
- package/dist/agent/subagent.d.ts +0 -116
- package/dist/agent/subagent.js +0 -507
- package/dist/agent/subagent.js.map +0 -1
- package/dist/checkpoint/index.d.ts +0 -9
- package/dist/checkpoint/index.js +0 -11
- package/dist/checkpoint/index.js.map +0 -1
- package/dist/checkpoint/manager.d.ts +0 -101
- package/dist/checkpoint/manager.js +0 -407
- package/dist/checkpoint/manager.js.map +0 -1
- package/dist/checkpoint/storage.d.ts +0 -39
- package/dist/checkpoint/storage.js +0 -350
- package/dist/checkpoint/storage.js.map +0 -1
- package/dist/checkpoint/types.d.ts +0 -111
- package/dist/checkpoint/types.js +0 -17
- package/dist/checkpoint/types.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -7
- package/dist/commands/cache.js +0 -284
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/custom-commands.d.ts +0 -77
- package/dist/commands/custom-commands.js +0 -251
- package/dist/commands/custom-commands.js.map +0 -1
- package/dist/commands/design.d.ts +0 -18
- package/dist/commands/design.js +0 -511
- package/dist/commands/design.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -6
- package/dist/commands/doctor.js +0 -773
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/frontend.d.ts +0 -9
- package/dist/commands/frontend.js +0 -645
- package/dist/commands/frontend.js.map +0 -1
- package/dist/commands/init/wizard.d.ts +0 -55
- package/dist/commands/init/wizard.js +0 -189
- package/dist/commands/init/wizard.js.map +0 -1
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.js +0 -195
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp-migrate.d.ts +0 -9
- package/dist/commands/mcp-migrate.js +0 -175
- package/dist/commands/mcp-migrate.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -2
- package/dist/commands/mcp.js +0 -1292
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/memory.d.ts +0 -6
- package/dist/commands/memory.js +0 -555
- package/dist/commands/memory.js.map +0 -1
- package/dist/commands/models.d.ts +0 -5
- package/dist/commands/models.js +0 -213
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/plan.d.ts +0 -43
- package/dist/commands/plan.js +0 -362
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/rewind.d.ts +0 -19
- package/dist/commands/rewind.js +0 -221
- package/dist/commands/rewind.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -14
- package/dist/commands/setup.js +0 -733
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/status.d.ts +0 -7
- package/dist/commands/status.js +0 -437
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/templates.d.ts +0 -5
- package/dist/commands/templates.js +0 -245
- package/dist/commands/templates.js.map +0 -1
- package/dist/commands/update.d.ts +0 -49
- package/dist/commands/update.js +0 -366
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/usage.d.ts +0 -8
- package/dist/commands/usage.js +0 -264
- package/dist/commands/usage.js.map +0 -1
- package/dist/commands/vscode.d.ts +0 -7
- package/dist/commands/vscode.js +0 -419
- package/dist/commands/vscode.js.map +0 -1
- package/dist/constants.d.ts +0 -236
- package/dist/constants.js +0 -288
- package/dist/constants.js.map +0 -1
- package/dist/design/figma-alias.d.ts +0 -170
- package/dist/design/figma-alias.js +0 -577
- package/dist/design/figma-alias.js.map +0 -1
- package/dist/design/figma-audit.d.ts +0 -40
- package/dist/design/figma-audit.js +0 -383
- package/dist/design/figma-audit.js.map +0 -1
- package/dist/design/figma-client.d.ts +0 -131
- package/dist/design/figma-client.js +0 -369
- package/dist/design/figma-client.js.map +0 -1
- package/dist/design/figma-map.d.ts +0 -29
- package/dist/design/figma-map.js +0 -346
- package/dist/design/figma-map.js.map +0 -1
- package/dist/design/figma-tokens.d.ts +0 -73
- package/dist/design/figma-tokens.js +0 -448
- package/dist/design/figma-tokens.js.map +0 -1
- package/dist/design/index.d.ts +0 -13
- package/dist/design/index.js +0 -20
- package/dist/design/index.js.map +0 -1
- package/dist/design/types.d.ts +0 -98
- package/dist/design/types.js +0 -9
- package/dist/design/types.js.map +0 -1
- package/dist/hooks/hook-runner.d.ts +0 -142
- package/dist/hooks/hook-runner.js +0 -436
- package/dist/hooks/hook-runner.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -9
- package/dist/hooks/index.js +0 -10
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/manager.d.ts +0 -84
- package/dist/hooks/manager.js +0 -348
- package/dist/hooks/manager.js.map +0 -1
- package/dist/hooks/types.d.ts +0 -134
- package/dist/hooks/types.js +0 -9
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/ipc/index.d.ts +0 -9
- package/dist/ipc/index.js +0 -10
- package/dist/ipc/index.js.map +0 -1
- package/dist/ipc/vscode-client.d.ts +0 -200
- package/dist/ipc/vscode-client.js +0 -495
- package/dist/ipc/vscode-client.js.map +0 -1
- package/dist/llm/client.d.ts +0 -205
- package/dist/llm/client.js +0 -735
- package/dist/llm/client.js.map +0 -1
- package/dist/llm/tools.d.ts +0 -102
- package/dist/llm/tools.js +0 -275
- package/dist/llm/tools.js.map +0 -1
- package/dist/llm/types.d.ts +0 -428
- package/dist/llm/types.js +0 -194
- package/dist/llm/types.js.map +0 -1
- package/dist/mcp/automatosx-auto-discovery.d.ts +0 -66
- package/dist/mcp/automatosx-auto-discovery.js +0 -169
- package/dist/mcp/automatosx-auto-discovery.js.map +0 -1
- package/dist/mcp/automatosx-loader.d.ts +0 -99
- package/dist/mcp/automatosx-loader.js +0 -250
- package/dist/mcp/automatosx-loader.js.map +0 -1
- package/dist/mcp/cancellation.d.ts +0 -182
- package/dist/mcp/cancellation.js +0 -275
- package/dist/mcp/cancellation.js.map +0 -1
- package/dist/mcp/client-v2.d.ts +0 -500
- package/dist/mcp/client-v2.js +0 -1433
- package/dist/mcp/client-v2.js.map +0 -1
- package/dist/mcp/client.d.ts +0 -170
- package/dist/mcp/client.js +0 -232
- package/dist/mcp/client.js.map +0 -1
- package/dist/mcp/config-detector.d.ts +0 -90
- package/dist/mcp/config-detector.js +0 -250
- package/dist/mcp/config-detector.js.map +0 -1
- package/dist/mcp/config-migrator.d.ts +0 -68
- package/dist/mcp/config-migrator.js +0 -291
- package/dist/mcp/config-migrator.js.map +0 -1
- package/dist/mcp/config.d.ts +0 -24
- package/dist/mcp/config.js +0 -273
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/constants.d.ts +0 -66
- package/dist/mcp/constants.js +0 -85
- package/dist/mcp/constants.js.map +0 -1
- package/dist/mcp/content-length-transport.d.ts +0 -106
- package/dist/mcp/content-length-transport.js +0 -413
- package/dist/mcp/content-length-transport.js.map +0 -1
- package/dist/mcp/debug.d.ts +0 -211
- package/dist/mcp/debug.js +0 -404
- package/dist/mcp/debug.js.map +0 -1
- package/dist/mcp/error-formatter.d.ts +0 -40
- package/dist/mcp/error-formatter.js +0 -207
- package/dist/mcp/error-formatter.js.map +0 -1
- package/dist/mcp/error-remediation.d.ts +0 -45
- package/dist/mcp/error-remediation.js +0 -291
- package/dist/mcp/error-remediation.js.map +0 -1
- package/dist/mcp/health.d.ts +0 -120
- package/dist/mcp/health.js +0 -267
- package/dist/mcp/health.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -56
- package/dist/mcp/index.js +0 -89
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/invariants.d.ts +0 -141
- package/dist/mcp/invariants.js +0 -243
- package/dist/mcp/invariants.js.map +0 -1
- package/dist/mcp/mutex-safe.d.ts +0 -151
- package/dist/mcp/mutex-safe.js +0 -260
- package/dist/mcp/mutex-safe.js.map +0 -1
- package/dist/mcp/progress.d.ts +0 -155
- package/dist/mcp/progress.js +0 -252
- package/dist/mcp/progress.js.map +0 -1
- package/dist/mcp/prompts.d.ts +0 -68
- package/dist/mcp/prompts.js +0 -129
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/provider-mcp-loader.d.ts +0 -130
- package/dist/mcp/provider-mcp-loader.js +0 -292
- package/dist/mcp/provider-mcp-loader.js.map +0 -1
- package/dist/mcp/reconnection.d.ts +0 -101
- package/dist/mcp/reconnection.js +0 -253
- package/dist/mcp/reconnection.js.map +0 -1
- package/dist/mcp/registry.d.ts +0 -75
- package/dist/mcp/registry.js +0 -276
- package/dist/mcp/registry.js.map +0 -1
- package/dist/mcp/resources.d.ts +0 -58
- package/dist/mcp/resources.js +0 -144
- package/dist/mcp/resources.js.map +0 -1
- package/dist/mcp/schema-validator.d.ts +0 -82
- package/dist/mcp/schema-validator.js +0 -161
- package/dist/mcp/schema-validator.js.map +0 -1
- package/dist/mcp/ssrf-protection.d.ts +0 -86
- package/dist/mcp/ssrf-protection.js +0 -311
- package/dist/mcp/ssrf-protection.js.map +0 -1
- package/dist/mcp/subscriptions.d.ts +0 -168
- package/dist/mcp/subscriptions.js +0 -248
- package/dist/mcp/subscriptions.js.map +0 -1
- package/dist/mcp/templates.d.ts +0 -52
- package/dist/mcp/templates.js +0 -627
- package/dist/mcp/templates.js.map +0 -1
- package/dist/mcp/transports.d.ts +0 -80
- package/dist/mcp/transports.js +0 -237
- package/dist/mcp/transports.js.map +0 -1
- package/dist/mcp/type-safety.d.ts +0 -225
- package/dist/mcp/type-safety.js +0 -237
- package/dist/mcp/type-safety.js.map +0 -1
- package/dist/mcp/validation.d.ts +0 -29
- package/dist/mcp/validation.js +0 -339
- package/dist/mcp/validation.js.map +0 -1
- package/dist/mcp/zai-detector.d.ts +0 -63
- package/dist/mcp/zai-detector.js +0 -193
- package/dist/mcp/zai-detector.js.map +0 -1
- package/dist/mcp/zai-templates.d.ts +0 -90
- package/dist/mcp/zai-templates.js +0 -157
- package/dist/mcp/zai-templates.js.map +0 -1
- package/dist/memory/context-generator.d.ts +0 -84
- package/dist/memory/context-generator.js +0 -546
- package/dist/memory/context-generator.js.map +0 -1
- package/dist/memory/context-injector.d.ts +0 -97
- package/dist/memory/context-injector.js +0 -159
- package/dist/memory/context-injector.js.map +0 -1
- package/dist/memory/context-store.d.ts +0 -103
- package/dist/memory/context-store.js +0 -264
- package/dist/memory/context-store.js.map +0 -1
- package/dist/memory/index.d.ts +0 -43
- package/dist/memory/index.js +0 -49
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/provider-context-store.d.ts +0 -127
- package/dist/memory/provider-context-store.js +0 -385
- package/dist/memory/provider-context-store.js.map +0 -1
- package/dist/memory/schemas.d.ts +0 -118
- package/dist/memory/schemas.js +0 -106
- package/dist/memory/schemas.js.map +0 -1
- package/dist/memory/stats-collector.d.ts +0 -73
- package/dist/memory/stats-collector.js +0 -170
- package/dist/memory/stats-collector.js.map +0 -1
- package/dist/memory/types.d.ts +0 -177
- package/dist/memory/types.js +0 -73
- package/dist/memory/types.js.map +0 -1
- package/dist/permissions/index.d.ts +0 -6
- package/dist/permissions/index.js +0 -7
- package/dist/permissions/index.js.map +0 -1
- package/dist/permissions/permission-manager.d.ts +0 -149
- package/dist/permissions/permission-manager.js +0 -410
- package/dist/permissions/permission-manager.js.map +0 -1
- package/dist/planner/dependency-resolver.d.ts +0 -72
- package/dist/planner/dependency-resolver.js +0 -272
- package/dist/planner/dependency-resolver.js.map +0 -1
- package/dist/planner/index.d.ts +0 -12
- package/dist/planner/index.js +0 -28
- package/dist/planner/index.js.map +0 -1
- package/dist/planner/plan-generator.d.ts +0 -74
- package/dist/planner/plan-generator.js +0 -244
- package/dist/planner/plan-generator.js.map +0 -1
- package/dist/planner/plan-storage.d.ts +0 -113
- package/dist/planner/plan-storage.js +0 -398
- package/dist/planner/plan-storage.js.map +0 -1
- package/dist/planner/prompts/planning-prompt.d.ts +0 -62
- package/dist/planner/prompts/planning-prompt.js +0 -414
- package/dist/planner/prompts/planning-prompt.js.map +0 -1
- package/dist/planner/task-planner.d.ts +0 -139
- package/dist/planner/task-planner.js +0 -532
- package/dist/planner/task-planner.js.map +0 -1
- package/dist/planner/token-estimator.d.ts +0 -63
- package/dist/planner/token-estimator.js +0 -295
- package/dist/planner/token-estimator.js.map +0 -1
- package/dist/planner/types.d.ts +0 -425
- package/dist/planner/types.js +0 -213
- package/dist/planner/types.js.map +0 -1
- package/dist/provider/config.d.ts +0 -227
- package/dist/provider/config.js +0 -430
- package/dist/provider/config.js.map +0 -1
- package/dist/schemas/api-schemas.d.ts +0 -45
- package/dist/schemas/api-schemas.js +0 -129
- package/dist/schemas/api-schemas.js.map +0 -1
- package/dist/schemas/confirmation-schemas.d.ts +0 -39
- package/dist/schemas/confirmation-schemas.js +0 -48
- package/dist/schemas/confirmation-schemas.js.map +0 -1
- package/dist/schemas/index-unified.d.ts +0 -12
- package/dist/schemas/index-unified.js +0 -17
- package/dist/schemas/index-unified.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -83
- package/dist/schemas/index.js +0 -139
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/settings-schemas.d.ts +0 -186
- package/dist/schemas/settings-schemas.js +0 -324
- package/dist/schemas/settings-schemas.js.map +0 -1
- package/dist/schemas/tool-schemas.d.ts +0 -127
- package/dist/schemas/tool-schemas.js +0 -84
- package/dist/schemas/tool-schemas.js.map +0 -1
- package/dist/schemas/yaml-schemas.d.ts +0 -231
- package/dist/schemas/yaml-schemas.js +0 -199
- package/dist/schemas/yaml-schemas.js.map +0 -1
- package/dist/sdk/errors.d.ts +0 -100
- package/dist/sdk/errors.js +0 -138
- package/dist/sdk/errors.js.map +0 -1
- package/dist/sdk/index.d.ts +0 -901
- package/dist/sdk/index.js +0 -1272
- package/dist/sdk/index.js.map +0 -1
- package/dist/sdk/progress-reporter.d.ts +0 -123
- package/dist/sdk/progress-reporter.js +0 -220
- package/dist/sdk/progress-reporter.js.map +0 -1
- package/dist/sdk/testing.d.ts +0 -427
- package/dist/sdk/testing.js +0 -725
- package/dist/sdk/testing.js.map +0 -1
- package/dist/sdk/tool-registry.d.ts +0 -194
- package/dist/sdk/tool-registry.js +0 -326
- package/dist/sdk/tool-registry.js.map +0 -1
- package/dist/sdk/types.d.ts +0 -53
- package/dist/sdk/types.js +0 -8
- package/dist/sdk/types.js.map +0 -1
- package/dist/sdk/unified-logger.d.ts +0 -173
- package/dist/sdk/unified-logger.js +0 -327
- package/dist/sdk/unified-logger.js.map +0 -1
- package/dist/sdk/version.d.ts +0 -163
- package/dist/sdk/version.js +0 -205
- package/dist/sdk/version.js.map +0 -1
- package/dist/tools/ask-user.d.ts +0 -126
- package/dist/tools/ask-user.js +0 -290
- package/dist/tools/ask-user.js.map +0 -1
- package/dist/tools/ax-agent.d.ts +0 -71
- package/dist/tools/ax-agent.js +0 -283
- package/dist/tools/ax-agent.js.map +0 -1
- package/dist/tools/bash-output.d.ts +0 -25
- package/dist/tools/bash-output.js +0 -146
- package/dist/tools/bash-output.js.map +0 -1
- package/dist/tools/bash.d.ts +0 -67
- package/dist/tools/bash.js +0 -522
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/confirmation-tool.d.ts +0 -16
- package/dist/tools/confirmation-tool.js +0 -76
- package/dist/tools/confirmation-tool.js.map +0 -1
- package/dist/tools/definitions/ask-user.d.ts +0 -8
- package/dist/tools/definitions/ask-user.js +0 -168
- package/dist/tools/definitions/ask-user.js.map +0 -1
- package/dist/tools/definitions/ax-agent.d.ts +0 -8
- package/dist/tools/definitions/ax-agent.js +0 -276
- package/dist/tools/definitions/ax-agent.js.map +0 -1
- package/dist/tools/definitions/bash-output.d.ts +0 -7
- package/dist/tools/definitions/bash-output.js +0 -78
- package/dist/tools/definitions/bash-output.js.map +0 -1
- package/dist/tools/definitions/bash.d.ts +0 -8
- package/dist/tools/definitions/bash.js +0 -152
- package/dist/tools/definitions/bash.js.map +0 -1
- package/dist/tools/definitions/create-file.d.ts +0 -7
- package/dist/tools/definitions/create-file.js +0 -129
- package/dist/tools/definitions/create-file.js.map +0 -1
- package/dist/tools/definitions/design.d.ts +0 -12
- package/dist/tools/definitions/design.js +0 -368
- package/dist/tools/definitions/design.js.map +0 -1
- package/dist/tools/definitions/index.d.ts +0 -49
- package/dist/tools/definitions/index.js +0 -87
- package/dist/tools/definitions/index.js.map +0 -1
- package/dist/tools/definitions/multi-edit.d.ts +0 -7
- package/dist/tools/definitions/multi-edit.js +0 -123
- package/dist/tools/definitions/multi-edit.js.map +0 -1
- package/dist/tools/definitions/search.d.ts +0 -7
- package/dist/tools/definitions/search.js +0 -159
- package/dist/tools/definitions/search.js.map +0 -1
- package/dist/tools/definitions/str-replace-editor.d.ts +0 -7
- package/dist/tools/definitions/str-replace-editor.js +0 -145
- package/dist/tools/definitions/str-replace-editor.js.map +0 -1
- package/dist/tools/definitions/todo.d.ts +0 -8
- package/dist/tools/definitions/todo.js +0 -261
- package/dist/tools/definitions/todo.js.map +0 -1
- package/dist/tools/definitions/view-file.d.ts +0 -7
- package/dist/tools/definitions/view-file.js +0 -111
- package/dist/tools/definitions/view-file.js.map +0 -1
- package/dist/tools/design-tool.d.ts +0 -68
- package/dist/tools/design-tool.js +0 -299
- package/dist/tools/design-tool.js.map +0 -1
- package/dist/tools/format-generators.d.ts +0 -62
- package/dist/tools/format-generators.js +0 -291
- package/dist/tools/format-generators.js.map +0 -1
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -11
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/priority-registry.d.ts +0 -124
- package/dist/tools/priority-registry.js +0 -401
- package/dist/tools/priority-registry.js.map +0 -1
- package/dist/tools/priority.d.ts +0 -158
- package/dist/tools/priority.js +0 -350
- package/dist/tools/priority.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -146
- package/dist/tools/registry.js +0 -171
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/search.d.ts +0 -85
- package/dist/tools/search.js +0 -430
- package/dist/tools/search.js.map +0 -1
- package/dist/tools/text-editor.d.ts +0 -87
- package/dist/tools/text-editor.js +0 -1369
- package/dist/tools/text-editor.js.map +0 -1
- package/dist/tools/todo-tool.d.ts +0 -20
- package/dist/tools/todo-tool.js +0 -186
- package/dist/tools/todo-tool.js.map +0 -1
- package/dist/tools/types.d.ts +0 -175
- package/dist/tools/types.js +0 -11
- package/dist/tools/types.js.map +0 -1
- package/dist/types/index.d.ts +0 -30
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/types/project-analysis.d.ts +0 -84
- package/dist/types/project-analysis.js +0 -5
- package/dist/types/project-analysis.js.map +0 -1
- package/dist/types/template.d.ts +0 -53
- package/dist/types/template.js +0 -5
- package/dist/types/template.js.map +0 -1
- package/dist/ui/app.d.ts +0 -7
- package/dist/ui/app.js +0 -102
- package/dist/ui/app.js.map +0 -1
- package/dist/ui/components/api-key-input.d.ts +0 -7
- package/dist/ui/components/api-key-input.js +0 -92
- package/dist/ui/components/api-key-input.js.map +0 -1
- package/dist/ui/components/chat-history.d.ts +0 -12
- package/dist/ui/components/chat-history.js +0 -391
- package/dist/ui/components/chat-history.js.map +0 -1
- package/dist/ui/components/chat-input.d.ts +0 -13
- package/dist/ui/components/chat-input.js +0 -179
- package/dist/ui/components/chat-input.js.map +0 -1
- package/dist/ui/components/chat-interface.d.ts +0 -11
- package/dist/ui/components/chat-interface.js +0 -830
- package/dist/ui/components/chat-interface.js.map +0 -1
- package/dist/ui/components/collapsible-tool-result.d.ts +0 -42
- package/dist/ui/components/collapsible-tool-result.js +0 -216
- package/dist/ui/components/collapsible-tool-result.js.map +0 -1
- package/dist/ui/components/command-suggestions.d.ts +0 -29
- package/dist/ui/components/command-suggestions.js +0 -88
- package/dist/ui/components/command-suggestions.js.map +0 -1
- package/dist/ui/components/confirmation-dialog.d.ts +0 -11
- package/dist/ui/components/confirmation-dialog.js +0 -100
- package/dist/ui/components/confirmation-dialog.js.map +0 -1
- package/dist/ui/components/context-breakdown.d.ts +0 -23
- package/dist/ui/components/context-breakdown.js +0 -124
- package/dist/ui/components/context-breakdown.js.map +0 -1
- package/dist/ui/components/diff-renderer.d.ts +0 -13
- package/dist/ui/components/diff-renderer.js +0 -192
- package/dist/ui/components/diff-renderer.js.map +0 -1
- package/dist/ui/components/index.d.ts +0 -18
- package/dist/ui/components/index.js +0 -20
- package/dist/ui/components/index.js.map +0 -1
- package/dist/ui/components/keyboard-help.d.ts +0 -17
- package/dist/ui/components/keyboard-help.js +0 -122
- package/dist/ui/components/keyboard-help.js.map +0 -1
- package/dist/ui/components/keyboard-hints.d.ts +0 -35
- package/dist/ui/components/keyboard-hints.js +0 -142
- package/dist/ui/components/keyboard-hints.js.map +0 -1
- package/dist/ui/components/loading-spinner.d.ts +0 -9
- package/dist/ui/components/loading-spinner.js +0 -120
- package/dist/ui/components/loading-spinner.js.map +0 -1
- package/dist/ui/components/mcp-dashboard.d.ts +0 -15
- package/dist/ui/components/mcp-dashboard.js +0 -520
- package/dist/ui/components/mcp-dashboard.js.map +0 -1
- package/dist/ui/components/mcp-status.d.ts +0 -5
- package/dist/ui/components/mcp-status.js +0 -58
- package/dist/ui/components/mcp-status.js.map +0 -1
- package/dist/ui/components/model-selection.d.ts +0 -12
- package/dist/ui/components/model-selection.js +0 -17
- package/dist/ui/components/model-selection.js.map +0 -1
- package/dist/ui/components/phase-progress.d.ts +0 -21
- package/dist/ui/components/phase-progress.js +0 -185
- package/dist/ui/components/phase-progress.js.map +0 -1
- package/dist/ui/components/question-dialog.d.ts +0 -17
- package/dist/ui/components/question-dialog.js +0 -181
- package/dist/ui/components/question-dialog.js.map +0 -1
- package/dist/ui/components/quick-actions.d.ts +0 -12
- package/dist/ui/components/quick-actions.js +0 -171
- package/dist/ui/components/quick-actions.js.map +0 -1
- package/dist/ui/components/reasoning-display.d.ts +0 -36
- package/dist/ui/components/reasoning-display.js +0 -46
- package/dist/ui/components/reasoning-display.js.map +0 -1
- package/dist/ui/components/status-bar.d.ts +0 -47
- package/dist/ui/components/status-bar.js +0 -310
- package/dist/ui/components/status-bar.js.map +0 -1
- package/dist/ui/components/subagent-monitor.d.ts +0 -41
- package/dist/ui/components/subagent-monitor.js +0 -122
- package/dist/ui/components/subagent-monitor.js.map +0 -1
- package/dist/ui/components/toast-notification.d.ts +0 -197
- package/dist/ui/components/toast-notification.js +0 -190
- package/dist/ui/components/toast-notification.js.map +0 -1
- package/dist/ui/components/tool-group-display.d.ts +0 -19
- package/dist/ui/components/tool-group-display.js +0 -222
- package/dist/ui/components/tool-group-display.js.map +0 -1
- package/dist/ui/components/virtualized-chat-history.d.ts +0 -33
- package/dist/ui/components/virtualized-chat-history.js +0 -182
- package/dist/ui/components/virtualized-chat-history.js.map +0 -1
- package/dist/ui/components/welcome-panel.d.ts +0 -11
- package/dist/ui/components/welcome-panel.js +0 -225
- package/dist/ui/components/welcome-panel.js.map +0 -1
- package/dist/ui/hooks/use-chat-reducer.d.ts +0 -69
- package/dist/ui/hooks/use-chat-reducer.js +0 -118
- package/dist/ui/hooks/use-chat-reducer.js.map +0 -1
- package/dist/ui/hooks/use-enhanced-input.d.ts +0 -53
- package/dist/ui/hooks/use-enhanced-input.js +0 -1275
- package/dist/ui/hooks/use-enhanced-input.js.map +0 -1
- package/dist/ui/hooks/use-input-handler.d.ts +0 -79
- package/dist/ui/hooks/use-input-handler.js +0 -2251
- package/dist/ui/hooks/use-input-handler.js.map +0 -1
- package/dist/ui/hooks/use-input-history.d.ts +0 -9
- package/dist/ui/hooks/use-input-history.js +0 -168
- package/dist/ui/hooks/use-input-history.js.map +0 -1
- package/dist/ui/shared/max-sized-box.d.ts +0 -17
- package/dist/ui/shared/max-sized-box.js +0 -14
- package/dist/ui/shared/max-sized-box.js.map +0 -1
- package/dist/ui/themes/index.d.ts +0 -5
- package/dist/ui/themes/index.js +0 -5
- package/dist/ui/themes/index.js.map +0 -1
- package/dist/ui/themes/theme-registry.d.ts +0 -55
- package/dist/ui/themes/theme-registry.js +0 -202
- package/dist/ui/themes/theme-registry.js.map +0 -1
- package/dist/ui/utils/bracketed-paste-handler.d.ts +0 -97
- package/dist/ui/utils/bracketed-paste-handler.js +0 -322
- package/dist/ui/utils/bracketed-paste-handler.js.map +0 -1
- package/dist/ui/utils/change-summarizer.d.ts +0 -20
- package/dist/ui/utils/change-summarizer.js +0 -282
- package/dist/ui/utils/change-summarizer.js.map +0 -1
- package/dist/ui/utils/code-colorizer.d.ts +0 -9
- package/dist/ui/utils/code-colorizer.js +0 -13
- package/dist/ui/utils/code-colorizer.js.map +0 -1
- package/dist/ui/utils/colors.d.ts +0 -41
- package/dist/ui/utils/colors.js +0 -80
- package/dist/ui/utils/colors.js.map +0 -1
- package/dist/ui/utils/image-handler.d.ts +0 -29
- package/dist/ui/utils/image-handler.js +0 -129
- package/dist/ui/utils/image-handler.js.map +0 -1
- package/dist/ui/utils/markdown-renderer.d.ts +0 -4
- package/dist/ui/utils/markdown-renderer.js +0 -40
- package/dist/ui/utils/markdown-renderer.js.map +0 -1
- package/dist/ui/utils/semantic-action-detector.d.ts +0 -49
- package/dist/ui/utils/semantic-action-detector.js +0 -339
- package/dist/ui/utils/semantic-action-detector.js.map +0 -1
- package/dist/ui/utils/tool-grouper.d.ts +0 -94
- package/dist/ui/utils/tool-grouper.js +0 -618
- package/dist/ui/utils/tool-grouper.js.map +0 -1
- package/dist/utils/api-error.d.ts +0 -61
- package/dist/utils/api-error.js +0 -176
- package/dist/utils/api-error.js.map +0 -1
- package/dist/utils/audit-logger.d.ts +0 -206
- package/dist/utils/audit-logger.js +0 -286
- package/dist/utils/audit-logger.js.map +0 -1
- package/dist/utils/auto-accept-logger.d.ts +0 -175
- package/dist/utils/auto-accept-logger.js +0 -423
- package/dist/utils/auto-accept-logger.js.map +0 -1
- package/dist/utils/automatosx-detector.d.ts +0 -19
- package/dist/utils/automatosx-detector.js +0 -52
- package/dist/utils/automatosx-detector.js.map +0 -1
- package/dist/utils/background-task-manager.d.ts +0 -114
- package/dist/utils/background-task-manager.js +0 -470
- package/dist/utils/background-task-manager.js.map +0 -1
- package/dist/utils/cache.d.ts +0 -77
- package/dist/utils/cache.js +0 -180
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/command-security.d.ts +0 -85
- package/dist/utils/command-security.js +0 -210
- package/dist/utils/command-security.js.map +0 -1
- package/dist/utils/config-loader.d.ts +0 -190
- package/dist/utils/config-loader.js +0 -108
- package/dist/utils/config-loader.js.map +0 -1
- package/dist/utils/confirmation-service.d.ts +0 -51
- package/dist/utils/confirmation-service.js +0 -220
- package/dist/utils/confirmation-service.js.map +0 -1
- package/dist/utils/console-messenger.d.ts +0 -80
- package/dist/utils/console-messenger.js +0 -142
- package/dist/utils/console-messenger.js.map +0 -1
- package/dist/utils/custom-instructions.d.ts +0 -1
- package/dist/utils/custom-instructions.js +0 -24
- package/dist/utils/custom-instructions.js.map +0 -1
- package/dist/utils/encryption.d.ts +0 -86
- package/dist/utils/encryption.js +0 -236
- package/dist/utils/encryption.js.map +0 -1
- package/dist/utils/enhanced-error-messages.d.ts +0 -33
- package/dist/utils/enhanced-error-messages.js +0 -440
- package/dist/utils/enhanced-error-messages.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -65
- package/dist/utils/error-handler.js +0 -148
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/error-translator.d.ts +0 -25
- package/dist/utils/error-translator.js +0 -203
- package/dist/utils/error-translator.js.map +0 -1
- package/dist/utils/external-editor.d.ts +0 -47
- package/dist/utils/external-editor.js +0 -179
- package/dist/utils/external-editor.js.map +0 -1
- package/dist/utils/file-cache.d.ts +0 -148
- package/dist/utils/file-cache.js +0 -413
- package/dist/utils/file-cache.js.map +0 -1
- package/dist/utils/file-lock.d.ts +0 -141
- package/dist/utils/file-lock.js +0 -554
- package/dist/utils/file-lock.js.map +0 -1
- package/dist/utils/file-mentions.d.ts +0 -68
- package/dist/utils/file-mentions.js +0 -225
- package/dist/utils/file-mentions.js.map +0 -1
- package/dist/utils/history-manager.d.ts +0 -52
- package/dist/utils/history-manager.js +0 -211
- package/dist/utils/history-manager.js.map +0 -1
- package/dist/utils/history-migration.d.ts +0 -9
- package/dist/utils/history-migration.js +0 -37
- package/dist/utils/history-migration.js.map +0 -1
- package/dist/utils/image-processor.d.ts +0 -33
- package/dist/utils/image-processor.js +0 -124
- package/dist/utils/image-processor.js.map +0 -1
- package/dist/utils/index.d.ts +0 -92
- package/dist/utils/index.js +0 -111
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/init-previewer.d.ts +0 -56
- package/dist/utils/init-previewer.js +0 -239
- package/dist/utils/init-previewer.js.map +0 -1
- package/dist/utils/init-validator.d.ts +0 -65
- package/dist/utils/init-validator.js +0 -252
- package/dist/utils/init-validator.js.map +0 -1
- package/dist/utils/input-sanitizer.d.ts +0 -210
- package/dist/utils/input-sanitizer.js +0 -362
- package/dist/utils/input-sanitizer.js.map +0 -1
- package/dist/utils/instruction-generator.d.ts +0 -21
- package/dist/utils/instruction-generator.js +0 -233
- package/dist/utils/instruction-generator.js.map +0 -1
- package/dist/utils/json-utils.d.ts +0 -72
- package/dist/utils/json-utils.js +0 -226
- package/dist/utils/json-utils.js.map +0 -1
- package/dist/utils/llm-optimized-instruction-generator.d.ts +0 -36
- package/dist/utils/llm-optimized-instruction-generator.js +0 -365
- package/dist/utils/llm-optimized-instruction-generator.js.map +0 -1
- package/dist/utils/message-optimizer.d.ts +0 -100
- package/dist/utils/message-optimizer.js +0 -297
- package/dist/utils/message-optimizer.js.map +0 -1
- package/dist/utils/onboarding-manager.d.ts +0 -45
- package/dist/utils/onboarding-manager.js +0 -131
- package/dist/utils/onboarding-manager.js.map +0 -1
- package/dist/utils/parallel-analyzer.d.ts +0 -123
- package/dist/utils/parallel-analyzer.js +0 -241
- package/dist/utils/parallel-analyzer.js.map +0 -1
- package/dist/utils/paste-utils.d.ts +0 -99
- package/dist/utils/paste-utils.js +0 -295
- package/dist/utils/paste-utils.js.map +0 -1
- package/dist/utils/path-helpers.d.ts +0 -8
- package/dist/utils/path-helpers.js +0 -35
- package/dist/utils/path-helpers.js.map +0 -1
- package/dist/utils/path-security.d.ts +0 -92
- package/dist/utils/path-security.js +0 -300
- package/dist/utils/path-security.js.map +0 -1
- package/dist/utils/path-utils.d.ts +0 -83
- package/dist/utils/path-utils.js +0 -122
- package/dist/utils/path-utils.js.map +0 -1
- package/dist/utils/path-validator.d.ts +0 -66
- package/dist/utils/path-validator.js +0 -141
- package/dist/utils/path-validator.js.map +0 -1
- package/dist/utils/performance.d.ts +0 -74
- package/dist/utils/performance.js +0 -133
- package/dist/utils/performance.js.map +0 -1
- package/dist/utils/process-pool.d.ts +0 -109
- package/dist/utils/process-pool.js +0 -332
- package/dist/utils/process-pool.js.map +0 -1
- package/dist/utils/progress-tracker.d.ts +0 -51
- package/dist/utils/progress-tracker.js +0 -152
- package/dist/utils/progress-tracker.js.map +0 -1
- package/dist/utils/project-analyzer.d.ts +0 -49
- package/dist/utils/project-analyzer.js +0 -396
- package/dist/utils/project-analyzer.js.map +0 -1
- package/dist/utils/prompt-builder.d.ts +0 -14
- package/dist/utils/prompt-builder.js +0 -100
- package/dist/utils/prompt-builder.js.map +0 -1
- package/dist/utils/provider-context.d.ts +0 -243
- package/dist/utils/provider-context.js +0 -421
- package/dist/utils/provider-context.js.map +0 -1
- package/dist/utils/provider-file-cache.d.ts +0 -91
- package/dist/utils/provider-file-cache.js +0 -165
- package/dist/utils/provider-file-cache.js.map +0 -1
- package/dist/utils/provider-settings.d.ts +0 -181
- package/dist/utils/provider-settings.js +0 -450
- package/dist/utils/provider-settings.js.map +0 -1
- package/dist/utils/rate-limiter.d.ts +0 -222
- package/dist/utils/rate-limiter.js +0 -338
- package/dist/utils/rate-limiter.js.map +0 -1
- package/dist/utils/retry-helper.d.ts +0 -81
- package/dist/utils/retry-helper.js +0 -244
- package/dist/utils/retry-helper.js.map +0 -1
- package/dist/utils/safety-rules.d.ts +0 -64
- package/dist/utils/safety-rules.js +0 -225
- package/dist/utils/safety-rules.js.map +0 -1
- package/dist/utils/settings-manager.d.ts +0 -256
- package/dist/utils/settings-manager.js +0 -967
- package/dist/utils/settings-manager.js.map +0 -1
- package/dist/utils/setup-validator.d.ts +0 -47
- package/dist/utils/setup-validator.js +0 -304
- package/dist/utils/setup-validator.js.map +0 -1
- package/dist/utils/string-utils.d.ts +0 -19
- package/dist/utils/string-utils.js +0 -28
- package/dist/utils/string-utils.js.map +0 -1
- package/dist/utils/template-manager.d.ts +0 -62
- package/dist/utils/template-manager.js +0 -366
- package/dist/utils/template-manager.js.map +0 -1
- package/dist/utils/text-utils.d.ts +0 -82
- package/dist/utils/text-utils.js +0 -203
- package/dist/utils/text-utils.js.map +0 -1
- package/dist/utils/token-counter.d.ts +0 -76
- package/dist/utils/token-counter.js +0 -231
- package/dist/utils/token-counter.js.map +0 -1
- package/dist/utils/usage-tracker.d.ts +0 -78
- package/dist/utils/usage-tracker.js +0 -126
- package/dist/utils/usage-tracker.js.map +0 -1
- package/dist/utils/version.d.ts +0 -14
- package/dist/utils/version.js +0 -70
- package/dist/utils/version.js.map +0 -1
package/dist/mcp/client-v2.js
DELETED
|
@@ -1,1433 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type-Safe MCP Client (Phase 1 Improvements)
|
|
3
|
-
*
|
|
4
|
-
* Improvements applied:
|
|
5
|
-
* 1. SafeMutex with lock tokens (prevents race conditions)
|
|
6
|
-
* 2. Result types for all public APIs (explicit error handling)
|
|
7
|
-
* 3. State machine for connection tracking (type-safe states)
|
|
8
|
-
* 4. Branded types for ServerName/ToolName (prevent confusion)
|
|
9
|
-
* 5. Invariant checks (runtime validation)
|
|
10
|
-
*
|
|
11
|
-
* Coverage: 70% → 85%+ (Phase 1)
|
|
12
|
-
*/
|
|
13
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
14
|
-
import { ProgressNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
15
|
-
import { EventEmitter } from "events";
|
|
16
|
-
import { createTransport } from "./transports.js";
|
|
17
|
-
import { MCP_CONFIG, ERROR_MESSAGES } from "../constants.js";
|
|
18
|
-
import { MCPServerConfigSchema } from "../schemas/settings-schemas.js";
|
|
19
|
-
import { getTokenCounter } from "../utils/token-counter.js";
|
|
20
|
-
// Phase 1: Import type safety utilities
|
|
21
|
-
import { SafeKeyedMutex } from "./mutex-safe.js";
|
|
22
|
-
import { Ok, Err, toError } from "./type-safety.js";
|
|
23
|
-
import { createServerName, createToolName } from "./type-safety.js";
|
|
24
|
-
import { assertValidServerName } from "./invariants.js";
|
|
25
|
-
import { getProgressTracker } from "./progress.js";
|
|
26
|
-
import { getCancellationManager, isRequestCancelled } from "./cancellation.js";
|
|
27
|
-
import { getSubscriptionManager } from "./subscriptions.js";
|
|
28
|
-
import { getToolOutputValidator } from "./schema-validator.js";
|
|
29
|
-
import { randomUUID } from 'crypto';
|
|
30
|
-
/**
|
|
31
|
-
* Default reconnection configuration
|
|
32
|
-
*/
|
|
33
|
-
export const DEFAULT_RECONNECTION_CONFIG = {
|
|
34
|
-
enabled: true,
|
|
35
|
-
maxRetries: 5,
|
|
36
|
-
initialDelayMs: 1000,
|
|
37
|
-
maxDelayMs: MCP_CONFIG.RECONNECT_MAX_DELAY,
|
|
38
|
-
backoffMultiplier: 2
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Default health check configuration
|
|
42
|
-
*/
|
|
43
|
-
export const DEFAULT_HEALTH_CHECK_CONFIG = {
|
|
44
|
-
enabled: true,
|
|
45
|
-
intervalMs: MCP_CONFIG.HEALTH_CHECK_INTERVAL
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Type-safe MCP Manager with improved safety
|
|
49
|
-
*/
|
|
50
|
-
export class MCPManagerV2 extends EventEmitter {
|
|
51
|
-
// Phase 1: Replace Maps with state machine
|
|
52
|
-
connections = new Map();
|
|
53
|
-
tools = new Map();
|
|
54
|
-
prompts = new Map(); // key: mcp__servername__promptname
|
|
55
|
-
// Phase 1: Use SafeMutex instead of pendingConnections Map
|
|
56
|
-
connectionMutex = new SafeKeyedMutex();
|
|
57
|
-
initializationPromise = null;
|
|
58
|
-
tokenCounter = getTokenCounter();
|
|
59
|
-
disposed = false;
|
|
60
|
-
disposing = false;
|
|
61
|
-
disposePromise = null;
|
|
62
|
-
// Phase 2: Reconnection management
|
|
63
|
-
reconnectionConfig;
|
|
64
|
-
healthCheckConfig;
|
|
65
|
-
reconnectionAttempts = new Map();
|
|
66
|
-
reconnectionTimers = new Map();
|
|
67
|
-
serverConfigs = new Map();
|
|
68
|
-
healthCheckTimer = null;
|
|
69
|
-
healthCheckInFlight = false;
|
|
70
|
-
// MCP Client identification (sent to MCP servers during initialization)
|
|
71
|
-
clientName;
|
|
72
|
-
clientVersion;
|
|
73
|
-
constructor(reconnectionConfig = {}, healthCheckConfig = {}, clientConfig) {
|
|
74
|
-
super();
|
|
75
|
-
this.reconnectionConfig = {
|
|
76
|
-
...DEFAULT_RECONNECTION_CONFIG,
|
|
77
|
-
...reconnectionConfig
|
|
78
|
-
};
|
|
79
|
-
this.healthCheckConfig = {
|
|
80
|
-
...DEFAULT_HEALTH_CHECK_CONFIG,
|
|
81
|
-
...healthCheckConfig
|
|
82
|
-
};
|
|
83
|
-
// Use provided client name/version or fall back to MCP_CONFIG defaults
|
|
84
|
-
this.clientName = clientConfig?.name ?? MCP_CONFIG.CLIENT_NAME;
|
|
85
|
-
this.clientVersion = clientConfig?.version ?? MCP_CONFIG.CLIENT_VERSION;
|
|
86
|
-
// Start health checks if enabled
|
|
87
|
-
if (this.healthCheckConfig.enabled) {
|
|
88
|
-
this.startHealthChecks();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Transition server to failed state (reduces duplication)
|
|
93
|
-
*/
|
|
94
|
-
_setFailedState(serverName, error) {
|
|
95
|
-
this.connections.set(serverName, {
|
|
96
|
-
status: 'failed',
|
|
97
|
-
serverName,
|
|
98
|
-
error,
|
|
99
|
-
failedAt: Date.now()
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Add MCP server with type-safe connection management
|
|
104
|
-
*
|
|
105
|
-
* Phase 1 improvements:
|
|
106
|
-
* - Returns Result instead of throwing
|
|
107
|
-
* - Uses SafeMutex for concurrency control
|
|
108
|
-
* - Tracks state machine transitions
|
|
109
|
-
* - Validates inputs with invariants
|
|
110
|
-
*/
|
|
111
|
-
async addServer(config) {
|
|
112
|
-
// Phase 1: Check if disposed
|
|
113
|
-
if (this.disposed || this.disposing) {
|
|
114
|
-
return Err(new Error('MCPManager is disposed'));
|
|
115
|
-
}
|
|
116
|
-
// Phase 1: Validate server name (branded type creation)
|
|
117
|
-
const serverName = createServerName(config.name);
|
|
118
|
-
if (!serverName) {
|
|
119
|
-
return Err(new Error(`Invalid server name: "${config.name}"`));
|
|
120
|
-
}
|
|
121
|
-
// Phase 1: Check current state
|
|
122
|
-
const currentState = this.connections.get(serverName);
|
|
123
|
-
if (currentState) {
|
|
124
|
-
switch (currentState.status) {
|
|
125
|
-
case 'connected':
|
|
126
|
-
return Ok(undefined); // Already connected
|
|
127
|
-
case 'connecting':
|
|
128
|
-
// Wait for existing connection attempt
|
|
129
|
-
return await currentState.promise;
|
|
130
|
-
case 'disconnecting':
|
|
131
|
-
return Err(new Error(`Server ${serverName} is disconnecting`));
|
|
132
|
-
case 'failed':
|
|
133
|
-
// Can retry after failure
|
|
134
|
-
break;
|
|
135
|
-
case 'idle':
|
|
136
|
-
// Can connect
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Phase 1: Use SafeMutex for concurrency control
|
|
141
|
-
const mutexResult = await this.connectionMutex.runExclusive(serverName, async () => {
|
|
142
|
-
// Double-check state inside mutex
|
|
143
|
-
const state = this.connections.get(serverName);
|
|
144
|
-
if (state?.status === 'connected') {
|
|
145
|
-
return Ok(undefined);
|
|
146
|
-
}
|
|
147
|
-
return await this._addServerInternal(serverName, config);
|
|
148
|
-
});
|
|
149
|
-
// Unwrap nested Result
|
|
150
|
-
if (!mutexResult.success) {
|
|
151
|
-
return mutexResult;
|
|
152
|
-
}
|
|
153
|
-
return mutexResult.value;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Internal connection logic with state transitions
|
|
157
|
-
*/
|
|
158
|
-
async _addServerInternal(serverName, config) {
|
|
159
|
-
// Validate config with Zod
|
|
160
|
-
const validationResult = MCPServerConfigSchema.safeParse(config);
|
|
161
|
-
if (!validationResult.success) {
|
|
162
|
-
const error = new Error(`Invalid MCP server config: ${validationResult.error.message}`);
|
|
163
|
-
this._setFailedState(serverName, error);
|
|
164
|
-
return Err(error);
|
|
165
|
-
}
|
|
166
|
-
const validatedConfig = validationResult.data;
|
|
167
|
-
// Phase 2: Store server config for reconnection attempts
|
|
168
|
-
this.serverConfigs.set(serverName, validatedConfig);
|
|
169
|
-
// Handle legacy stdio-only configuration
|
|
170
|
-
let transportConfig = validatedConfig.transport;
|
|
171
|
-
if (!transportConfig && validatedConfig.command) {
|
|
172
|
-
transportConfig = {
|
|
173
|
-
type: 'stdio',
|
|
174
|
-
command: validatedConfig.command,
|
|
175
|
-
args: validatedConfig.args,
|
|
176
|
-
env: validatedConfig.env
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
if (!transportConfig) {
|
|
180
|
-
const error = new Error(ERROR_MESSAGES.TRANSPORT_CONFIG_REQUIRED);
|
|
181
|
-
this._setFailedState(serverName, error);
|
|
182
|
-
return Err(error);
|
|
183
|
-
}
|
|
184
|
-
// Pass quiet option from server config to transport config
|
|
185
|
-
const transportWithQuiet = {
|
|
186
|
-
...transportConfig,
|
|
187
|
-
quiet: validatedConfig.quiet ?? false
|
|
188
|
-
};
|
|
189
|
-
try {
|
|
190
|
-
// Transition to connecting state
|
|
191
|
-
const startedAt = Date.now();
|
|
192
|
-
const connectingPromise = (async () => {
|
|
193
|
-
try {
|
|
194
|
-
// Create transport (with quiet option for stderr suppression)
|
|
195
|
-
const transport = createTransport(transportWithQuiet);
|
|
196
|
-
// Create client with provider-specific identification
|
|
197
|
-
const client = new Client({
|
|
198
|
-
name: this.clientName,
|
|
199
|
-
version: this.clientVersion
|
|
200
|
-
}, {
|
|
201
|
-
capabilities: {} // SDK v1.22+ doesn't have tools in client capabilities
|
|
202
|
-
});
|
|
203
|
-
// Connect with configurable initialization timeout
|
|
204
|
-
// Default is MCP_CONFIG.DEFAULT_TIMEOUT (60s), but servers using npx may need longer
|
|
205
|
-
const initTimeout = validatedConfig.initTimeout ?? MCP_CONFIG.DEFAULT_TIMEOUT;
|
|
206
|
-
const sdkTransport = await transport.connect();
|
|
207
|
-
await client.connect(sdkTransport, { timeout: initTimeout });
|
|
208
|
-
// Set up MCP notification handlers for progress and resource updates
|
|
209
|
-
this.setupNotificationHandlers(client, serverName);
|
|
210
|
-
// If dispose started while connecting, shut down and abort transition
|
|
211
|
-
if (this.disposing || this.disposed) {
|
|
212
|
-
try {
|
|
213
|
-
await client.close();
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
// best-effort close during disposal
|
|
217
|
-
}
|
|
218
|
-
try {
|
|
219
|
-
await transport.disconnect();
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// ignore during disposal
|
|
223
|
-
}
|
|
224
|
-
// Remove the stale connecting entry so shutdown can proceed
|
|
225
|
-
const state = this.connections.get(serverName);
|
|
226
|
-
if (state?.status === 'connecting') {
|
|
227
|
-
this.connections.delete(serverName);
|
|
228
|
-
}
|
|
229
|
-
return Err(new Error(`MCPManager is disposing - aborted connection for ${serverName}`));
|
|
230
|
-
}
|
|
231
|
-
// List tools
|
|
232
|
-
const toolsResult = await client.listTools();
|
|
233
|
-
// Register tools with branded types
|
|
234
|
-
for (const tool of toolsResult.tools) {
|
|
235
|
-
const toolName = createToolName(`mcp__${serverName}__${tool.name}`);
|
|
236
|
-
if (!toolName) {
|
|
237
|
-
console.warn(`Invalid tool name: ${tool.name}`);
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
const mcpTool = {
|
|
241
|
-
name: toolName,
|
|
242
|
-
description: tool.description || `Tool from ${serverName} server`,
|
|
243
|
-
inputSchema: tool.inputSchema,
|
|
244
|
-
// MCP 2025-06-18: Include output schema if provided by server
|
|
245
|
-
outputSchema: tool.outputSchema,
|
|
246
|
-
serverName
|
|
247
|
-
};
|
|
248
|
-
this.tools.set(toolName, mcpTool);
|
|
249
|
-
}
|
|
250
|
-
// Transition to connected state
|
|
251
|
-
this.connections.set(serverName, {
|
|
252
|
-
status: 'connected',
|
|
253
|
-
serverName,
|
|
254
|
-
client,
|
|
255
|
-
transport,
|
|
256
|
-
connectedAt: Date.now()
|
|
257
|
-
});
|
|
258
|
-
this.emit('serverAdded', serverName, toolsResult.tools.length);
|
|
259
|
-
return Ok(undefined);
|
|
260
|
-
}
|
|
261
|
-
catch (error) {
|
|
262
|
-
const err = toError(error);
|
|
263
|
-
this._setFailedState(serverName, err);
|
|
264
|
-
this.emit('serverError', serverName, err);
|
|
265
|
-
if (this.reconnectionConfig.enabled && !this.disposed) {
|
|
266
|
-
this.scheduleReconnection(serverName, validatedConfig);
|
|
267
|
-
}
|
|
268
|
-
return Err(err);
|
|
269
|
-
}
|
|
270
|
-
})();
|
|
271
|
-
this.connections.set(serverName, {
|
|
272
|
-
status: 'connecting',
|
|
273
|
-
serverName,
|
|
274
|
-
startedAt,
|
|
275
|
-
promise: connectingPromise
|
|
276
|
-
});
|
|
277
|
-
return await connectingPromise;
|
|
278
|
-
}
|
|
279
|
-
catch (error) {
|
|
280
|
-
const err = toError(error);
|
|
281
|
-
this._setFailedState(serverName, err);
|
|
282
|
-
if (this.reconnectionConfig.enabled && !this.disposed) {
|
|
283
|
-
this.scheduleReconnection(serverName, validatedConfig);
|
|
284
|
-
}
|
|
285
|
-
return Err(err);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Remove MCP server with proper state transitions
|
|
290
|
-
*/
|
|
291
|
-
async removeServer(serverName) {
|
|
292
|
-
// Phase 1: Check if disposed
|
|
293
|
-
if (this.disposed) {
|
|
294
|
-
return Err(new Error('MCPManager is disposed'));
|
|
295
|
-
}
|
|
296
|
-
// Phase 1: Validate server name
|
|
297
|
-
assertValidServerName(serverName);
|
|
298
|
-
// Phase 2: Cancel any pending reconnection attempts
|
|
299
|
-
this.cancelReconnection(serverName);
|
|
300
|
-
this.reconnectionAttempts.delete(serverName);
|
|
301
|
-
this.serverConfigs.delete(serverName);
|
|
302
|
-
// BUG FIX: Use mutex to prevent TOCTOU race with addServer/callTool
|
|
303
|
-
const mutexResult = await this.connectionMutex.runExclusive(serverName, async () => {
|
|
304
|
-
// Re-check state inside mutex (prevent race conditions)
|
|
305
|
-
const state = this.connections.get(serverName);
|
|
306
|
-
if (!state) {
|
|
307
|
-
return Err(new Error(`Server ${serverName} not found`));
|
|
308
|
-
}
|
|
309
|
-
// Check if we can disconnect from current state
|
|
310
|
-
if (state.status === 'connecting') {
|
|
311
|
-
return Err(new Error(`Server ${serverName} is still connecting`));
|
|
312
|
-
}
|
|
313
|
-
if (state.status === 'disconnecting') {
|
|
314
|
-
return Err(new Error(`Server ${serverName} is already disconnecting`));
|
|
315
|
-
}
|
|
316
|
-
if (state.status !== 'connected') {
|
|
317
|
-
// Remove from map if not connected
|
|
318
|
-
this.connections.delete(serverName);
|
|
319
|
-
return Ok(undefined);
|
|
320
|
-
}
|
|
321
|
-
return await this._removeServerInternal(serverName, state);
|
|
322
|
-
});
|
|
323
|
-
// Unwrap nested Result
|
|
324
|
-
if (!mutexResult.success) {
|
|
325
|
-
return mutexResult;
|
|
326
|
-
}
|
|
327
|
-
return mutexResult.value;
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Internal disconnection logic with state transitions
|
|
331
|
-
*/
|
|
332
|
-
async _removeServerInternal(serverName, state) {
|
|
333
|
-
// Transition to disconnecting state
|
|
334
|
-
this.connections.set(serverName, {
|
|
335
|
-
status: 'disconnecting',
|
|
336
|
-
serverName,
|
|
337
|
-
client: state.client,
|
|
338
|
-
transport: state.transport
|
|
339
|
-
});
|
|
340
|
-
try {
|
|
341
|
-
// Remove tools
|
|
342
|
-
for (const [toolName, tool] of this.tools.entries()) {
|
|
343
|
-
if (tool.serverName === serverName) {
|
|
344
|
-
this.tools.delete(toolName);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
// Disconnect client
|
|
348
|
-
const clientResult = await this.closeClient(state.client, serverName);
|
|
349
|
-
// Disconnect transport
|
|
350
|
-
const transportResult = await this.disconnectTransport(state.transport, serverName);
|
|
351
|
-
// Aggregate errors
|
|
352
|
-
const errors = [];
|
|
353
|
-
if (!clientResult.success)
|
|
354
|
-
errors.push(clientResult.error);
|
|
355
|
-
if (!transportResult.success)
|
|
356
|
-
errors.push(transportResult.error);
|
|
357
|
-
// Transition to idle state
|
|
358
|
-
this.connections.delete(serverName);
|
|
359
|
-
this.emit('serverRemoved', serverName);
|
|
360
|
-
if (errors.length > 0) {
|
|
361
|
-
return Err(new AggregateError(errors, `Failed to fully disconnect ${serverName}`));
|
|
362
|
-
}
|
|
363
|
-
return Ok(undefined);
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
// Even if error, remove from state
|
|
367
|
-
this.connections.delete(serverName);
|
|
368
|
-
return Err(toError(error));
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Close client with error handling
|
|
373
|
-
*/
|
|
374
|
-
async closeClient(client, serverName) {
|
|
375
|
-
try {
|
|
376
|
-
await client.close();
|
|
377
|
-
return Ok(undefined);
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
const err = toError(error);
|
|
381
|
-
console.warn(`Error closing MCP client ${serverName}:`, err);
|
|
382
|
-
return Err(err);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Disconnect transport with error handling
|
|
387
|
-
*/
|
|
388
|
-
async disconnectTransport(transport, serverName) {
|
|
389
|
-
try {
|
|
390
|
-
await transport.disconnect();
|
|
391
|
-
return Ok(undefined);
|
|
392
|
-
}
|
|
393
|
-
catch (error) {
|
|
394
|
-
const err = toError(error);
|
|
395
|
-
console.warn(`Error disconnecting MCP transport ${serverName}:`, err);
|
|
396
|
-
return Err(err);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Call MCP tool with type safety and optional schema validation
|
|
401
|
-
*
|
|
402
|
-
* @param toolName - The tool to call
|
|
403
|
-
* @param arguments_ - Tool arguments
|
|
404
|
-
* @param options - Optional settings for validation and MCP _meta
|
|
405
|
-
* @returns Result containing the tool result with optional schema validation
|
|
406
|
-
*/
|
|
407
|
-
async callTool(toolName, arguments_, options) {
|
|
408
|
-
if (this.disposed) {
|
|
409
|
-
return Err(new Error('MCPManager is disposed'));
|
|
410
|
-
}
|
|
411
|
-
const tool = this.tools.get(toolName);
|
|
412
|
-
if (!tool) {
|
|
413
|
-
return Err(new Error(`Tool ${toolName} not found`));
|
|
414
|
-
}
|
|
415
|
-
// BUG FIX: Get client reference inside mutex to prevent TOCTOU race with removeServer
|
|
416
|
-
const mutexResult = await this.connectionMutex.runExclusive(tool.serverName, async () => {
|
|
417
|
-
// Re-check state inside mutex
|
|
418
|
-
const state = this.connections.get(tool.serverName);
|
|
419
|
-
if (!state) {
|
|
420
|
-
return Err(new Error(`Server ${tool.serverName} not found`));
|
|
421
|
-
}
|
|
422
|
-
if (state.status !== 'connected') {
|
|
423
|
-
return Err(new Error(`Server ${tool.serverName} not connected (status: ${state.status})`));
|
|
424
|
-
}
|
|
425
|
-
// Return client snapshot (mutex released after this, but client reference is safe to use)
|
|
426
|
-
return Ok(state.client);
|
|
427
|
-
});
|
|
428
|
-
// Unwrap nested Result
|
|
429
|
-
if (!mutexResult.success) {
|
|
430
|
-
return mutexResult;
|
|
431
|
-
}
|
|
432
|
-
const clientResult = mutexResult.value;
|
|
433
|
-
if (!clientResult.success) {
|
|
434
|
-
return clientResult;
|
|
435
|
-
}
|
|
436
|
-
const client = clientResult.value;
|
|
437
|
-
try {
|
|
438
|
-
// BUG FIX: Re-validate connection state before making call to handle race with removeServer
|
|
439
|
-
// Between mutex release and here, removeServer could have been called
|
|
440
|
-
const currentState = this.connections.get(tool.serverName);
|
|
441
|
-
if (!currentState || currentState.status !== 'connected') {
|
|
442
|
-
return Err(new Error(`Server ${tool.serverName} disconnected during tool call preparation (status: ${currentState?.status ?? 'removed'})`));
|
|
443
|
-
}
|
|
444
|
-
// Extract original tool name
|
|
445
|
-
const prefix = `mcp__${tool.serverName}__`;
|
|
446
|
-
const originalToolName = toolName.startsWith(prefix)
|
|
447
|
-
? toolName.substring(prefix.length)
|
|
448
|
-
: toolName;
|
|
449
|
-
// Validate arguments
|
|
450
|
-
const safeArgs = (arguments_ && typeof arguments_ === 'object' && !Array.isArray(arguments_))
|
|
451
|
-
? arguments_
|
|
452
|
-
: {};
|
|
453
|
-
// Get server-specific timeout configuration
|
|
454
|
-
const serverConfig = this.serverConfigs.get(tool.serverName);
|
|
455
|
-
const timeout = serverConfig?.timeout ?? MCP_CONFIG.DEFAULT_TIMEOUT;
|
|
456
|
-
// Build call params with optional _meta for progress/cancellation
|
|
457
|
-
const callParams = {
|
|
458
|
-
name: originalToolName,
|
|
459
|
-
arguments: safeArgs
|
|
460
|
-
};
|
|
461
|
-
// Include _meta fields if provided (for progress tracking and cancellation)
|
|
462
|
-
const meta = {};
|
|
463
|
-
if (options?._meta?.progressToken !== undefined) {
|
|
464
|
-
meta.progressToken = options._meta.progressToken;
|
|
465
|
-
}
|
|
466
|
-
if (options?._meta?.requestId !== undefined) {
|
|
467
|
-
meta.requestId = options._meta.requestId;
|
|
468
|
-
}
|
|
469
|
-
if (meta.progressToken !== undefined || meta.requestId !== undefined) {
|
|
470
|
-
callParams._meta = meta;
|
|
471
|
-
}
|
|
472
|
-
// Build request options with timeout and optional abort signal
|
|
473
|
-
const requestOptions = { timeout };
|
|
474
|
-
if (options?.signal) {
|
|
475
|
-
requestOptions.signal = options.signal;
|
|
476
|
-
}
|
|
477
|
-
// Call tool with timeout (mutex released, but client reference is still valid)
|
|
478
|
-
// MCP SDK accepts { timeout?: number, signal?: AbortSignal } as third parameter
|
|
479
|
-
const result = await client.callTool(callParams, undefined, requestOptions);
|
|
480
|
-
// Apply token limiting
|
|
481
|
-
if (MCP_CONFIG.TRUNCATION_ENABLED) {
|
|
482
|
-
const resultText = JSON.stringify(result.content);
|
|
483
|
-
const tokenCount = this.tokenCounter.countTokens(resultText);
|
|
484
|
-
if (tokenCount > MCP_CONFIG.TOKEN_HARD_LIMIT) {
|
|
485
|
-
const truncatedText = this.truncateToTokenLimit(resultText, MCP_CONFIG.TOKEN_HARD_LIMIT);
|
|
486
|
-
result.content = [
|
|
487
|
-
{ type: 'text', text: truncatedText },
|
|
488
|
-
{
|
|
489
|
-
type: 'text',
|
|
490
|
-
text: `\n\n⚠️ Output truncated: ${tokenCount.toLocaleString()} tokens exceeded limit of ${MCP_CONFIG.TOKEN_HARD_LIMIT.toLocaleString()} tokens`
|
|
491
|
-
}
|
|
492
|
-
];
|
|
493
|
-
this.emit('token-limit-exceeded', {
|
|
494
|
-
toolName,
|
|
495
|
-
serverName: tool.serverName,
|
|
496
|
-
originalTokens: tokenCount,
|
|
497
|
-
truncatedTokens: MCP_CONFIG.TOKEN_HARD_LIMIT
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
else if (tokenCount > MCP_CONFIG.TOKEN_WARNING_THRESHOLD) {
|
|
501
|
-
this.emit('token-warning', {
|
|
502
|
-
toolName,
|
|
503
|
-
serverName: tool.serverName,
|
|
504
|
-
tokenCount,
|
|
505
|
-
threshold: MCP_CONFIG.TOKEN_WARNING_THRESHOLD
|
|
506
|
-
});
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
// Phase 2: Schema validation (if enabled and tool has outputSchema)
|
|
510
|
-
const validatedResult = result;
|
|
511
|
-
const shouldValidate = options?.validateOutput ?? true; // Default to enabled
|
|
512
|
-
if (shouldValidate && tool.outputSchema) {
|
|
513
|
-
const validator = getToolOutputValidator();
|
|
514
|
-
const content = Array.isArray(result.content) ? result.content : [];
|
|
515
|
-
const validationResult = validator.validateContent(tool.outputSchema, content);
|
|
516
|
-
validatedResult.schemaValidation = validationResult;
|
|
517
|
-
// Emit event on validation failure (for monitoring)
|
|
518
|
-
if (validationResult.status === 'invalid') {
|
|
519
|
-
this.emit('schema-validation-failed', {
|
|
520
|
-
toolName,
|
|
521
|
-
serverName: tool.serverName,
|
|
522
|
-
errors: validationResult.errors,
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return Ok(validatedResult);
|
|
527
|
-
}
|
|
528
|
-
catch (error) {
|
|
529
|
-
// BUG FIX: Check if the error is due to server disconnection during call
|
|
530
|
-
// This handles the race condition where removeServer was called mid-operation
|
|
531
|
-
const currentState = this.connections.get(tool.serverName);
|
|
532
|
-
if (!currentState || currentState.status === 'disconnecting' || currentState.status === 'failed') {
|
|
533
|
-
return Err(new Error(`Server ${tool.serverName} was disconnected during tool execution. Original error: ${toError(error).message}`));
|
|
534
|
-
}
|
|
535
|
-
return Err(toError(error));
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Call MCP tool with progress tracking
|
|
540
|
-
*
|
|
541
|
-
* MCP Specification: Supports notifications/progress for long-running operations.
|
|
542
|
-
*
|
|
543
|
-
* FIX: Now properly forwards _meta.progressToken to the MCP server so it can
|
|
544
|
-
* attach progress notifications to this specific request.
|
|
545
|
-
*
|
|
546
|
-
* @param toolName - The tool to call
|
|
547
|
-
* @param arguments_ - Tool arguments
|
|
548
|
-
* @param options - Progress tracking options
|
|
549
|
-
* @returns Result containing the tool result or error
|
|
550
|
-
*/
|
|
551
|
-
async callToolWithProgress(toolName, arguments_, options) {
|
|
552
|
-
const progressTracker = getProgressTracker();
|
|
553
|
-
const token = progressTracker.createToken();
|
|
554
|
-
// Register progress callback
|
|
555
|
-
if (options?.onProgress) {
|
|
556
|
-
progressTracker.onProgress(token, options.onProgress);
|
|
557
|
-
}
|
|
558
|
-
try {
|
|
559
|
-
// Call the base callTool with _meta.progressToken so the server knows
|
|
560
|
-
// where to send progress notifications
|
|
561
|
-
return await this.callTool(toolName, arguments_, {
|
|
562
|
-
_meta: { progressToken: token }
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
|
-
finally {
|
|
566
|
-
progressTracker.cleanup(token);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* Call MCP tool with cancellation support
|
|
571
|
-
*
|
|
572
|
-
* MCP Specification: Supports notifications/cancelled for aborting operations.
|
|
573
|
-
*
|
|
574
|
-
* FIX: Now properly propagates AbortSignal to the MCP SDK so cancellation
|
|
575
|
-
* actually stops the server work instead of just racing locally. Also sends
|
|
576
|
-
* notifications/cancelled to the server so it can clean up.
|
|
577
|
-
*
|
|
578
|
-
* @param toolName - The tool to call
|
|
579
|
-
* @param arguments_ - Tool arguments
|
|
580
|
-
* @returns Result containing the tool result, cancellation status, or error
|
|
581
|
-
*/
|
|
582
|
-
async callToolCancellable(toolName, arguments_) {
|
|
583
|
-
if (this.disposed) {
|
|
584
|
-
return Err(new Error('MCPManager is disposed'));
|
|
585
|
-
}
|
|
586
|
-
const tool = this.tools.get(toolName);
|
|
587
|
-
if (!tool) {
|
|
588
|
-
return Err(new Error(`Tool ${toolName} not found`));
|
|
589
|
-
}
|
|
590
|
-
const cancellationManager = getCancellationManager();
|
|
591
|
-
const requestId = randomUUID();
|
|
592
|
-
const abortController = new AbortController();
|
|
593
|
-
// Register the cancellable request
|
|
594
|
-
cancellationManager.register({
|
|
595
|
-
id: requestId,
|
|
596
|
-
serverName: tool.serverName,
|
|
597
|
-
toolName,
|
|
598
|
-
startedAt: new Date(),
|
|
599
|
-
abortController,
|
|
600
|
-
});
|
|
601
|
-
try {
|
|
602
|
-
// FIX: Pass AbortSignal directly to the MCP SDK so cancellation actually
|
|
603
|
-
// stops the server work. The SDK will abort the underlying request when
|
|
604
|
-
// the signal is triggered.
|
|
605
|
-
const result = await this.callTool(toolName, arguments_, {
|
|
606
|
-
_meta: { requestId },
|
|
607
|
-
signal: abortController.signal
|
|
608
|
-
});
|
|
609
|
-
// Check if the signal was aborted after the call completed
|
|
610
|
-
if (abortController.signal.aborted) {
|
|
611
|
-
return Ok({
|
|
612
|
-
content: [],
|
|
613
|
-
isCancelled: true,
|
|
614
|
-
cancelReason: 'User cancelled',
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
return result;
|
|
618
|
-
}
|
|
619
|
-
catch (error) {
|
|
620
|
-
// Check if this was a cancellation (either from our manager or SDK abort)
|
|
621
|
-
const err = toError(error);
|
|
622
|
-
const isAborted = abortController.signal.aborted ||
|
|
623
|
-
cancellationManager.isCancelled(requestId) ||
|
|
624
|
-
isRequestCancelled(error) ||
|
|
625
|
-
err.name === 'AbortError';
|
|
626
|
-
if (isAborted) {
|
|
627
|
-
return Ok({
|
|
628
|
-
content: [],
|
|
629
|
-
isCancelled: true,
|
|
630
|
-
cancelReason: 'User cancelled',
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
return Err(err);
|
|
634
|
-
}
|
|
635
|
-
finally {
|
|
636
|
-
cancellationManager.cleanup(requestId);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Cancel the most recent active request
|
|
641
|
-
*
|
|
642
|
-
* @param reason - Optional reason for cancellation
|
|
643
|
-
* @returns Cancellation result
|
|
644
|
-
*/
|
|
645
|
-
async cancelCurrentRequest(reason) {
|
|
646
|
-
const cancellationManager = getCancellationManager();
|
|
647
|
-
const request = cancellationManager.getMostRecentRequest();
|
|
648
|
-
if (request) {
|
|
649
|
-
return await cancellationManager.cancel(request.id, reason);
|
|
650
|
-
}
|
|
651
|
-
return undefined;
|
|
652
|
-
}
|
|
653
|
-
/**
|
|
654
|
-
* Cancel all active requests
|
|
655
|
-
*
|
|
656
|
-
* @param reason - Optional reason for cancellation
|
|
657
|
-
* @returns Array of cancellation results
|
|
658
|
-
*/
|
|
659
|
-
async cancelAllRequests(reason) {
|
|
660
|
-
const cancellationManager = getCancellationManager();
|
|
661
|
-
return await cancellationManager.cancelAll(reason);
|
|
662
|
-
}
|
|
663
|
-
/**
|
|
664
|
-
* Check if there are any active cancellable requests
|
|
665
|
-
*/
|
|
666
|
-
hasActiveRequests() {
|
|
667
|
-
return getCancellationManager().hasActiveRequests();
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Get the count of active cancellable requests
|
|
671
|
-
*/
|
|
672
|
-
getActiveRequestCount() {
|
|
673
|
-
return getCancellationManager().getActiveRequestCount();
|
|
674
|
-
}
|
|
675
|
-
// =========================================================================
|
|
676
|
-
// Resource Subscriptions (MCP 2025-06-18)
|
|
677
|
-
// =========================================================================
|
|
678
|
-
/**
|
|
679
|
-
* Subscribe to a resource
|
|
680
|
-
*
|
|
681
|
-
* @param serverName - Server providing the resource
|
|
682
|
-
* @param uri - Resource URI to subscribe to
|
|
683
|
-
* @returns Result indicating success or error
|
|
684
|
-
*/
|
|
685
|
-
async subscribeResource(serverName, uri) {
|
|
686
|
-
return await getSubscriptionManager().subscribe(serverName, uri);
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Unsubscribe from a resource
|
|
690
|
-
*
|
|
691
|
-
* @param serverName - Server providing the resource
|
|
692
|
-
* @param uri - Resource URI to unsubscribe from
|
|
693
|
-
* @returns Result indicating success or error
|
|
694
|
-
*/
|
|
695
|
-
async unsubscribeResource(serverName, uri) {
|
|
696
|
-
return await getSubscriptionManager().unsubscribe(serverName, uri);
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* Get all active resource subscriptions
|
|
700
|
-
*/
|
|
701
|
-
getResourceSubscriptions() {
|
|
702
|
-
return getSubscriptionManager().getActiveSubscriptions();
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Check if subscribed to a resource
|
|
706
|
-
*/
|
|
707
|
-
isSubscribedToResource(serverName, uri) {
|
|
708
|
-
return getSubscriptionManager().isSubscribed(serverName, uri);
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Set up notification handlers for MCP server
|
|
712
|
-
*
|
|
713
|
-
* Handles:
|
|
714
|
-
* - notifications/progress - Progress updates for long-running operations
|
|
715
|
-
* - notifications/resources/updated - Resource change notifications
|
|
716
|
-
* - notifications/resources/list_changed - Resource list changes
|
|
717
|
-
*/
|
|
718
|
-
setupNotificationHandlers(client, serverName) {
|
|
719
|
-
const progressTracker = getProgressTracker();
|
|
720
|
-
// Handle progress notifications
|
|
721
|
-
try {
|
|
722
|
-
client.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
|
723
|
-
const { params } = notification;
|
|
724
|
-
if (params.progressToken !== undefined && params.progress !== undefined) {
|
|
725
|
-
progressTracker.handleNotification({
|
|
726
|
-
progressToken: params.progressToken,
|
|
727
|
-
progress: params.progress,
|
|
728
|
-
total: params.total,
|
|
729
|
-
message: undefined, // Not in standard schema
|
|
730
|
-
});
|
|
731
|
-
this.emit('progress', { serverName, ...params });
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
catch {
|
|
736
|
-
// Server may not support progress notifications
|
|
737
|
-
}
|
|
738
|
-
// Handle resource update notifications
|
|
739
|
-
const subscriptionManager = getSubscriptionManager();
|
|
740
|
-
try {
|
|
741
|
-
client.setNotificationHandler(ResourceUpdatedNotificationSchema, (notification) => {
|
|
742
|
-
const { params } = notification;
|
|
743
|
-
if (params.uri) {
|
|
744
|
-
subscriptionManager.handleResourceUpdated(serverName, params.uri);
|
|
745
|
-
this.emit('resource-updated', serverName, params.uri);
|
|
746
|
-
}
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
catch {
|
|
750
|
-
// Server may not support resource notifications
|
|
751
|
-
}
|
|
752
|
-
// Handle resource list change notifications
|
|
753
|
-
try {
|
|
754
|
-
client.setNotificationHandler(ResourceListChangedNotificationSchema, () => {
|
|
755
|
-
subscriptionManager.handleResourceListChanged(serverName);
|
|
756
|
-
this.emit('resource-list-changed', serverName);
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
catch {
|
|
760
|
-
// Server may not support resource notifications
|
|
761
|
-
}
|
|
762
|
-
// Wire up subscription manager with request sender
|
|
763
|
-
subscriptionManager.setSendRequest(async (srvName, method, uri) => {
|
|
764
|
-
if (srvName !== serverName) {
|
|
765
|
-
return Err(new Error(`Server mismatch: ${srvName} vs ${serverName}`));
|
|
766
|
-
}
|
|
767
|
-
try {
|
|
768
|
-
if (method === 'resources/subscribe') {
|
|
769
|
-
await client.subscribeResource({ uri });
|
|
770
|
-
}
|
|
771
|
-
else {
|
|
772
|
-
await client.unsubscribeResource({ uri });
|
|
773
|
-
}
|
|
774
|
-
return Ok(undefined);
|
|
775
|
-
}
|
|
776
|
-
catch (error) {
|
|
777
|
-
return Err(error instanceof Error ? error : new Error(String(error)));
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
// Wire up subscription manager capabilities checker
|
|
781
|
-
subscriptionManager.setCheckCapabilities(async (srvName) => {
|
|
782
|
-
if (srvName !== serverName) {
|
|
783
|
-
return { supportsSubscriptions: false };
|
|
784
|
-
}
|
|
785
|
-
// Check server capabilities
|
|
786
|
-
const caps = client.getServerCapabilities();
|
|
787
|
-
return {
|
|
788
|
-
supportsSubscriptions: Boolean(caps?.resources?.subscribe),
|
|
789
|
-
};
|
|
790
|
-
});
|
|
791
|
-
// Wire up cancellation notification sender
|
|
792
|
-
const cancellationManager = getCancellationManager();
|
|
793
|
-
cancellationManager.setSendNotification(async (srvName, requestId, reason) => {
|
|
794
|
-
if (srvName !== serverName)
|
|
795
|
-
return;
|
|
796
|
-
try {
|
|
797
|
-
// Send cancellation notification via the client
|
|
798
|
-
await client.notification({
|
|
799
|
-
method: 'notifications/cancelled',
|
|
800
|
-
params: {
|
|
801
|
-
requestId,
|
|
802
|
-
reason: reason ?? 'User cancelled',
|
|
803
|
-
},
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
catch {
|
|
807
|
-
// Server may not support cancellation
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
}
|
|
811
|
-
/**
|
|
812
|
-
* Truncate text to fit within token limit
|
|
813
|
-
* UNICODE FIX: Uses grapheme clusters
|
|
814
|
-
*/
|
|
815
|
-
truncateToTokenLimit(text, maxTokens) {
|
|
816
|
-
// BUG FIX: Handle edge case where maxTokens is 0 or negative
|
|
817
|
-
if (maxTokens <= 0) {
|
|
818
|
-
return '';
|
|
819
|
-
}
|
|
820
|
-
const chars = Array.from(text);
|
|
821
|
-
// BUG FIX: Initialize result to empty string, not full text
|
|
822
|
-
// This ensures that if no valid truncation is found, we return empty
|
|
823
|
-
let low = 0;
|
|
824
|
-
let high = chars.length;
|
|
825
|
-
let result = '';
|
|
826
|
-
while (low <= high) {
|
|
827
|
-
const mid = Math.floor((low + high) / 2);
|
|
828
|
-
const truncated = chars.slice(0, mid).join('');
|
|
829
|
-
const tokens = this.tokenCounter.countTokens(truncated);
|
|
830
|
-
if (tokens <= maxTokens) {
|
|
831
|
-
result = truncated;
|
|
832
|
-
low = mid + 1;
|
|
833
|
-
}
|
|
834
|
-
else {
|
|
835
|
-
high = mid - 1;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
return result;
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Get all tools
|
|
842
|
-
*/
|
|
843
|
-
getTools() {
|
|
844
|
-
return Array.from(this.tools.values());
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Get all connected servers
|
|
848
|
-
*/
|
|
849
|
-
getServers() {
|
|
850
|
-
const connected = [];
|
|
851
|
-
for (const [serverName, state] of this.connections.entries()) {
|
|
852
|
-
if (state.status === 'connected') {
|
|
853
|
-
connected.push(serverName);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
return connected;
|
|
857
|
-
}
|
|
858
|
-
/**
|
|
859
|
-
* Get MCP connection status summary
|
|
860
|
-
* Returns counts of connected, failed, connecting, and total servers
|
|
861
|
-
*/
|
|
862
|
-
getConnectionStatus() {
|
|
863
|
-
let connected = 0;
|
|
864
|
-
let failed = 0;
|
|
865
|
-
let connecting = 0;
|
|
866
|
-
for (const state of this.connections.values()) {
|
|
867
|
-
switch (state.status) {
|
|
868
|
-
case 'connected':
|
|
869
|
-
connected++;
|
|
870
|
-
break;
|
|
871
|
-
case 'failed':
|
|
872
|
-
failed++;
|
|
873
|
-
break;
|
|
874
|
-
case 'connecting':
|
|
875
|
-
connecting++;
|
|
876
|
-
break;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
return {
|
|
880
|
-
connected,
|
|
881
|
-
failed,
|
|
882
|
-
connecting,
|
|
883
|
-
total: this.connections.size,
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Get connection state for a server
|
|
888
|
-
*/
|
|
889
|
-
getConnectionState(serverName) {
|
|
890
|
-
return this.connections.get(serverName);
|
|
891
|
-
}
|
|
892
|
-
/**
|
|
893
|
-
* Get all prompts from connected servers
|
|
894
|
-
*/
|
|
895
|
-
getPrompts() {
|
|
896
|
-
return Array.from(this.prompts.values());
|
|
897
|
-
}
|
|
898
|
-
/**
|
|
899
|
-
* List prompts from a specific server
|
|
900
|
-
*/
|
|
901
|
-
async listServerPrompts(serverName) {
|
|
902
|
-
// BUG FIX: Check disposed flag before operating on resources
|
|
903
|
-
if (this.disposed) {
|
|
904
|
-
return Err(new Error('MCPManager has been disposed'));
|
|
905
|
-
}
|
|
906
|
-
const state = this.connections.get(serverName);
|
|
907
|
-
if (!state || state.status !== 'connected') {
|
|
908
|
-
return Err(new Error(`Server ${serverName} not connected`));
|
|
909
|
-
}
|
|
910
|
-
try {
|
|
911
|
-
const result = await state.client.listPrompts();
|
|
912
|
-
const serverPrompts = [];
|
|
913
|
-
for (const prompt of result.prompts) {
|
|
914
|
-
const mcpPrompt = {
|
|
915
|
-
serverName,
|
|
916
|
-
name: prompt.name,
|
|
917
|
-
description: prompt.description,
|
|
918
|
-
arguments: prompt.arguments,
|
|
919
|
-
};
|
|
920
|
-
const key = `mcp__${serverName}__${prompt.name}`;
|
|
921
|
-
this.prompts.set(key, mcpPrompt);
|
|
922
|
-
serverPrompts.push(mcpPrompt);
|
|
923
|
-
}
|
|
924
|
-
return Ok(serverPrompts);
|
|
925
|
-
}
|
|
926
|
-
catch {
|
|
927
|
-
// Server may not support prompts - return empty array
|
|
928
|
-
return Ok([]);
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Get a specific prompt from a server
|
|
933
|
-
*/
|
|
934
|
-
async getPrompt(serverName, promptName, args) {
|
|
935
|
-
// BUG FIX: Check disposed flag before operating on resources
|
|
936
|
-
if (this.disposed) {
|
|
937
|
-
return Err(new Error('MCPManager has been disposed'));
|
|
938
|
-
}
|
|
939
|
-
const state = this.connections.get(serverName);
|
|
940
|
-
if (!state || state.status !== 'connected') {
|
|
941
|
-
return Err(new Error(`Server ${serverName} not connected`));
|
|
942
|
-
}
|
|
943
|
-
try {
|
|
944
|
-
const result = await state.client.getPrompt({
|
|
945
|
-
name: promptName,
|
|
946
|
-
arguments: args,
|
|
947
|
-
});
|
|
948
|
-
return Ok({
|
|
949
|
-
description: result.description,
|
|
950
|
-
messages: result.messages || [],
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
catch (error) {
|
|
954
|
-
return Err(toError(error));
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Discover prompts from all connected servers
|
|
959
|
-
* PERF: Parallelized - servers are independent, no need to wait sequentially
|
|
960
|
-
*/
|
|
961
|
-
async discoverPrompts() {
|
|
962
|
-
if (this.disposed) {
|
|
963
|
-
return;
|
|
964
|
-
}
|
|
965
|
-
const connectedServers = this.getServers();
|
|
966
|
-
if (connectedServers.length === 0) {
|
|
967
|
-
return;
|
|
968
|
-
}
|
|
969
|
-
// Parallel discovery - each server is independent
|
|
970
|
-
await Promise.allSettled(connectedServers.map(serverName => this.listServerPrompts(serverName)));
|
|
971
|
-
}
|
|
972
|
-
/**
|
|
973
|
-
* Get transport type for a server
|
|
974
|
-
*/
|
|
975
|
-
getTransportType(serverName) {
|
|
976
|
-
const state = this.connections.get(serverName);
|
|
977
|
-
if (!state) {
|
|
978
|
-
return Err(new Error(`Server ${serverName} not found`));
|
|
979
|
-
}
|
|
980
|
-
if (state.status !== 'connected') {
|
|
981
|
-
return Err(new Error(`Server ${serverName} not connected`));
|
|
982
|
-
}
|
|
983
|
-
const type = state.transport.getType();
|
|
984
|
-
return Ok(type);
|
|
985
|
-
}
|
|
986
|
-
// =========================================================================
|
|
987
|
-
// Server Capabilities (Figma MCP Fix #3)
|
|
988
|
-
// =========================================================================
|
|
989
|
-
/**
|
|
990
|
-
* Get capabilities for a specific MCP server
|
|
991
|
-
*
|
|
992
|
-
* This allows agents to tailor their behavior based on server capabilities.
|
|
993
|
-
* For example, Figma MCP servers may support long-running exports with progress.
|
|
994
|
-
*
|
|
995
|
-
* @param serverName - The server to query capabilities for
|
|
996
|
-
* @returns Result containing capability summary or error
|
|
997
|
-
*
|
|
998
|
-
* @example
|
|
999
|
-
* ```typescript
|
|
1000
|
-
* const caps = manager.getServerCapabilities(serverName);
|
|
1001
|
-
* if (caps.success && caps.value.supportsProgress) {
|
|
1002
|
-
* // Use callToolWithProgress for better UX
|
|
1003
|
-
* await manager.callToolWithProgress(toolName, args, { onProgress });
|
|
1004
|
-
* }
|
|
1005
|
-
* ```
|
|
1006
|
-
*/
|
|
1007
|
-
getServerCapabilities(serverName) {
|
|
1008
|
-
if (this.disposed) {
|
|
1009
|
-
return Err(new Error('MCPManager is disposed'));
|
|
1010
|
-
}
|
|
1011
|
-
const state = this.connections.get(serverName);
|
|
1012
|
-
if (!state) {
|
|
1013
|
-
return Err(new Error(`Server ${serverName} not found`));
|
|
1014
|
-
}
|
|
1015
|
-
if (state.status !== 'connected') {
|
|
1016
|
-
return Err(new Error(`Server ${serverName} not connected (status: ${state.status})`));
|
|
1017
|
-
}
|
|
1018
|
-
try {
|
|
1019
|
-
const rawCaps = state.client.getServerCapabilities();
|
|
1020
|
-
const capabilities = {
|
|
1021
|
-
// Resources support
|
|
1022
|
-
supportsResources: Boolean(rawCaps?.resources),
|
|
1023
|
-
supportsResourceSubscriptions: Boolean(rawCaps?.resources?.subscribe),
|
|
1024
|
-
supportsResourceListChanged: Boolean(rawCaps?.resources?.listChanged),
|
|
1025
|
-
// Tools support
|
|
1026
|
-
supportsTools: Boolean(rawCaps?.tools),
|
|
1027
|
-
supportsToolListChanged: Boolean(rawCaps?.tools?.listChanged),
|
|
1028
|
-
// Prompts support
|
|
1029
|
-
supportsPrompts: Boolean(rawCaps?.prompts),
|
|
1030
|
-
supportsPromptListChanged: Boolean(rawCaps?.prompts?.listChanged),
|
|
1031
|
-
// Logging support
|
|
1032
|
-
supportsLogging: Boolean(rawCaps?.logging),
|
|
1033
|
-
// Experimental features
|
|
1034
|
-
experimental: rawCaps?.experimental || {},
|
|
1035
|
-
// Raw capabilities for advanced use
|
|
1036
|
-
raw: rawCaps || {},
|
|
1037
|
-
};
|
|
1038
|
-
return Ok(capabilities);
|
|
1039
|
-
}
|
|
1040
|
-
catch (error) {
|
|
1041
|
-
return Err(toError(error));
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Get capabilities for all connected servers
|
|
1046
|
-
*
|
|
1047
|
-
* @returns Map of server names to their capabilities
|
|
1048
|
-
*/
|
|
1049
|
-
getAllServerCapabilities() {
|
|
1050
|
-
const result = new Map();
|
|
1051
|
-
for (const serverName of this.getServers()) {
|
|
1052
|
-
const caps = this.getServerCapabilities(serverName);
|
|
1053
|
-
if (caps.success) {
|
|
1054
|
-
result.set(serverName, caps.value);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
return result;
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Check if a server supports a specific capability
|
|
1061
|
-
*
|
|
1062
|
-
* @param serverName - Server to check
|
|
1063
|
-
* @param capability - Capability to check for
|
|
1064
|
-
* @returns true if the server supports the capability
|
|
1065
|
-
*/
|
|
1066
|
-
serverSupports(serverName, capability) {
|
|
1067
|
-
const caps = this.getServerCapabilities(serverName);
|
|
1068
|
-
if (!caps.success) {
|
|
1069
|
-
return false;
|
|
1070
|
-
}
|
|
1071
|
-
return Boolean(caps.value[capability]);
|
|
1072
|
-
}
|
|
1073
|
-
// =========================================================================
|
|
1074
|
-
// Resource Access (Fix for resources.ts compatibility)
|
|
1075
|
-
// =========================================================================
|
|
1076
|
-
/**
|
|
1077
|
-
* Get the MCP client for a specific server
|
|
1078
|
-
*
|
|
1079
|
-
* This is used by resources.ts to access listResources/readResource
|
|
1080
|
-
*
|
|
1081
|
-
* @param serverName - The server name
|
|
1082
|
-
* @returns Result containing the client or error
|
|
1083
|
-
*/
|
|
1084
|
-
getClient(serverName) {
|
|
1085
|
-
if (this.disposed) {
|
|
1086
|
-
return Err(new Error('MCPManager is disposed'));
|
|
1087
|
-
}
|
|
1088
|
-
const state = this.connections.get(serverName);
|
|
1089
|
-
if (!state) {
|
|
1090
|
-
return Err(new Error(`Server ${serverName} not found`));
|
|
1091
|
-
}
|
|
1092
|
-
if (state.status !== 'connected') {
|
|
1093
|
-
return Err(new Error(`Server ${serverName} not connected (status: ${state.status})`));
|
|
1094
|
-
}
|
|
1095
|
-
return Ok(state.client);
|
|
1096
|
-
}
|
|
1097
|
-
/**
|
|
1098
|
-
* List resources from a specific server
|
|
1099
|
-
*
|
|
1100
|
-
* @param serverName - The server name
|
|
1101
|
-
* @returns Result containing resources or error
|
|
1102
|
-
*/
|
|
1103
|
-
async listResources(serverName) {
|
|
1104
|
-
if (this.disposed) {
|
|
1105
|
-
return Err(new Error('MCPManager is disposed'));
|
|
1106
|
-
}
|
|
1107
|
-
const clientResult = this.getClient(serverName);
|
|
1108
|
-
if (!clientResult.success) {
|
|
1109
|
-
return clientResult;
|
|
1110
|
-
}
|
|
1111
|
-
try {
|
|
1112
|
-
const result = await clientResult.value.listResources();
|
|
1113
|
-
return Ok(result.resources.map(r => ({
|
|
1114
|
-
uri: r.uri,
|
|
1115
|
-
name: r.name || r.uri,
|
|
1116
|
-
description: r.description,
|
|
1117
|
-
mimeType: r.mimeType,
|
|
1118
|
-
})));
|
|
1119
|
-
}
|
|
1120
|
-
catch {
|
|
1121
|
-
// Server may not support resources
|
|
1122
|
-
return Ok([]);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
/**
|
|
1126
|
-
* Read a resource from a specific server
|
|
1127
|
-
*
|
|
1128
|
-
* @param serverName - The server name
|
|
1129
|
-
* @param uri - Resource URI
|
|
1130
|
-
* @returns Result containing resource content or error
|
|
1131
|
-
*/
|
|
1132
|
-
async readResource(serverName, uri) {
|
|
1133
|
-
if (this.disposed) {
|
|
1134
|
-
return Err(new Error('MCPManager is disposed'));
|
|
1135
|
-
}
|
|
1136
|
-
const clientResult = this.getClient(serverName);
|
|
1137
|
-
if (!clientResult.success) {
|
|
1138
|
-
return clientResult;
|
|
1139
|
-
}
|
|
1140
|
-
try {
|
|
1141
|
-
const result = await clientResult.value.readResource({ uri });
|
|
1142
|
-
// Extract text content
|
|
1143
|
-
if (result.contents && result.contents.length > 0) {
|
|
1144
|
-
const content = result.contents[0];
|
|
1145
|
-
if ('text' in content && content.text) {
|
|
1146
|
-
return Ok(content.text);
|
|
1147
|
-
}
|
|
1148
|
-
if ('blob' in content && content.blob) {
|
|
1149
|
-
// Handle base64 encoded content
|
|
1150
|
-
return Ok(Buffer.from(content.blob, 'base64').toString('utf-8'));
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
return Ok('');
|
|
1154
|
-
}
|
|
1155
|
-
catch (error) {
|
|
1156
|
-
return Err(toError(error));
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Schedule reconnection for a failed server with exponential backoff
|
|
1161
|
-
*
|
|
1162
|
-
* Phase 2: Automatic reconnection logic
|
|
1163
|
-
*
|
|
1164
|
-
* @param serverName - Server to reconnect
|
|
1165
|
-
* @param config - Server configuration
|
|
1166
|
-
*/
|
|
1167
|
-
scheduleReconnection(serverName, config) {
|
|
1168
|
-
// Cancel any existing reconnection timer
|
|
1169
|
-
this.cancelReconnection(serverName);
|
|
1170
|
-
// Get current attempt count
|
|
1171
|
-
const attempts = this.reconnectionAttempts.get(serverName) || 0;
|
|
1172
|
-
// Check if we've exceeded max retries
|
|
1173
|
-
if (attempts >= this.reconnectionConfig.maxRetries) {
|
|
1174
|
-
this.emit('reconnection-failed', serverName, attempts, 'Max retries exceeded');
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
// Calculate exponential backoff delay
|
|
1178
|
-
const baseDelay = this.reconnectionConfig.initialDelayMs;
|
|
1179
|
-
const multiplier = Math.pow(this.reconnectionConfig.backoffMultiplier, attempts);
|
|
1180
|
-
const calculatedDelay = Math.min(baseDelay * multiplier, this.reconnectionConfig.maxDelayMs);
|
|
1181
|
-
// Emit reconnection scheduled event
|
|
1182
|
-
this.emit('reconnection-scheduled', serverName, attempts + 1, calculatedDelay);
|
|
1183
|
-
// Schedule reconnection attempt
|
|
1184
|
-
const timer = setTimeout(() => {
|
|
1185
|
-
// BUG FIX: Check if disposed before attempting reconnection
|
|
1186
|
-
// Timer may fire after dispose() was called
|
|
1187
|
-
if (this.disposing) {
|
|
1188
|
-
return;
|
|
1189
|
-
}
|
|
1190
|
-
// Increment attempt count
|
|
1191
|
-
this.reconnectionAttempts.set(serverName, attempts + 1);
|
|
1192
|
-
// Attempt reconnection (wrapped in IIFE to handle async properly)
|
|
1193
|
-
void (async () => {
|
|
1194
|
-
const result = await this.addServer(config);
|
|
1195
|
-
if (result.success) {
|
|
1196
|
-
// Success! Reset attempt counter
|
|
1197
|
-
this.reconnectionAttempts.delete(serverName);
|
|
1198
|
-
this.emit('reconnection-succeeded', serverName, attempts + 1);
|
|
1199
|
-
}
|
|
1200
|
-
// Failed - will be rescheduled by addServer error handling
|
|
1201
|
-
// (which calls scheduleReconnection again)
|
|
1202
|
-
})();
|
|
1203
|
-
}, calculatedDelay);
|
|
1204
|
-
this.reconnectionTimers.set(serverName, timer);
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Cancel reconnection for a server
|
|
1208
|
-
*/
|
|
1209
|
-
cancelReconnection(serverName) {
|
|
1210
|
-
const timer = this.reconnectionTimers.get(serverName);
|
|
1211
|
-
if (timer) {
|
|
1212
|
-
clearTimeout(timer);
|
|
1213
|
-
this.reconnectionTimers.delete(serverName);
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Perform health check on a single server
|
|
1218
|
-
*
|
|
1219
|
-
* @param serverName - Server to check
|
|
1220
|
-
* @returns Result indicating health status
|
|
1221
|
-
*/
|
|
1222
|
-
async healthCheck(serverName) {
|
|
1223
|
-
// BUG FIX: Check disposed flag before operating on resources
|
|
1224
|
-
if (this.disposed) {
|
|
1225
|
-
return Err(new Error('MCPManager has been disposed'));
|
|
1226
|
-
}
|
|
1227
|
-
const state = this.connections.get(serverName);
|
|
1228
|
-
if (!state) {
|
|
1229
|
-
return Err(new Error(`Server ${serverName} not found`));
|
|
1230
|
-
}
|
|
1231
|
-
if (state.status !== 'connected') {
|
|
1232
|
-
return Ok(false); // Not connected = not healthy
|
|
1233
|
-
}
|
|
1234
|
-
try {
|
|
1235
|
-
// Simple health check: try to list tools
|
|
1236
|
-
await state.client.listTools();
|
|
1237
|
-
return Ok(true); // Healthy
|
|
1238
|
-
}
|
|
1239
|
-
catch (error) {
|
|
1240
|
-
this.emit('server-unhealthy', serverName, error);
|
|
1241
|
-
const err = toError(error);
|
|
1242
|
-
this._setFailedState(serverName, err);
|
|
1243
|
-
try {
|
|
1244
|
-
await state.client.close();
|
|
1245
|
-
await state.transport.disconnect();
|
|
1246
|
-
}
|
|
1247
|
-
catch (closeError) {
|
|
1248
|
-
console.warn(`Error closing unhealthy server ${serverName}:`, closeError);
|
|
1249
|
-
}
|
|
1250
|
-
const config = this.serverConfigs.get(serverName);
|
|
1251
|
-
if (config && this.reconnectionConfig.enabled && !this.disposed) {
|
|
1252
|
-
this.scheduleReconnection(serverName, config);
|
|
1253
|
-
}
|
|
1254
|
-
return Ok(false);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
/**
|
|
1258
|
-
* Start periodic health checks for all connected servers
|
|
1259
|
-
* PERF: Parallelized - health checks are independent per server
|
|
1260
|
-
*/
|
|
1261
|
-
startHealthChecks() {
|
|
1262
|
-
if (this.healthCheckTimer) {
|
|
1263
|
-
return; // Already running
|
|
1264
|
-
}
|
|
1265
|
-
const runHealthChecks = async () => {
|
|
1266
|
-
if (this.healthCheckInFlight || this.disposed || this.disposing) {
|
|
1267
|
-
return;
|
|
1268
|
-
}
|
|
1269
|
-
this.healthCheckInFlight = true;
|
|
1270
|
-
const connectedServers = Array.from(this.connections.entries())
|
|
1271
|
-
.filter(([_, state]) => state.status === 'connected')
|
|
1272
|
-
.map(([name, _]) => name);
|
|
1273
|
-
try {
|
|
1274
|
-
// Parallel health checks - each server is independent
|
|
1275
|
-
await Promise.allSettled(connectedServers.map(serverName => this.healthCheck(serverName)));
|
|
1276
|
-
}
|
|
1277
|
-
finally {
|
|
1278
|
-
this.healthCheckInFlight = false;
|
|
1279
|
-
}
|
|
1280
|
-
};
|
|
1281
|
-
// Run initial health check
|
|
1282
|
-
runHealthChecks().catch(error => {
|
|
1283
|
-
console.warn('Health check error:', error);
|
|
1284
|
-
});
|
|
1285
|
-
// Schedule periodic checks
|
|
1286
|
-
// Use .unref() to prevent timer from blocking process exit
|
|
1287
|
-
this.healthCheckTimer = setInterval(() => {
|
|
1288
|
-
runHealthChecks().catch(error => {
|
|
1289
|
-
console.warn('Health check error:', error);
|
|
1290
|
-
});
|
|
1291
|
-
}, this.healthCheckConfig.intervalMs);
|
|
1292
|
-
this.healthCheckTimer.unref();
|
|
1293
|
-
}
|
|
1294
|
-
/**
|
|
1295
|
-
* Stop periodic health checks
|
|
1296
|
-
*/
|
|
1297
|
-
stopHealthChecks() {
|
|
1298
|
-
if (this.healthCheckTimer) {
|
|
1299
|
-
clearInterval(this.healthCheckTimer);
|
|
1300
|
-
this.healthCheckTimer = null;
|
|
1301
|
-
}
|
|
1302
|
-
this.healthCheckInFlight = false;
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Shutdown all servers
|
|
1306
|
-
*/
|
|
1307
|
-
async shutdown() {
|
|
1308
|
-
const serverNames = Array.from(this.connections.keys());
|
|
1309
|
-
const results = await Promise.allSettled(serverNames.map(name => this.removeServer(name)));
|
|
1310
|
-
const errors = [];
|
|
1311
|
-
results.forEach((result, index) => {
|
|
1312
|
-
if (result.status === 'rejected') {
|
|
1313
|
-
console.warn(`Failed to remove server ${serverNames[index]}:`, result.reason);
|
|
1314
|
-
errors.push(result.reason);
|
|
1315
|
-
}
|
|
1316
|
-
else if (!result.value.success) {
|
|
1317
|
-
errors.push(result.value.error);
|
|
1318
|
-
}
|
|
1319
|
-
});
|
|
1320
|
-
if (errors.length > 0) {
|
|
1321
|
-
return Err(new AggregateError(errors, 'Shutdown had errors'));
|
|
1322
|
-
}
|
|
1323
|
-
return Ok(undefined);
|
|
1324
|
-
}
|
|
1325
|
-
/**
|
|
1326
|
-
* Ensure servers initialized
|
|
1327
|
-
*/
|
|
1328
|
-
async ensureServersInitialized() {
|
|
1329
|
-
if (this.initializationPromise) {
|
|
1330
|
-
return this.initializationPromise;
|
|
1331
|
-
}
|
|
1332
|
-
if (this.connections.size === 0 && !this.initializationPromise) {
|
|
1333
|
-
this.initializationPromise = (async () => {
|
|
1334
|
-
try {
|
|
1335
|
-
const { loadMCPConfig } = await import('../mcp/config.js');
|
|
1336
|
-
const config = loadMCPConfig();
|
|
1337
|
-
const initPromises = config.servers.map(async (serverConfig) => {
|
|
1338
|
-
const serverName = createServerName(serverConfig.name);
|
|
1339
|
-
if (!serverName) {
|
|
1340
|
-
console.warn(`Invalid server name: ${serverConfig.name}`);
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
const result = await this.addServer(serverConfig);
|
|
1344
|
-
if (!result.success) {
|
|
1345
|
-
console.warn(`Failed to initialize MCP server ${serverName}:`, result.error);
|
|
1346
|
-
}
|
|
1347
|
-
});
|
|
1348
|
-
const initResults = await Promise.allSettled(initPromises);
|
|
1349
|
-
const initErrors = initResults
|
|
1350
|
-
.filter((result) => result.status === 'rejected')
|
|
1351
|
-
.map(result => toError(result.reason));
|
|
1352
|
-
if (initErrors.length > 0) {
|
|
1353
|
-
return Err(new AggregateError(initErrors, 'Some MCP servers failed to initialize'));
|
|
1354
|
-
}
|
|
1355
|
-
return Ok(undefined);
|
|
1356
|
-
}
|
|
1357
|
-
catch (error) {
|
|
1358
|
-
console.error('Failed to initialize MCP servers:', error);
|
|
1359
|
-
return Err(toError(error));
|
|
1360
|
-
}
|
|
1361
|
-
finally {
|
|
1362
|
-
this.initializationPromise = null;
|
|
1363
|
-
}
|
|
1364
|
-
})();
|
|
1365
|
-
}
|
|
1366
|
-
if (this.initializationPromise) {
|
|
1367
|
-
return await this.initializationPromise;
|
|
1368
|
-
}
|
|
1369
|
-
return Ok(undefined);
|
|
1370
|
-
}
|
|
1371
|
-
/**
|
|
1372
|
-
* Dispose all resources
|
|
1373
|
-
*/
|
|
1374
|
-
async dispose() {
|
|
1375
|
-
if (this.disposePromise) {
|
|
1376
|
-
return this.disposePromise;
|
|
1377
|
-
}
|
|
1378
|
-
this.disposePromise = (async () => {
|
|
1379
|
-
if (this.disposed) {
|
|
1380
|
-
return Ok(undefined);
|
|
1381
|
-
}
|
|
1382
|
-
this.disposing = true;
|
|
1383
|
-
try {
|
|
1384
|
-
// Phase 2: Stop health checks
|
|
1385
|
-
this.stopHealthChecks();
|
|
1386
|
-
// Phase 2: Cancel all reconnection timers
|
|
1387
|
-
for (const timer of this.reconnectionTimers.values()) {
|
|
1388
|
-
clearTimeout(timer);
|
|
1389
|
-
}
|
|
1390
|
-
this.reconnectionTimers.clear();
|
|
1391
|
-
this.reconnectionAttempts.clear();
|
|
1392
|
-
this.serverConfigs.clear();
|
|
1393
|
-
// Wait for any in-flight connections to finish to avoid post-dispose transitions
|
|
1394
|
-
const connectingPromises = Array.from(this.connections.values())
|
|
1395
|
-
.filter((state) => state.status === 'connecting')
|
|
1396
|
-
.map(async (state) => {
|
|
1397
|
-
try {
|
|
1398
|
-
return await state.promise;
|
|
1399
|
-
}
|
|
1400
|
-
catch (error) {
|
|
1401
|
-
return Err(toError(error));
|
|
1402
|
-
}
|
|
1403
|
-
});
|
|
1404
|
-
if (connectingPromises.length > 0) {
|
|
1405
|
-
await Promise.allSettled(connectingPromises);
|
|
1406
|
-
}
|
|
1407
|
-
const shutdownResult = await this.shutdown();
|
|
1408
|
-
this.removeAllListeners();
|
|
1409
|
-
return shutdownResult;
|
|
1410
|
-
}
|
|
1411
|
-
finally {
|
|
1412
|
-
this.disposed = true;
|
|
1413
|
-
this.disposing = false;
|
|
1414
|
-
}
|
|
1415
|
-
})();
|
|
1416
|
-
return this.disposePromise;
|
|
1417
|
-
}
|
|
1418
|
-
/**
|
|
1419
|
-
* Clean up resources and remove all event listeners.
|
|
1420
|
-
* @deprecated Use dispose() instead for complete cleanup.
|
|
1421
|
-
* This method now delegates to dispose() for backwards compatibility.
|
|
1422
|
-
*/
|
|
1423
|
-
destroy() {
|
|
1424
|
-
// Fire-and-forget since dispose() is async
|
|
1425
|
-
// Callers needing to await cleanup should use dispose() directly
|
|
1426
|
-
this.dispose().catch(() => {
|
|
1427
|
-
// Suppress errors during destroy - best effort cleanup
|
|
1428
|
-
});
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
// Re-export from type-safety for external use
|
|
1432
|
-
export { createServerName, createToolName };
|
|
1433
|
-
//# sourceMappingURL=client-v2.js.map
|