@vybestack/llxprt-code-core 0.1.13 → 0.1.14-nightly.250729.2076f7c6
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/README.md +24 -0
- package/dist/src/code_assist/codeAssist.d.ts +2 -1
- package/dist/src/code_assist/codeAssist.js +4 -3
- package/dist/src/code_assist/codeAssist.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +9 -2
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +94 -2
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +5 -6
- package/dist/src/code_assist/server.js +7 -70
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/setup.d.ts +6 -1
- package/dist/src/code_assist/setup.js +4 -1
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/setup.test.js +4 -1
- package/dist/src/code_assist/setup.test.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +2 -2
- package/dist/src/config/config.d.ts +25 -3
- package/dist/src/config/config.js +47 -10
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +1 -26
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/flashFallback.test.js +1 -1
- package/dist/src/config/flashFallback.test.js.map +1 -1
- package/dist/src/core/client.d.ts +6 -2
- package/dist/src/core/client.js +41 -18
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +78 -24
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +1 -1
- package/dist/src/core/contentGenerator.js +1 -1
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolScheduler.js +14 -1
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +80 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +4 -3
- package/dist/src/core/geminiChat.js +8 -11
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiRequest.js +2 -37
- package/dist/src/core/geminiRequest.js.map +1 -1
- package/dist/src/core/logger.js +6 -0
- package/dist/src/core/logger.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +5 -5
- package/dist/src/core/prompts.js +42 -18
- package/dist/src/core/prompts.js.map +1 -1
- package/dist/src/core/prompts.test.js +121 -4
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/core/turn.d.ts +7 -2
- package/dist/src/core/turn.js +9 -0
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +129 -0
- package/dist/src/core/turn.test.js.map +1 -1
- package/dist/src/ide/ide-client.d.ts +28 -0
- package/dist/src/ide/ide-client.js +79 -0
- package/dist/src/ide/ide-client.js.map +1 -0
- package/dist/src/ide/ideContext.d.ts +174 -0
- package/dist/src/{services → ide}/ideContext.js +28 -25
- package/dist/src/ide/ideContext.js.map +1 -0
- package/dist/src/{services → ide}/ideContext.test.js +39 -39
- package/dist/src/ide/ideContext.test.js.map +1 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +4 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.d.ts +23 -0
- package/dist/src/mcp/google-auth-provider.js +63 -0
- package/dist/src/mcp/google-auth-provider.js.map +1 -0
- package/dist/src/mcp/google-auth-provider.test.js +54 -0
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -0
- package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
- package/dist/src/providers/gemini/GeminiProvider.d.ts +2 -0
- package/dist/src/providers/gemini/GeminiProvider.integration.test.js +36 -0
- package/dist/src/providers/gemini/GeminiProvider.integration.test.js.map +1 -1
- package/dist/src/providers/gemini/GeminiProvider.js +57 -10
- package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.js +10 -7
- package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.d.ts +4 -4
- package/dist/src/services/fileDiscoveryService.js +8 -8
- package/dist/src/services/gitService.js +1 -1
- package/dist/src/services/gitService.js.map +1 -1
- package/dist/src/services/gitService.test.js +1 -1
- package/dist/src/services/gitService.test.js.map +1 -1
- package/dist/src/services/loopDetectionService.d.ts +48 -5
- package/dist/src/services/loopDetectionService.js +127 -41
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +50 -123
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +2 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +17 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +16 -15
- package/dist/src/telemetry/constants.js +16 -15
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/file-exporters.d.ts +28 -0
- package/dist/src/telemetry/file-exporters.js +62 -0
- package/dist/src/telemetry/file-exporters.js.map +1 -0
- package/dist/src/telemetry/loggers.d.ts +2 -1
- package/dist/src/telemetry/loggers.js +18 -3
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/sdk.js +22 -7
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +9 -2
- package/dist/src/telemetry/types.js +13 -1
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/tools/ToolFormatter.js +19 -1
- package/dist/src/tools/ToolFormatter.js.map +1 -1
- package/dist/src/tools/edit.js +10 -4
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +12 -0
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/grep.test.js +1 -1
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.d.ts +5 -2
- package/dist/src/tools/ls.js +39 -10
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +5 -1
- package/dist/src/tools/mcp-client.js +416 -29
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +46 -6
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.js +1 -1
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +34 -0
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/read-file.js +1 -1
- package/dist/src/tools/read-file.test.js +98 -69
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.d.ts +5 -2
- package/dist/src/tools/read-many-files.js +61 -16
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +5 -2
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +15 -26
- package/dist/src/tools/shell.js +137 -358
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +73 -318
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +13 -1
- package/dist/src/tools/tool-registry.js +45 -1
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +3 -3
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.d.ts +2 -0
- package/dist/src/utils/bfsFileSearch.js +4 -1
- package/dist/src/utils/bfsFileSearch.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.test.js +108 -105
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
- package/dist/src/utils/editCorrector.js +4 -4
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editCorrector.test.js +1 -1
- package/dist/src/utils/editor.js +16 -10
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/editor.test.js +128 -28
- package/dist/src/utils/editor.test.js.map +1 -1
- package/dist/src/utils/errorReporting.d.ts +1 -1
- package/dist/src/utils/errorReporting.js +2 -2
- package/dist/src/utils/errorReporting.js.map +1 -1
- package/dist/src/utils/errorReporting.test.js +44 -38
- package/dist/src/utils/errorReporting.test.js.map +1 -1
- package/dist/src/utils/fileUtils.d.ts +4 -4
- package/dist/src/utils/fileUtils.js +31 -15
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +37 -37
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/getFolderStructure.d.ts +3 -2
- package/dist/src/utils/getFolderStructure.js +27 -28
- package/dist/src/utils/getFolderStructure.js.map +1 -1
- package/dist/src/utils/getFolderStructure.test.js +169 -185
- package/dist/src/utils/getFolderStructure.test.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.js +4 -7
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +71 -62
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +2 -1
- package/dist/src/utils/memoryDiscovery.js +11 -5
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +160 -371
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/partUtils.d.ts +14 -0
- package/dist/src/utils/partUtils.js +65 -0
- package/dist/src/utils/partUtils.js.map +1 -0
- package/dist/src/utils/partUtils.test.d.ts +6 -0
- package/dist/src/utils/partUtils.test.js +130 -0
- package/dist/src/utils/partUtils.test.js.map +1 -0
- package/dist/src/utils/paths.d.ts +11 -0
- package/dist/src/utils/paths.js +17 -1
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/quotaErrorDetection.js.map +1 -1
- package/dist/src/utils/retry.js +1 -1
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/schemaValidator.js +5 -2
- package/dist/src/utils/schemaValidator.js.map +1 -1
- package/dist/src/utils/shell-utils.d.ts +44 -0
- package/dist/src/utils/shell-utils.js +243 -0
- package/dist/src/utils/shell-utils.js.map +1 -0
- package/dist/src/utils/shell-utils.test.d.ts +6 -0
- package/dist/src/utils/shell-utils.test.js +450 -0
- package/dist/src/utils/shell-utils.test.js.map +1 -0
- package/dist/src/utils/summarizer.js +1 -30
- package/dist/src/utils/summarizer.js.map +1 -1
- package/dist/src/utils/systemEncoding.d.ts +40 -0
- package/dist/src/utils/systemEncoding.js +149 -0
- package/dist/src/utils/systemEncoding.js.map +1 -0
- package/dist/src/utils/systemEncoding.test.d.ts +6 -0
- package/dist/src/utils/systemEncoding.test.js +368 -0
- package/dist/src/utils/systemEncoding.test.js.map +1 -0
- package/dist/src/utils/user_account.test.js +1 -1
- package/dist/src/utils/user_account.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -1
- package/dist/src/core/geminiRequest.test.js +0 -72
- package/dist/src/core/geminiRequest.test.js.map +0 -1
- package/dist/src/services/ideContext.d.ts +0 -126
- package/dist/src/services/ideContext.js.map +0 -1
- package/dist/src/services/ideContext.test.js.map +0 -1
- /package/dist/src/{services → ide}/ideContext.test.d.ts +0 -0
- /package/dist/src/{core/geminiRequest.test.d.ts → mcp/google-auth-provider.test.d.ts} +0 -0
package/dist/src/tools/ls.js
CHANGED
|
@@ -8,6 +8,7 @@ import path from 'path';
|
|
|
8
8
|
import { BaseTool, Icon } from './tools.js';
|
|
9
9
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
|
10
10
|
import { makeRelative, shortenPath } from '../utils/paths.js';
|
|
11
|
+
import { DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js';
|
|
11
12
|
import { Type } from '@google/genai';
|
|
12
13
|
import { isWithinRoot } from '../utils/fileUtils.js';
|
|
13
14
|
/**
|
|
@@ -30,9 +31,19 @@ export class LSTool extends BaseTool {
|
|
|
30
31
|
},
|
|
31
32
|
type: Type.ARRAY,
|
|
32
33
|
},
|
|
33
|
-
|
|
34
|
-
description: 'Optional: Whether to respect
|
|
35
|
-
type: Type.
|
|
34
|
+
file_filtering_options: {
|
|
35
|
+
description: 'Optional: Whether to respect ignore patterns from .gitignore or .llxprtignore',
|
|
36
|
+
type: Type.OBJECT,
|
|
37
|
+
properties: {
|
|
38
|
+
respect_git_ignore: {
|
|
39
|
+
description: 'Optional: Whether to respect .gitignore patterns when listing files. Only available in git repositories. Defaults to true.',
|
|
40
|
+
type: Type.BOOLEAN,
|
|
41
|
+
},
|
|
42
|
+
respect_llxprt_ignore: {
|
|
43
|
+
description: 'Optional: Whether to respect .llxprtignore patterns when listing files. Defaults to true.',
|
|
44
|
+
type: Type.BOOLEAN,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
36
47
|
},
|
|
37
48
|
},
|
|
38
49
|
required: ['path'],
|
|
@@ -119,12 +130,18 @@ export class LSTool extends BaseTool {
|
|
|
119
130
|
return this.errorResult(`Error: Path is not a directory: ${params.path}`, `Path is not a directory.`);
|
|
120
131
|
}
|
|
121
132
|
const files = fs.readdirSync(params.path);
|
|
133
|
+
const defaultFileIgnores = this.config.getFileFilteringOptions() ?? DEFAULT_FILE_FILTERING_OPTIONS;
|
|
134
|
+
const fileFilteringOptions = {
|
|
135
|
+
respectGitIgnore: params.file_filtering_options?.respect_git_ignore ??
|
|
136
|
+
defaultFileIgnores.respectGitIgnore,
|
|
137
|
+
respectLlxprtIgnore: params.file_filtering_options?.respect_llxprt_ignore ??
|
|
138
|
+
defaultFileIgnores.respectLlxprtIgnore,
|
|
139
|
+
};
|
|
122
140
|
// Get centralized file discovery service
|
|
123
|
-
const respectGitIgnore = params.respect_git_ignore ??
|
|
124
|
-
this.config.getFileFilteringRespectGitIgnore();
|
|
125
141
|
const fileDiscovery = this.config.getFileService();
|
|
126
142
|
const entries = [];
|
|
127
143
|
let gitIgnoredCount = 0;
|
|
144
|
+
let llxprtIgnoredCount = 0;
|
|
128
145
|
if (files.length === 0) {
|
|
129
146
|
// Changed error message to be more neutral for LLM
|
|
130
147
|
return {
|
|
@@ -138,12 +155,17 @@ export class LSTool extends BaseTool {
|
|
|
138
155
|
}
|
|
139
156
|
const fullPath = path.join(params.path, file);
|
|
140
157
|
const relativePath = path.relative(this.config.getTargetDir(), fullPath);
|
|
141
|
-
// Check if this file should be
|
|
142
|
-
if (respectGitIgnore &&
|
|
158
|
+
// Check if this file should be ignored based on git or llxprt ignore rules
|
|
159
|
+
if (fileFilteringOptions.respectGitIgnore &&
|
|
143
160
|
fileDiscovery.shouldGitIgnoreFile(relativePath)) {
|
|
144
161
|
gitIgnoredCount++;
|
|
145
162
|
continue;
|
|
146
163
|
}
|
|
164
|
+
if (fileFilteringOptions.respectLlxprtIgnore &&
|
|
165
|
+
fileDiscovery.shouldLlxprtIgnoreFile(relativePath)) {
|
|
166
|
+
llxprtIgnoredCount++;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
147
169
|
try {
|
|
148
170
|
const stats = fs.statSync(fullPath);
|
|
149
171
|
const isDir = stats.isDirectory();
|
|
@@ -173,12 +195,19 @@ export class LSTool extends BaseTool {
|
|
|
173
195
|
.map((entry) => `${entry.isDirectory ? '[DIR] ' : ''}${entry.name}`)
|
|
174
196
|
.join('\n');
|
|
175
197
|
let resultMessage = `Directory listing for ${params.path}:\n${directoryContent}`;
|
|
198
|
+
const ignoredMessages = [];
|
|
176
199
|
if (gitIgnoredCount > 0) {
|
|
177
|
-
|
|
200
|
+
ignoredMessages.push(`${gitIgnoredCount} git-ignored`);
|
|
201
|
+
}
|
|
202
|
+
if (llxprtIgnoredCount > 0) {
|
|
203
|
+
ignoredMessages.push(`${llxprtIgnoredCount} llxprt-ignored`);
|
|
204
|
+
}
|
|
205
|
+
if (ignoredMessages.length > 0) {
|
|
206
|
+
resultMessage += `\n\n(${ignoredMessages.join(', ')})`;
|
|
178
207
|
}
|
|
179
208
|
let displayMessage = `Listed ${entries.length} item(s).`;
|
|
180
|
-
if (
|
|
181
|
-
displayMessage += ` (${
|
|
209
|
+
if (ignoredMessages.length > 0) {
|
|
210
|
+
displayMessage += ` (${ignoredMessages.join(', ')})`;
|
|
182
211
|
}
|
|
183
212
|
return {
|
|
184
213
|
llmContent: resultMessage,
|
package/dist/src/tools/ls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/tools/ls.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAc,IAAI,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/tools/ls.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,10 @@ export declare enum MCPDiscoveryState {
|
|
|
32
32
|
/** Discovery has completed (with or without errors) */
|
|
33
33
|
COMPLETED = "completed"
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Map to track which MCP servers have been discovered to require OAuth
|
|
37
|
+
*/
|
|
38
|
+
export declare const mcpServerRequiresOAuth: Map<string, boolean>;
|
|
35
39
|
/**
|
|
36
40
|
* Event listeners for MCP server status changes
|
|
37
41
|
*/
|
|
@@ -104,7 +108,7 @@ export declare function discoverTools(mcpServerName: string, mcpServerConfig: MC
|
|
|
104
108
|
*/
|
|
105
109
|
export declare function connectToMcpServer(mcpServerName: string, mcpServerConfig: MCPServerConfig, debugMode: boolean): Promise<Client>;
|
|
106
110
|
/** Visible for Testing */
|
|
107
|
-
export declare function createTransport(mcpServerName: string, mcpServerConfig: MCPServerConfig, debugMode: boolean): Transport
|
|
111
|
+
export declare function createTransport(mcpServerName: string, mcpServerConfig: MCPServerConfig, debugMode: boolean): Promise<Transport>;
|
|
108
112
|
/** Visible for testing */
|
|
109
113
|
export declare function isEnabled(funcDecl: FunctionDeclaration, mcpServerName: string, mcpServerConfig: MCPServerConfig): boolean;
|
|
110
114
|
export {};
|
|
@@ -8,9 +8,14 @@ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
|
|
|
8
8
|
import { SSEClientTransport, } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
9
9
|
import { StreamableHTTPClientTransport, } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
10
10
|
import { parse } from 'shell-quote';
|
|
11
|
+
import { AuthProviderType } from '../config/config.js';
|
|
12
|
+
import { GoogleCredentialProvider } from '../mcp/google-auth-provider.js';
|
|
11
13
|
import { DiscoveredMCPTool } from './mcp-tool.js';
|
|
12
14
|
import { mcpToTool } from '@google/genai';
|
|
13
|
-
import {
|
|
15
|
+
import { MCPOAuthProvider } from '../mcp/oauth-provider.js';
|
|
16
|
+
import { OAuthUtils } from '../mcp/oauth-utils.js';
|
|
17
|
+
import { MCPOAuthTokenStorage } from '../mcp/oauth-token-storage.js';
|
|
18
|
+
import { getErrorMessage } from '../utils/errors.js';
|
|
14
19
|
export const MCP_DEFAULT_TIMEOUT_MSEC = 10 * 60 * 1000; // default to 10 minutes
|
|
15
20
|
/**
|
|
16
21
|
* Enum representing the connection status of an MCP server
|
|
@@ -44,6 +49,10 @@ const mcpServerStatusesInternal = new Map();
|
|
|
44
49
|
* Track the overall MCP discovery state
|
|
45
50
|
*/
|
|
46
51
|
let mcpDiscoveryState = MCPDiscoveryState.NOT_STARTED;
|
|
52
|
+
/**
|
|
53
|
+
* Map to track which MCP servers have been discovered to require OAuth
|
|
54
|
+
*/
|
|
55
|
+
export const mcpServerRequiresOAuth = new Map();
|
|
47
56
|
const statusChangeListeners = [];
|
|
48
57
|
/**
|
|
49
58
|
* Add a listener for MCP server status changes
|
|
@@ -88,6 +97,132 @@ export function getAllMCPServerStatuses() {
|
|
|
88
97
|
export function getMCPDiscoveryState() {
|
|
89
98
|
return mcpDiscoveryState;
|
|
90
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Parse www-authenticate header to extract OAuth metadata URI.
|
|
102
|
+
*
|
|
103
|
+
* @param wwwAuthenticate The www-authenticate header value
|
|
104
|
+
* @returns The resource metadata URI if found, null otherwise
|
|
105
|
+
*/
|
|
106
|
+
function _parseWWWAuthenticate(wwwAuthenticate) {
|
|
107
|
+
// Parse header like: Bearer realm="MCP Server", resource_metadata_uri="https://..."
|
|
108
|
+
const resourceMetadataMatch = wwwAuthenticate.match(/resource_metadata_uri="([^"]+)"/);
|
|
109
|
+
return resourceMetadataMatch ? resourceMetadataMatch[1] : null;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Extract WWW-Authenticate header from error message string.
|
|
113
|
+
* This is a more robust approach than regex matching.
|
|
114
|
+
*
|
|
115
|
+
* @param errorString The error message string
|
|
116
|
+
* @returns The www-authenticate header value if found, null otherwise
|
|
117
|
+
*/
|
|
118
|
+
function extractWWWAuthenticateHeader(errorString) {
|
|
119
|
+
// Try multiple patterns to extract the header
|
|
120
|
+
const patterns = [
|
|
121
|
+
/www-authenticate:\s*([^\n\r]+)/i,
|
|
122
|
+
/WWW-Authenticate:\s*([^\n\r]+)/i,
|
|
123
|
+
/"www-authenticate":\s*"([^"]+)"/i,
|
|
124
|
+
/'www-authenticate':\s*'([^']+)'/i,
|
|
125
|
+
];
|
|
126
|
+
for (const pattern of patterns) {
|
|
127
|
+
const match = errorString.match(pattern);
|
|
128
|
+
if (match) {
|
|
129
|
+
return match[1].trim();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Handle automatic OAuth discovery and authentication for a server.
|
|
136
|
+
*
|
|
137
|
+
* @param mcpServerName The name of the MCP server
|
|
138
|
+
* @param mcpServerConfig The MCP server configuration
|
|
139
|
+
* @param wwwAuthenticate The www-authenticate header value
|
|
140
|
+
* @returns True if OAuth was successfully configured and authenticated, false otherwise
|
|
141
|
+
*/
|
|
142
|
+
async function handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthenticate) {
|
|
143
|
+
try {
|
|
144
|
+
console.log(`🔐 '${mcpServerName}' requires OAuth authentication`);
|
|
145
|
+
// Always try to parse the resource metadata URI from the www-authenticate header
|
|
146
|
+
let oauthConfig;
|
|
147
|
+
const resourceMetadataUri = OAuthUtils.parseWWWAuthenticateHeader(wwwAuthenticate);
|
|
148
|
+
if (resourceMetadataUri) {
|
|
149
|
+
oauthConfig = await OAuthUtils.discoverOAuthConfig(resourceMetadataUri);
|
|
150
|
+
}
|
|
151
|
+
else if (mcpServerConfig.url) {
|
|
152
|
+
// Fallback: try to discover OAuth config from the base URL for SSE
|
|
153
|
+
const sseUrl = new URL(mcpServerConfig.url);
|
|
154
|
+
const baseUrl = `${sseUrl.protocol}//${sseUrl.host}`;
|
|
155
|
+
oauthConfig = await OAuthUtils.discoverOAuthConfig(baseUrl);
|
|
156
|
+
}
|
|
157
|
+
else if (mcpServerConfig.httpUrl) {
|
|
158
|
+
// Fallback: try to discover OAuth config from the base URL for HTTP
|
|
159
|
+
const httpUrl = new URL(mcpServerConfig.httpUrl);
|
|
160
|
+
const baseUrl = `${httpUrl.protocol}//${httpUrl.host}`;
|
|
161
|
+
oauthConfig = await OAuthUtils.discoverOAuthConfig(baseUrl);
|
|
162
|
+
}
|
|
163
|
+
if (!oauthConfig) {
|
|
164
|
+
console.error(`❌ Could not configure OAuth for '${mcpServerName}' - please authenticate manually with /mcp auth ${mcpServerName}`);
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
// OAuth configuration discovered - proceed with authentication
|
|
168
|
+
// Create OAuth configuration for authentication
|
|
169
|
+
const oauthAuthConfig = {
|
|
170
|
+
enabled: true,
|
|
171
|
+
authorizationUrl: oauthConfig.authorizationUrl,
|
|
172
|
+
tokenUrl: oauthConfig.tokenUrl,
|
|
173
|
+
scopes: oauthConfig.scopes || [],
|
|
174
|
+
};
|
|
175
|
+
// Perform OAuth authentication
|
|
176
|
+
console.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
177
|
+
await MCPOAuthProvider.authenticate(mcpServerName, oauthAuthConfig);
|
|
178
|
+
console.log(`OAuth authentication successful for server '${mcpServerName}'`);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
console.error(`Failed to handle automatic OAuth for server '${mcpServerName}': ${getErrorMessage(error)}`);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Create a transport with OAuth token for the given server configuration.
|
|
188
|
+
*
|
|
189
|
+
* @param mcpServerName The name of the MCP server
|
|
190
|
+
* @param mcpServerConfig The MCP server configuration
|
|
191
|
+
* @param accessToken The OAuth access token
|
|
192
|
+
* @returns The transport with OAuth token, or null if creation fails
|
|
193
|
+
*/
|
|
194
|
+
async function createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken) {
|
|
195
|
+
try {
|
|
196
|
+
if (mcpServerConfig.httpUrl) {
|
|
197
|
+
// Create HTTP transport with OAuth token
|
|
198
|
+
const oauthTransportOptions = {
|
|
199
|
+
requestInit: {
|
|
200
|
+
headers: {
|
|
201
|
+
...mcpServerConfig.headers,
|
|
202
|
+
Authorization: `Bearer ${accessToken}`,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), oauthTransportOptions);
|
|
207
|
+
}
|
|
208
|
+
else if (mcpServerConfig.url) {
|
|
209
|
+
// Create SSE transport with OAuth token in Authorization header
|
|
210
|
+
return new SSEClientTransport(new URL(mcpServerConfig.url), {
|
|
211
|
+
requestInit: {
|
|
212
|
+
headers: {
|
|
213
|
+
...mcpServerConfig.headers,
|
|
214
|
+
Authorization: `Bearer ${accessToken}`,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
console.error(`Failed to create OAuth transport for server '${mcpServerName}': ${getErrorMessage(error)}`);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
91
226
|
/**
|
|
92
227
|
* Discovers tools from all configured MCP servers and registers them with the tool registry.
|
|
93
228
|
* It orchestrates the connection and discovery process for each server defined in the
|
|
@@ -144,15 +279,7 @@ export async function connectAndDiscover(mcpServerName, mcpServerConfig, toolReg
|
|
|
144
279
|
mcpClient.onerror = (error) => {
|
|
145
280
|
console.error(`MCP ERROR (${mcpServerName}):`, error.toString());
|
|
146
281
|
updateMCPServerStatus(mcpServerName, MCPServerStatus.DISCONNECTED);
|
|
147
|
-
if (mcpServerName === IDE_SERVER_NAME) {
|
|
148
|
-
ideContext.clearActiveFileContext();
|
|
149
|
-
}
|
|
150
282
|
};
|
|
151
|
-
if (mcpServerName === IDE_SERVER_NAME) {
|
|
152
|
-
mcpClient.setNotificationHandler(ActiveFileNotificationSchema, (notification) => {
|
|
153
|
-
ideContext.setActiveFileContext(notification.params);
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
283
|
const tools = await discoverTools(mcpServerName, mcpServerConfig, mcpClient);
|
|
157
284
|
for (const tool of tools) {
|
|
158
285
|
toolRegistry.registerTool(tool);
|
|
@@ -164,7 +291,7 @@ export async function connectAndDiscover(mcpServerName, mcpServerConfig, toolReg
|
|
|
164
291
|
}
|
|
165
292
|
}
|
|
166
293
|
catch (error) {
|
|
167
|
-
console.error(`Error connecting to MCP server '${mcpServerName}'
|
|
294
|
+
console.error(`Error connecting to MCP server '${mcpServerName}': ${getErrorMessage(error)}`);
|
|
168
295
|
updateMCPServerStatus(mcpServerName, MCPServerStatus.DISCONNECTED);
|
|
169
296
|
}
|
|
170
297
|
}
|
|
@@ -229,7 +356,7 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
229
356
|
};
|
|
230
357
|
}
|
|
231
358
|
try {
|
|
232
|
-
const transport = createTransport(mcpServerName, mcpServerConfig, debugMode);
|
|
359
|
+
const transport = await createTransport(mcpServerName, mcpServerConfig, debugMode);
|
|
233
360
|
try {
|
|
234
361
|
await mcpClient.connect(transport, {
|
|
235
362
|
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
@@ -242,29 +369,280 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
242
369
|
}
|
|
243
370
|
}
|
|
244
371
|
catch (error) {
|
|
245
|
-
//
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
372
|
+
// Check if this is a 401 error that might indicate OAuth is required
|
|
373
|
+
const errorString = String(error);
|
|
374
|
+
if (errorString.includes('401') &&
|
|
375
|
+
(mcpServerConfig.httpUrl || mcpServerConfig.url)) {
|
|
376
|
+
mcpServerRequiresOAuth.set(mcpServerName, true);
|
|
377
|
+
// Only trigger automatic OAuth discovery for HTTP servers or when OAuth is explicitly configured
|
|
378
|
+
// For SSE servers, we should not trigger new OAuth flows automatically
|
|
379
|
+
const shouldTriggerOAuth = mcpServerConfig.httpUrl || mcpServerConfig.oauth?.enabled;
|
|
380
|
+
if (!shouldTriggerOAuth) {
|
|
381
|
+
// For SSE servers without explicit OAuth config, if a token was found but rejected, report it accurately.
|
|
382
|
+
const credentials = await MCPOAuthTokenStorage.getToken(mcpServerName);
|
|
383
|
+
if (credentials) {
|
|
384
|
+
const hasStoredTokens = await MCPOAuthProvider.getValidToken(mcpServerName, {
|
|
385
|
+
// Pass client ID if available
|
|
386
|
+
clientId: credentials.clientId,
|
|
387
|
+
});
|
|
388
|
+
if (hasStoredTokens) {
|
|
389
|
+
console.log(`Stored OAuth token for SSE server '${mcpServerName}' was rejected. ` +
|
|
390
|
+
`Please re-authenticate using: /mcp auth ${mcpServerName}`);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
console.log(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
394
|
+
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
throw new Error(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
398
|
+
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
399
|
+
}
|
|
400
|
+
// Try to extract www-authenticate header from the error
|
|
401
|
+
let wwwAuthenticate = extractWWWAuthenticateHeader(errorString);
|
|
402
|
+
// If we didn't get the header from the error string, try to get it from the server
|
|
403
|
+
if (!wwwAuthenticate && mcpServerConfig.url) {
|
|
404
|
+
console.log(`No www-authenticate header in error, trying to fetch it from server...`);
|
|
405
|
+
try {
|
|
406
|
+
const response = await fetch(mcpServerConfig.url, {
|
|
407
|
+
method: 'HEAD',
|
|
408
|
+
headers: {
|
|
409
|
+
Accept: 'text/event-stream',
|
|
410
|
+
},
|
|
411
|
+
signal: AbortSignal.timeout(5000),
|
|
412
|
+
});
|
|
413
|
+
if (response.status === 401) {
|
|
414
|
+
wwwAuthenticate = response.headers.get('www-authenticate');
|
|
415
|
+
if (wwwAuthenticate) {
|
|
416
|
+
console.log(`Found www-authenticate header from server: ${wwwAuthenticate}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
catch (fetchError) {
|
|
421
|
+
console.debug(`Failed to fetch www-authenticate header: ${getErrorMessage(fetchError)}`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (wwwAuthenticate) {
|
|
425
|
+
console.log(`Received 401 with www-authenticate header: ${wwwAuthenticate}`);
|
|
426
|
+
// Try automatic OAuth discovery and authentication
|
|
427
|
+
const oauthSuccess = await handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthenticate);
|
|
428
|
+
if (oauthSuccess) {
|
|
429
|
+
// Retry connection with OAuth token
|
|
430
|
+
console.log(`Retrying connection to '${mcpServerName}' with OAuth token...`);
|
|
431
|
+
// Get the valid token - we need to create a proper OAuth config
|
|
432
|
+
// The token should already be available from the authentication process
|
|
433
|
+
const credentials = await MCPOAuthTokenStorage.getToken(mcpServerName);
|
|
434
|
+
if (credentials) {
|
|
435
|
+
const accessToken = await MCPOAuthProvider.getValidToken(mcpServerName, {
|
|
436
|
+
// Pass client ID if available
|
|
437
|
+
clientId: credentials.clientId,
|
|
438
|
+
});
|
|
439
|
+
if (accessToken) {
|
|
440
|
+
// Create transport with OAuth token
|
|
441
|
+
const oauthTransport = await createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken);
|
|
442
|
+
if (oauthTransport) {
|
|
443
|
+
try {
|
|
444
|
+
await mcpClient.connect(oauthTransport, {
|
|
445
|
+
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
446
|
+
});
|
|
447
|
+
// Connection successful with OAuth
|
|
448
|
+
return mcpClient;
|
|
449
|
+
}
|
|
450
|
+
catch (retryError) {
|
|
451
|
+
console.error(`Failed to connect with OAuth token: ${getErrorMessage(retryError)}`);
|
|
452
|
+
throw retryError;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
console.error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
457
|
+
throw new Error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
console.error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
462
|
+
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
console.error(`Failed to get credentials for server '${mcpServerName}' after successful OAuth authentication`);
|
|
467
|
+
throw new Error(`Failed to get credentials for server '${mcpServerName}' after successful OAuth authentication`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
console.error(`Failed to handle automatic OAuth for server '${mcpServerName}'`);
|
|
472
|
+
throw new Error(`Failed to handle automatic OAuth for server '${mcpServerName}'`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// No www-authenticate header found, but we got a 401
|
|
477
|
+
// Only try OAuth discovery for HTTP servers or when OAuth is explicitly configured
|
|
478
|
+
// For SSE servers, we should not trigger new OAuth flows automatically
|
|
479
|
+
const shouldTryDiscovery = mcpServerConfig.httpUrl || mcpServerConfig.oauth?.enabled;
|
|
480
|
+
if (!shouldTryDiscovery) {
|
|
481
|
+
const credentials = await MCPOAuthTokenStorage.getToken(mcpServerName);
|
|
482
|
+
if (credentials) {
|
|
483
|
+
const hasStoredTokens = await MCPOAuthProvider.getValidToken(mcpServerName, {
|
|
484
|
+
// Pass client ID if available
|
|
485
|
+
clientId: credentials.clientId,
|
|
486
|
+
});
|
|
487
|
+
if (hasStoredTokens) {
|
|
488
|
+
console.log(`Stored OAuth token for SSE server '${mcpServerName}' was rejected. ` +
|
|
489
|
+
`Please re-authenticate using: /mcp auth ${mcpServerName}`);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
console.log(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
493
|
+
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
throw new Error(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
497
|
+
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
498
|
+
}
|
|
499
|
+
// For SSE servers, try to discover OAuth configuration from the base URL
|
|
500
|
+
console.log(`🔍 Attempting OAuth discovery for '${mcpServerName}'...`);
|
|
501
|
+
if (mcpServerConfig.url) {
|
|
502
|
+
const sseUrl = new URL(mcpServerConfig.url);
|
|
503
|
+
const baseUrl = `${sseUrl.protocol}//${sseUrl.host}`;
|
|
504
|
+
try {
|
|
505
|
+
// Try to discover OAuth configuration from the base URL
|
|
506
|
+
const oauthConfig = await OAuthUtils.discoverOAuthConfig(baseUrl);
|
|
507
|
+
if (oauthConfig) {
|
|
508
|
+
console.log(`Discovered OAuth configuration from base URL for server '${mcpServerName}'`);
|
|
509
|
+
// Create OAuth configuration for authentication
|
|
510
|
+
const oauthAuthConfig = {
|
|
511
|
+
enabled: true,
|
|
512
|
+
authorizationUrl: oauthConfig.authorizationUrl,
|
|
513
|
+
tokenUrl: oauthConfig.tokenUrl,
|
|
514
|
+
scopes: oauthConfig.scopes || [],
|
|
515
|
+
};
|
|
516
|
+
// Perform OAuth authentication
|
|
517
|
+
console.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
518
|
+
await MCPOAuthProvider.authenticate(mcpServerName, oauthAuthConfig);
|
|
519
|
+
// Retry connection with OAuth token
|
|
520
|
+
const credentials = await MCPOAuthTokenStorage.getToken(mcpServerName);
|
|
521
|
+
if (credentials) {
|
|
522
|
+
const accessToken = await MCPOAuthProvider.getValidToken(mcpServerName, {
|
|
523
|
+
// Pass client ID if available
|
|
524
|
+
clientId: credentials.clientId,
|
|
525
|
+
});
|
|
526
|
+
if (accessToken) {
|
|
527
|
+
// Create transport with OAuth token
|
|
528
|
+
const oauthTransport = await createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken);
|
|
529
|
+
if (oauthTransport) {
|
|
530
|
+
try {
|
|
531
|
+
await mcpClient.connect(oauthTransport, {
|
|
532
|
+
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
533
|
+
});
|
|
534
|
+
// Connection successful with OAuth
|
|
535
|
+
return mcpClient;
|
|
536
|
+
}
|
|
537
|
+
catch (retryError) {
|
|
538
|
+
console.error(`Failed to connect with OAuth token: ${getErrorMessage(retryError)}`);
|
|
539
|
+
throw retryError;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
console.error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
544
|
+
throw new Error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
console.error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
549
|
+
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
console.error(`Failed to get stored credentials for server '${mcpServerName}'`);
|
|
554
|
+
throw new Error(`Failed to get stored credentials for server '${mcpServerName}'`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
console.error(`❌ Could not configure OAuth for '${mcpServerName}' - please authenticate manually with /mcp auth ${mcpServerName}`);
|
|
559
|
+
throw new Error(`OAuth configuration failed for '${mcpServerName}'. Please authenticate manually with /mcp auth ${mcpServerName}`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
catch (discoveryError) {
|
|
563
|
+
console.error(`❌ OAuth discovery failed for '${mcpServerName}' - please authenticate manually with /mcp auth ${mcpServerName}`);
|
|
564
|
+
throw discoveryError;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
console.error(`❌ '${mcpServerName}' requires authentication but no OAuth configuration found`);
|
|
569
|
+
throw new Error(`MCP server '${mcpServerName}' requires authentication. Please configure OAuth or check server settings.`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
// Handle other connection errors
|
|
575
|
+
// Create a concise error message
|
|
576
|
+
const errorMessage = error.message || String(error);
|
|
577
|
+
const isNetworkError = errorMessage.includes('ENOTFOUND') ||
|
|
578
|
+
errorMessage.includes('ECONNREFUSED');
|
|
579
|
+
let conciseError;
|
|
580
|
+
if (isNetworkError) {
|
|
581
|
+
conciseError = `Cannot connect to '${mcpServerName}' - server may be down or URL incorrect`;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
conciseError = `Connection failed for '${mcpServerName}': ${errorMessage}`;
|
|
585
|
+
}
|
|
586
|
+
if (process.env.SANDBOX) {
|
|
587
|
+
conciseError += ` (check sandbox availability)`;
|
|
588
|
+
}
|
|
589
|
+
throw new Error(conciseError);
|
|
259
590
|
}
|
|
260
|
-
throw new Error(errorString);
|
|
261
591
|
}
|
|
262
592
|
}
|
|
263
593
|
/** Visible for Testing */
|
|
264
|
-
export function createTransport(mcpServerName, mcpServerConfig, debugMode) {
|
|
594
|
+
export async function createTransport(mcpServerName, mcpServerConfig, debugMode) {
|
|
595
|
+
if (mcpServerConfig.authProviderType === AuthProviderType.GOOGLE_CREDENTIALS) {
|
|
596
|
+
const provider = new GoogleCredentialProvider(mcpServerConfig);
|
|
597
|
+
const transportOptions = {
|
|
598
|
+
authProvider: provider,
|
|
599
|
+
};
|
|
600
|
+
if (mcpServerConfig.httpUrl) {
|
|
601
|
+
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), transportOptions);
|
|
602
|
+
}
|
|
603
|
+
else if (mcpServerConfig.url) {
|
|
604
|
+
return new SSEClientTransport(new URL(mcpServerConfig.url), transportOptions);
|
|
605
|
+
}
|
|
606
|
+
throw new Error('No URL configured for Google Credentials MCP server');
|
|
607
|
+
}
|
|
608
|
+
// Check if we have OAuth configuration or stored tokens
|
|
609
|
+
let accessToken = null;
|
|
610
|
+
let hasOAuthConfig = mcpServerConfig.oauth?.enabled;
|
|
611
|
+
if (hasOAuthConfig && mcpServerConfig.oauth) {
|
|
612
|
+
accessToken = await MCPOAuthProvider.getValidToken(mcpServerName, mcpServerConfig.oauth);
|
|
613
|
+
if (!accessToken) {
|
|
614
|
+
console.error(`MCP server '${mcpServerName}' requires OAuth authentication. ` +
|
|
615
|
+
`Please authenticate using the /mcp auth command.`);
|
|
616
|
+
throw new Error(`MCP server '${mcpServerName}' requires OAuth authentication. ` +
|
|
617
|
+
`Please authenticate using the /mcp auth command.`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
// Check if we have stored OAuth tokens for this server (from previous authentication)
|
|
622
|
+
const credentials = await MCPOAuthTokenStorage.getToken(mcpServerName);
|
|
623
|
+
if (credentials) {
|
|
624
|
+
accessToken = await MCPOAuthProvider.getValidToken(mcpServerName, {
|
|
625
|
+
// Pass client ID if available
|
|
626
|
+
clientId: credentials.clientId,
|
|
627
|
+
});
|
|
628
|
+
if (accessToken) {
|
|
629
|
+
hasOAuthConfig = true;
|
|
630
|
+
console.log(`Found stored OAuth token for server '${mcpServerName}'`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
265
634
|
if (mcpServerConfig.httpUrl) {
|
|
266
635
|
const transportOptions = {};
|
|
267
|
-
|
|
636
|
+
// Set up headers with OAuth token if available
|
|
637
|
+
if (hasOAuthConfig && accessToken) {
|
|
638
|
+
transportOptions.requestInit = {
|
|
639
|
+
headers: {
|
|
640
|
+
...mcpServerConfig.headers,
|
|
641
|
+
Authorization: `Bearer ${accessToken}`,
|
|
642
|
+
},
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
else if (mcpServerConfig.headers) {
|
|
268
646
|
transportOptions.requestInit = {
|
|
269
647
|
headers: mcpServerConfig.headers,
|
|
270
648
|
};
|
|
@@ -273,7 +651,16 @@ export function createTransport(mcpServerName, mcpServerConfig, debugMode) {
|
|
|
273
651
|
}
|
|
274
652
|
if (mcpServerConfig.url) {
|
|
275
653
|
const transportOptions = {};
|
|
276
|
-
|
|
654
|
+
// Set up headers with OAuth token if available
|
|
655
|
+
if (hasOAuthConfig && accessToken) {
|
|
656
|
+
transportOptions.requestInit = {
|
|
657
|
+
headers: {
|
|
658
|
+
...mcpServerConfig.headers,
|
|
659
|
+
Authorization: `Bearer ${accessToken}`,
|
|
660
|
+
},
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
else if (mcpServerConfig.headers) {
|
|
277
664
|
transportOptions.requestInit = {
|
|
278
665
|
headers: mcpServerConfig.headers,
|
|
279
666
|
};
|