mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
## What changed - Upgrade `rmcp` and `rmcp-macros` from 3.1.2 to 3.1.3. - Preserve authentication-required and retryable transport classifications when modern MCP discovery falls back to legacy initialization. - Prevent unrelated discovery errors from triggering legacy fallback while retaining their diagnostics. ## Testing - Cover authentication challenges and transient initialization failures during legacy fallback. - Verify that a failed OAuth issuer check does not consume the pending authorization state. GitOrigin-RevId: 957c0873fec1148883dd163fbaeb77d7593d8c53
62 lines
2.4 KiB
Rust
62 lines
2.4 KiB
Rust
use anyhow::Error;
|
|
use rmcp::service::ClientInitializeError;
|
|
use rmcp::service::ServiceError;
|
|
use rmcp::transport::DynamicTransportError;
|
|
use rmcp::transport::auth::AuthError;
|
|
use rmcp::transport::streamable_http_client::StreamableHttpError;
|
|
|
|
use crate::http_client_adapter::StreamableHttpClientAdapterError;
|
|
use crate::rmcp_client::ClientOperationError;
|
|
|
|
/// Returns whether an RMCP client error indicates that authentication is required.
|
|
///
|
|
/// This does not distinguish first-time login from reauthentication.
|
|
/// Streamable HTTP initialization errors are stored inside RMCP's dynamic
|
|
/// transport error, which is not part of the standard error source chain.
|
|
pub fn is_authentication_required_error(error: &Error) -> bool {
|
|
error.chain().any(|source| {
|
|
source
|
|
.downcast_ref::<AuthError>()
|
|
.is_some_and(auth_error_requires_authentication)
|
|
|| source
|
|
.downcast_ref::<ClientInitializeError>()
|
|
.is_some_and(|mut error| {
|
|
while let ClientInitializeError::LegacyFallbackFailed { fallback, .. } = error {
|
|
error = fallback;
|
|
}
|
|
matches!(
|
|
error,
|
|
ClientInitializeError::TransportError { error, .. }
|
|
if transport_error_requires_authentication(error)
|
|
)
|
|
})
|
|
|| source
|
|
.downcast_ref::<ClientOperationError>()
|
|
.is_some_and(|error| {
|
|
matches!(
|
|
error,
|
|
ClientOperationError::Service(ServiceError::TransportSend(error))
|
|
if transport_error_requires_authentication(error)
|
|
)
|
|
})
|
|
})
|
|
}
|
|
|
|
fn transport_error_requires_authentication(error: &DynamicTransportError) -> bool {
|
|
error
|
|
.error
|
|
.downcast_ref::<StreamableHttpError<StreamableHttpClientAdapterError>>()
|
|
.is_some_and(|error| match error {
|
|
StreamableHttpError::AuthRequired(_) => true,
|
|
StreamableHttpError::Auth(auth_error) => auth_error_requires_authentication(auth_error),
|
|
_ => false,
|
|
})
|
|
}
|
|
|
|
fn auth_error_requires_authentication(error: &AuthError) -> bool {
|
|
matches!(
|
|
error,
|
|
AuthError::AuthorizationRequired | AuthError::TokenExpired
|
|
)
|
|
}
|