@dotsetlabs/bellwether 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +291 -0
- package/LICENSE +21 -0
- package/README.md +739 -0
- package/dist/auth/credentials.d.ts +64 -0
- package/dist/auth/credentials.js +218 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/keychain.d.ts +64 -0
- package/dist/auth/keychain.js +268 -0
- package/dist/baseline/ab-testing.d.ts +80 -0
- package/dist/baseline/ab-testing.js +236 -0
- package/dist/baseline/ai-compatibility-scorer.d.ts +95 -0
- package/dist/baseline/ai-compatibility-scorer.js +606 -0
- package/dist/baseline/calibration.d.ts +77 -0
- package/dist/baseline/calibration.js +136 -0
- package/dist/baseline/category-matching.d.ts +85 -0
- package/dist/baseline/category-matching.js +289 -0
- package/dist/baseline/change-impact-analyzer.d.ts +98 -0
- package/dist/baseline/change-impact-analyzer.js +592 -0
- package/dist/baseline/comparator.d.ts +64 -0
- package/dist/baseline/comparator.js +916 -0
- package/dist/baseline/confidence.d.ts +55 -0
- package/dist/baseline/confidence.js +122 -0
- package/dist/baseline/converter.d.ts +61 -0
- package/dist/baseline/converter.js +585 -0
- package/dist/baseline/dependency-analyzer.d.ts +89 -0
- package/dist/baseline/dependency-analyzer.js +567 -0
- package/dist/baseline/deprecation-tracker.d.ts +133 -0
- package/dist/baseline/deprecation-tracker.js +322 -0
- package/dist/baseline/diff.d.ts +55 -0
- package/dist/baseline/diff.js +1584 -0
- package/dist/baseline/documentation-scorer.d.ts +205 -0
- package/dist/baseline/documentation-scorer.js +466 -0
- package/dist/baseline/embeddings.d.ts +118 -0
- package/dist/baseline/embeddings.js +251 -0
- package/dist/baseline/error-analyzer.d.ts +198 -0
- package/dist/baseline/error-analyzer.js +721 -0
- package/dist/baseline/evaluation/evaluator.d.ts +42 -0
- package/dist/baseline/evaluation/evaluator.js +323 -0
- package/dist/baseline/evaluation/expanded-dataset.d.ts +45 -0
- package/dist/baseline/evaluation/expanded-dataset.js +1164 -0
- package/dist/baseline/evaluation/golden-dataset.d.ts +58 -0
- package/dist/baseline/evaluation/golden-dataset.js +717 -0
- package/dist/baseline/evaluation/index.d.ts +15 -0
- package/dist/baseline/evaluation/index.js +15 -0
- package/dist/baseline/evaluation/types.d.ts +186 -0
- package/dist/baseline/evaluation/types.js +8 -0
- package/dist/baseline/external-dependency-detector.d.ts +181 -0
- package/dist/baseline/external-dependency-detector.js +524 -0
- package/dist/baseline/golden-output.d.ts +162 -0
- package/dist/baseline/golden-output.js +636 -0
- package/dist/baseline/health-scorer.d.ts +174 -0
- package/dist/baseline/health-scorer.js +451 -0
- package/dist/baseline/incremental-checker.d.ts +97 -0
- package/dist/baseline/incremental-checker.js +174 -0
- package/dist/baseline/index.d.ts +31 -0
- package/dist/baseline/index.js +42 -0
- package/dist/baseline/migration-generator.d.ts +137 -0
- package/dist/baseline/migration-generator.js +554 -0
- package/dist/baseline/migrations.d.ts +60 -0
- package/dist/baseline/migrations.js +197 -0
- package/dist/baseline/performance-tracker.d.ts +214 -0
- package/dist/baseline/performance-tracker.js +577 -0
- package/dist/baseline/pr-comment-generator.d.ts +117 -0
- package/dist/baseline/pr-comment-generator.js +546 -0
- package/dist/baseline/response-fingerprint.d.ts +127 -0
- package/dist/baseline/response-fingerprint.js +728 -0
- package/dist/baseline/response-schema-tracker.d.ts +129 -0
- package/dist/baseline/response-schema-tracker.js +420 -0
- package/dist/baseline/risk-scorer.d.ts +54 -0
- package/dist/baseline/risk-scorer.js +434 -0
- package/dist/baseline/saver.d.ts +89 -0
- package/dist/baseline/saver.js +554 -0
- package/dist/baseline/scenario-generator.d.ts +151 -0
- package/dist/baseline/scenario-generator.js +905 -0
- package/dist/baseline/schema-compare.d.ts +86 -0
- package/dist/baseline/schema-compare.js +557 -0
- package/dist/baseline/schema-evolution.d.ts +189 -0
- package/dist/baseline/schema-evolution.js +467 -0
- package/dist/baseline/semantic.d.ts +203 -0
- package/dist/baseline/semantic.js +908 -0
- package/dist/baseline/synonyms.d.ts +60 -0
- package/dist/baseline/synonyms.js +386 -0
- package/dist/baseline/telemetry.d.ts +165 -0
- package/dist/baseline/telemetry.js +294 -0
- package/dist/baseline/test-pruner.d.ts +120 -0
- package/dist/baseline/test-pruner.js +387 -0
- package/dist/baseline/types.d.ts +449 -0
- package/dist/baseline/types.js +5 -0
- package/dist/baseline/version.d.ts +138 -0
- package/dist/baseline/version.js +206 -0
- package/dist/cache/index.d.ts +5 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/response-cache.d.ts +151 -0
- package/dist/cache/response-cache.js +287 -0
- package/dist/ci/index.d.ts +60 -0
- package/dist/ci/index.js +342 -0
- package/dist/cli/commands/auth.d.ts +12 -0
- package/dist/cli/commands/auth.js +352 -0
- package/dist/cli/commands/badge.d.ts +3 -0
- package/dist/cli/commands/badge.js +74 -0
- package/dist/cli/commands/baseline-accept.d.ts +15 -0
- package/dist/cli/commands/baseline-accept.js +178 -0
- package/dist/cli/commands/baseline-migrate.d.ts +12 -0
- package/dist/cli/commands/baseline-migrate.js +164 -0
- package/dist/cli/commands/baseline.d.ts +14 -0
- package/dist/cli/commands/baseline.js +449 -0
- package/dist/cli/commands/beta.d.ts +10 -0
- package/dist/cli/commands/beta.js +231 -0
- package/dist/cli/commands/check.d.ts +11 -0
- package/dist/cli/commands/check.js +820 -0
- package/dist/cli/commands/cloud/badge.d.ts +3 -0
- package/dist/cli/commands/cloud/badge.js +74 -0
- package/dist/cli/commands/cloud/diff.d.ts +6 -0
- package/dist/cli/commands/cloud/diff.js +79 -0
- package/dist/cli/commands/cloud/history.d.ts +6 -0
- package/dist/cli/commands/cloud/history.js +102 -0
- package/dist/cli/commands/cloud/link.d.ts +9 -0
- package/dist/cli/commands/cloud/link.js +119 -0
- package/dist/cli/commands/cloud/login.d.ts +7 -0
- package/dist/cli/commands/cloud/login.js +499 -0
- package/dist/cli/commands/cloud/projects.d.ts +6 -0
- package/dist/cli/commands/cloud/projects.js +44 -0
- package/dist/cli/commands/cloud/shared.d.ts +7 -0
- package/dist/cli/commands/cloud/shared.js +42 -0
- package/dist/cli/commands/cloud/teams.d.ts +8 -0
- package/dist/cli/commands/cloud/teams.js +169 -0
- package/dist/cli/commands/cloud/upload.d.ts +8 -0
- package/dist/cli/commands/cloud/upload.js +181 -0
- package/dist/cli/commands/contract.d.ts +11 -0
- package/dist/cli/commands/contract.js +280 -0
- package/dist/cli/commands/discover.d.ts +3 -0
- package/dist/cli/commands/discover.js +82 -0
- package/dist/cli/commands/eval.d.ts +9 -0
- package/dist/cli/commands/eval.js +187 -0
- package/dist/cli/commands/explore.d.ts +11 -0
- package/dist/cli/commands/explore.js +437 -0
- package/dist/cli/commands/feedback.d.ts +9 -0
- package/dist/cli/commands/feedback.js +174 -0
- package/dist/cli/commands/golden.d.ts +12 -0
- package/dist/cli/commands/golden.js +407 -0
- package/dist/cli/commands/history.d.ts +10 -0
- package/dist/cli/commands/history.js +202 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.js +219 -0
- package/dist/cli/commands/interview.d.ts +3 -0
- package/dist/cli/commands/interview.js +903 -0
- package/dist/cli/commands/link.d.ts +10 -0
- package/dist/cli/commands/link.js +169 -0
- package/dist/cli/commands/login.d.ts +7 -0
- package/dist/cli/commands/login.js +499 -0
- package/dist/cli/commands/preset.d.ts +33 -0
- package/dist/cli/commands/preset.js +297 -0
- package/dist/cli/commands/profile.d.ts +33 -0
- package/dist/cli/commands/profile.js +286 -0
- package/dist/cli/commands/registry.d.ts +11 -0
- package/dist/cli/commands/registry.js +146 -0
- package/dist/cli/commands/shared.d.ts +79 -0
- package/dist/cli/commands/shared.js +196 -0
- package/dist/cli/commands/teams.d.ts +8 -0
- package/dist/cli/commands/teams.js +169 -0
- package/dist/cli/commands/test.d.ts +9 -0
- package/dist/cli/commands/test.js +500 -0
- package/dist/cli/commands/upload.d.ts +8 -0
- package/dist/cli/commands/upload.js +223 -0
- package/dist/cli/commands/validate-config.d.ts +6 -0
- package/dist/cli/commands/validate-config.js +35 -0
- package/dist/cli/commands/verify.d.ts +11 -0
- package/dist/cli/commands/verify.js +283 -0
- package/dist/cli/commands/watch.d.ts +12 -0
- package/dist/cli/commands/watch.js +253 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +178 -0
- package/dist/cli/interactive.d.ts +47 -0
- package/dist/cli/interactive.js +216 -0
- package/dist/cli/output/terminal-reporter.d.ts +19 -0
- package/dist/cli/output/terminal-reporter.js +104 -0
- package/dist/cli/output.d.ts +226 -0
- package/dist/cli/output.js +438 -0
- package/dist/cli/utils/env.d.ts +5 -0
- package/dist/cli/utils/env.js +14 -0
- package/dist/cli/utils/progress.d.ts +59 -0
- package/dist/cli/utils/progress.js +206 -0
- package/dist/cli/utils/server-context.d.ts +10 -0
- package/dist/cli/utils/server-context.js +36 -0
- package/dist/cloud/auth.d.ts +144 -0
- package/dist/cloud/auth.js +374 -0
- package/dist/cloud/client.d.ts +24 -0
- package/dist/cloud/client.js +65 -0
- package/dist/cloud/http-client.d.ts +38 -0
- package/dist/cloud/http-client.js +215 -0
- package/dist/cloud/index.d.ts +23 -0
- package/dist/cloud/index.js +25 -0
- package/dist/cloud/mock-client.d.ts +107 -0
- package/dist/cloud/mock-client.js +545 -0
- package/dist/cloud/types.d.ts +515 -0
- package/dist/cloud/types.js +15 -0
- package/dist/config/defaults.d.ts +160 -0
- package/dist/config/defaults.js +169 -0
- package/dist/config/loader.d.ts +24 -0
- package/dist/config/loader.js +122 -0
- package/dist/config/template.d.ts +42 -0
- package/dist/config/template.js +647 -0
- package/dist/config/validator.d.ts +2112 -0
- package/dist/config/validator.js +658 -0
- package/dist/constants/cloud.d.ts +107 -0
- package/dist/constants/cloud.js +110 -0
- package/dist/constants/core.d.ts +521 -0
- package/dist/constants/core.js +556 -0
- package/dist/constants/testing.d.ts +1283 -0
- package/dist/constants/testing.js +1568 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +10 -0
- package/dist/contract/index.d.ts +6 -0
- package/dist/contract/index.js +5 -0
- package/dist/contract/validator.d.ts +177 -0
- package/dist/contract/validator.js +574 -0
- package/dist/cost/index.d.ts +6 -0
- package/dist/cost/index.js +5 -0
- package/dist/cost/tracker.d.ts +134 -0
- package/dist/cost/tracker.js +313 -0
- package/dist/discovery/discovery.d.ts +16 -0
- package/dist/discovery/discovery.js +173 -0
- package/dist/discovery/types.d.ts +51 -0
- package/dist/discovery/types.js +2 -0
- package/dist/docs/agents.d.ts +3 -0
- package/dist/docs/agents.js +995 -0
- package/dist/docs/contract.d.ts +51 -0
- package/dist/docs/contract.js +1681 -0
- package/dist/docs/generator.d.ts +4 -0
- package/dist/docs/generator.js +4 -0
- package/dist/docs/html-reporter.d.ts +9 -0
- package/dist/docs/html-reporter.js +757 -0
- package/dist/docs/index.d.ts +10 -0
- package/dist/docs/index.js +11 -0
- package/dist/docs/junit-reporter.d.ts +18 -0
- package/dist/docs/junit-reporter.js +210 -0
- package/dist/docs/report.d.ts +14 -0
- package/dist/docs/report.js +44 -0
- package/dist/docs/sarif-reporter.d.ts +19 -0
- package/dist/docs/sarif-reporter.js +335 -0
- package/dist/docs/shared.d.ts +35 -0
- package/dist/docs/shared.js +162 -0
- package/dist/docs/templates.d.ts +12 -0
- package/dist/docs/templates.js +76 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.js +6 -0
- package/dist/errors/retry.d.ts +92 -0
- package/dist/errors/retry.js +323 -0
- package/dist/errors/types.d.ts +321 -0
- package/dist/errors/types.js +584 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +32 -0
- package/dist/interview/dependency-resolver.d.ts +11 -0
- package/dist/interview/dependency-resolver.js +32 -0
- package/dist/interview/interviewer.d.ts +232 -0
- package/dist/interview/interviewer.js +1939 -0
- package/dist/interview/mock-response-generator.d.ts +7 -0
- package/dist/interview/mock-response-generator.js +102 -0
- package/dist/interview/orchestrator.d.ts +237 -0
- package/dist/interview/orchestrator.js +1296 -0
- package/dist/interview/rate-limiter.d.ts +15 -0
- package/dist/interview/rate-limiter.js +55 -0
- package/dist/interview/response-validator.d.ts +10 -0
- package/dist/interview/response-validator.js +132 -0
- package/dist/interview/schema-inferrer.d.ts +8 -0
- package/dist/interview/schema-inferrer.js +71 -0
- package/dist/interview/schema-test-generator.d.ts +71 -0
- package/dist/interview/schema-test-generator.js +834 -0
- package/dist/interview/smart-value-generator.d.ts +155 -0
- package/dist/interview/smart-value-generator.js +554 -0
- package/dist/interview/stateful-test-runner.d.ts +19 -0
- package/dist/interview/stateful-test-runner.js +106 -0
- package/dist/interview/types.d.ts +561 -0
- package/dist/interview/types.js +2 -0
- package/dist/llm/anthropic.d.ts +41 -0
- package/dist/llm/anthropic.js +355 -0
- package/dist/llm/client.d.ts +123 -0
- package/dist/llm/client.js +42 -0
- package/dist/llm/factory.d.ts +38 -0
- package/dist/llm/factory.js +145 -0
- package/dist/llm/fallback.d.ts +140 -0
- package/dist/llm/fallback.js +379 -0
- package/dist/llm/index.d.ts +18 -0
- package/dist/llm/index.js +15 -0
- package/dist/llm/ollama.d.ts +37 -0
- package/dist/llm/ollama.js +330 -0
- package/dist/llm/openai.d.ts +25 -0
- package/dist/llm/openai.js +320 -0
- package/dist/llm/token-budget.d.ts +161 -0
- package/dist/llm/token-budget.js +395 -0
- package/dist/logging/logger.d.ts +70 -0
- package/dist/logging/logger.js +130 -0
- package/dist/metrics/collector.d.ts +106 -0
- package/dist/metrics/collector.js +547 -0
- package/dist/metrics/index.d.ts +7 -0
- package/dist/metrics/index.js +7 -0
- package/dist/metrics/prometheus.d.ts +20 -0
- package/dist/metrics/prometheus.js +241 -0
- package/dist/metrics/types.d.ts +209 -0
- package/dist/metrics/types.js +5 -0
- package/dist/persona/builtins.d.ts +54 -0
- package/dist/persona/builtins.js +219 -0
- package/dist/persona/index.d.ts +8 -0
- package/dist/persona/index.js +8 -0
- package/dist/persona/loader.d.ts +30 -0
- package/dist/persona/loader.js +190 -0
- package/dist/persona/types.d.ts +144 -0
- package/dist/persona/types.js +5 -0
- package/dist/persona/validation.d.ts +94 -0
- package/dist/persona/validation.js +332 -0
- package/dist/prompts/index.d.ts +5 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/templates.d.ts +180 -0
- package/dist/prompts/templates.js +431 -0
- package/dist/registry/client.d.ts +49 -0
- package/dist/registry/client.js +191 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +6 -0
- package/dist/registry/types.d.ts +140 -0
- package/dist/registry/types.js +6 -0
- package/dist/scenarios/evaluator.d.ts +43 -0
- package/dist/scenarios/evaluator.js +206 -0
- package/dist/scenarios/index.d.ts +10 -0
- package/dist/scenarios/index.js +9 -0
- package/dist/scenarios/loader.d.ts +20 -0
- package/dist/scenarios/loader.js +285 -0
- package/dist/scenarios/types.d.ts +153 -0
- package/dist/scenarios/types.js +8 -0
- package/dist/security/index.d.ts +17 -0
- package/dist/security/index.js +18 -0
- package/dist/security/payloads.d.ts +61 -0
- package/dist/security/payloads.js +268 -0
- package/dist/security/security-tester.d.ts +42 -0
- package/dist/security/security-tester.js +582 -0
- package/dist/security/types.d.ts +166 -0
- package/dist/security/types.js +8 -0
- package/dist/transport/base-transport.d.ts +59 -0
- package/dist/transport/base-transport.js +38 -0
- package/dist/transport/http-transport.d.ts +67 -0
- package/dist/transport/http-transport.js +238 -0
- package/dist/transport/mcp-client.d.ts +141 -0
- package/dist/transport/mcp-client.js +496 -0
- package/dist/transport/sse-transport.d.ts +88 -0
- package/dist/transport/sse-transport.js +316 -0
- package/dist/transport/stdio-transport.d.ts +43 -0
- package/dist/transport/stdio-transport.js +238 -0
- package/dist/transport/types.d.ts +125 -0
- package/dist/transport/types.js +16 -0
- package/dist/utils/concurrency.d.ts +123 -0
- package/dist/utils/concurrency.js +213 -0
- package/dist/utils/formatters.d.ts +16 -0
- package/dist/utils/formatters.js +37 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/jsonpath.d.ts +87 -0
- package/dist/utils/jsonpath.js +326 -0
- package/dist/utils/markdown.d.ts +113 -0
- package/dist/utils/markdown.js +265 -0
- package/dist/utils/network.d.ts +14 -0
- package/dist/utils/network.js +17 -0
- package/dist/utils/sanitize.d.ts +92 -0
- package/dist/utils/sanitize.js +191 -0
- package/dist/utils/semantic.d.ts +194 -0
- package/dist/utils/semantic.js +1051 -0
- package/dist/utils/smart-truncate.d.ts +94 -0
- package/dist/utils/smart-truncate.js +361 -0
- package/dist/utils/timeout.d.ts +153 -0
- package/dist/utils/timeout.js +205 -0
- package/dist/utils/yaml-parser.d.ts +58 -0
- package/dist/utils/yaml-parser.js +86 -0
- package/dist/validation/index.d.ts +32 -0
- package/dist/validation/index.js +32 -0
- package/dist/validation/semantic-test-generator.d.ts +50 -0
- package/dist/validation/semantic-test-generator.js +176 -0
- package/dist/validation/semantic-types.d.ts +66 -0
- package/dist/validation/semantic-types.js +94 -0
- package/dist/validation/semantic-validator.d.ts +38 -0
- package/dist/validation/semantic-validator.js +340 -0
- package/dist/verification/index.d.ts +6 -0
- package/dist/verification/index.js +5 -0
- package/dist/verification/types.d.ts +133 -0
- package/dist/verification/types.js +5 -0
- package/dist/verification/verifier.d.ts +30 -0
- package/dist/verification/verifier.js +309 -0
- package/dist/version.d.ts +19 -0
- package/dist/version.js +48 -0
- package/dist/workflow/auto-generator.d.ts +27 -0
- package/dist/workflow/auto-generator.js +513 -0
- package/dist/workflow/discovery.d.ts +40 -0
- package/dist/workflow/discovery.js +195 -0
- package/dist/workflow/executor.d.ts +82 -0
- package/dist/workflow/executor.js +611 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.js +10 -0
- package/dist/workflow/loader.d.ts +24 -0
- package/dist/workflow/loader.js +194 -0
- package/dist/workflow/state-tracker.d.ts +98 -0
- package/dist/workflow/state-tracker.js +424 -0
- package/dist/workflow/types.d.ts +337 -0
- package/dist/workflow/types.js +5 -0
- package/package.json +94 -0
- package/schemas/bellwether-check.schema.json +651 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type SSETransportConfig } from './sse-transport.js';
|
|
2
|
+
import { type HTTPTransportConfig } from './http-transport.js';
|
|
3
|
+
import { type TransportType } from './base-transport.js';
|
|
4
|
+
import type { MCPInitializeResult, MCPTool, MCPPrompt, MCPResource, MCPToolCallResult, MCPResourceReadResult, MCPPromptGetResult, MCPServerCapabilities } from './types.js';
|
|
5
|
+
export interface MCPClientOptions {
|
|
6
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
7
|
+
timeout?: number;
|
|
8
|
+
/** Environment variables for the server process */
|
|
9
|
+
env?: Record<string, string>;
|
|
10
|
+
/** Delay before sending first request to allow server startup (default: 500ms) */
|
|
11
|
+
startupDelay?: number;
|
|
12
|
+
/** Enable debug logging */
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
/** Transport type to use (default: stdio) */
|
|
15
|
+
transport?: TransportType;
|
|
16
|
+
/** Configuration for SSE transport */
|
|
17
|
+
sseConfig?: Omit<SSETransportConfig, 'debug'>;
|
|
18
|
+
/** Configuration for HTTP transport */
|
|
19
|
+
httpConfig?: Omit<HTTPTransportConfig, 'debug'>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* MCPClient connects to an MCP server via various transports and provides
|
|
23
|
+
* methods to interact with the server's capabilities.
|
|
24
|
+
*
|
|
25
|
+
* Supported transports:
|
|
26
|
+
* - stdio: Local subprocess communication (default)
|
|
27
|
+
* - sse: Server-Sent Events for remote servers
|
|
28
|
+
* - streamable-http: HTTP POST with streaming responses
|
|
29
|
+
*/
|
|
30
|
+
export declare class MCPClient {
|
|
31
|
+
private process;
|
|
32
|
+
private transport;
|
|
33
|
+
private requestId;
|
|
34
|
+
private pendingRequests;
|
|
35
|
+
private serverCapabilities;
|
|
36
|
+
private timeout;
|
|
37
|
+
private startupDelay;
|
|
38
|
+
private serverReady;
|
|
39
|
+
private readyPromise;
|
|
40
|
+
private debug;
|
|
41
|
+
private transportType;
|
|
42
|
+
private sseConfig?;
|
|
43
|
+
private httpConfig?;
|
|
44
|
+
private logger;
|
|
45
|
+
/** Flag to prevent race condition during cleanup - ignore messages when true */
|
|
46
|
+
private cleaningUp;
|
|
47
|
+
constructor(options?: MCPClientOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Get the current transport type.
|
|
50
|
+
*/
|
|
51
|
+
getTransportType(): TransportType;
|
|
52
|
+
private log;
|
|
53
|
+
/**
|
|
54
|
+
* Check if an environment variable name looks like a secret.
|
|
55
|
+
*/
|
|
56
|
+
private isSensitiveEnvVar;
|
|
57
|
+
/**
|
|
58
|
+
* Filter sensitive environment variables before passing to subprocess.
|
|
59
|
+
* Uses both explicit list and pattern matching to catch common secret naming conventions.
|
|
60
|
+
*/
|
|
61
|
+
private filterEnv;
|
|
62
|
+
/**
|
|
63
|
+
* Connect to an MCP server by spawning it as a subprocess.
|
|
64
|
+
*/
|
|
65
|
+
connect(command: string, args?: string[], env?: Record<string, string>): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Connect to a remote MCP server via SSE or HTTP.
|
|
68
|
+
*
|
|
69
|
+
* @param url - The base URL of the MCP server
|
|
70
|
+
* @param options - Optional configuration overrides
|
|
71
|
+
*/
|
|
72
|
+
connectRemote(url: string, options?: {
|
|
73
|
+
transport?: 'sse' | 'streamable-http';
|
|
74
|
+
sessionId?: string;
|
|
75
|
+
headers?: Record<string, string>;
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Set up event handlers for the transport.
|
|
79
|
+
*/
|
|
80
|
+
private setupTransportHandlers;
|
|
81
|
+
/**
|
|
82
|
+
* Wait for minimum startup delay before sending requests.
|
|
83
|
+
* The actual "ready" state is confirmed by successful initialization.
|
|
84
|
+
* This delay allows the server process to fully start before we attempt communication.
|
|
85
|
+
*/
|
|
86
|
+
private waitForStartup;
|
|
87
|
+
/**
|
|
88
|
+
* Initialize the MCP connection with the server.
|
|
89
|
+
* This is the explicit confirmation that the server is ready.
|
|
90
|
+
* On failure, all pending requests are cleared.
|
|
91
|
+
*/
|
|
92
|
+
initialize(): Promise<MCPInitializeResult>;
|
|
93
|
+
/**
|
|
94
|
+
* Clear all pending requests with an error.
|
|
95
|
+
* Used when initialization fails or connection is lost.
|
|
96
|
+
*/
|
|
97
|
+
private clearPendingRequests;
|
|
98
|
+
/**
|
|
99
|
+
* List all tools available on the server.
|
|
100
|
+
*/
|
|
101
|
+
listTools(): Promise<MCPTool[]>;
|
|
102
|
+
/**
|
|
103
|
+
* List all prompts available on the server.
|
|
104
|
+
*/
|
|
105
|
+
listPrompts(): Promise<MCPPrompt[]>;
|
|
106
|
+
/**
|
|
107
|
+
* List all resources available on the server.
|
|
108
|
+
*/
|
|
109
|
+
listResources(): Promise<MCPResource[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Read a resource from the server by URI.
|
|
112
|
+
*/
|
|
113
|
+
readResource(uri: string): Promise<MCPResourceReadResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Get a prompt from the server with the given arguments.
|
|
116
|
+
*/
|
|
117
|
+
getPrompt(name: string, args?: Record<string, string>): Promise<MCPPromptGetResult>;
|
|
118
|
+
/**
|
|
119
|
+
* Call a tool on the server.
|
|
120
|
+
*/
|
|
121
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<MCPToolCallResult>;
|
|
122
|
+
/**
|
|
123
|
+
* Get server capabilities.
|
|
124
|
+
*/
|
|
125
|
+
getCapabilities(): MCPServerCapabilities | null;
|
|
126
|
+
/**
|
|
127
|
+
* Check if the server is ready (startup delay complete and initialized).
|
|
128
|
+
* Note: This only indicates if startup delay has passed - true readiness
|
|
129
|
+
* is confirmed by successful initialization.
|
|
130
|
+
*/
|
|
131
|
+
isServerReady(): boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Disconnect from the server.
|
|
134
|
+
*/
|
|
135
|
+
disconnect(): Promise<void>;
|
|
136
|
+
private sendRequest;
|
|
137
|
+
private sendNotification;
|
|
138
|
+
private handleMessage;
|
|
139
|
+
private cleanup;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=mcp-client.d.ts.map
|
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { StdioTransport } from './stdio-transport.js';
|
|
3
|
+
import { SSETransport } from './sse-transport.js';
|
|
4
|
+
import { HTTPTransport } from './http-transport.js';
|
|
5
|
+
import { getLogger, startTiming } from '../logging/logger.js';
|
|
6
|
+
import { TIMEOUTS, MCP } from '../constants.js';
|
|
7
|
+
import { VERSION } from '../version.js';
|
|
8
|
+
/**
|
|
9
|
+
* Environment variables to filter out when spawning MCP server processes.
|
|
10
|
+
* These may contain sensitive credentials that should not be exposed.
|
|
11
|
+
*/
|
|
12
|
+
const FILTERED_ENV_VARS = new Set([
|
|
13
|
+
// LLM API keys
|
|
14
|
+
'OPENAI_API_KEY',
|
|
15
|
+
'ANTHROPIC_API_KEY',
|
|
16
|
+
'GOOGLE_API_KEY',
|
|
17
|
+
'AZURE_OPENAI_API_KEY',
|
|
18
|
+
'COHERE_API_KEY',
|
|
19
|
+
'HUGGINGFACE_API_KEY',
|
|
20
|
+
'REPLICATE_API_TOKEN',
|
|
21
|
+
// Bellwether-specific
|
|
22
|
+
'BELLWETHER_SESSION',
|
|
23
|
+
// Cloud provider credentials
|
|
24
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
25
|
+
'AWS_SESSION_TOKEN',
|
|
26
|
+
'AZURE_CLIENT_SECRET',
|
|
27
|
+
'GOOGLE_APPLICATION_CREDENTIALS',
|
|
28
|
+
// SCM/CI tokens
|
|
29
|
+
'GITHUB_TOKEN',
|
|
30
|
+
'GH_TOKEN',
|
|
31
|
+
'GITLAB_TOKEN',
|
|
32
|
+
'BITBUCKET_TOKEN',
|
|
33
|
+
'NPM_TOKEN',
|
|
34
|
+
'PYPI_TOKEN',
|
|
35
|
+
// Database credentials
|
|
36
|
+
'DATABASE_URL',
|
|
37
|
+
'DATABASE_PASSWORD',
|
|
38
|
+
'POSTGRES_PASSWORD',
|
|
39
|
+
'MYSQL_PASSWORD',
|
|
40
|
+
'REDIS_PASSWORD',
|
|
41
|
+
'MONGODB_URI',
|
|
42
|
+
// Application secrets
|
|
43
|
+
'COOKIE_SECRET',
|
|
44
|
+
'SESSION_SECRET',
|
|
45
|
+
'JWT_SECRET',
|
|
46
|
+
'ENCRYPTION_KEY',
|
|
47
|
+
'PRIVATE_KEY',
|
|
48
|
+
]);
|
|
49
|
+
/**
|
|
50
|
+
* Patterns for environment variable names that should be filtered.
|
|
51
|
+
* Matches common naming conventions for secrets.
|
|
52
|
+
*/
|
|
53
|
+
const FILTERED_ENV_PATTERNS = [
|
|
54
|
+
/_API_KEY$/i,
|
|
55
|
+
/_SECRET$/i,
|
|
56
|
+
/_TOKEN$/i,
|
|
57
|
+
/_PASSWORD$/i,
|
|
58
|
+
/_PRIVATE_KEY$/i,
|
|
59
|
+
/_CREDENTIALS$/i,
|
|
60
|
+
/^SECRET_/i,
|
|
61
|
+
/^PRIVATE_/i,
|
|
62
|
+
];
|
|
63
|
+
const DEFAULT_TIMEOUT = TIMEOUTS.DEFAULT;
|
|
64
|
+
const DEFAULT_STARTUP_DELAY = TIMEOUTS.SERVER_STARTUP;
|
|
65
|
+
/**
|
|
66
|
+
* MCPClient connects to an MCP server via various transports and provides
|
|
67
|
+
* methods to interact with the server's capabilities.
|
|
68
|
+
*
|
|
69
|
+
* Supported transports:
|
|
70
|
+
* - stdio: Local subprocess communication (default)
|
|
71
|
+
* - sse: Server-Sent Events for remote servers
|
|
72
|
+
* - streamable-http: HTTP POST with streaming responses
|
|
73
|
+
*/
|
|
74
|
+
export class MCPClient {
|
|
75
|
+
process = null;
|
|
76
|
+
transport = null;
|
|
77
|
+
requestId = 0;
|
|
78
|
+
pendingRequests = new Map();
|
|
79
|
+
serverCapabilities = null;
|
|
80
|
+
timeout;
|
|
81
|
+
startupDelay;
|
|
82
|
+
serverReady = false;
|
|
83
|
+
readyPromise = null;
|
|
84
|
+
debug;
|
|
85
|
+
transportType;
|
|
86
|
+
sseConfig;
|
|
87
|
+
httpConfig;
|
|
88
|
+
logger = getLogger('mcp-client');
|
|
89
|
+
/** Flag to prevent race condition during cleanup - ignore messages when true */
|
|
90
|
+
cleaningUp = false;
|
|
91
|
+
constructor(options) {
|
|
92
|
+
this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;
|
|
93
|
+
this.startupDelay = options?.startupDelay ?? DEFAULT_STARTUP_DELAY;
|
|
94
|
+
this.debug = options?.debug ?? false;
|
|
95
|
+
this.transportType = options?.transport ?? 'stdio';
|
|
96
|
+
this.sseConfig = options?.sseConfig;
|
|
97
|
+
this.httpConfig = options?.httpConfig;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the current transport type.
|
|
101
|
+
*/
|
|
102
|
+
getTransportType() {
|
|
103
|
+
return this.transportType;
|
|
104
|
+
}
|
|
105
|
+
log(...args) {
|
|
106
|
+
if (this.debug) {
|
|
107
|
+
this.logger.debug({ args }, 'MCP Debug');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if an environment variable name looks like a secret.
|
|
112
|
+
*/
|
|
113
|
+
isSensitiveEnvVar(name) {
|
|
114
|
+
// Check explicit list
|
|
115
|
+
if (FILTERED_ENV_VARS.has(name)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
// Check patterns
|
|
119
|
+
return FILTERED_ENV_PATTERNS.some(pattern => pattern.test(name));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Filter sensitive environment variables before passing to subprocess.
|
|
123
|
+
* Uses both explicit list and pattern matching to catch common secret naming conventions.
|
|
124
|
+
*/
|
|
125
|
+
filterEnv(baseEnv, additionalEnv) {
|
|
126
|
+
const filtered = {};
|
|
127
|
+
// Copy process.env, filtering out sensitive variables
|
|
128
|
+
for (const [key, value] of Object.entries(baseEnv)) {
|
|
129
|
+
if (value !== undefined && !this.isSensitiveEnvVar(key)) {
|
|
130
|
+
filtered[key] = value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Add additional env vars (these are explicitly provided, so allow them)
|
|
134
|
+
if (additionalEnv) {
|
|
135
|
+
Object.assign(filtered, additionalEnv);
|
|
136
|
+
}
|
|
137
|
+
return filtered;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Connect to an MCP server by spawning it as a subprocess.
|
|
141
|
+
*/
|
|
142
|
+
async connect(command, args = [], env) {
|
|
143
|
+
this.logger.info({ command, args: args.length }, 'Connecting to MCP server');
|
|
144
|
+
// Reset cleanup flag for new connection
|
|
145
|
+
this.cleaningUp = false;
|
|
146
|
+
// Filter out sensitive environment variables before spawning subprocess
|
|
147
|
+
const filteredEnv = this.filterEnv(process.env, env);
|
|
148
|
+
this.process = spawn(command, args, {
|
|
149
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
150
|
+
env: filteredEnv,
|
|
151
|
+
});
|
|
152
|
+
if (!this.process.stdout || !this.process.stdin) {
|
|
153
|
+
throw new Error('Failed to create stdio streams for server process');
|
|
154
|
+
}
|
|
155
|
+
this.transport = new StdioTransport(this.process.stdout, this.process.stdin, { debug: this.debug });
|
|
156
|
+
this.transport.on('message', (msg) => {
|
|
157
|
+
this.log('Received:', JSON.stringify(msg));
|
|
158
|
+
this.handleMessage(msg);
|
|
159
|
+
});
|
|
160
|
+
this.transport.on('error', (error) => {
|
|
161
|
+
this.logger.error({ error: error.message }, 'Transport error');
|
|
162
|
+
});
|
|
163
|
+
this.transport.on('close', () => {
|
|
164
|
+
this.logger.debug('Transport closed');
|
|
165
|
+
this.cleanup();
|
|
166
|
+
});
|
|
167
|
+
this.process.on('error', (error) => {
|
|
168
|
+
this.logger.error({ error: error.message }, 'Process error');
|
|
169
|
+
this.cleanup();
|
|
170
|
+
});
|
|
171
|
+
this.process.on('exit', (code) => {
|
|
172
|
+
if (code !== 0) {
|
|
173
|
+
this.logger.warn({ exitCode: code }, 'Server process exited with non-zero code');
|
|
174
|
+
}
|
|
175
|
+
this.cleanup();
|
|
176
|
+
});
|
|
177
|
+
this.process.stderr?.on('data', (data) => {
|
|
178
|
+
const msg = data.toString().trim();
|
|
179
|
+
if (msg) {
|
|
180
|
+
this.logger.debug({ stderr: msg }, 'Server stderr');
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
this.readyPromise = this.waitForStartup();
|
|
184
|
+
this.logger.debug('Startup delay complete, connection established');
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Connect to a remote MCP server via SSE or HTTP.
|
|
188
|
+
*
|
|
189
|
+
* @param url - The base URL of the MCP server
|
|
190
|
+
* @param options - Optional configuration overrides
|
|
191
|
+
*/
|
|
192
|
+
async connectRemote(url, options) {
|
|
193
|
+
const transport = options?.transport ?? (this.transportType === 'stdio' ? 'sse' : this.transportType);
|
|
194
|
+
this.transportType = transport;
|
|
195
|
+
// Reset cleanup flag for new connection
|
|
196
|
+
this.cleaningUp = false;
|
|
197
|
+
this.logger.info({ url, transport }, 'Connecting to remote MCP server');
|
|
198
|
+
if (transport === 'sse') {
|
|
199
|
+
const sseTransport = new SSETransport({
|
|
200
|
+
baseUrl: url,
|
|
201
|
+
sessionId: options?.sessionId ?? this.sseConfig?.sessionId,
|
|
202
|
+
headers: options?.headers ?? this.sseConfig?.headers,
|
|
203
|
+
timeout: this.timeout,
|
|
204
|
+
debug: this.debug,
|
|
205
|
+
...this.sseConfig,
|
|
206
|
+
});
|
|
207
|
+
await sseTransport.connect();
|
|
208
|
+
this.transport = sseTransport;
|
|
209
|
+
}
|
|
210
|
+
else if (transport === 'streamable-http') {
|
|
211
|
+
const httpTransport = new HTTPTransport({
|
|
212
|
+
baseUrl: url,
|
|
213
|
+
sessionId: options?.sessionId ?? this.httpConfig?.sessionId,
|
|
214
|
+
headers: options?.headers ?? this.httpConfig?.headers,
|
|
215
|
+
timeout: this.timeout,
|
|
216
|
+
debug: this.debug,
|
|
217
|
+
...this.httpConfig,
|
|
218
|
+
});
|
|
219
|
+
await httpTransport.connect();
|
|
220
|
+
this.transport = httpTransport;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
throw new Error(`Unsupported transport type: ${transport}`);
|
|
224
|
+
}
|
|
225
|
+
this.setupTransportHandlers();
|
|
226
|
+
// For remote transports, server is ready immediately
|
|
227
|
+
this.serverReady = true;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Set up event handlers for the transport.
|
|
231
|
+
*/
|
|
232
|
+
setupTransportHandlers() {
|
|
233
|
+
if (!this.transport)
|
|
234
|
+
return;
|
|
235
|
+
this.transport.on('message', (msg) => {
|
|
236
|
+
this.log('Received:', JSON.stringify(msg));
|
|
237
|
+
this.handleMessage(msg);
|
|
238
|
+
});
|
|
239
|
+
this.transport.on('error', (error) => {
|
|
240
|
+
this.logger.error({ error: error.message }, 'Transport error');
|
|
241
|
+
});
|
|
242
|
+
this.transport.on('close', () => {
|
|
243
|
+
this.logger.debug('Transport closed');
|
|
244
|
+
this.cleanup();
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Wait for minimum startup delay before sending requests.
|
|
249
|
+
* The actual "ready" state is confirmed by successful initialization.
|
|
250
|
+
* This delay allows the server process to fully start before we attempt communication.
|
|
251
|
+
*/
|
|
252
|
+
async waitForStartup() {
|
|
253
|
+
// Enforce minimum startup delay to allow server to fully start
|
|
254
|
+
// npx-based servers often need significant time to download and start
|
|
255
|
+
const delay = Math.max(this.startupDelay, TIMEOUTS.MIN_SERVER_STARTUP_WAIT);
|
|
256
|
+
this.logger.debug({ delay }, 'Waiting for server startup');
|
|
257
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
258
|
+
// Mark server as ready (startup delay complete)
|
|
259
|
+
// Note: This only means we can *try* to initialize - actual readiness
|
|
260
|
+
// is confirmed by successful initialization response
|
|
261
|
+
this.serverReady = true;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Initialize the MCP connection with the server.
|
|
265
|
+
* This is the explicit confirmation that the server is ready.
|
|
266
|
+
* On failure, all pending requests are cleared.
|
|
267
|
+
*/
|
|
268
|
+
async initialize() {
|
|
269
|
+
// Wait for startup delay to complete
|
|
270
|
+
if (this.readyPromise) {
|
|
271
|
+
await this.readyPromise;
|
|
272
|
+
this.readyPromise = null;
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const result = await this.sendRequest('initialize', {
|
|
276
|
+
protocolVersion: MCP.PROTOCOL_VERSION,
|
|
277
|
+
capabilities: {},
|
|
278
|
+
clientInfo: {
|
|
279
|
+
name: 'bellwether',
|
|
280
|
+
version: VERSION,
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
this.serverCapabilities = result.capabilities;
|
|
284
|
+
// Send initialized notification
|
|
285
|
+
this.sendNotification('notifications/initialized', {});
|
|
286
|
+
this.logger.info({ capabilities: result.capabilities }, 'MCP server initialized successfully');
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
// Clear all pending requests on initialization failure
|
|
291
|
+
// This prevents stale requests from hanging around
|
|
292
|
+
this.clearPendingRequests(error instanceof Error ? error.message : 'Initialization failed');
|
|
293
|
+
// Re-throw the error for the caller to handle
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Clear all pending requests with an error.
|
|
299
|
+
* Used when initialization fails or connection is lost.
|
|
300
|
+
*/
|
|
301
|
+
clearPendingRequests(reason) {
|
|
302
|
+
const pendingCount = this.pendingRequests.size;
|
|
303
|
+
if (pendingCount > 0) {
|
|
304
|
+
this.logger.debug({ count: pendingCount, reason }, 'Clearing pending requests');
|
|
305
|
+
}
|
|
306
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
307
|
+
clearTimeout(pending.timer);
|
|
308
|
+
pending.reject(new Error(`Request ${id} cancelled: ${reason}`));
|
|
309
|
+
}
|
|
310
|
+
this.pendingRequests.clear();
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* List all tools available on the server.
|
|
314
|
+
*/
|
|
315
|
+
async listTools() {
|
|
316
|
+
const result = await this.sendRequest('tools/list', {});
|
|
317
|
+
return result.tools;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* List all prompts available on the server.
|
|
321
|
+
*/
|
|
322
|
+
async listPrompts() {
|
|
323
|
+
const result = await this.sendRequest('prompts/list', {});
|
|
324
|
+
return result.prompts;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* List all resources available on the server.
|
|
328
|
+
*/
|
|
329
|
+
async listResources() {
|
|
330
|
+
const result = await this.sendRequest('resources/list', {});
|
|
331
|
+
return result.resources;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Read a resource from the server by URI.
|
|
335
|
+
*/
|
|
336
|
+
async readResource(uri) {
|
|
337
|
+
const done = startTiming(this.logger, `readResource:${uri}`);
|
|
338
|
+
try {
|
|
339
|
+
const result = await this.sendRequest('resources/read', {
|
|
340
|
+
uri,
|
|
341
|
+
});
|
|
342
|
+
done();
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
done();
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get a prompt from the server with the given arguments.
|
|
352
|
+
*/
|
|
353
|
+
async getPrompt(name, args = {}) {
|
|
354
|
+
const done = startTiming(this.logger, `getPrompt:${name}`);
|
|
355
|
+
try {
|
|
356
|
+
const result = await this.sendRequest('prompts/get', {
|
|
357
|
+
name,
|
|
358
|
+
arguments: args,
|
|
359
|
+
});
|
|
360
|
+
done();
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
done();
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Call a tool on the server.
|
|
370
|
+
*/
|
|
371
|
+
async callTool(name, args = {}) {
|
|
372
|
+
const done = startTiming(this.logger, `callTool:${name}`);
|
|
373
|
+
try {
|
|
374
|
+
const result = await this.sendRequest('tools/call', {
|
|
375
|
+
name,
|
|
376
|
+
arguments: args,
|
|
377
|
+
});
|
|
378
|
+
done();
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
done();
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get server capabilities.
|
|
388
|
+
*/
|
|
389
|
+
getCapabilities() {
|
|
390
|
+
return this.serverCapabilities;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Check if the server is ready (startup delay complete and initialized).
|
|
394
|
+
* Note: This only indicates if startup delay has passed - true readiness
|
|
395
|
+
* is confirmed by successful initialization.
|
|
396
|
+
*/
|
|
397
|
+
isServerReady() {
|
|
398
|
+
return this.serverReady;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Disconnect from the server.
|
|
402
|
+
*/
|
|
403
|
+
async disconnect() {
|
|
404
|
+
if (this.process) {
|
|
405
|
+
// Send graceful shutdown signal
|
|
406
|
+
this.process.kill('SIGTERM');
|
|
407
|
+
// Wait for process to exit or force kill after timeout
|
|
408
|
+
await new Promise((resolve) => {
|
|
409
|
+
const timeout = setTimeout(() => {
|
|
410
|
+
this.process?.kill('SIGKILL');
|
|
411
|
+
resolve();
|
|
412
|
+
}, TIMEOUTS.SHUTDOWN_KILL);
|
|
413
|
+
this.process?.once('exit', () => {
|
|
414
|
+
clearTimeout(timeout);
|
|
415
|
+
resolve();
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
this.cleanup();
|
|
420
|
+
}
|
|
421
|
+
sendRequest(method, params) {
|
|
422
|
+
return new Promise((resolve, reject) => {
|
|
423
|
+
if (!this.transport) {
|
|
424
|
+
reject(new Error('Not connected to server'));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const id = ++this.requestId;
|
|
428
|
+
const request = {
|
|
429
|
+
jsonrpc: MCP.JSONRPC_VERSION,
|
|
430
|
+
id,
|
|
431
|
+
method,
|
|
432
|
+
params,
|
|
433
|
+
};
|
|
434
|
+
const timer = setTimeout(() => {
|
|
435
|
+
this.pendingRequests.delete(id);
|
|
436
|
+
reject(new Error(`Request timeout: ${method}`));
|
|
437
|
+
}, this.timeout);
|
|
438
|
+
this.pendingRequests.set(id, {
|
|
439
|
+
resolve: resolve,
|
|
440
|
+
reject,
|
|
441
|
+
timer,
|
|
442
|
+
});
|
|
443
|
+
this.log('Sending:', JSON.stringify(request));
|
|
444
|
+
this.transport.send(request);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
sendNotification(method, params) {
|
|
448
|
+
if (!this.transport)
|
|
449
|
+
return;
|
|
450
|
+
this.transport.send({
|
|
451
|
+
jsonrpc: MCP.JSONRPC_VERSION,
|
|
452
|
+
method,
|
|
453
|
+
params,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
handleMessage(msg) {
|
|
457
|
+
// Ignore messages during cleanup to prevent race conditions
|
|
458
|
+
// This avoids double-rejecting promises or accessing cleared timers
|
|
459
|
+
if (this.cleaningUp) {
|
|
460
|
+
this.log('Ignoring message during cleanup:', JSON.stringify(msg));
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
// Check if it's a response to a pending request
|
|
464
|
+
if ('id' in msg && msg.id !== undefined) {
|
|
465
|
+
const pending = this.pendingRequests.get(msg.id);
|
|
466
|
+
if (pending) {
|
|
467
|
+
clearTimeout(pending.timer);
|
|
468
|
+
this.pendingRequests.delete(msg.id);
|
|
469
|
+
const response = msg;
|
|
470
|
+
if (response.error) {
|
|
471
|
+
pending.reject(new Error(`${response.error.message} (code: ${response.error.code})`));
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
pending.resolve(response.result);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// Notifications from server are logged but not processed
|
|
479
|
+
}
|
|
480
|
+
cleanup() {
|
|
481
|
+
if (this.cleaningUp) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
// Set cleanup flag to prevent race conditions with handleMessage
|
|
485
|
+
// Any messages arriving after this point will be ignored
|
|
486
|
+
this.cleaningUp = true;
|
|
487
|
+
// Clear all pending requests with appropriate error
|
|
488
|
+
this.clearPendingRequests('Connection closed');
|
|
489
|
+
this.transport?.close();
|
|
490
|
+
this.transport = null;
|
|
491
|
+
this.process = null;
|
|
492
|
+
this.serverCapabilities = null;
|
|
493
|
+
this.serverReady = false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=mcp-client.js.map
|