@@ -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+
480516async 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
577582async function disconnect ( ) : Promise < void > {
0 commit comments