@@ -73,24 +73,24 @@ def initialize( # rubocop:disable Metrics/ParameterLists
7373 @protocol_version = nil
7474 @session_id = session_id
7575
76- @resource_metadata_url = nil
77- @client_id = SecureRandom . uuid
78-
79- @reconnection_options = ReconnectionOptions . new ( **reconnection )
80- @oauth_provider = oauth_provider
81- @rate_limiter = Support ::RateLimiter . new ( **rate_limit ) if rate_limit
82-
83- @id_counter = 0
84- @id_mutex = Mutex . new
85- @pending_requests = { }
86- @pending_mutex = Mutex . new
87- @running = true
88- @abort_controller = nil
89- @sse_thread = nil
90- @sse_mutex = Mutex . new
91-
92- # Track if we've attempted auth flow to prevent infinite loops
93- @auth_retry_attempted = false
76+ @resource_metadata_url = nil
77+ @client_id = SecureRandom . uuid
78+
79+ @reconnection_options = ReconnectionOptions . new ( **reconnection )
80+ @oauth_provider = oauth_provider
81+ @rate_limiter = Support ::RateLimiter . new ( **rate_limit ) if rate_limit
82+
83+ @id_counter = 0
84+ @id_mutex = Mutex . new
85+ @pending_requests = { }
86+ @pending_mutex = Mutex . new
87+ @running = true
88+ @abort_controller = nil
89+ @sse_thread = nil
90+ @sse_mutex = Mutex . new
91+
92+ # Track if we've attempted auth flow to prevent infinite loops
93+ @auth_retry_attempted = false
9494
9595 # Thread-safe collection of all HTTPX clients
9696 @clients = [ ]
@@ -489,67 +489,64 @@ def extract_resource_metadata_url(response)
489489 end
490490
491491 def handle_authentication_challenge ( response , request_id , original_message )
492- # If we've already attempted auth retry, don't try again (prevent infinite loop)
493- if @auth_retry_attempted
494- RubyLLM ::MCP . logger . warn ( "Authentication retry already attempted, raising error" )
495- @auth_retry_attempted = false # Reset for next request
496- raise Errors ::AuthenticationRequiredError . new (
497- message : "OAuth authentication required (401 Unauthorized) - retry failed"
498- )
499- end
500-
501- # No OAuth provider configured - can't handle challenge
502- unless @oauth_provider
503- raise Errors ::AuthenticationRequiredError . new (
504- message : "OAuth authentication required (401 Unauthorized) but no OAuth provider configured"
505- )
506- end
492+ check_retry_guard!
493+ check_oauth_provider_configured!
507494
508495 RubyLLM ::MCP . logger . info ( "Received 401 Unauthorized, attempting automatic authentication" )
509496
510- # Extract challenge information from response
511497 www_authenticate = response . headers [ "www-authenticate" ]
512498 resource_metadata_url = extract_resource_metadata_url ( response )
513499
514- begin
515- # Set flag to prevent infinite retry loop
516- @auth_retry_attempted = true
517-
518- # Ask OAuth provider to handle the challenge
519- success = @oauth_provider . handle_authentication_challenge (
520- www_authenticate : www_authenticate ,
521- resource_metadata_url : resource_metadata_url &.to_s ,
522- requested_scope : nil
523- )
500+ attempt_authentication_retry ( www_authenticate , resource_metadata_url , request_id , original_message )
501+ end
524502
525- if success
526- RubyLLM :: MCP . logger . info ( "Authentication challenge handled successfully, retrying request" )
503+ def check_retry_guard!
504+ return unless @auth_retry_attempted
527505
528- # Retry the original request with new auth (flag stays true to prevent loop)
529- result = send_http_request ( original_message , request_id , is_initialization : false )
506+ RubyLLM ::MCP . logger . warn ( "Authentication retry already attempted, raising error" )
507+ @auth_retry_attempted = false
508+ raise Errors ::AuthenticationRequiredError . new (
509+ message : "OAuth authentication required (401 Unauthorized) - retry failed"
510+ )
511+ end
530512
531- # Only reset flag after successful retry
532- @auth_retry_attempted = false
533- return result
534- end
535- rescue Errors ::AuthenticationRequiredError => e
536- # Reset flag and re-raise
537- @auth_retry_attempted = false
538- raise e
539- rescue StandardError => e
540- # Reset flag and wrap error
513+ def check_oauth_provider_configured!
514+ return if @oauth_provider
515+
516+ raise Errors ::AuthenticationRequiredError . new (
517+ message : "OAuth authentication required (401 Unauthorized) but no OAuth provider configured"
518+ )
519+ end
520+
521+ def attempt_authentication_retry ( www_authenticate , resource_metadata_url , request_id , original_message )
522+ @auth_retry_attempted = true
523+
524+ success = @oauth_provider . handle_authentication_challenge (
525+ www_authenticate : www_authenticate ,
526+ resource_metadata_url : resource_metadata_url &.to_s ,
527+ requested_scope : nil
528+ )
529+
530+ if success
531+ RubyLLM ::MCP . logger . info ( "Authentication challenge handled successfully, retrying request" )
532+ result = send_http_request ( original_message , request_id , is_initialization : false )
541533 @auth_retry_attempted = false
542- RubyLLM ::MCP . logger . error ( "Authentication challenge handling failed: #{ e . message } " )
543- raise Errors ::AuthenticationRequiredError . new (
544- message : "OAuth authentication failed: #{ e . message } "
545- )
534+ return result
546535 end
547536
548- # If we get here, authentication didn't succeed
549537 @auth_retry_attempted = false
550538 raise Errors ::AuthenticationRequiredError . new (
551539 message : "OAuth authentication required (401 Unauthorized)"
552540 )
541+ rescue Errors ::AuthenticationRequiredError => e
542+ @auth_retry_attempted = false
543+ raise e
544+ rescue StandardError => e
545+ @auth_retry_attempted = false
546+ RubyLLM ::MCP . logger . error ( "Authentication challenge handling failed: #{ e . message } " )
547+ raise Errors ::AuthenticationRequiredError . new (
548+ message : "OAuth authentication failed: #{ e . message } "
549+ )
553550 end
554551
555552 def start_sse_stream ( options = StartSSEOptions . new )
0 commit comments