From 9a8f8cebc32dae115376d9c665a6c7a7b93faaa7 Mon Sep 17 00:00:00 2001 From: Coffee Date: Tue, 17 Mar 2026 15:00:14 +0800 Subject: [PATCH] Avoid DB dependency in companion MCP CLI tests --- src/cli/mcp.rs | 115 +++++++++++++++++++++++----------------- src/tools/mcp/config.rs | 15 +++++- 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/cli/mcp.rs b/src/cli/mcp.rs index 589acc54..6c887aa9 100644 --- a/src/cli/mcp.rs +++ b/src/cli/mcp.rs @@ -8,9 +8,10 @@ use std::sync::Arc; use clap::{Args, Subcommand}; -use crate::config::Config; +use crate::config::{Config, LlmConfig}; use crate::db::Database; use crate::secrets::SecretsStore; +use crate::settings::Settings; use crate::tools::mcp::{ McpClient, McpProcessManager, McpServerConfig, McpSessionManager, OAuthConfig, auth::{authorize_mcp_server, is_authenticated}, @@ -506,54 +507,68 @@ async fn test_server(name: String, user_id: String) -> anyhow::Result<()> { // Create client let session_manager = Arc::new(McpSessionManager::new()); - - // Always check for stored tokens (from either pre-configured OAuth or DCR) - let secrets = get_secrets_store().await?; - let has_tokens = is_authenticated(&server, &secrets, &user_id).await; - - let client = if server.uses_runtime_auth_source() { + let (client, has_tokens) = if server.uses_runtime_auth_source() { let process_manager = Arc::new(McpProcessManager::new()); - let config = crate::config::Config::from_env().await?; - let nearai_session = crate::llm::create_session_manager(config.llm.session.clone()).await; - create_client_from_config( - server.clone(), - &session_manager, - Some(nearai_session), - config.llm.nearai.api_key.clone(), - &process_manager, - None, - "default", + let llm = resolve_llm_from_env()?; + let nearai_session = crate::llm::create_session_manager(llm.session.clone()).await; + ( + create_client_from_config( + server.clone(), + &session_manager, + Some(nearai_session), + llm.nearai.api_key.clone(), + &process_manager, + None, + "default", + ) + .await + .map_err(|e| anyhow::anyhow!("{}", e))?, + false, ) - .await - .map_err(|e| anyhow::anyhow!("{}", e))? - } else if has_tokens { - // We have stored tokens, use authenticated client - McpClient::new_authenticated(server.clone(), session_manager.clone(), secrets, user_id) - } else if server.requires_auth() { - // OAuth configured but no tokens - need to authenticate - println!(); - println!( - " ✗ Not authenticated. Run 'ironclaw mcp auth {}' first.", - name - ); - println!(); - return Ok(()); } else { - // Use the factory to dispatch on transport type (HTTP, stdio, unix) - let process_manager = Arc::new(McpProcessManager::new()); - let config = crate::config::Config::from_env().await?; - let nearai_session = crate::llm::create_session_manager(config.llm.session.clone()).await; - create_client_from_config( - server.clone(), - &session_manager, - Some(nearai_session), - config.llm.nearai.api_key.clone(), - &process_manager, - None, - "default", - ) - .await - .map_err(|e| anyhow::anyhow!("{}", e))? + // Only initialize the secrets store for non-runtime-auth servers that + // can actually use persisted OAuth/DCR tokens. + let secrets = get_secrets_store().await?; + let has_tokens = is_authenticated(&server, &secrets, &user_id).await; + + if has_tokens { + ( + McpClient::new_authenticated( + server.clone(), + session_manager.clone(), + secrets, + user_id, + ), + true, + ) + } else if server.requires_auth() { + println!(); + println!( + " ✗ Not authenticated. Run 'ironclaw mcp auth {}' first.", + name + ); + println!(); + return Ok(()); + } else { + // Use the factory to dispatch on transport type (HTTP, stdio, unix) + let process_manager = Arc::new(McpProcessManager::new()); + let llm = resolve_llm_from_env()?; + let nearai_session = crate::llm::create_session_manager(llm.session.clone()).await; + ( + create_client_from_config( + server.clone(), + &session_manager, + Some(nearai_session), + llm.nearai.api_key.clone(), + &process_manager, + None, + "default", + ) + .await + .map_err(|e| anyhow::anyhow!("{}", e))?, + false, + ) + } }; // Test connection @@ -667,8 +682,8 @@ async fn load_servers(db: Option<&dyn Database>) -> Result anyhow::Result Result { + LlmConfig::resolve(&Settings::default()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/tools/mcp/config.rs b/src/tools/mcp/config.rs index cc7912c6..cb9456c2 100644 --- a/src/tools/mcp/config.rs +++ b/src/tools/mcp/config.rs @@ -303,11 +303,22 @@ pub fn is_nearai_companion_server_name(name: &str) -> bool { pub fn derive_nearai_companion_mcp_server( config: &crate::config::Config, ) -> Option { - if config.llm.backend != "nearai" { + derive_nearai_companion_mcp_server_from_llm(&config.llm) +} + +/// Build the companion chat-api MCP server from an LLM config. +/// +/// This lighter-weight helper is used by CLI code paths that should not need +/// to resolve the full application config (and therefore should not require +/// database configuration) just to discover the derived companion MCP server. +pub fn derive_nearai_companion_mcp_server_from_llm( + llm: &crate::config::LlmConfig, +) -> Option { + if llm.backend != "nearai" { return None; } - let base = config.llm.nearai.base_url.trim_end_matches('/'); + let base = llm.nearai.base_url.trim_end_matches('/'); let mcp_base = base .strip_suffix("/v1") .unwrap_or(base)