@@ -308,13 +308,16 @@ export namespace MCP {
308308 let authProvider : McpOAuthProvider | undefined
309309
310310 if ( ! oauthDisabled ) {
311+ await McpOAuthCallback . ensureRunning ( oauthConfig ?. redirectUri )
312+
311313 authProvider = new McpOAuthProvider (
312314 key ,
313315 mcp . url ,
314316 {
315317 clientId : oauthConfig ?. clientId ,
316318 clientSecret : oauthConfig ?. clientSecret ,
317319 scope : oauthConfig ?. scope ,
320+ redirectUri : oauthConfig ?. redirectUri ,
318321 } ,
319322 {
320323 onRedirect : async ( url ) => {
@@ -344,6 +347,7 @@ export namespace MCP {
344347
345348 let lastError : Error | undefined
346349 const connectTimeout = mcp . timeout ?? DEFAULT_TIMEOUT
350+
347351 for ( const { name, transport } of transports ) {
348352 try {
349353 const client = new Client ( {
@@ -570,7 +574,8 @@ export namespace MCP {
570574
571575 for ( const [ clientName , client ] of Object . entries ( clientsSnapshot ) ) {
572576 // Only include tools from connected MCPs (skip disabled ones)
573- if ( s . status [ clientName ] ?. status !== "connected" ) {
577+ const clientStatus = s . status [ clientName ] ?. status
578+ if ( clientStatus !== "connected" ) {
574579 continue
575580 }
576581
@@ -720,8 +725,10 @@ export namespace MCP {
720725 throw new Error ( `MCP server ${ mcpName } has OAuth explicitly disabled` )
721726 }
722727
723- // Start the callback server
724- await McpOAuthCallback . ensureRunning ( )
728+ // OAuth config is optional - if not provided, we'll use auto-discovery
729+ const oauthConfig = typeof mcpConfig . oauth === "object" ? mcpConfig . oauth : undefined
730+
731+ await McpOAuthCallback . ensureRunning ( oauthConfig ?. redirectUri )
725732
726733 // Generate and store a cryptographically secure state parameter BEFORE creating the provider
727734 // The SDK will call provider.state() to read this value
@@ -731,8 +738,6 @@ export namespace MCP {
731738 await McpAuth . updateOAuthState ( mcpName , oauthState )
732739
733740 // Create a new auth provider for this flow
734- // OAuth config is optional - if not provided, we'll use auto-discovery
735- const oauthConfig = typeof mcpConfig . oauth === "object" ? mcpConfig . oauth : undefined
736741 let capturedUrl : URL | undefined
737742 const authProvider = new McpOAuthProvider (
738743 mcpName ,
@@ -741,6 +746,7 @@ export namespace MCP {
741746 clientId : oauthConfig ?. clientId ,
742747 clientSecret : oauthConfig ?. clientSecret ,
743748 scope : oauthConfig ?. scope ,
749+ redirectUri : oauthConfig ?. redirectUri ,
744750 } ,
745751 {
746752 onRedirect : async ( url ) => {
@@ -769,6 +775,7 @@ export namespace MCP {
769775 pendingOAuthTransports . set ( mcpName , transport )
770776 return { authorizationUrl : capturedUrl . toString ( ) }
771777 }
778+
772779 throw error
773780 }
774781 }
@@ -778,9 +785,9 @@ export namespace MCP {
778785 * Opens the browser and waits for callback.
779786 */
780787 export async function authenticate ( mcpName : string ) : Promise < Status > {
781- const { authorizationUrl } = await startAuth ( mcpName )
788+ const result = await startAuth ( mcpName )
782789
783- if ( ! authorizationUrl ) {
790+ if ( ! result . authorizationUrl ) {
784791 // Already authenticated
785792 const s = await state ( )
786793 return s . status [ mcpName ] ?? { status : "connected" }
@@ -794,9 +801,9 @@ export namespace MCP {
794801
795802 // The SDK has already added the state parameter to the authorization URL
796803 // We just need to open the browser
797- log . info ( "opening browser for oauth" , { mcpName, url : authorizationUrl , state : oauthState } )
804+ log . info ( "opening browser for oauth" , { mcpName, url : result . authorizationUrl , state : oauthState } )
798805 try {
799- const subprocess = await open ( authorizationUrl )
806+ const subprocess = await open ( result . authorizationUrl )
800807 // The open package spawns a detached process and returns immediately.
801808 // We need to listen for errors which fire asynchronously:
802809 // - "error" event: command not found (ENOENT)
@@ -819,7 +826,7 @@ export namespace MCP {
819826 // Browser opening failed (e.g., in remote/headless sessions like SSH, devcontainers)
820827 // Emit event so CLI can display the URL for manual opening
821828 log . warn ( "failed to open browser, user must open URL manually" , { mcpName, error } )
822- Bus . publish ( BrowserOpenFailed , { mcpName, url : authorizationUrl } )
829+ Bus . publish ( BrowserOpenFailed , { mcpName, url : result . authorizationUrl } )
823830 }
824831
825832 // Wait for callback using the OAuth state parameter
0 commit comments