@google/gemini-cli-core 0.31.0-preview.2 → 0.32.0-preview.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/dist/docs/changelogs/index.md +22 -0
- package/dist/docs/changelogs/latest.md +307 -352
- package/dist/docs/changelogs/preview.md +391 -293
- package/dist/docs/cli/plan-mode.md +29 -7
- package/dist/docs/cli/settings.md +15 -6
- package/dist/docs/cli/telemetry.md +39 -11
- package/dist/docs/extensions/reference.md +36 -0
- package/dist/docs/get-started/installation.md +1 -1
- package/dist/docs/local-development.md +49 -43
- package/dist/docs/reference/configuration.md +32 -0
- package/dist/docs/reference/keyboard-shortcuts.md +6 -6
- package/dist/docs/reference/policy-engine.md +4 -3
- package/dist/docs/resources/faq.md +13 -0
- package/dist/docs/resources/tos-privacy.md +6 -0
- package/dist/docs/resources/uninstall.md +1 -10
- package/dist/docs/tools/mcp-server.md +22 -0
- package/dist/src/agents/a2a-client-manager.d.ts +7 -6
- package/dist/src/agents/a2a-client-manager.js +8 -9
- package/dist/src/agents/a2a-client-manager.js.map +1 -1
- package/dist/src/agents/a2a-client-manager.test.js +45 -31
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -1
- package/dist/src/agents/a2aUtils.d.ts +25 -7
- package/dist/src/agents/a2aUtils.js +165 -58
- package/dist/src/agents/a2aUtils.js.map +1 -1
- package/dist/src/agents/a2aUtils.test.js +170 -27
- package/dist/src/agents/a2aUtils.test.js.map +1 -1
- package/dist/src/agents/generalist-agent.js +1 -2
- package/dist/src/agents/generalist-agent.js.map +1 -1
- package/dist/src/agents/registry.test.js +4 -2
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/remote-invocation.d.ts +2 -1
- package/dist/src/agents/remote-invocation.js +41 -22
- package/dist/src/agents/remote-invocation.js.map +1 -1
- package/dist/src/agents/remote-invocation.test.js +196 -56
- package/dist/src/agents/remote-invocation.test.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.js +1 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js +1 -1
- package/dist/src/agents/subagent-tool.js +15 -2
- package/dist/src/agents/subagent-tool.js.map +1 -1
- package/dist/src/agents/subagent-tool.test.js +31 -0
- package/dist/src/agents/subagent-tool.test.js.map +1 -1
- package/dist/src/billing/billing.d.ts +80 -0
- package/dist/src/billing/billing.js +127 -0
- package/dist/src/billing/billing.js.map +1 -0
- package/dist/src/billing/billing.test.d.ts +6 -0
- package/dist/src/billing/billing.test.js +182 -0
- package/dist/src/billing/billing.test.js.map +1 -0
- package/dist/src/billing/index.d.ts +6 -0
- package/dist/src/billing/index.js +7 -0
- package/dist/src/billing/index.js.map +1 -0
- package/dist/src/code_assist/codeAssist.js +1 -1
- package/dist/src/code_assist/codeAssist.js.map +1 -1
- package/dist/src/code_assist/codeAssist.test.js +2 -2
- package/dist/src/code_assist/codeAssist.test.js.map +1 -1
- package/dist/src/code_assist/converter.d.ts +9 -4
- package/dist/src/code_assist/converter.js +17 -2
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/converter.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +6 -3
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +1 -0
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +9 -4
- package/dist/src/code_assist/server.js +86 -5
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +11 -0
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/setup.d.ts +2 -1
- package/dist/src/code_assist/setup.js +15 -4
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +33 -10
- package/dist/src/code_assist/types.js.map +1 -1
- package/dist/src/config/config.d.ts +50 -4
- package/dist/src/config/config.js +77 -3
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +151 -1
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +1 -0
- package/dist/src/config/storage.js +4 -1
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +3 -2
- package/dist/src/core/contentGenerator.js +9 -2
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolScheduler.js +2 -1
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +21 -2
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/fakeContentGenerator.d.ts +2 -1
- package/dist/src/core/fakeContentGenerator.js +1 -0
- package/dist/src/core/fakeContentGenerator.js.map +1 -1
- package/dist/src/core/geminiChat.js +6 -2
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +34 -0
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/localLiteRtLmClient.d.ts +24 -0
- package/dist/src/core/localLiteRtLmClient.js +77 -0
- package/dist/src/core/localLiteRtLmClient.js.map +1 -0
- package/dist/src/core/localLiteRtLmClient.test.d.ts +6 -0
- package/dist/src/core/localLiteRtLmClient.test.js +87 -0
- package/dist/src/core/localLiteRtLmClient.test.js.map +1 -0
- package/dist/src/core/loggingContentGenerator.d.ts +2 -1
- package/dist/src/core/loggingContentGenerator.js +39 -17
- package/dist/src/core/loggingContentGenerator.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.test.js +122 -5
- package/dist/src/core/loggingContentGenerator.test.js.map +1 -1
- package/dist/src/core/prompts.test.js +1 -1
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/fallback/handler.js +2 -0
- package/dist/src/fallback/handler.js.map +1 -1
- package/dist/src/fallback/types.d.ts +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/policy/config.d.ts +18 -6
- package/dist/src/policy/config.js +51 -14
- package/dist/src/policy/config.js.map +1 -1
- package/dist/src/policy/config.test.js +26 -26
- package/dist/src/policy/config.test.js.map +1 -1
- package/dist/src/policy/persistence.test.js +9 -14
- package/dist/src/policy/persistence.test.js.map +1 -1
- package/dist/src/policy/policies/plan.toml +1 -1
- package/dist/src/policy/policy-engine.d.ts +8 -0
- package/dist/src/policy/policy-engine.js +12 -0
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +93 -0
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/policy-updater.test.js +1 -1
- package/dist/src/policy/policy-updater.test.js.map +1 -1
- package/dist/src/policy/toml-loader.d.ts +1 -1
- package/dist/src/policy/toml-loader.js +4 -2
- package/dist/src/policy/toml-loader.js.map +1 -1
- package/dist/src/policy/toml-loader.test.js +15 -12
- package/dist/src/policy/toml-loader.test.js.map +1 -1
- package/dist/src/policy/workspace-policy.test.js +10 -10
- package/dist/src/prompts/snippets.js +43 -27
- package/dist/src/prompts/snippets.js.map +1 -1
- package/dist/src/routing/modelRouterService.js +19 -11
- package/dist/src/routing/modelRouterService.js.map +1 -1
- package/dist/src/routing/modelRouterService.test.js +38 -1
- package/dist/src/routing/modelRouterService.test.js.map +1 -1
- package/dist/src/routing/routingStrategy.d.ts +3 -2
- package/dist/src/routing/strategies/classifierStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/classifierStrategy.js +1 -1
- package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/classifierStrategy.test.js +15 -13
- package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/compositeStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/compositeStrategy.js +3 -3
- package/dist/src/routing/strategies/compositeStrategy.js.map +1 -1
- package/dist/src/routing/strategies/compositeStrategy.test.js +10 -8
- package/dist/src/routing/strategies/compositeStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/defaultStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/defaultStrategy.js +1 -1
- package/dist/src/routing/strategies/defaultStrategy.js.map +1 -1
- package/dist/src/routing/strategies/defaultStrategy.test.js +8 -4
- package/dist/src/routing/strategies/defaultStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.test.js +6 -5
- package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/gemmaClassifierStrategy.d.ts +14 -0
- package/dist/src/routing/strategies/gemmaClassifierStrategy.js +182 -0
- package/dist/src/routing/strategies/gemmaClassifierStrategy.js.map +1 -0
- package/dist/src/routing/strategies/gemmaClassifierStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/gemmaClassifierStrategy.test.js +218 -0
- package/dist/src/routing/strategies/gemmaClassifierStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js +24 -22
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.d.ts +2 -1
- package/dist/src/routing/strategies/overrideStrategy.js +1 -1
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.test.js +5 -4
- package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -1
- package/dist/src/scheduler/scheduler.d.ts +1 -0
- package/dist/src/scheduler/scheduler.js +18 -7
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/scheduler/scheduler.test.js +19 -1
- package/dist/src/scheduler/scheduler.test.js.map +1 -1
- package/dist/src/scheduler/scheduler_parallel.test.js +94 -3
- package/dist/src/scheduler/scheduler_parallel.test.js.map +1 -1
- package/dist/src/scheduler/tool-executor.js +21 -12
- package/dist/src/scheduler/tool-executor.js.map +1 -1
- package/dist/src/scheduler/tool-executor.test.js +54 -0
- package/dist/src/scheduler/tool-executor.test.js.map +1 -1
- package/dist/src/services/trackerService.d.ts +49 -0
- package/dist/src/services/trackerService.js +172 -0
- package/dist/src/services/trackerService.js.map +1 -0
- package/dist/src/services/trackerService.test.d.ts +6 -0
- package/dist/src/services/trackerService.test.js +117 -0
- package/dist/src/services/trackerService.test.js.map +1 -0
- package/dist/src/services/trackerTypes.d.ts +51 -0
- package/dist/src/services/trackerTypes.js +33 -0
- package/dist/src/services/trackerTypes.js.map +1 -0
- package/dist/src/telemetry/billingEvents.d.ts +75 -0
- package/dist/src/telemetry/billingEvents.js +181 -0
- package/dist/src/telemetry/billingEvents.js.map +1 -0
- package/dist/src/telemetry/billingEvents.test.d.ts +6 -0
- package/dist/src/telemetry/billingEvents.test.js +139 -0
- package/dist/src/telemetry/billingEvents.test.js.map +1 -0
- package/dist/src/telemetry/conseca-logger.test.js +1 -0
- package/dist/src/telemetry/conseca-logger.test.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +25 -0
- package/dist/src/telemetry/constants.js +29 -0
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +3 -1
- package/dist/src/telemetry/index.js +5 -1
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -0
- package/dist/src/telemetry/loggers.js +10 -0
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +16 -0
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +28 -0
- package/dist/src/telemetry/metrics.js +40 -0
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/sanitize.test.js +1 -0
- package/dist/src/telemetry/sanitize.test.js.map +1 -1
- package/dist/src/telemetry/sdk.test.js +1 -0
- package/dist/src/telemetry/sdk.test.js.map +1 -1
- package/dist/src/telemetry/telemetryAttributes.js +2 -0
- package/dist/src/telemetry/telemetryAttributes.js.map +1 -1
- package/dist/src/telemetry/trace.d.ts +2 -1
- package/dist/src/telemetry/trace.js +13 -18
- package/dist/src/telemetry/trace.js.map +1 -1
- package/dist/src/telemetry/trace.test.d.ts +6 -0
- package/dist/src/telemetry/trace.test.js +116 -0
- package/dist/src/telemetry/trace.test.js.map +1 -0
- package/dist/src/tools/confirmation-policy.test.js +1 -0
- package/dist/src/tools/confirmation-policy.test.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js +2 -2
- package/dist/src/tools/definitions/model-family-sets/default-legacy.js.map +1 -1
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js +3 -3
- package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
- package/dist/src/tools/grep-utils.d.ts +1 -1
- package/dist/src/tools/grep-utils.js +4 -4
- package/dist/src/tools/grep-utils.js.map +1 -1
- package/dist/src/tools/grep.d.ts +1 -1
- package/dist/src/tools/grep.js +9 -9
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +8 -5
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/line-endings.test.js +3 -11
- package/dist/src/tools/line-endings.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.d.ts +25 -0
- package/dist/src/tools/mcp-client-manager.js +66 -3
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +47 -0
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +20 -9
- package/dist/src/tools/mcp-client.js +50 -46
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +96 -84
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +3 -3
- package/dist/src/tools/mcp-tool.js +1 -0
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/ripGrep.d.ts +1 -1
- package/dist/src/tools/ripGrep.js +7 -7
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +10 -7
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +1 -0
- package/dist/src/tools/tools.js +1 -0
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/write-file.js +4 -17
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +29 -83
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/editCorrector.d.ts +1 -42
- package/dist/src/utils/editCorrector.js +9 -461
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editCorrector.test.js +17 -421
- package/dist/src/utils/editCorrector.test.js.map +1 -1
- package/dist/src/utils/envExpansion.js.map +1 -1
- package/dist/src/utils/errors.js +7 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/errors_timeout.test.d.ts +6 -0
- package/dist/src/utils/errors_timeout.test.js +40 -0
- package/dist/src/utils/errors_timeout.test.js.map +1 -0
- package/dist/src/utils/extensionLoader.js +35 -0
- package/dist/src/utils/extensionLoader.js.map +1 -1
- package/dist/src/utils/extensionLoader.test.js +36 -0
- package/dist/src/utils/extensionLoader.test.js.map +1 -1
- package/dist/src/utils/fetch.js +13 -2
- package/dist/src/utils/fetch.js.map +1 -1
- package/dist/src/utils/fileUtils.js +0 -1
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +0 -1
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/flashFallback.test.js +24 -0
- package/dist/src/utils/flashFallback.test.js.map +1 -1
- package/dist/src/utils/googleErrors.d.ts +2 -2
- package/dist/src/utils/googleQuotaErrors.d.ts +3 -1
- package/dist/src/utils/googleQuotaErrors.js +22 -12
- package/dist/src/utils/googleQuotaErrors.js.map +1 -1
- package/dist/src/utils/googleQuotaErrors.test.js +33 -1
- package/dist/src/utils/googleQuotaErrors.test.js.map +1 -1
- package/dist/src/utils/retry.js +4 -2
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +20 -0
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/schemaValidator.js +0 -1
- package/dist/src/utils/schemaValidator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.31.0-preview.1.tgz +0 -0
|
@@ -25,6 +25,13 @@ const EMPTY_CONFIG = {
|
|
|
25
25
|
allowedEnvironmentVariables: [],
|
|
26
26
|
blockedEnvironmentVariables: [],
|
|
27
27
|
};
|
|
28
|
+
const MOCK_CONTEXT_DEFAULT = {
|
|
29
|
+
sanitizationConfig: EMPTY_CONFIG,
|
|
30
|
+
emitMcpDiagnostic: vi.fn(),
|
|
31
|
+
setUserInteractedWithMcp: vi.fn(),
|
|
32
|
+
isTrustedFolder: vi.fn().mockReturnValue(true),
|
|
33
|
+
};
|
|
34
|
+
let MOCK_CONTEXT = MOCK_CONTEXT_DEFAULT;
|
|
28
35
|
vi.mock('@modelcontextprotocol/sdk/client/stdio.js');
|
|
29
36
|
vi.mock('@modelcontextprotocol/sdk/client/index.js');
|
|
30
37
|
vi.mock('@google/genai');
|
|
@@ -43,6 +50,12 @@ describe('mcp-client', () => {
|
|
|
43
50
|
let workspaceContext;
|
|
44
51
|
let testWorkspace;
|
|
45
52
|
beforeEach(() => {
|
|
53
|
+
MOCK_CONTEXT = {
|
|
54
|
+
sanitizationConfig: EMPTY_CONFIG,
|
|
55
|
+
emitMcpDiagnostic: vi.fn(),
|
|
56
|
+
setUserInteractedWithMcp: vi.fn(),
|
|
57
|
+
isTrustedFolder: vi.fn().mockReturnValue(true),
|
|
58
|
+
};
|
|
46
59
|
// create a tmp dir for this test
|
|
47
60
|
// Create a unique temporary directory for the workspace to avoid conflicts
|
|
48
61
|
testWorkspace = fs.mkdtempSync(path.join(os.tmpdir(), 'gemini-agent-test-'));
|
|
@@ -95,9 +108,9 @@ describe('mcp-client', () => {
|
|
|
95
108
|
};
|
|
96
109
|
const client = new McpClient('test-server', {
|
|
97
110
|
command: 'test-command',
|
|
98
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
111
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
99
112
|
await client.connect();
|
|
100
|
-
await client.discover(
|
|
113
|
+
await client.discover(MOCK_CONTEXT);
|
|
101
114
|
expect(mockedClient.listTools).toHaveBeenCalledWith({}, expect.objectContaining({ timeout: 600000, progressReporter: client }));
|
|
102
115
|
});
|
|
103
116
|
it('should not skip tools even if a parameter is missing a type', async () => {
|
|
@@ -157,9 +170,9 @@ describe('mcp-client', () => {
|
|
|
157
170
|
};
|
|
158
171
|
const client = new McpClient('test-server', {
|
|
159
172
|
command: 'test-command',
|
|
160
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
173
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
161
174
|
await client.connect();
|
|
162
|
-
await client.discover(
|
|
175
|
+
await client.discover(MOCK_CONTEXT);
|
|
163
176
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledTimes(2);
|
|
164
177
|
expect(consoleWarnSpy).not.toHaveBeenCalled();
|
|
165
178
|
consoleWarnSpy.mockRestore();
|
|
@@ -194,10 +207,10 @@ describe('mcp-client', () => {
|
|
|
194
207
|
};
|
|
195
208
|
const client = new McpClient('test-server', {
|
|
196
209
|
command: 'test-command',
|
|
197
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
210
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
198
211
|
await client.connect();
|
|
199
|
-
await expect(client.discover(
|
|
200
|
-
expect(
|
|
212
|
+
await expect(client.discover(MOCK_CONTEXT)).rejects.toThrow('Test error');
|
|
213
|
+
expect(MOCK_CONTEXT.emitMcpDiagnostic).toHaveBeenCalledWith('error', `Error discovering prompts from test-server: Test error`, expect.any(Error), 'test-server');
|
|
201
214
|
});
|
|
202
215
|
it('should not discover tools if server does not support them', async () => {
|
|
203
216
|
const mockedClient = {
|
|
@@ -229,9 +242,9 @@ describe('mcp-client', () => {
|
|
|
229
242
|
};
|
|
230
243
|
const client = new McpClient('test-server', {
|
|
231
244
|
command: 'test-command',
|
|
232
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
245
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
233
246
|
await client.connect();
|
|
234
|
-
await expect(client.discover(
|
|
247
|
+
await expect(client.discover(MOCK_CONTEXT)).rejects.toThrow('No prompts, tools, or resources found on the server.');
|
|
235
248
|
});
|
|
236
249
|
it('should discover tools if server supports them', async () => {
|
|
237
250
|
const mockedClient = {
|
|
@@ -272,9 +285,9 @@ describe('mcp-client', () => {
|
|
|
272
285
|
};
|
|
273
286
|
const client = new McpClient('test-server', {
|
|
274
287
|
command: 'test-command',
|
|
275
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
288
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
276
289
|
await client.connect();
|
|
277
|
-
await client.discover(
|
|
290
|
+
await client.discover(MOCK_CONTEXT);
|
|
278
291
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
|
279
292
|
});
|
|
280
293
|
it('should register tool with readOnlyHint and preserve annotations', async () => {
|
|
@@ -322,7 +335,7 @@ describe('mcp-client', () => {
|
|
|
322
335
|
setResourcesForServer: vi.fn(),
|
|
323
336
|
removeResourcesByServer: vi.fn(),
|
|
324
337
|
};
|
|
325
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
338
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
326
339
|
await client.connect();
|
|
327
340
|
await client.discover(mockConfig);
|
|
328
341
|
// Verify tool registration
|
|
@@ -379,7 +392,7 @@ describe('mcp-client', () => {
|
|
|
379
392
|
setResourcesForServer: vi.fn(),
|
|
380
393
|
removeResourcesByServer: vi.fn(),
|
|
381
394
|
};
|
|
382
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
395
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
383
396
|
await client.connect();
|
|
384
397
|
await client.discover(mockConfig);
|
|
385
398
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
|
@@ -434,7 +447,7 @@ describe('mcp-client', () => {
|
|
|
434
447
|
setResourcesForServer: vi.fn(),
|
|
435
448
|
removeResourcesByServer: vi.fn(),
|
|
436
449
|
};
|
|
437
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
450
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
438
451
|
await client.connect();
|
|
439
452
|
await client.discover(mockConfig);
|
|
440
453
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
|
@@ -500,9 +513,9 @@ describe('mcp-client', () => {
|
|
|
500
513
|
};
|
|
501
514
|
const client = new McpClient('test-server', {
|
|
502
515
|
command: 'test-command',
|
|
503
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
516
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
504
517
|
await client.connect();
|
|
505
|
-
await client.discover(
|
|
518
|
+
await client.discover(MOCK_CONTEXT);
|
|
506
519
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
|
507
520
|
const registeredTool = vi.mocked(mockedToolRegistry.registerTool).mock
|
|
508
521
|
.calls[0][0];
|
|
@@ -564,9 +577,9 @@ describe('mcp-client', () => {
|
|
|
564
577
|
};
|
|
565
578
|
const client = new McpClient('test-server', {
|
|
566
579
|
command: 'test-command',
|
|
567
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
580
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
568
581
|
await client.connect();
|
|
569
|
-
await client.discover(
|
|
582
|
+
await client.discover(MOCK_CONTEXT);
|
|
570
583
|
expect(resourceRegistry.setResourcesForServer).toHaveBeenCalledWith('test-server', [
|
|
571
584
|
expect.objectContaining({
|
|
572
585
|
uri: 'file:///tmp/resource.txt',
|
|
@@ -632,16 +645,16 @@ describe('mcp-client', () => {
|
|
|
632
645
|
};
|
|
633
646
|
const client = new McpClient('test-server', {
|
|
634
647
|
command: 'test-command',
|
|
635
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
648
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
636
649
|
await client.connect();
|
|
637
|
-
await client.discover(
|
|
650
|
+
await client.discover(MOCK_CONTEXT);
|
|
638
651
|
expect(mockedClient.setNotificationHandler).toHaveBeenCalledTimes(2);
|
|
639
652
|
expect(resourceListHandler).toBeDefined();
|
|
640
653
|
await resourceListHandler?.({
|
|
641
654
|
method: 'notifications/resources/list_changed',
|
|
642
655
|
});
|
|
643
656
|
expect(resourceRegistry.setResourcesForServer).toHaveBeenLastCalledWith('test-server', [expect.objectContaining({ uri: 'file:///tmp/two.txt' })]);
|
|
644
|
-
expect(
|
|
657
|
+
expect(MOCK_CONTEXT.emitMcpDiagnostic).toHaveBeenCalledWith('info', 'Resources updated for server: test-server', undefined, 'test-server');
|
|
645
658
|
});
|
|
646
659
|
it('refreshes prompts when prompt list change notification is received', async () => {
|
|
647
660
|
let listCallCount = 0;
|
|
@@ -691,9 +704,9 @@ describe('mcp-client', () => {
|
|
|
691
704
|
};
|
|
692
705
|
const client = new McpClient('test-server', {
|
|
693
706
|
command: 'test-command',
|
|
694
|
-
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext,
|
|
707
|
+
}, mockedToolRegistry, promptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
695
708
|
await client.connect();
|
|
696
|
-
await client.discover(
|
|
709
|
+
await client.discover(MOCK_CONTEXT);
|
|
697
710
|
expect(mockedClient.setNotificationHandler).toHaveBeenCalledTimes(2);
|
|
698
711
|
expect(promptListHandler).toBeDefined();
|
|
699
712
|
await promptListHandler?.({
|
|
@@ -701,7 +714,7 @@ describe('mcp-client', () => {
|
|
|
701
714
|
});
|
|
702
715
|
expect(promptRegistry.removePromptsByServer).toHaveBeenCalledWith('test-server');
|
|
703
716
|
expect(promptRegistry.registerPrompt).toHaveBeenLastCalledWith(expect.objectContaining({ name: 'two' }));
|
|
704
|
-
expect(
|
|
717
|
+
expect(MOCK_CONTEXT.emitMcpDiagnostic).toHaveBeenCalledWith('info', 'Prompts updated for server: test-server', undefined, 'test-server');
|
|
705
718
|
});
|
|
706
719
|
it('should remove tools and prompts on disconnect', async () => {
|
|
707
720
|
const mockedClient = {
|
|
@@ -748,9 +761,9 @@ describe('mcp-client', () => {
|
|
|
748
761
|
};
|
|
749
762
|
const client = new McpClient('test-server', {
|
|
750
763
|
command: 'test-command',
|
|
751
|
-
}, mockedToolRegistry, mockedPromptRegistry, resourceRegistry, workspaceContext,
|
|
764
|
+
}, mockedToolRegistry, mockedPromptRegistry, resourceRegistry, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
752
765
|
await client.connect();
|
|
753
|
-
await client.discover(
|
|
766
|
+
await client.discover(MOCK_CONTEXT);
|
|
754
767
|
expect(mockedToolRegistry.registerTool).toHaveBeenCalledOnce();
|
|
755
768
|
expect(mockedPromptRegistry.registerPrompt).toHaveBeenCalledOnce();
|
|
756
769
|
await client.disconnect();
|
|
@@ -778,7 +791,7 @@ describe('mcp-client', () => {
|
|
|
778
791
|
};
|
|
779
792
|
vi.mocked(ClientLib.Client).mockReturnValue(mockedClient);
|
|
780
793
|
vi.spyOn(SdkClientStdioLib, 'StdioClientTransport').mockReturnValue({});
|
|
781
|
-
const client = new McpClient('test-server', { command: 'test-command' }, {}, {}, {}, workspaceContext,
|
|
794
|
+
const client = new McpClient('test-server', { command: 'test-command' }, {}, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
782
795
|
await client.connect();
|
|
783
796
|
expect(mockedClient.setNotificationHandler).toHaveBeenCalledWith(ToolListChangedNotificationSchema, expect.any(Function));
|
|
784
797
|
});
|
|
@@ -793,7 +806,7 @@ describe('mcp-client', () => {
|
|
|
793
806
|
};
|
|
794
807
|
vi.mocked(ClientLib.Client).mockReturnValue(mockedClient);
|
|
795
808
|
vi.spyOn(SdkClientStdioLib, 'StdioClientTransport').mockReturnValue({});
|
|
796
|
-
const client = new McpClient('test-server', { command: 'test-command' }, {}, {}, {}, workspaceContext,
|
|
809
|
+
const client = new McpClient('test-server', { command: 'test-command' }, {}, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
797
810
|
await client.connect();
|
|
798
811
|
expect(mockedClient.setNotificationHandler).toHaveBeenCalledOnce();
|
|
799
812
|
});
|
|
@@ -828,7 +841,7 @@ describe('mcp-client', () => {
|
|
|
828
841
|
};
|
|
829
842
|
const onToolsUpdatedSpy = vi.fn().mockResolvedValue(undefined);
|
|
830
843
|
// Initialize client with onToolsUpdated callback
|
|
831
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
844
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1', onToolsUpdatedSpy);
|
|
832
845
|
// 1. Connect (sets up listener)
|
|
833
846
|
await client.connect();
|
|
834
847
|
// 2. Extract the callback passed to setNotificationHandler
|
|
@@ -845,7 +858,7 @@ describe('mcp-client', () => {
|
|
|
845
858
|
// It should notify the manager
|
|
846
859
|
expect(onToolsUpdatedSpy).toHaveBeenCalled();
|
|
847
860
|
// It should emit feedback event
|
|
848
|
-
expect(
|
|
861
|
+
expect(MOCK_CONTEXT.emitMcpDiagnostic).toHaveBeenCalledWith('info', 'Tools updated for server: test-server', undefined, 'test-server');
|
|
849
862
|
});
|
|
850
863
|
it('should handle errors during tool refresh gracefully', async () => {
|
|
851
864
|
const mockedClient = {
|
|
@@ -866,7 +879,7 @@ describe('mcp-client', () => {
|
|
|
866
879
|
removeMcpToolsByServer: vi.fn(),
|
|
867
880
|
getMessageBus: vi.fn().mockReturnValue(undefined),
|
|
868
881
|
};
|
|
869
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
882
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
870
883
|
await client.connect();
|
|
871
884
|
const notificationCallback = mockedClient.setNotificationHandler.mock.calls[0][1];
|
|
872
885
|
// Trigger notification - should fail internally but catch the error
|
|
@@ -909,8 +922,8 @@ describe('mcp-client', () => {
|
|
|
909
922
|
getMessageBus: vi.fn().mockReturnValue(undefined),
|
|
910
923
|
};
|
|
911
924
|
const onToolsUpdatedSpy = vi.fn().mockResolvedValue(undefined);
|
|
912
|
-
const clientA = new McpClient('server-A', { command: 'cmd-a' }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
913
|
-
const clientB = new McpClient('server-B', { command: 'cmd-b' }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
925
|
+
const clientA = new McpClient('server-A', { command: 'cmd-a' }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1', onToolsUpdatedSpy);
|
|
926
|
+
const clientB = new McpClient('server-B', { command: 'cmd-b' }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1', onToolsUpdatedSpy);
|
|
914
927
|
await clientA.connect();
|
|
915
928
|
await clientB.connect();
|
|
916
929
|
const handlerA = mockClientA.setNotificationHandler.mock.calls[0][1];
|
|
@@ -959,7 +972,7 @@ describe('mcp-client', () => {
|
|
|
959
972
|
};
|
|
960
973
|
const client = new McpClient('test-server',
|
|
961
974
|
// Set a short timeout
|
|
962
|
-
{ command: 'test-command', timeout: 100 }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
975
|
+
{ command: 'test-command', timeout: 100 }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1');
|
|
963
976
|
await client.connect();
|
|
964
977
|
const notificationCallback = mockedClient.setNotificationHandler.mock.calls[0][1];
|
|
965
978
|
const refreshPromise = notificationCallback();
|
|
@@ -993,7 +1006,7 @@ describe('mcp-client', () => {
|
|
|
993
1006
|
getMessageBus: vi.fn().mockReturnValue(undefined),
|
|
994
1007
|
};
|
|
995
1008
|
const onToolsUpdatedSpy = vi.fn().mockResolvedValue(undefined);
|
|
996
|
-
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext,
|
|
1009
|
+
const client = new McpClient('test-server', { command: 'test-command' }, mockedToolRegistry, {}, {}, workspaceContext, MOCK_CONTEXT, false, '0.0.1', onToolsUpdatedSpy);
|
|
997
1010
|
await client.connect();
|
|
998
1011
|
const notificationCallback = mockedClient.setNotificationHandler.mock.calls[0][1];
|
|
999
1012
|
await notificationCallback();
|
|
@@ -1027,7 +1040,7 @@ describe('mcp-client', () => {
|
|
|
1027
1040
|
it('without headers', async () => {
|
|
1028
1041
|
const transport = await createTransport('test-server', {
|
|
1029
1042
|
httpUrl: 'http://test-server',
|
|
1030
|
-
}, false,
|
|
1043
|
+
}, false, MOCK_CONTEXT);
|
|
1031
1044
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1032
1045
|
expect(transport).toMatchObject({
|
|
1033
1046
|
_url: new URL('http://test-server'),
|
|
@@ -1038,7 +1051,7 @@ describe('mcp-client', () => {
|
|
|
1038
1051
|
const transport = await createTransport('test-server', {
|
|
1039
1052
|
httpUrl: 'http://test-server',
|
|
1040
1053
|
headers: { Authorization: 'derp' },
|
|
1041
|
-
}, false,
|
|
1054
|
+
}, false, MOCK_CONTEXT);
|
|
1042
1055
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1043
1056
|
expect(transport).toMatchObject({
|
|
1044
1057
|
_url: new URL('http://test-server'),
|
|
@@ -1052,7 +1065,7 @@ describe('mcp-client', () => {
|
|
|
1052
1065
|
it('without headers', async () => {
|
|
1053
1066
|
const transport = await createTransport('test-server', {
|
|
1054
1067
|
url: 'http://test-server',
|
|
1055
|
-
}, false,
|
|
1068
|
+
}, false, MOCK_CONTEXT);
|
|
1056
1069
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1057
1070
|
expect(transport).toMatchObject({
|
|
1058
1071
|
_url: new URL('http://test-server'),
|
|
@@ -1063,7 +1076,7 @@ describe('mcp-client', () => {
|
|
|
1063
1076
|
const transport = await createTransport('test-server', {
|
|
1064
1077
|
url: 'http://test-server',
|
|
1065
1078
|
headers: { Authorization: 'derp' },
|
|
1066
|
-
}, false,
|
|
1079
|
+
}, false, MOCK_CONTEXT);
|
|
1067
1080
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1068
1081
|
expect(transport).toMatchObject({
|
|
1069
1082
|
_url: new URL('http://test-server'),
|
|
@@ -1076,7 +1089,7 @@ describe('mcp-client', () => {
|
|
|
1076
1089
|
const transport = await createTransport('test-server', {
|
|
1077
1090
|
url: 'http://test-server',
|
|
1078
1091
|
type: 'http',
|
|
1079
|
-
}, false,
|
|
1092
|
+
}, false, MOCK_CONTEXT);
|
|
1080
1093
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1081
1094
|
expect(transport).toMatchObject({
|
|
1082
1095
|
_url: new URL('http://test-server'),
|
|
@@ -1087,7 +1100,7 @@ describe('mcp-client', () => {
|
|
|
1087
1100
|
const transport = await createTransport('test-server', {
|
|
1088
1101
|
url: 'http://test-server',
|
|
1089
1102
|
type: 'sse',
|
|
1090
|
-
}, false,
|
|
1103
|
+
}, false, MOCK_CONTEXT);
|
|
1091
1104
|
expect(transport).toBeInstanceOf(SSEClientTransport);
|
|
1092
1105
|
expect(transport).toMatchObject({
|
|
1093
1106
|
_url: new URL('http://test-server'),
|
|
@@ -1097,7 +1110,7 @@ describe('mcp-client', () => {
|
|
|
1097
1110
|
it('without type defaults to StreamableHTTPClientTransport', async () => {
|
|
1098
1111
|
const transport = await createTransport('test-server', {
|
|
1099
1112
|
url: 'http://test-server',
|
|
1100
|
-
}, false,
|
|
1113
|
+
}, false, MOCK_CONTEXT);
|
|
1101
1114
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1102
1115
|
expect(transport).toMatchObject({
|
|
1103
1116
|
_url: new URL('http://test-server'),
|
|
@@ -1109,7 +1122,7 @@ describe('mcp-client', () => {
|
|
|
1109
1122
|
url: 'http://test-server',
|
|
1110
1123
|
type: 'http',
|
|
1111
1124
|
headers: { Authorization: 'Bearer token' },
|
|
1112
|
-
}, false,
|
|
1125
|
+
}, false, MOCK_CONTEXT);
|
|
1113
1126
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1114
1127
|
expect(transport).toMatchObject({
|
|
1115
1128
|
_url: new URL('http://test-server'),
|
|
@@ -1123,7 +1136,7 @@ describe('mcp-client', () => {
|
|
|
1123
1136
|
url: 'http://test-server',
|
|
1124
1137
|
type: 'sse',
|
|
1125
1138
|
headers: { 'X-API-Key': 'key123' },
|
|
1126
|
-
}, false,
|
|
1139
|
+
}, false, MOCK_CONTEXT);
|
|
1127
1140
|
expect(transport).toBeInstanceOf(SSEClientTransport);
|
|
1128
1141
|
expect(transport).toMatchObject({
|
|
1129
1142
|
_url: new URL('http://test-server'),
|
|
@@ -1136,7 +1149,7 @@ describe('mcp-client', () => {
|
|
|
1136
1149
|
const transport = await createTransport('test-server', {
|
|
1137
1150
|
httpUrl: 'http://test-server-http',
|
|
1138
1151
|
url: 'http://test-server-url',
|
|
1139
|
-
}, false,
|
|
1152
|
+
}, false, MOCK_CONTEXT);
|
|
1140
1153
|
// httpUrl should take priority and create HTTP transport
|
|
1141
1154
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1142
1155
|
expect(transport).toMatchObject({
|
|
@@ -1154,7 +1167,7 @@ describe('mcp-client', () => {
|
|
|
1154
1167
|
args: ['--foo', 'bar'],
|
|
1155
1168
|
env: { FOO: 'bar' },
|
|
1156
1169
|
cwd: 'test/cwd',
|
|
1157
|
-
}, false,
|
|
1170
|
+
}, false, MOCK_CONTEXT);
|
|
1158
1171
|
expect(mockedTransport).toHaveBeenCalledWith({
|
|
1159
1172
|
command: 'test-command',
|
|
1160
1173
|
args: ['--foo', 'bar'],
|
|
@@ -1172,7 +1185,7 @@ describe('mcp-client', () => {
|
|
|
1172
1185
|
args: ['--foo', 'bar'],
|
|
1173
1186
|
env: {},
|
|
1174
1187
|
cwd: 'test/cwd',
|
|
1175
|
-
}, false,
|
|
1188
|
+
}, false, MOCK_CONTEXT);
|
|
1176
1189
|
const callArgs = mockedTransport.mock.calls[0][0];
|
|
1177
1190
|
expect(callArgs.env).toBeDefined();
|
|
1178
1191
|
expect(callArgs.env['GEMINI_CLI']).toBe('1');
|
|
@@ -1199,7 +1212,7 @@ describe('mcp-client', () => {
|
|
|
1199
1212
|
contextFiles: [],
|
|
1200
1213
|
id: '',
|
|
1201
1214
|
},
|
|
1202
|
-
}, false,
|
|
1215
|
+
}, false, MOCK_CONTEXT);
|
|
1203
1216
|
const callArgs = mockedTransport.mock.calls[0][0];
|
|
1204
1217
|
expect(callArgs.env).toBeDefined();
|
|
1205
1218
|
expect(callArgs.env['GEMINI_CLI_EXT_VAR']).toBeUndefined();
|
|
@@ -1226,7 +1239,7 @@ describe('mcp-client', () => {
|
|
|
1226
1239
|
contextFiles: [],
|
|
1227
1240
|
id: '',
|
|
1228
1241
|
},
|
|
1229
|
-
}, false,
|
|
1242
|
+
}, false, MOCK_CONTEXT);
|
|
1230
1243
|
const callArgs = mockedTransport.mock.calls[0][0];
|
|
1231
1244
|
expect(callArgs.env).toBeDefined();
|
|
1232
1245
|
expect(callArgs.env['GEMINI_CLI_EXT_VAR']).toBe('defined-value');
|
|
@@ -1256,7 +1269,7 @@ describe('mcp-client', () => {
|
|
|
1256
1269
|
contextFiles: [],
|
|
1257
1270
|
id: '',
|
|
1258
1271
|
},
|
|
1259
|
-
}, false,
|
|
1272
|
+
}, false, MOCK_CONTEXT);
|
|
1260
1273
|
const callArgs = mockedTransport.mock.calls[0][0];
|
|
1261
1274
|
expect(callArgs.env).toBeDefined();
|
|
1262
1275
|
expect(callArgs.env['GEMINI_CLI_EXT_VAR']).toBe('ext-value');
|
|
@@ -1278,7 +1291,7 @@ describe('mcp-client', () => {
|
|
|
1278
1291
|
TEST_EXPANDED: 'Value is $GEMINI_TEST_VAR',
|
|
1279
1292
|
SECRET_KEY: 'intentional-secret-123',
|
|
1280
1293
|
},
|
|
1281
|
-
}, false,
|
|
1294
|
+
}, false, MOCK_CONTEXT);
|
|
1282
1295
|
const callArgs = mockedTransport.mock.calls[0][0];
|
|
1283
1296
|
expect(callArgs.env).toBeDefined();
|
|
1284
1297
|
expect(callArgs.env['TEST_EXPANDED']).toBe('Value is expanded-value');
|
|
@@ -1307,13 +1320,12 @@ describe('mcp-client', () => {
|
|
|
1307
1320
|
headers: {
|
|
1308
1321
|
'X-Goog-User-Project': 'myproject',
|
|
1309
1322
|
},
|
|
1310
|
-
}, false,
|
|
1323
|
+
}, false, MOCK_CONTEXT);
|
|
1311
1324
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1312
|
-
|
|
1313
|
-
const authProvider =
|
|
1325
|
+
const testableTransport = transport;
|
|
1326
|
+
const authProvider = testableTransport._authProvider;
|
|
1314
1327
|
expect(authProvider).toBeInstanceOf(GoogleCredentialProvider);
|
|
1315
|
-
|
|
1316
|
-
const googUserProject = transport._requestInit?.headers?.['X-Goog-User-Project'];
|
|
1328
|
+
const googUserProject = testableTransport._requestInit?.headers?.['X-Goog-User-Project'];
|
|
1317
1329
|
expect(googUserProject).toBe('myproject');
|
|
1318
1330
|
});
|
|
1319
1331
|
it('should use headers from GoogleCredentialProvider', async () => {
|
|
@@ -1327,12 +1339,12 @@ describe('mcp-client', () => {
|
|
|
1327
1339
|
oauth: {
|
|
1328
1340
|
scopes: ['scope1'],
|
|
1329
1341
|
},
|
|
1330
|
-
}, false,
|
|
1342
|
+
}, false, MOCK_CONTEXT);
|
|
1331
1343
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1332
1344
|
expect(mockGetRequestHeaders).toHaveBeenCalled();
|
|
1333
|
-
|
|
1334
|
-
const headers =
|
|
1335
|
-
expect(headers['X-Goog-User-Project']).toBe('provider-project');
|
|
1345
|
+
const testableTransport = transport;
|
|
1346
|
+
const headers = testableTransport._requestInit?.headers;
|
|
1347
|
+
expect(headers?.['X-Goog-User-Project']).toBe('provider-project');
|
|
1336
1348
|
});
|
|
1337
1349
|
it('should prioritize provider headers over config headers', async () => {
|
|
1338
1350
|
const mockGetRequestHeaders = vi.fn().mockResolvedValue({
|
|
@@ -1348,11 +1360,11 @@ describe('mcp-client', () => {
|
|
|
1348
1360
|
headers: {
|
|
1349
1361
|
'X-Goog-User-Project': 'config-project',
|
|
1350
1362
|
},
|
|
1351
|
-
}, false,
|
|
1363
|
+
}, false, MOCK_CONTEXT);
|
|
1352
1364
|
expect(transport).toBeInstanceOf(StreamableHTTPClientTransport);
|
|
1353
|
-
|
|
1354
|
-
const headers =
|
|
1355
|
-
expect(headers['X-Goog-User-Project']).toBe('provider-project');
|
|
1365
|
+
const testableTransport = transport;
|
|
1366
|
+
const headers = testableTransport._requestInit?.headers;
|
|
1367
|
+
expect(headers?.['X-Goog-User-Project']).toBe('provider-project');
|
|
1356
1368
|
});
|
|
1357
1369
|
it('should use GoogleCredentialProvider with SSE transport', async () => {
|
|
1358
1370
|
const transport = await createTransport('test-server', {
|
|
@@ -1362,10 +1374,10 @@ describe('mcp-client', () => {
|
|
|
1362
1374
|
oauth: {
|
|
1363
1375
|
scopes: ['scope1'],
|
|
1364
1376
|
},
|
|
1365
|
-
}, false,
|
|
1377
|
+
}, false, MOCK_CONTEXT);
|
|
1366
1378
|
expect(transport).toBeInstanceOf(SSEClientTransport);
|
|
1367
|
-
|
|
1368
|
-
const authProvider =
|
|
1379
|
+
const testableTransport = transport;
|
|
1380
|
+
const authProvider = testableTransport._authProvider;
|
|
1369
1381
|
expect(authProvider).toBeInstanceOf(GoogleCredentialProvider);
|
|
1370
1382
|
});
|
|
1371
1383
|
it('should throw an error if no URL is provided with GoogleCredentialProvider', async () => {
|
|
@@ -1374,7 +1386,7 @@ describe('mcp-client', () => {
|
|
|
1374
1386
|
oauth: {
|
|
1375
1387
|
scopes: ['scope1'],
|
|
1376
1388
|
},
|
|
1377
|
-
}, false,
|
|
1389
|
+
}, false, MOCK_CONTEXT)).rejects.toThrow('URL must be provided in the config for Google Credentials provider');
|
|
1378
1390
|
});
|
|
1379
1391
|
});
|
|
1380
1392
|
});
|
|
@@ -1486,18 +1498,18 @@ describe('connectToMcpServer with OAuth', () => {
|
|
|
1486
1498
|
tokenUrl,
|
|
1487
1499
|
scopes: ['test-scope'],
|
|
1488
1500
|
});
|
|
1489
|
-
// We need this to be
|
|
1490
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1501
|
+
// We need this to be typed to dig into its private state.
|
|
1491
1502
|
let capturedTransport;
|
|
1492
1503
|
vi.mocked(mockedClient.connect).mockImplementationOnce(async (transport) => {
|
|
1493
1504
|
capturedTransport = transport;
|
|
1494
1505
|
return Promise.resolve();
|
|
1495
1506
|
});
|
|
1496
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext,
|
|
1507
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext, MOCK_CONTEXT);
|
|
1497
1508
|
expect(client).toBe(mockedClient);
|
|
1498
1509
|
expect(mockedClient.connect).toHaveBeenCalledTimes(2);
|
|
1499
1510
|
expect(mockAuthProvider.authenticate).toHaveBeenCalledOnce();
|
|
1500
|
-
const authHeader = capturedTransport._requestInit
|
|
1511
|
+
const authHeader = capturedTransport._requestInit
|
|
1512
|
+
?.headers?.['Authorization'];
|
|
1501
1513
|
expect(authHeader).toBe('Bearer test-access-token');
|
|
1502
1514
|
});
|
|
1503
1515
|
it('should discover oauth config if not in www-authenticate header', async () => {
|
|
@@ -1511,19 +1523,19 @@ describe('connectToMcpServer with OAuth', () => {
|
|
|
1511
1523
|
scopes: ['test-scope'],
|
|
1512
1524
|
});
|
|
1513
1525
|
vi.mocked(mockAuthProvider.getValidToken).mockResolvedValue('test-access-token-from-discovery');
|
|
1514
|
-
// We need this to be
|
|
1515
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1526
|
+
// We need this to be typed to dig into its private state.
|
|
1516
1527
|
let capturedTransport;
|
|
1517
1528
|
vi.mocked(mockedClient.connect).mockImplementationOnce(async (transport) => {
|
|
1518
1529
|
capturedTransport = transport;
|
|
1519
1530
|
return Promise.resolve();
|
|
1520
1531
|
});
|
|
1521
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext,
|
|
1532
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext, MOCK_CONTEXT);
|
|
1522
1533
|
expect(client).toBe(mockedClient);
|
|
1523
1534
|
expect(mockedClient.connect).toHaveBeenCalledTimes(2);
|
|
1524
1535
|
expect(mockAuthProvider.authenticate).toHaveBeenCalledOnce();
|
|
1525
1536
|
expect(OAuthUtils.discoverOAuthConfig).toHaveBeenCalledWith(serverUrl);
|
|
1526
|
-
const authHeader = capturedTransport._requestInit
|
|
1537
|
+
const authHeader = capturedTransport._requestInit
|
|
1538
|
+
?.headers?.['Authorization'];
|
|
1527
1539
|
expect(authHeader).toBe('Bearer test-access-token-from-discovery');
|
|
1528
1540
|
});
|
|
1529
1541
|
it('should use discoverOAuthFromWWWAuthenticate when it succeeds and skip discoverOAuthConfig', async () => {
|
|
@@ -1538,7 +1550,7 @@ describe('connectToMcpServer with OAuth', () => {
|
|
|
1538
1550
|
scopes: ['read'],
|
|
1539
1551
|
});
|
|
1540
1552
|
vi.mocked(mockedClient.connect).mockResolvedValueOnce(undefined);
|
|
1541
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext,
|
|
1553
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext, MOCK_CONTEXT);
|
|
1542
1554
|
expect(client).toBe(mockedClient);
|
|
1543
1555
|
expect(OAuthUtils.discoverOAuthFromWWWAuthenticate).toHaveBeenCalledWith(wwwAuthHeader, serverUrl);
|
|
1544
1556
|
expect(OAuthUtils.discoverOAuthConfig).not.toHaveBeenCalled();
|
|
@@ -1559,7 +1571,7 @@ describe('connectToMcpServer with OAuth', () => {
|
|
|
1559
1571
|
scopes: ['read'],
|
|
1560
1572
|
});
|
|
1561
1573
|
vi.mocked(mockedClient.connect).mockResolvedValueOnce(undefined);
|
|
1562
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext,
|
|
1574
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { httpUrl: serverUrl, oauth: { enabled: true } }, false, workspaceContext, MOCK_CONTEXT);
|
|
1563
1575
|
expect(client).toBe(mockedClient);
|
|
1564
1576
|
expect(OAuthUtils.discoverOAuthFromWWWAuthenticate).toHaveBeenCalledWith(wwwAuthHeader, serverUrl);
|
|
1565
1577
|
expect(OAuthUtils.extractBaseUrl).toHaveBeenCalledWith(serverUrl);
|
|
@@ -1592,13 +1604,13 @@ describe('connectToMcpServer - HTTP→SSE fallback', () => {
|
|
|
1592
1604
|
});
|
|
1593
1605
|
it('should NOT trigger fallback when type="http" is explicit', async () => {
|
|
1594
1606
|
vi.mocked(mockedClient.connect).mockRejectedValueOnce(new Error('Connection failed'));
|
|
1595
|
-
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', type: 'http' }, false, workspaceContext,
|
|
1607
|
+
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', type: 'http' }, false, workspaceContext, MOCK_CONTEXT)).rejects.toThrow('Connection failed');
|
|
1596
1608
|
// Should only try once (no fallback)
|
|
1597
1609
|
expect(mockedClient.connect).toHaveBeenCalledTimes(1);
|
|
1598
1610
|
});
|
|
1599
1611
|
it('should NOT trigger fallback when type="sse" is explicit', async () => {
|
|
1600
1612
|
vi.mocked(mockedClient.connect).mockRejectedValueOnce(new Error('Connection failed'));
|
|
1601
|
-
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', type: 'sse' }, false, workspaceContext,
|
|
1613
|
+
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', type: 'sse' }, false, workspaceContext, MOCK_CONTEXT)).rejects.toThrow('Connection failed');
|
|
1602
1614
|
// Should only try once (no fallback)
|
|
1603
1615
|
expect(mockedClient.connect).toHaveBeenCalledTimes(1);
|
|
1604
1616
|
});
|
|
@@ -1606,7 +1618,7 @@ describe('connectToMcpServer - HTTP→SSE fallback', () => {
|
|
|
1606
1618
|
vi.mocked(mockedClient.connect)
|
|
1607
1619
|
.mockRejectedValueOnce(new StreamableHTTPError(500, 'Server error'))
|
|
1608
1620
|
.mockResolvedValueOnce(undefined);
|
|
1609
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext,
|
|
1621
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext, MOCK_CONTEXT);
|
|
1610
1622
|
expect(client).toBe(mockedClient);
|
|
1611
1623
|
// First HTTP attempt fails, second SSE attempt succeeds
|
|
1612
1624
|
expect(mockedClient.connect).toHaveBeenCalledTimes(2);
|
|
@@ -1617,14 +1629,14 @@ describe('connectToMcpServer - HTTP→SSE fallback', () => {
|
|
|
1617
1629
|
vi.mocked(mockedClient.connect)
|
|
1618
1630
|
.mockRejectedValueOnce(httpError)
|
|
1619
1631
|
.mockRejectedValueOnce(sseError);
|
|
1620
|
-
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext,
|
|
1632
|
+
await expect(connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext, MOCK_CONTEXT)).rejects.toThrow('Server error');
|
|
1621
1633
|
expect(mockedClient.connect).toHaveBeenCalledTimes(2);
|
|
1622
1634
|
});
|
|
1623
1635
|
it('should handle HTTP 404 followed by SSE success', async () => {
|
|
1624
1636
|
vi.mocked(mockedClient.connect)
|
|
1625
1637
|
.mockRejectedValueOnce(new StreamableHTTPError(404, 'Not Found'))
|
|
1626
1638
|
.mockResolvedValueOnce(undefined);
|
|
1627
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext,
|
|
1639
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server' }, false, workspaceContext, MOCK_CONTEXT);
|
|
1628
1640
|
expect(client).toBe(mockedClient);
|
|
1629
1641
|
expect(mockedClient.connect).toHaveBeenCalledTimes(2);
|
|
1630
1642
|
});
|
|
@@ -1685,7 +1697,7 @@ describe('connectToMcpServer - OAuth with transport fallback', () => {
|
|
|
1685
1697
|
.mockRejectedValueOnce(new StreamableHTTPError(404, 'Not Found'))
|
|
1686
1698
|
.mockRejectedValueOnce(new StreamableHTTPError(401, 'Unauthorized'))
|
|
1687
1699
|
.mockResolvedValueOnce(undefined);
|
|
1688
|
-
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', oauth: { enabled: true } }, false, workspaceContext,
|
|
1700
|
+
const client = await connectToMcpServer('0.0.1', 'test-server', { url: 'http://test-server', oauth: { enabled: true } }, false, workspaceContext, MOCK_CONTEXT);
|
|
1689
1701
|
expect(client).toBe(mockedClient);
|
|
1690
1702
|
expect(mockedClient.connect).toHaveBeenCalledTimes(3);
|
|
1691
1703
|
expect(mockAuthProvider.authenticate).toHaveBeenCalledOnce();
|