@google/gemini-cli-core 0.21.0-nightly.20251203.533a3fb31 → 0.21.0-nightly.20251205.f4f2bcbd9
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/google-gemini-cli-core-0.21.0-nightly.20251202.2d935b379.tgz +0 -0
- package/dist/src/code_assist/oauth2.d.ts +2 -0
- package/dist/src/code_assist/oauth2.js +28 -12
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +40 -2
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/commands/restore.d.ts +19 -0
- package/dist/src/commands/restore.js +45 -0
- package/dist/src/commands/restore.js.map +1 -0
- package/dist/src/commands/restore.test.d.ts +6 -0
- package/dist/src/commands/restore.test.js +136 -0
- package/dist/src/commands/restore.test.js.map +1 -0
- package/dist/src/commands/types.d.ts +41 -0
- package/dist/src/commands/types.js +7 -0
- package/dist/src/commands/types.js.map +1 -0
- package/dist/src/config/config.d.ts +17 -2
- package/dist/src/config/config.js +28 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/core/client.js +2 -1
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +23 -0
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +4 -0
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/sessionHookTriggers.d.ts +28 -0
- package/dist/src/core/sessionHookTriggers.js +68 -0
- package/dist/src/core/sessionHookTriggers.js.map +1 -0
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/hooks/hookEventHandler.js +51 -0
- package/dist/src/hooks/hookEventHandler.js.map +1 -1
- package/dist/src/hooks/hookRegistry.js +8 -1
- package/dist/src/hooks/hookRegistry.js.map +1 -1
- package/dist/src/hooks/hookRegistry.test.js +1 -0
- package/dist/src/hooks/hookRegistry.test.js.map +1 -1
- package/dist/src/hooks/hookRunner.js +12 -2
- package/dist/src/hooks/hookRunner.js.map +1 -1
- package/dist/src/hooks/hookSystem.test.js +124 -0
- package/dist/src/hooks/hookSystem.test.js.map +1 -1
- package/dist/src/hooks/index.d.ts +3 -1
- package/dist/src/hooks/index.js +3 -0
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/types.d.ts +1 -2
- package/dist/src/hooks/types.js +0 -1
- package/dist/src/hooks/types.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/json-formatter.d.ts +2 -2
- package/dist/src/output/json-formatter.js +6 -3
- package/dist/src/output/json-formatter.js.map +1 -1
- package/dist/src/output/json-formatter.test.js +35 -9
- package/dist/src/output/json-formatter.test.js.map +1 -1
- package/dist/src/output/types.d.ts +1 -0
- package/dist/src/output/types.js.map +1 -1
- package/dist/src/services/chatCompressionService.js +12 -0
- package/dist/src/services/chatCompressionService.js.map +1 -1
- package/dist/src/services/chatCompressionService.test.js +2 -0
- package/dist/src/services/chatCompressionService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +5 -18
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +29 -2
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +20 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +49 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +3 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/config.js +2 -0
- package/dist/src/telemetry/config.js.map +1 -1
- package/dist/src/telemetry/config.test.js +25 -0
- package/dist/src/telemetry/config.test.js.map +1 -1
- package/dist/src/telemetry/gcp-exporters.d.ts +4 -3
- package/dist/src/telemetry/gcp-exporters.js +7 -4
- package/dist/src/telemetry/gcp-exporters.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +1 -1
- package/dist/src/telemetry/index.js +1 -1
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.js +335 -335
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +15 -0
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/sdk.d.ts +9 -2
- package/dist/src/telemetry/sdk.js +126 -16
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/telemetry/sdk.test.js +111 -28
- package/dist/src/telemetry/sdk.test.js.map +1 -1
- package/dist/src/telemetry/startupProfiler.test.js +4 -0
- package/dist/src/telemetry/startupProfiler.test.js.map +1 -1
- package/dist/src/telemetry/telemetry.test.js +10 -3
- package/dist/src/telemetry/telemetry.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.js +15 -4
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +17 -2
- package/dist/src/tools/mcp-client.js +319 -166
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +466 -26
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/modifiable-tool.test.js +22 -13
- package/dist/src/tools/modifiable-tool.test.js.map +1 -1
- package/dist/src/utils/debugLogger.d.ts +3 -0
- package/dist/src/utils/debugLogger.js +27 -0
- package/dist/src/utils/debugLogger.js.map +1 -1
- package/dist/src/utils/editCorrector.test.js +4 -0
- package/dist/src/utils/editCorrector.test.js.map +1 -1
- package/dist/src/utils/editor.d.ts +9 -1
- package/dist/src/utils/editor.js +23 -14
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/errors.d.ts +8 -0
- package/dist/src/utils/errors.js +32 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/errors.test.d.ts +6 -0
- package/dist/src/utils/errors.test.js +36 -0
- package/dist/src/utils/errors.test.js.map +1 -0
- package/dist/src/utils/nextSpeakerChecker.test.js +4 -0
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
- package/dist/src/utils/retry.js +38 -5
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +35 -4
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/terminalSerializer.test.js +17 -0
- package/dist/src/utils/terminalSerializer.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv
|
|
|
8
8
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
9
9
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
10
10
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
11
|
-
import { ListRootsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { ListRootsRequestSchema, ToolListChangedNotificationSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
12
12
|
import { parse } from 'shell-quote';
|
|
13
13
|
import { AuthProviderType } from '../config/config.js';
|
|
14
14
|
import { GoogleCredentialProvider } from '../mcp/google-auth-provider.js';
|
|
@@ -19,7 +19,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
19
19
|
import { MCPOAuthProvider } from '../mcp/oauth-provider.js';
|
|
20
20
|
import { MCPOAuthTokenStorage } from '../mcp/oauth-token-storage.js';
|
|
21
21
|
import { OAuthUtils } from '../mcp/oauth-utils.js';
|
|
22
|
-
import { getErrorMessage } from '../utils/errors.js';
|
|
22
|
+
import { getErrorMessage, isAuthenticationError, UnauthorizedError, } from '../utils/errors.js';
|
|
23
23
|
import { debugLogger } from '../utils/debugLogger.js';
|
|
24
24
|
import { coreEvents } from '../utils/events.js';
|
|
25
25
|
export const MCP_DEFAULT_TIMEOUT_MSEC = 10 * 60 * 1000; // default to 10 minutes
|
|
@@ -61,17 +61,23 @@ export class McpClient {
|
|
|
61
61
|
toolRegistry;
|
|
62
62
|
promptRegistry;
|
|
63
63
|
workspaceContext;
|
|
64
|
+
cliConfig;
|
|
64
65
|
debugMode;
|
|
66
|
+
onToolsUpdated;
|
|
65
67
|
client;
|
|
66
68
|
transport;
|
|
67
69
|
status = MCPServerStatus.DISCONNECTED;
|
|
68
|
-
|
|
70
|
+
isRefreshing = false;
|
|
71
|
+
pendingRefresh = false;
|
|
72
|
+
constructor(serverName, serverConfig, toolRegistry, promptRegistry, workspaceContext, cliConfig, debugMode, onToolsUpdated) {
|
|
69
73
|
this.serverName = serverName;
|
|
70
74
|
this.serverConfig = serverConfig;
|
|
71
75
|
this.toolRegistry = toolRegistry;
|
|
72
76
|
this.promptRegistry = promptRegistry;
|
|
73
77
|
this.workspaceContext = workspaceContext;
|
|
78
|
+
this.cliConfig = cliConfig;
|
|
74
79
|
this.debugMode = debugMode;
|
|
80
|
+
this.onToolsUpdated = onToolsUpdated;
|
|
75
81
|
}
|
|
76
82
|
/**
|
|
77
83
|
* Connects to the MCP server.
|
|
@@ -83,6 +89,15 @@ export class McpClient {
|
|
|
83
89
|
this.updateStatus(MCPServerStatus.CONNECTING);
|
|
84
90
|
try {
|
|
85
91
|
this.client = await connectToMcpServer(this.serverName, this.serverConfig, this.debugMode, this.workspaceContext);
|
|
92
|
+
// setup dynamic tool listener
|
|
93
|
+
const capabilities = this.client.getServerCapabilities();
|
|
94
|
+
if (capabilities?.tools?.listChanged) {
|
|
95
|
+
debugLogger.log(`Server '${this.serverName}' supports tool updates. Listening for changes...`);
|
|
96
|
+
this.client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
97
|
+
debugLogger.log(`🔔 Received tool update notification from '${this.serverName}'`);
|
|
98
|
+
await this.refreshTools();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
86
101
|
const originalOnError = this.client.onerror;
|
|
87
102
|
this.client.onerror = (error) => {
|
|
88
103
|
if (this.status !== MCPServerStatus.CONNECTED) {
|
|
@@ -150,9 +165,11 @@ export class McpClient {
|
|
|
150
165
|
throw new Error(`Client is not connected, must connect before interacting with the server. Current state is ${this.status}`);
|
|
151
166
|
}
|
|
152
167
|
}
|
|
153
|
-
async discoverTools(cliConfig) {
|
|
168
|
+
async discoverTools(cliConfig, options) {
|
|
154
169
|
this.assertConnected();
|
|
155
|
-
return discoverTools(this.serverName, this.serverConfig, this.client, cliConfig, this.toolRegistry.getMessageBus()
|
|
170
|
+
return discoverTools(this.serverName, this.serverConfig, this.client, cliConfig, this.toolRegistry.getMessageBus(), options ?? {
|
|
171
|
+
timeout: this.serverConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
172
|
+
});
|
|
156
173
|
}
|
|
157
174
|
async discoverPrompts() {
|
|
158
175
|
this.assertConnected();
|
|
@@ -164,6 +181,59 @@ export class McpClient {
|
|
|
164
181
|
getInstructions() {
|
|
165
182
|
return this.client?.getInstructions();
|
|
166
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Refreshes the tools for this server by re-querying the MCP `tools/list` endpoint.
|
|
186
|
+
*
|
|
187
|
+
* This method implements a **Coalescing Pattern** to handle rapid bursts of notifications
|
|
188
|
+
* (e.g., during server startup or bulk updates) without overwhelming the server or
|
|
189
|
+
* creating race conditions in the global ToolRegistry.
|
|
190
|
+
*/
|
|
191
|
+
async refreshTools() {
|
|
192
|
+
if (this.isRefreshing) {
|
|
193
|
+
debugLogger.log(`Tool refresh for '${this.serverName}' is already in progress. Pending update.`);
|
|
194
|
+
this.pendingRefresh = true;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
this.isRefreshing = true;
|
|
198
|
+
try {
|
|
199
|
+
do {
|
|
200
|
+
this.pendingRefresh = false;
|
|
201
|
+
if (this.status !== MCPServerStatus.CONNECTED || !this.client)
|
|
202
|
+
break;
|
|
203
|
+
const timeoutMs = this.serverConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC;
|
|
204
|
+
const abortController = new AbortController();
|
|
205
|
+
const timeoutId = setTimeout(() => abortController.abort(), timeoutMs);
|
|
206
|
+
let newTools;
|
|
207
|
+
try {
|
|
208
|
+
newTools = await this.discoverTools(this.cliConfig, {
|
|
209
|
+
signal: abortController.signal,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
debugLogger.error(`Discovery failed during refresh: ${getErrorMessage(err)}`);
|
|
214
|
+
clearTimeout(timeoutId);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
this.toolRegistry.removeMcpToolsByServer(this.serverName);
|
|
218
|
+
for (const tool of newTools) {
|
|
219
|
+
this.toolRegistry.registerTool(tool);
|
|
220
|
+
}
|
|
221
|
+
this.toolRegistry.sortTools();
|
|
222
|
+
if (this.onToolsUpdated) {
|
|
223
|
+
await this.onToolsUpdated(abortController.signal);
|
|
224
|
+
}
|
|
225
|
+
clearTimeout(timeoutId);
|
|
226
|
+
coreEvents.emitFeedback('info', `Tools updated for server: ${this.serverName}`);
|
|
227
|
+
} while (this.pendingRefresh);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
debugLogger.error(`Critical error in refresh loop for ${this.serverName}: ${getErrorMessage(error)}`);
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
this.isRefreshing = false;
|
|
234
|
+
this.pendingRefresh = false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
167
237
|
}
|
|
168
238
|
/**
|
|
169
239
|
* Map to track the status of each MCP server within the core package
|
|
@@ -322,21 +392,6 @@ function createAuthProvider(mcpServerConfig) {
|
|
|
322
392
|
}
|
|
323
393
|
return undefined;
|
|
324
394
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Create a transport for URL based servers (remote servers).
|
|
327
|
-
*
|
|
328
|
-
* @param mcpServerConfig The MCP server configuration
|
|
329
|
-
* @param transportOptions The transport options
|
|
330
|
-
*/
|
|
331
|
-
function createUrlTransport(mcpServerConfig, transportOptions) {
|
|
332
|
-
if (mcpServerConfig.httpUrl) {
|
|
333
|
-
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), transportOptions);
|
|
334
|
-
}
|
|
335
|
-
if (mcpServerConfig.url) {
|
|
336
|
-
return new SSEClientTransport(new URL(mcpServerConfig.url), transportOptions);
|
|
337
|
-
}
|
|
338
|
-
throw new Error('No URL configured for MCP Server');
|
|
339
|
-
}
|
|
340
395
|
/**
|
|
341
396
|
* Create a transport with OAuth token for the given server configuration.
|
|
342
397
|
*
|
|
@@ -353,7 +408,7 @@ async function createTransportWithOAuth(mcpServerName, mcpServerConfig, accessTo
|
|
|
353
408
|
const transportOptions = {
|
|
354
409
|
requestInit: createTransportRequestInit(mcpServerConfig, headers),
|
|
355
410
|
};
|
|
356
|
-
return createUrlTransport(mcpServerConfig, transportOptions);
|
|
411
|
+
return createUrlTransport(mcpServerName, mcpServerConfig, transportOptions);
|
|
357
412
|
}
|
|
358
413
|
catch (error) {
|
|
359
414
|
coreEvents.emitFeedback('error', `Failed to create OAuth transport for server '${mcpServerName}': ${getErrorMessage(error)}`, error);
|
|
@@ -445,7 +500,7 @@ export async function connectAndDiscover(mcpServerName, mcpServerConfig, toolReg
|
|
|
445
500
|
};
|
|
446
501
|
// Attempt to discover both prompts and tools
|
|
447
502
|
const prompts = await discoverPrompts(mcpServerName, mcpClient, promptRegistry);
|
|
448
|
-
const tools = await discoverTools(mcpServerName, mcpServerConfig, mcpClient, cliConfig, toolRegistry.getMessageBus());
|
|
503
|
+
const tools = await discoverTools(mcpServerName, mcpServerConfig, mcpClient, cliConfig, toolRegistry.getMessageBus(), { timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC });
|
|
449
504
|
// If we have neither prompts nor tools, it's a failed discovery
|
|
450
505
|
if (prompts.length === 0 && tools.length === 0) {
|
|
451
506
|
throw new Error('No prompts or tools found on the server.');
|
|
@@ -479,12 +534,12 @@ export async function connectAndDiscover(mcpServerName, mcpServerConfig, toolReg
|
|
|
479
534
|
* @returns A promise that resolves to an array of discovered and enabled tools.
|
|
480
535
|
* @throws An error if no enabled tools are found or if the server provides invalid function declarations.
|
|
481
536
|
*/
|
|
482
|
-
export async function discoverTools(mcpServerName, mcpServerConfig, mcpClient, cliConfig, messageBus) {
|
|
537
|
+
export async function discoverTools(mcpServerName, mcpServerConfig, mcpClient, cliConfig, messageBus, options) {
|
|
483
538
|
try {
|
|
484
539
|
// Only request tools if the server supports them.
|
|
485
540
|
if (mcpClient.getServerCapabilities()?.tools == null)
|
|
486
541
|
return [];
|
|
487
|
-
const response = await mcpClient.listTools({});
|
|
542
|
+
const response = await mcpClient.listTools({}, options);
|
|
488
543
|
const discoveredTools = [];
|
|
489
544
|
for (const toolDef of response.tools) {
|
|
490
545
|
try {
|
|
@@ -639,6 +694,116 @@ export async function invokeMcpPrompt(mcpServerName, mcpClient, promptName, prom
|
|
|
639
694
|
export function hasNetworkTransport(config) {
|
|
640
695
|
return !!(config.url || config.httpUrl);
|
|
641
696
|
}
|
|
697
|
+
/**
|
|
698
|
+
* Helper function to retrieve a stored OAuth token for an MCP server.
|
|
699
|
+
* Handles token validation and refresh automatically.
|
|
700
|
+
*
|
|
701
|
+
* @param serverName The name of the MCP server
|
|
702
|
+
* @returns The valid access token, or null if no token is stored
|
|
703
|
+
*/
|
|
704
|
+
async function getStoredOAuthToken(serverName) {
|
|
705
|
+
const tokenStorage = new MCPOAuthTokenStorage();
|
|
706
|
+
const credentials = await tokenStorage.getCredentials(serverName);
|
|
707
|
+
if (!credentials)
|
|
708
|
+
return null;
|
|
709
|
+
const authProvider = new MCPOAuthProvider(tokenStorage);
|
|
710
|
+
return authProvider.getValidToken(serverName, {
|
|
711
|
+
// Pass client ID if available
|
|
712
|
+
clientId: credentials.clientId,
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Helper function to create an SSE transport with optional OAuth authentication.
|
|
717
|
+
*
|
|
718
|
+
* @param config The MCP server configuration
|
|
719
|
+
* @param accessToken Optional OAuth access token for authentication
|
|
720
|
+
* @returns A configured SSE transport ready for connection
|
|
721
|
+
*/
|
|
722
|
+
function createSSETransportWithAuth(config, accessToken) {
|
|
723
|
+
const headers = {
|
|
724
|
+
...config.headers,
|
|
725
|
+
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
|
726
|
+
};
|
|
727
|
+
const options = {};
|
|
728
|
+
if (Object.keys(headers).length > 0) {
|
|
729
|
+
options.requestInit = { headers };
|
|
730
|
+
}
|
|
731
|
+
return new SSEClientTransport(new URL(config.url), options);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Helper function to connect a client using SSE transport with optional OAuth.
|
|
735
|
+
*
|
|
736
|
+
* @param client The MCP client to connect
|
|
737
|
+
* @param config The MCP server configuration
|
|
738
|
+
* @param accessToken Optional OAuth access token for authentication
|
|
739
|
+
*/
|
|
740
|
+
async function connectWithSSETransport(client, config, accessToken) {
|
|
741
|
+
const transport = createSSETransportWithAuth(config, accessToken);
|
|
742
|
+
await client.connect(transport, {
|
|
743
|
+
timeout: config.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Helper function to show authentication required message and throw error.
|
|
748
|
+
* Checks if there's a stored token that was rejected (requires re-auth).
|
|
749
|
+
*
|
|
750
|
+
* @param serverName The name of the MCP server
|
|
751
|
+
* @throws Always throws an error with authentication instructions
|
|
752
|
+
*/
|
|
753
|
+
async function showAuthRequiredMessage(serverName) {
|
|
754
|
+
const hasRejectedToken = !!(await getStoredOAuthToken(serverName));
|
|
755
|
+
const message = hasRejectedToken
|
|
756
|
+
? `MCP server '${serverName}' rejected stored OAuth token. Please re-authenticate using: /mcp auth ${serverName}`
|
|
757
|
+
: `MCP server '${serverName}' requires authentication using: /mcp auth ${serverName}`;
|
|
758
|
+
coreEvents.emitFeedback('info', message);
|
|
759
|
+
throw new UnauthorizedError(message);
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Helper function to retry connection with OAuth token after authentication.
|
|
763
|
+
* Handles both HTTP and SSE transports based on what previously failed.
|
|
764
|
+
*
|
|
765
|
+
* @param client The MCP client to connect
|
|
766
|
+
* @param serverName The name of the MCP server
|
|
767
|
+
* @param config The MCP server configuration
|
|
768
|
+
* @param accessToken The OAuth access token to use
|
|
769
|
+
* @param httpReturned404 Whether the HTTP transport returned 404 (indicating SSE-only server)
|
|
770
|
+
*/
|
|
771
|
+
async function retryWithOAuth(client, serverName, config, accessToken, httpReturned404) {
|
|
772
|
+
if (httpReturned404) {
|
|
773
|
+
// HTTP returned 404, only try SSE
|
|
774
|
+
debugLogger.log(`Retrying SSE connection to '${serverName}' with OAuth token...`);
|
|
775
|
+
await connectWithSSETransport(client, config, accessToken);
|
|
776
|
+
debugLogger.log(`Successfully connected to '${serverName}' using SSE with OAuth.`);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
// HTTP returned 401, try HTTP with OAuth first
|
|
780
|
+
debugLogger.log(`Retrying connection to '${serverName}' with OAuth token...`);
|
|
781
|
+
const httpTransport = await createTransportWithOAuth(serverName, config, accessToken);
|
|
782
|
+
if (!httpTransport) {
|
|
783
|
+
throw new Error(`Failed to create OAuth transport for server '${serverName}'`);
|
|
784
|
+
}
|
|
785
|
+
try {
|
|
786
|
+
await client.connect(httpTransport, {
|
|
787
|
+
timeout: config.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
788
|
+
});
|
|
789
|
+
debugLogger.log(`Successfully connected to '${serverName}' using HTTP with OAuth.`);
|
|
790
|
+
}
|
|
791
|
+
catch (httpError) {
|
|
792
|
+
await httpTransport.close();
|
|
793
|
+
// If HTTP+OAuth returns 404 and auto-detection enabled, try SSE+OAuth
|
|
794
|
+
if (String(httpError).includes('404') &&
|
|
795
|
+
config.url &&
|
|
796
|
+
!config.type &&
|
|
797
|
+
!config.httpUrl) {
|
|
798
|
+
debugLogger.log(`HTTP with OAuth returned 404, trying SSE with OAuth...`);
|
|
799
|
+
await connectWithSSETransport(client, config, accessToken);
|
|
800
|
+
debugLogger.log(`Successfully connected to '${serverName}' using SSE with OAuth.`);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
throw httpError;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
642
807
|
/**
|
|
643
808
|
* Creates and connects an MCP client to a server based on the provided configuration.
|
|
644
809
|
* It determines the appropriate transport (Stdio, SSE, or Streamable HTTP) and
|
|
@@ -698,6 +863,9 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
698
863
|
unlistenDirectories?.();
|
|
699
864
|
unlistenDirectories = undefined;
|
|
700
865
|
};
|
|
866
|
+
let firstAttemptError = null;
|
|
867
|
+
let httpReturned404 = false; // Track if HTTP returned 404 to skip it in OAuth retry
|
|
868
|
+
let sseError = null; // Track SSE fallback error
|
|
701
869
|
try {
|
|
702
870
|
const transport = await createTransport(mcpServerName, mcpServerConfig, debugMode);
|
|
703
871
|
try {
|
|
@@ -708,52 +876,92 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
708
876
|
}
|
|
709
877
|
catch (error) {
|
|
710
878
|
await transport.close();
|
|
879
|
+
firstAttemptError = error;
|
|
711
880
|
throw error;
|
|
712
881
|
}
|
|
713
882
|
}
|
|
714
|
-
catch (
|
|
883
|
+
catch (initialError) {
|
|
884
|
+
let error = initialError;
|
|
885
|
+
// Check if this is a 401 error FIRST (before attempting SSE fallback)
|
|
886
|
+
// This ensures OAuth flow happens before we try SSE
|
|
887
|
+
if (isAuthenticationError(error) && hasNetworkTransport(mcpServerConfig)) {
|
|
888
|
+
// Continue to OAuth handling below (after SSE fallback section)
|
|
889
|
+
}
|
|
890
|
+
else if (
|
|
891
|
+
// If not 401, and HTTP failed with url without explicit type, try SSE fallback
|
|
892
|
+
firstAttemptError &&
|
|
893
|
+
mcpServerConfig.url &&
|
|
894
|
+
!mcpServerConfig.type &&
|
|
895
|
+
!mcpServerConfig.httpUrl) {
|
|
896
|
+
// Check if HTTP returned 404 - if so, we know it's not an HTTP server
|
|
897
|
+
httpReturned404 = String(firstAttemptError).includes('404');
|
|
898
|
+
const logMessage = httpReturned404
|
|
899
|
+
? `HTTP returned 404, trying SSE transport...`
|
|
900
|
+
: `HTTP connection failed, attempting SSE fallback...`;
|
|
901
|
+
debugLogger.log(`MCP server '${mcpServerName}': ${logMessage}`);
|
|
902
|
+
try {
|
|
903
|
+
// Try SSE with stored OAuth token if available
|
|
904
|
+
// This ensures that SSE fallback works for authenticated servers
|
|
905
|
+
await connectWithSSETransport(mcpClient, mcpServerConfig, await getStoredOAuthToken(mcpServerName));
|
|
906
|
+
debugLogger.log(`MCP server '${mcpServerName}': Successfully connected using SSE transport.`);
|
|
907
|
+
return mcpClient;
|
|
908
|
+
}
|
|
909
|
+
catch (sseFallbackError) {
|
|
910
|
+
sseError = sseFallbackError;
|
|
911
|
+
// If SSE also returned 401, handle OAuth below
|
|
912
|
+
if (isAuthenticationError(sseError)) {
|
|
913
|
+
debugLogger.log(`MCP server '${mcpServerName}': SSE returned 401, OAuth authentication required.`);
|
|
914
|
+
// Update error to be the SSE error for OAuth handling
|
|
915
|
+
error = sseError;
|
|
916
|
+
// Continue to OAuth handling below
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
debugLogger.log(`MCP server '${mcpServerName}': SSE fallback also failed.`);
|
|
920
|
+
// Both failed without 401, throw the original error
|
|
921
|
+
throw firstAttemptError;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
715
925
|
// Check if this is a 401 error that might indicate OAuth is required
|
|
716
|
-
|
|
717
|
-
if (errorString.includes('401') && hasNetworkTransport(mcpServerConfig)) {
|
|
926
|
+
if (isAuthenticationError(error) && hasNetworkTransport(mcpServerConfig)) {
|
|
718
927
|
mcpServerRequiresOAuth.set(mcpServerName, true);
|
|
719
|
-
// Only trigger automatic OAuth
|
|
720
|
-
//
|
|
721
|
-
const shouldTriggerOAuth = mcpServerConfig.
|
|
928
|
+
// Only trigger automatic OAuth if explicitly enabled in config
|
|
929
|
+
// Otherwise, show error and tell user to run /mcp auth command
|
|
930
|
+
const shouldTriggerOAuth = mcpServerConfig.oauth?.enabled;
|
|
722
931
|
if (!shouldTriggerOAuth) {
|
|
723
|
-
|
|
724
|
-
const tokenStorage = new MCPOAuthTokenStorage();
|
|
725
|
-
const credentials = await tokenStorage.getCredentials(mcpServerName);
|
|
726
|
-
if (credentials) {
|
|
727
|
-
const authProvider = new MCPOAuthProvider(tokenStorage);
|
|
728
|
-
const hasStoredTokens = await authProvider.getValidToken(mcpServerName, {
|
|
729
|
-
// Pass client ID if available
|
|
730
|
-
clientId: credentials.clientId,
|
|
731
|
-
});
|
|
732
|
-
if (hasStoredTokens) {
|
|
733
|
-
coreEvents.emitFeedback('error', `Stored OAuth token for SSE server '${mcpServerName}' was rejected. ` +
|
|
734
|
-
`Please re-authenticate using: /mcp auth ${mcpServerName}`);
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
coreEvents.emitFeedback('error', `401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
738
|
-
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
throw new Error(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
742
|
-
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
932
|
+
await showAuthRequiredMessage(mcpServerName);
|
|
743
933
|
}
|
|
744
934
|
// Try to extract www-authenticate header from the error
|
|
935
|
+
const errorString = String(error);
|
|
745
936
|
let wwwAuthenticate = extractWWWAuthenticateHeader(errorString);
|
|
746
937
|
// If we didn't get the header from the error string, try to get it from the server
|
|
747
938
|
if (!wwwAuthenticate && hasNetworkTransport(mcpServerConfig)) {
|
|
748
939
|
debugLogger.log(`No www-authenticate header in error, trying to fetch it from server...`);
|
|
749
940
|
try {
|
|
750
941
|
const urlToFetch = mcpServerConfig.httpUrl || mcpServerConfig.url;
|
|
942
|
+
// Determine correct Accept header based on what transport failed
|
|
943
|
+
let acceptHeader;
|
|
944
|
+
if (mcpServerConfig.httpUrl) {
|
|
945
|
+
acceptHeader = 'application/json';
|
|
946
|
+
}
|
|
947
|
+
else if (mcpServerConfig.type === 'http') {
|
|
948
|
+
acceptHeader = 'application/json';
|
|
949
|
+
}
|
|
950
|
+
else if (mcpServerConfig.type === 'sse') {
|
|
951
|
+
acceptHeader = 'text/event-stream';
|
|
952
|
+
}
|
|
953
|
+
else if (httpReturned404) {
|
|
954
|
+
// HTTP failed with 404, SSE returned 401 - use SSE header
|
|
955
|
+
acceptHeader = 'text/event-stream';
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
// HTTP returned 401 - use HTTP header
|
|
959
|
+
acceptHeader = 'application/json';
|
|
960
|
+
}
|
|
751
961
|
const response = await fetch(urlToFetch, {
|
|
752
962
|
method: 'HEAD',
|
|
753
963
|
headers: {
|
|
754
|
-
Accept:
|
|
755
|
-
? 'application/json'
|
|
756
|
-
: 'text/event-stream',
|
|
964
|
+
Accept: acceptHeader,
|
|
757
965
|
},
|
|
758
966
|
signal: AbortSignal.timeout(5000),
|
|
759
967
|
});
|
|
@@ -774,38 +982,12 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
774
982
|
const oauthSuccess = await handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthenticate);
|
|
775
983
|
if (oauthSuccess) {
|
|
776
984
|
// Retry connection with OAuth token
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
const tokenStorage = new MCPOAuthTokenStorage();
|
|
781
|
-
const credentials = await tokenStorage.getCredentials(mcpServerName);
|
|
782
|
-
if (credentials) {
|
|
783
|
-
const authProvider = new MCPOAuthProvider(tokenStorage);
|
|
784
|
-
const accessToken = await authProvider.getValidToken(mcpServerName, {
|
|
785
|
-
// Pass client ID if available
|
|
786
|
-
clientId: credentials.clientId,
|
|
787
|
-
});
|
|
788
|
-
if (accessToken) {
|
|
789
|
-
// Create transport with OAuth token
|
|
790
|
-
const oauthTransport = await createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken);
|
|
791
|
-
if (oauthTransport) {
|
|
792
|
-
await mcpClient.connect(oauthTransport, {
|
|
793
|
-
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
794
|
-
});
|
|
795
|
-
// Connection successful with OAuth
|
|
796
|
-
return mcpClient;
|
|
797
|
-
}
|
|
798
|
-
else {
|
|
799
|
-
throw new Error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
else {
|
|
807
|
-
throw new Error(`Failed to get credentials for server '${mcpServerName}' after successful OAuth authentication`);
|
|
985
|
+
const accessToken = await getStoredOAuthToken(mcpServerName);
|
|
986
|
+
if (!accessToken) {
|
|
987
|
+
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
808
988
|
}
|
|
989
|
+
await retryWithOAuth(mcpClient, mcpServerName, mcpServerConfig, accessToken, httpReturned404);
|
|
990
|
+
return mcpClient;
|
|
809
991
|
}
|
|
810
992
|
else {
|
|
811
993
|
throw new Error(`Failed to handle automatic OAuth for server '${mcpServerName}'`);
|
|
@@ -813,29 +995,10 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
813
995
|
}
|
|
814
996
|
else {
|
|
815
997
|
// No www-authenticate header found, but we got a 401
|
|
816
|
-
// Only try OAuth discovery
|
|
817
|
-
|
|
818
|
-
const shouldTryDiscovery = mcpServerConfig.httpUrl || mcpServerConfig.oauth?.enabled;
|
|
998
|
+
// Only try OAuth discovery when OAuth is explicitly enabled in config
|
|
999
|
+
const shouldTryDiscovery = mcpServerConfig.oauth?.enabled;
|
|
819
1000
|
if (!shouldTryDiscovery) {
|
|
820
|
-
|
|
821
|
-
const credentials = await tokenStorage.getCredentials(mcpServerName);
|
|
822
|
-
if (credentials) {
|
|
823
|
-
const authProvider = new MCPOAuthProvider(tokenStorage);
|
|
824
|
-
const hasStoredTokens = await authProvider.getValidToken(mcpServerName, {
|
|
825
|
-
// Pass client ID if available
|
|
826
|
-
clientId: credentials.clientId,
|
|
827
|
-
});
|
|
828
|
-
if (hasStoredTokens) {
|
|
829
|
-
coreEvents.emitFeedback('error', `Stored OAuth token for SSE server '${mcpServerName}' was rejected. ` +
|
|
830
|
-
`Please re-authenticate using: /mcp auth ${mcpServerName}`);
|
|
831
|
-
}
|
|
832
|
-
else {
|
|
833
|
-
coreEvents.emitFeedback('error', `401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
834
|
-
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
throw new Error(`401 error received for SSE server '${mcpServerName}' without OAuth configuration. ` +
|
|
838
|
-
`Please authenticate using: /mcp auth ${mcpServerName}`);
|
|
1001
|
+
await showAuthRequiredMessage(mcpServerName);
|
|
839
1002
|
}
|
|
840
1003
|
// For SSE/HTTP servers, try to discover OAuth configuration from the base URL
|
|
841
1004
|
debugLogger.log(`🔍 Attempting OAuth discovery for '${mcpServerName}'...`);
|
|
@@ -860,35 +1023,20 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
860
1023
|
const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
|
|
861
1024
|
await authProvider.authenticate(mcpServerName, oauthAuthConfig, authServerUrl);
|
|
862
1025
|
// Retry connection with OAuth token
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const authProvider = new MCPOAuthProvider(tokenStorage);
|
|
867
|
-
const accessToken = await authProvider.getValidToken(mcpServerName, {
|
|
868
|
-
// Pass client ID if available
|
|
869
|
-
clientId: credentials.clientId,
|
|
870
|
-
});
|
|
871
|
-
if (accessToken) {
|
|
872
|
-
// Create transport with OAuth token
|
|
873
|
-
const oauthTransport = await createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken);
|
|
874
|
-
if (oauthTransport) {
|
|
875
|
-
await mcpClient.connect(oauthTransport, {
|
|
876
|
-
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
877
|
-
});
|
|
878
|
-
// Connection successful with OAuth
|
|
879
|
-
return mcpClient;
|
|
880
|
-
}
|
|
881
|
-
else {
|
|
882
|
-
throw new Error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
else {
|
|
886
|
-
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
887
|
-
}
|
|
1026
|
+
const accessToken = await getStoredOAuthToken(mcpServerName);
|
|
1027
|
+
if (!accessToken) {
|
|
1028
|
+
throw new Error(`Failed to get OAuth token for server '${mcpServerName}'`);
|
|
888
1029
|
}
|
|
889
|
-
|
|
890
|
-
|
|
1030
|
+
// Create transport with OAuth token
|
|
1031
|
+
const oauthTransport = await createTransportWithOAuth(mcpServerName, mcpServerConfig, accessToken);
|
|
1032
|
+
if (!oauthTransport) {
|
|
1033
|
+
throw new Error(`Failed to create OAuth transport for server '${mcpServerName}'`);
|
|
891
1034
|
}
|
|
1035
|
+
await mcpClient.connect(oauthTransport, {
|
|
1036
|
+
timeout: mcpServerConfig.timeout ?? MCP_DEFAULT_TIMEOUT_MSEC,
|
|
1037
|
+
});
|
|
1038
|
+
// Connection successful with OAuth
|
|
1039
|
+
return mcpClient;
|
|
892
1040
|
}
|
|
893
1041
|
else {
|
|
894
1042
|
throw new Error(`OAuth configuration failed for '${mcpServerName}'. Please authenticate manually with /mcp auth ${mcpServerName}`);
|
|
@@ -901,23 +1049,38 @@ export async function connectToMcpServer(mcpServerName, mcpServerConfig, debugMo
|
|
|
901
1049
|
}
|
|
902
1050
|
else {
|
|
903
1051
|
// Handle other connection errors
|
|
904
|
-
//
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
}
|
|
918
|
-
|
|
1052
|
+
// Re-throw the original error to preserve its structure
|
|
1053
|
+
throw error;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Helper function to create the appropriate transport based on config
|
|
1059
|
+
* This handles the logic for httpUrl/url/type consistently
|
|
1060
|
+
*/
|
|
1061
|
+
function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
|
|
1062
|
+
// Priority 1: httpUrl (deprecated)
|
|
1063
|
+
if (mcpServerConfig.httpUrl) {
|
|
1064
|
+
if (mcpServerConfig.url) {
|
|
1065
|
+
debugLogger.warn(`MCP server '${mcpServerName}': Both 'httpUrl' and 'url' are configured. ` +
|
|
1066
|
+
`Using deprecated 'httpUrl'. Please migrate to 'url' with 'type: "http"'.`);
|
|
1067
|
+
}
|
|
1068
|
+
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), transportOptions);
|
|
1069
|
+
}
|
|
1070
|
+
// Priority 2 & 3: url with explicit type
|
|
1071
|
+
if (mcpServerConfig.url && mcpServerConfig.type) {
|
|
1072
|
+
if (mcpServerConfig.type === 'http') {
|
|
1073
|
+
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
|
|
1074
|
+
}
|
|
1075
|
+
else if (mcpServerConfig.type === 'sse') {
|
|
1076
|
+
return new SSEClientTransport(new URL(mcpServerConfig.url), transportOptions);
|
|
919
1077
|
}
|
|
920
1078
|
}
|
|
1079
|
+
// Priority 4: url without type (default to HTTP)
|
|
1080
|
+
if (mcpServerConfig.url) {
|
|
1081
|
+
return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
|
|
1082
|
+
}
|
|
1083
|
+
throw new Error(`No URL configured for MCP server '${mcpServerName}'`);
|
|
921
1084
|
}
|
|
922
1085
|
/** Visible for Testing */
|
|
923
1086
|
export async function createTransport(mcpServerName, mcpServerConfig, debugMode) {
|
|
@@ -937,33 +1100,23 @@ export async function createTransport(mcpServerName, mcpServerConfig, debugMode)
|
|
|
937
1100
|
if (authProvider === undefined) {
|
|
938
1101
|
// Check if we have OAuth configuration or stored tokens
|
|
939
1102
|
let accessToken = null;
|
|
940
|
-
|
|
941
|
-
if (hasOAuthConfig && mcpServerConfig.oauth) {
|
|
1103
|
+
if (mcpServerConfig.oauth?.enabled && mcpServerConfig.oauth) {
|
|
942
1104
|
const tokenStorage = new MCPOAuthTokenStorage();
|
|
943
1105
|
const mcpAuthProvider = new MCPOAuthProvider(tokenStorage);
|
|
944
1106
|
accessToken = await mcpAuthProvider.getValidToken(mcpServerName, mcpServerConfig.oauth);
|
|
945
1107
|
if (!accessToken) {
|
|
946
|
-
|
|
947
|
-
|
|
1108
|
+
// Emit info message (not error) since this is expected behavior
|
|
1109
|
+
coreEvents.emitFeedback('info', `MCP server '${mcpServerName}' requires authentication using: /mcp auth ${mcpServerName}`);
|
|
948
1110
|
}
|
|
949
1111
|
}
|
|
950
1112
|
else {
|
|
951
1113
|
// Check if we have stored OAuth tokens for this server (from previous authentication)
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const mcpAuthProvider = new MCPOAuthProvider(tokenStorage);
|
|
956
|
-
accessToken = await mcpAuthProvider.getValidToken(mcpServerName, {
|
|
957
|
-
// Pass client ID if available
|
|
958
|
-
clientId: credentials.clientId,
|
|
959
|
-
});
|
|
960
|
-
if (accessToken) {
|
|
961
|
-
hasOAuthConfig = true;
|
|
962
|
-
debugLogger.log(`Found stored OAuth token for server '${mcpServerName}'`);
|
|
963
|
-
}
|
|
1114
|
+
accessToken = await getStoredOAuthToken(mcpServerName);
|
|
1115
|
+
if (accessToken) {
|
|
1116
|
+
debugLogger.log(`Found stored OAuth token for server '${mcpServerName}'`);
|
|
964
1117
|
}
|
|
965
1118
|
}
|
|
966
|
-
if (
|
|
1119
|
+
if (accessToken) {
|
|
967
1120
|
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
968
1121
|
}
|
|
969
1122
|
}
|
|
@@ -971,7 +1124,7 @@ export async function createTransport(mcpServerName, mcpServerConfig, debugMode)
|
|
|
971
1124
|
requestInit: createTransportRequestInit(mcpServerConfig, headers),
|
|
972
1125
|
authProvider,
|
|
973
1126
|
};
|
|
974
|
-
return createUrlTransport(mcpServerConfig, transportOptions);
|
|
1127
|
+
return createUrlTransport(mcpServerName, mcpServerConfig, transportOptions);
|
|
975
1128
|
}
|
|
976
1129
|
if (mcpServerConfig.command) {
|
|
977
1130
|
const transport = new StdioClientTransport({
|