Skip to content

Commit fc4a6ec

Browse files
authored
fix: Connect error in URL elicitation example (#1136)
1 parent 9df0972 commit fc4a6ec

File tree

1 file changed

+51
-46
lines changed

1 file changed

+51
-46
lines changed

src/examples/client/elicitationUrlExample.ts

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,42 @@ async function waitForOAuthCallback(): Promise<string> {
477477
});
478478
}
479479

480+
/**
481+
* Attempts to connect to the MCP server with OAuth authentication.
482+
* Handles OAuth flow recursively if authorization is required.
483+
*/
484+
async function attemptConnection(oauthProvider: InMemoryOAuthClientProvider): Promise<void> {
485+
console.log('🚢 Creating transport with OAuth provider...');
486+
const baseUrl = new URL(serverUrl);
487+
transport = new StreamableHTTPClientTransport(baseUrl, {
488+
sessionId: sessionId,
489+
authProvider: oauthProvider
490+
});
491+
console.log('🚢 Transport created');
492+
493+
try {
494+
console.log('🔌 Attempting connection (this will trigger OAuth redirect if needed)...');
495+
await client!.connect(transport);
496+
sessionId = transport.sessionId;
497+
console.log('Transport created with session ID:', sessionId);
498+
console.log('✅ Connected successfully');
499+
} catch (error) {
500+
if (error instanceof UnauthorizedError) {
501+
console.log('🔐 OAuth required - waiting for authorization...');
502+
const callbackPromise = waitForOAuthCallback();
503+
const authCode = await callbackPromise;
504+
await transport.finishAuth(authCode);
505+
console.log('🔐 Authorization code received:', authCode);
506+
console.log('🔌 Reconnecting with authenticated transport...');
507+
// Recursively retry connection after OAuth completion
508+
await attemptConnection(oauthProvider);
509+
} else {
510+
console.error('❌ Connection failed with non-auth error:', error);
511+
throw error;
512+
}
513+
}
514+
}
515+
480516
async function connect(url?: string): Promise<void> {
481517
if (client) {
482518
console.log('Already connected. Disconnect first.');
@@ -487,7 +523,10 @@ async function connect(url?: string): Promise<void> {
487523
serverUrl = url;
488524
}
489525

526+
console.log(`🔗 Attempting to connect to ${serverUrl}...`);
527+
490528
// Create a new client with elicitation capability
529+
console.log('👤 Creating MCP client...');
491530
client = new Client(
492531
{
493532
name: 'example-client',
@@ -503,19 +542,7 @@ async function connect(url?: string): Promise<void> {
503542
}
504543
}
505544
);
506-
if (!transport) {
507-
// Only create a new transport if one doesn't exist
508-
transport = new StreamableHTTPClientTransport(new URL(serverUrl), {
509-
sessionId: sessionId,
510-
authProvider: oauthProvider,
511-
requestInit: {
512-
headers: {
513-
'Content-Type': 'application/json',
514-
Accept: 'application/json, text/event-stream'
515-
}
516-
}
517-
});
518-
}
545+
console.log('👤 Client created');
519546

520547
// Set up elicitation request handler with proper validation
521548
client.setRequestHandler(ElicitRequestSchema, elicitationRequestHandler);
@@ -536,42 +563,20 @@ async function connect(url?: string): Promise<void> {
536563
});
537564

538565
try {
539-
console.log(`Connecting to ${serverUrl}...`);
540-
// Connect the client
541-
await client.connect(transport);
542-
sessionId = transport.sessionId;
543-
console.log('Transport created with session ID:', sessionId);
566+
console.log('🔐 Starting OAuth flow...');
567+
await attemptConnection(oauthProvider!);
544568
console.log('Connected to MCP server');
569+
570+
// Set up error handler after connection is established so we don't double log errors
571+
client.onerror = error => {
572+
console.error('\x1b[31mClient error:', error, '\x1b[0m');
573+
};
545574
} catch (error) {
546-
if (error instanceof UnauthorizedError) {
547-
console.log('OAuth required - waiting for authorization...');
548-
const callbackPromise = waitForOAuthCallback();
549-
const authCode = await callbackPromise;
550-
await transport.finishAuth(authCode);
551-
console.log('🔐 Authorization code received:', authCode);
552-
console.log('🔌 Reconnecting with authenticated transport...');
553-
transport = new StreamableHTTPClientTransport(new URL(serverUrl), {
554-
sessionId: sessionId,
555-
authProvider: oauthProvider,
556-
requestInit: {
557-
headers: {
558-
'Content-Type': 'application/json',
559-
Accept: 'application/json, text/event-stream'
560-
}
561-
}
562-
});
563-
await client.connect(transport);
564-
} else {
565-
console.error('Failed to connect:', error);
566-
client = null;
567-
transport = null;
568-
return;
569-
}
575+
console.error('Failed to connect:', error);
576+
client = null;
577+
transport = null;
578+
return;
570579
}
571-
// Set up error handler after connection is established so we don't double log errors
572-
client.onerror = error => {
573-
console.error('\x1b[31mClient error:', error, '\x1b[0m');
574-
};
575580
}
576581

577582
async function disconnect(): Promise<void> {

0 commit comments

Comments
 (0)