Avoid NEAR AI login during MCP discovery

This commit is contained in:
Coffee
2026-03-19 14:46:55 +08:00
parent c779360730
commit 54981c32f4
3 changed files with 53 additions and 19 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ pub use config::{
};
pub use error::LlmError;
pub use failover::{CooldownConfig, FailoverProvider};
pub use nearai_auth::resolve_nearai_bearer_token;
pub use nearai_auth::{resolve_nearai_bearer_token, resolve_nearai_bearer_token_if_available};
pub use nearai_chat::{ModelInfo, NearAiChatProvider};
pub use provider::{
ChatMessage, CompletionRequest, CompletionResponse, ContentPart, FinishReason, ImageUrl,
+30 -16
View File
@@ -3,6 +3,32 @@ use secrecy::{ExposeSecret, SecretString};
use crate::llm::LlmError;
use crate::llm::session::SessionManager;
/// Resolve the active NEAR AI bearer token only if already available.
///
/// Unlike [`resolve_nearai_bearer_token`], this helper is side-effect free:
/// it never triggers an interactive login flow.
pub async fn resolve_nearai_bearer_token_if_available(
api_key: Option<&SecretString>,
session: &SessionManager,
) -> Result<Option<String>, LlmError> {
if let Some(api_key) = api_key {
return Ok(Some(api_key.expose_secret().to_string()));
}
if session.has_token().await {
let token = session.get_token().await?;
return Ok(Some(token.expose_secret().to_string()));
}
if let Ok(key) = std::env::var("NEARAI_API_KEY")
&& !key.is_empty()
{
return Ok(Some(key));
}
Ok(None)
}
/// Resolve the active NEAR AI bearer token.
///
/// Priority order:
@@ -14,26 +40,14 @@ pub async fn resolve_nearai_bearer_token(
api_key: Option<&SecretString>,
session: &SessionManager,
) -> Result<String, LlmError> {
if let Some(api_key) = api_key {
return Ok(api_key.expose_secret().to_string());
}
if session.has_token().await {
let token = session.get_token().await?;
return Ok(token.expose_secret().to_string());
if let Some(token) = resolve_nearai_bearer_token_if_available(api_key, session).await? {
return Ok(token);
}
session.ensure_authenticated().await?;
if session.has_token().await {
let token = session.get_token().await?;
return Ok(token.expose_secret().to_string());
}
if let Ok(key) = std::env::var("NEARAI_API_KEY")
&& !key.is_empty()
{
return Ok(key);
if let Some(token) = resolve_nearai_bearer_token_if_available(api_key, session).await? {
return Ok(token);
}
Err(LlmError::AuthFailed {
+22 -2
View File
@@ -308,12 +308,11 @@ impl McpClient {
));
};
crate::llm::resolve_nearai_bearer_token(
crate::llm::resolve_nearai_bearer_token_if_available(
self.nearai_api_key.as_ref(),
session_manager,
)
.await
.map(Some)
.map_err(|e| {
ToolError::ExternalService(format!(
"Failed to resolve NEAR AI token for MCP server '{}': {}",
@@ -885,6 +884,27 @@ mod tests {
);
}
#[tokio::test]
async fn test_build_request_headers_without_nearai_auth_does_not_trigger_login() {
use crate::llm::{
SessionConfig as NearAiSessionConfig, SessionManager as NearAiSessionManager,
};
let config = McpServerConfig::new("chat_api", "http://localhost:3000/mcp")
.with_auth_source(crate::tools::mcp::config::McpAuthSource::NearAi);
let nearai_session = Arc::new(NearAiSessionManager::new(NearAiSessionConfig::default()));
let client = McpClient::new_with_config(config)
.expect("valid MCP config")
.with_nearai_session_manager(nearai_session);
let headers = client.build_request_headers().await.expect("headers");
assert!(
!headers.contains_key("Authorization"),
"runtime auth should stay absent when no token is available"
);
}
#[test]
fn test_next_request_id_monotonically_increasing() {
let client = McpClient::new("http://localhost:1234");