use echo_agent::mcp::{McpManager, McpServerConfig};
use echo_agent::prelude::*;
#[tokio::main]
async fn main() -> echo_agent::error::Result<()> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt()
.with_env_filter(
std::env::var("RUST_LOG").unwrap_or_else(|_| "echo_agent=info,demo06_mcp=info".into()),
)
.init();
if !npx_available() {
return Err(echo_agent::error::ReactError::Other(
"demo06 验收失败:未找到 npx,请先安装 Node.js".to_string(),
));
}
println!("═══════════════════════════════════════════════════════");
println!(" Echo Agent × MCP 集成演示");
println!("═══════════════════════════════════════════════════════\n");
demo_raw_mcp_call().await?;
println!("\n{}", "─".repeat(55));
println!("Part 2: MCP 工具 + ReAct Agent 联合演示");
println!("{}\n", "─".repeat(55));
demo_agent_with_mcp().await?;
Ok(())
}
async fn demo_raw_mcp_call() -> echo_agent::error::Result<()> {
println!("Part 1: 直接通过 MCP 协议调用工具\n");
let mut manager = McpManager::new();
let config = McpServerConfig::stdio(
"filesystem",
"npx",
vec!["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
);
println!("正在启动 MCP 文件系统服务端...");
let tools = manager.connect(config).await?;
println!("✓ 已发现 {} 个工具:", tools.len());
for tool in &tools {
println!(" • {} — {}", tool.name(), tool.description());
}
if let Some(client) = manager.get_client("filesystem") {
println!("\n调用 list_directory 工具列出 /tmp 目录...");
let result = client
.call_tool("list_directory", serde_json::json!({ "path": "/tmp" }))
.await;
let r = result?;
let text = echo_agent::mcp::McpClient::content_to_text(&r.content);
if text.trim().is_empty() {
return Err(echo_agent::error::ReactError::Other(
"demo06 验收失败:list_directory 返回空结果".to_string(),
));
}
println!("工具返回结果:\n{}", text);
} else {
return Err(echo_agent::error::ReactError::Other(
"demo06 验收失败:未获取到 filesystem MCP 客户端".to_string(),
));
}
manager.close_all().await;
Ok(())
}
async fn demo_agent_with_mcp() -> echo_agent::error::Result<()> {
if std::env::var("OPENAI_API_KEY").is_err()
&& std::env::var("DEEPSEEK_API_KEY").is_err()
&& std::env::var("QWEN_API_KEY").is_err()
{
return Err(echo_agent::error::ReactError::Other(
"demo06 验收失败:未检测到任何 LLM API 密钥".to_string(),
));
}
let mut manager = McpManager::new();
let mcp_tools = manager
.connect(McpServerConfig::stdio(
"filesystem",
"npx",
vec!["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
))
.await?;
println!("MCP 工具已准备好,共 {} 个", mcp_tools.len());
let mut agent = ReactAgentBuilder::new()
.model("qwen3-max")
.name("file-agent")
.system_prompt("你是一个文件操作助手,可以使用 MCP 文件系统工具完成文件读写任务。在执行操作前先分析步骤,再依次执行。")
.enable_tools()
.build()?;
agent.add_tools(mcp_tools);
let task = "请帮我查看 /tmp 目录下有哪些文件,并创建一个名为 mcp_test.txt 的文件,\
内容为 'Hello from echo-agent MCP!',最后读取这个文件确认内容正确。";
println!("\n任务: {}\n", task);
let result = agent.execute(task).await?;
if result.trim().is_empty() {
return Err(echo_agent::error::ReactError::Other(
"demo06 验收失败:Agent + MCP 返回空结果".to_string(),
));
}
println!("\n✓ 任务完成!\n{}", result);
manager.close_all().await;
Ok(())
}
fn npx_available() -> bool {
std::process::Command::new("npx")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}