use mcpx::{
client::{ClientBuilder, ClientEvent},
protocol::logging::LoggingLevel,
error::Error,
};
use tokio::sync::mpsc;
async fn handle_events(mut receiver: mpsc::Receiver<ClientEvent>) {
println!("Starting event handler...");
while let Some(event) = receiver.recv().await {
match event {
ClientEvent::Connected {
server_info,
protocol_version,
capabilities,
instructions,
} => {
println!("Connected to server: {} {}", server_info.name, server_info.version);
println!("Protocol version: {}", protocol_version);
println!("Server capabilities:");
println!(" - Logging: {}", capabilities.logging);
println!(" - Completions: {}", capabilities.completions);
println!(" - Prompts: {}", capabilities.prompts);
println!(" - Resources: {}", capabilities.resources);
println!(" - Tools: {}", capabilities.tools);
if let Some(instructions) = instructions {
println!("Server instructions: {}", instructions);
}
}
ClientEvent::Disconnected { reason } => {
println!("Disconnected from server: {}", reason);
break;
}
ClientEvent::ResourcesChanged => {
println!("Resources changed");
}
ClientEvent::PromptsChanged => {
println!("Prompts changed");
}
ClientEvent::ToolsChanged => {
println!("Tools changed");
}
ClientEvent::RootsChanged => {
println!("Roots changed");
}
ClientEvent::ResourceUpdated { uri } => {
println!("Resource updated: {}", uri);
}
ClientEvent::LogMessage {
level,
logger,
data,
} => {
let logger_str = logger.as_deref().unwrap_or("unknown");
println!("[{:?}] [{}] {}", level, logger_str, data);
}
ClientEvent::Progress {
request_id,
token: _,
progress,
total,
message,
} => {
let total_str = total.map_or("?".to_string(), |t| t.to_string());
let message_str = message.as_deref().unwrap_or("");
println!(
"Progress for request {:?}: {}/{} {}",
request_id, progress, total_str, message_str
);
}
ClientEvent::Error { error } => {
println!("Error: {}", error);
}
}
}
println!("Event handler stopped");
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt()
.with_env_filter("mcpx=debug")
.init();
println!("📡 Creating MCP client with WebSocket transport...");
let (client, event_receiver) = ClientBuilder::new()
.with_implementation("simple-client", "0.1.0")
.with_roots(true) .with_roots_list_changed(true) .with_sampling(true) .with_websocket_url("ws://localhost:3000")
.build()?;
let event_handler = tokio::spawn(handle_events(event_receiver));
println!("🔌 Connecting to MCP server via WebSocket...");
println!(" URL: ws://localhost:3000");
match client.connect().await {
Ok(_) => println!("✅ Connected successfully!"),
Err(e) => {
println!("❌ Connection failed: {}", e);
println!(" Make sure an MCP server is running at the specified URL.");
return Ok(());
}
}
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("\n📚 Listing resources...");
match client.list_resources().await {
Ok(resources) => {
if resources.is_empty() {
println!(" No resources found.");
} else {
println!(" Found {} resources:", resources.len());
for (i, resource) in resources.iter().enumerate() {
println!(" {}. {} ({})", i+1, resource.name, resource.uri);
if let Some(desc) = &resource.description {
println!(" Description: {}", desc);
}
}
}
},
Err(e) => {
println!("❌ Failed to list resources: {}", e);
}
}
println!("\n🔍 Listing prompts...");
match client.list_prompts().await {
Ok(prompts) => {
if prompts.is_empty() {
println!(" No prompts found.");
} else {
println!(" Found {} prompts:", prompts.len());
for (i, prompt) in prompts.iter().enumerate() {
println!(" {}. {}", i+1, prompt.name);
if let Some(desc) = &prompt.description {
println!(" Description: {}", desc);
}
}
}
},
Err(e) => {
println!("❌ Failed to list prompts: {}", e);
}
}
println!("\n🛠️ Listing tools...");
match client.list_tools().await {
Ok(tools) => {
if tools.is_empty() {
println!(" No tools found.");
} else {
println!(" Found {} tools:", tools.len());
for (i, tool) in tools.iter().enumerate() {
println!(" {}. {}", i+1, tool.name);
if let Some(desc) = &tool.description {
println!(" Description: {}", desc);
}
}
}
},
Err(e) => {
println!("❌ Failed to list tools: {}", e);
}
}
println!("\n📝 Setting logging level to debug...");
match client.set_logging_level(LoggingLevel::Debug).await {
Ok(_) => {
println!(" ✅ Logging level set to debug");
}
Err(e) => {
println!(" ❌ Failed to set logging level: {}", e);
}
}
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("\n🔌 Disconnecting from server...");
client.disconnect().await?;
println!("✅ Disconnected successfully!");
event_handler.await.unwrap();
Ok(())
}