#![allow(clippy::expect_used, clippy::unwrap_used)]
use std::collections::HashMap;
use std::sync::Arc;
use capo_agent::mcp::{connect_all, disconnect_all, McpConfig, McpServerConfig};
use motosan_agent_loop::mcp::McpToolAdapter;
use motosan_agent_tool::ToolContext;
use tempfile::tempdir;
fn fixture_binary_path() -> std::path::PathBuf {
let target = std::env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".into());
std::path::PathBuf::from(target)
.join("debug")
.join("fake-mcp-stdio")
}
#[tokio::test]
async fn connect_list_call_disconnect_roundtrip() {
let bin = fixture_binary_path();
if !bin.exists() {
eprintln!(
"Skipping: fake-mcp-stdio not built at {}. Run `cargo build -p fake-mcp-stdio` first.",
bin.display()
);
return;
}
let mut servers = HashMap::new();
servers.insert(
"fake".into(),
McpServerConfig::Stdio {
command: bin.display().to_string(),
args: vec![],
env: HashMap::new(),
startup_timeout_ms: 5000,
enabled: true,
},
);
let cfg = McpConfig { servers };
let log_dir = tempdir().unwrap();
let started = connect_all(&cfg, log_dir.path()).await;
assert_eq!(started.len(), 1, "fake server should have connected");
let server = Arc::clone(&started[0].server);
let tools = McpToolAdapter::from_server(server)
.await
.expect("list_tools");
let names: Vec<String> = tools.iter().map(|t| t.def().name).collect();
assert!(names.contains(&"fake__echo".to_string()), "got {names:?}");
let echo = tools
.iter()
.find(|t| t.def().name == "fake__echo")
.expect("fake__echo tool");
let ctx = ToolContext::new("test", "capo");
let result = echo
.call(serde_json::json!({"text": "hello mcp"}), &ctx)
.await;
assert!(!result.is_error, "{result:?}");
assert_eq!(result.as_text(), Some("hello mcp"));
disconnect_all(&started).await;
let log_file = log_dir.path().join("fake.stderr.log");
let log = std::fs::read_to_string(&log_file)
.unwrap_or_else(|e| panic!("read {} failed: {e}", log_file.display()));
assert!(
log.contains("fake-mcp-stdio ready"),
"stderr log missing fixture line: {log:?}"
);
}