diff --git a/crates/rmcp/src/transport/auth.rs b/crates/rmcp/src/transport/auth.rs index 5e73a332..ac55e5e4 100644 --- a/crates/rmcp/src/transport/auth.rs +++ b/crates/rmcp/src/transport/auth.rs @@ -14,7 +14,7 @@ use reqwest::{Client as HttpClient, IntoUrl, StatusCode, Url, header::AUTHORIZAT use serde::{Deserialize, Serialize}; use thiserror::Error; use tokio::sync::{Mutex, RwLock}; -use tracing::{debug, error}; +use tracing::{debug, error, warn}; const DEFAULT_EXCHANGE_URL: &str = "http://localhost"; @@ -102,7 +102,7 @@ pub enum AuthError { pub struct AuthorizationMetadata { pub authorization_endpoint: String, pub token_endpoint: String, - pub registration_endpoint: String, + pub registration_endpoint: Option, pub issuer: Option, pub jwks_uri: Option, pub scopes_supported: Option>, @@ -273,7 +273,7 @@ impl AuthorizationManager { return Ok(metadata); } - debug!("No valid .well-known endpoint found, falling back to default endpoints"); + warn!("No valid .well-known endpoint found, falling back to default endpoints"); // fallback to default endpoints let mut auth_base = self.base_url.clone(); @@ -290,7 +290,7 @@ impl AuthorizationManager { Ok(AuthorizationMetadata { authorization_endpoint: create_endpoint("authorize"), token_endpoint: create_endpoint("token"), - registration_endpoint: create_endpoint("register"), + registration_endpoint: None, issuer: None, jwks_uri: None, scopes_supported: None, @@ -323,12 +323,10 @@ impl AuthorizationManager { let token_url = TokenUrl::new(metadata.token_endpoint.clone()) .map_err(|e| AuthError::OAuthError(format!("Invalid token URL: {}", e)))?; - // debug!("token url: {:?}", token_url); let client_id = ClientId::new(config.client_id); let redirect_url = RedirectUrl::new(config.redirect_uri.clone()) .map_err(|e| AuthError::OAuthError(format!("Invalid re URL: {}", e)))?; - debug!("client_id: {:?}", client_id); let mut client_builder = BasicClient::new(client_id.clone()) .set_auth_uri(auth_url) .set_token_uri(token_url) @@ -349,14 +347,16 @@ impl AuthorizationManager { redirect_uri: &str, ) -> Result { if self.metadata.is_none() { - error!("No authorization support detected"); return Err(AuthError::NoAuthorizationSupport); } let metadata = self.metadata.as_ref().unwrap(); - let registration_url = metadata.registration_endpoint.clone(); + let Some(registration_url) = metadata.registration_endpoint.as_ref() else { + return Err(AuthError::RegistrationFailed( + "Dynamic client registration not supported".to_string(), + )); + }; - debug!("registration url: {:?}", registration_url); // prepare registration request let registration_request = ClientRegistrationRequest { client_name: name.to_string(), @@ -369,8 +369,6 @@ impl AuthorizationManager { response_types: vec!["code".to_string()], }; - debug!("registration request: {:?}", registration_request); - let response = match self .http_client .post(registration_url) @@ -380,7 +378,6 @@ impl AuthorizationManager { { Ok(response) => response, Err(e) => { - error!("Registration request failed: {}", e); return Err(AuthError::RegistrationFailed(format!( "HTTP request error: {}", e @@ -395,7 +392,6 @@ impl AuthorizationManager { Err(_) => "cannot get error details".to_string(), }; - error!("Registration failed: HTTP {} - {}", status, error_text); return Err(AuthError::RegistrationFailed(format!( "HTTP {}: {}", status, error_text @@ -406,7 +402,6 @@ impl AuthorizationManager { let reg_response = match response.json::().await { Ok(response) => response, Err(e) => { - error!("Failed to parse registration response: {}", e); return Err(AuthError::RegistrationFailed(format!( "analyze response error: {}", e @@ -471,7 +466,6 @@ impl AuthorizationManager { pkce_verifier, csrf_token, }); - debug!("set authorization state: {:?}", self.state.read().await); Ok(auth_url.to_string()) } @@ -625,9 +619,9 @@ impl AuthorizationSession { redirect_uri: &str, client_name: Option<&str>, ) -> Result { - // set redirect uri + // Default client config let config = OAuthClientConfig { - client_id: "mcp-client".to_string(), // temporary id, will be updated by dynamic registration + client_id: "mcp-client".to_string(), client_secret: None, scopes: scopes.iter().map(|s| s.to_string()).collect(), redirect_uri: redirect_uri.to_string(), @@ -640,7 +634,10 @@ impl AuthorizationSession { { Ok(config) => config, Err(e) => { - eprintln!("Dynamic registration failed: {}", e); + warn!( + "Dynamic registration failed: {}, fallback to default config", + e + ); // fallback to default config config } diff --git a/examples/servers/src/complex_auth_sse.rs b/examples/servers/src/complex_auth_sse.rs index 71cbe9e4..b3919aa9 100644 --- a/examples/servers/src/complex_auth_sse.rs +++ b/examples/servers/src/complex_auth_sse.rs @@ -525,7 +525,7 @@ async fn oauth_authorization_server() -> impl IntoResponse { authorization_endpoint: format!("http://{}/oauth/authorize", BIND_ADDRESS), token_endpoint: format!("http://{}/oauth/token", BIND_ADDRESS), scopes_supported: Some(vec!["profile".to_string(), "email".to_string()]), - registration_endpoint: format!("http://{}/oauth/register", BIND_ADDRESS), + registration_endpoint: Some(format!("http://{}/oauth/register", BIND_ADDRESS)), issuer: Some(BIND_ADDRESS.to_string()), jwks_uri: Some(format!("http://{}/oauth/jwks", BIND_ADDRESS)), additional_fields,