clients/
clients.rs

1use mcp_client::{
2    client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait},
3    transport::{SseTransport, StdioTransport, Transport},
4    McpService,
5};
6use rand::Rng;
7use rand::SeedableRng;
8use std::time::Duration;
9use std::{collections::HashMap, sync::Arc};
10use tracing_subscriber::EnvFilter;
11
12#[tokio::main]
13async fn main() -> Result<(), Box<dyn std::error::Error>> {
14    // Initialize logging
15    tracing_subscriber::fmt()
16        .with_env_filter(
17            EnvFilter::from_default_env().add_directive("mcp_client=debug".parse().unwrap()),
18        )
19        .init();
20
21    let transport1 = StdioTransport::new("uvx", vec!["mcp-server-git".to_string()], HashMap::new());
22    let handle1 = transport1.start().await?;
23    let service1 = McpService::with_timeout(handle1, Duration::from_secs(30));
24    let client1 = McpClient::new(service1);
25
26    let transport2 = StdioTransport::new("uvx", vec!["mcp-server-git".to_string()], HashMap::new());
27    let handle2 = transport2.start().await?;
28    let service2 = McpService::with_timeout(handle2, Duration::from_secs(30));
29    let client2 = McpClient::new(service2);
30
31    let transport3 = SseTransport::new("http://localhost:8000/sse", HashMap::new());
32    let handle3 = transport3.start().await?;
33    let service3 = McpService::with_timeout(handle3, Duration::from_secs(10));
34    let client3 = McpClient::new(service3);
35
36    // Initialize both clients
37    let mut clients: Vec<Box<dyn McpClientTrait>> =
38        vec![Box::new(client1), Box::new(client2), Box::new(client3)];
39
40    // Initialize all clients
41    for (i, client) in clients.iter_mut().enumerate() {
42        let info = ClientInfo {
43            name: format!("example-client-{}", i + 1),
44            version: "1.0.0".to_string(),
45        };
46        let capabilities = ClientCapabilities::default();
47
48        println!("\nInitializing client {}", i + 1);
49        let init_result = client.initialize(info, capabilities).await?;
50        println!("Client {} initialized: {:?}", i + 1, init_result);
51    }
52
53    // List tools for all clients
54    for (i, client) in clients.iter_mut().enumerate() {
55        let tools = client.list_tools(None).await?;
56        println!("\nClient {} tools: {:?}", i + 1, tools);
57    }
58
59    println!("\n\n----------------------------------\n\n");
60
61    // Wrap clients in Arc before spawning tasks
62    let clients = Arc::new(clients);
63    let mut handles = vec![];
64
65    for i in 0..20 {
66        let clients = Arc::clone(&clients);
67        let handle = tokio::spawn(async move {
68            // let mut rng = rand::thread_rng();
69            let mut rng = rand::rngs::StdRng::from_entropy();
70            tokio::time::sleep(Duration::from_millis(rng.gen_range(5..50))).await;
71
72            // Randomly select an operation
73            match rng.gen_range(0..4) {
74                0 => {
75                    println!("\n{i}: Listing tools for client 1 (stdio)");
76                    match clients[0].list_tools(None).await {
77                        Ok(tools) => {
78                            println!("  {i}: -> Got tools, first one: {:?}", tools.tools.first())
79                        }
80                        Err(e) => println!("  {i}: -> Error: {}", e),
81                    }
82                }
83                1 => {
84                    println!("\n{i}: Calling tool for client 2 (stdio)");
85                    match clients[1]
86                        .call_tool("git_status", serde_json::json!({ "repo_path": "." }))
87                        .await
88                    {
89                        Ok(result) => println!(
90                            "  {i}: -> Tool execution result, is_error: {:?}",
91                            result.is_error
92                        ),
93                        Err(e) => println!("  {i}: -> Error: {}", e),
94                    }
95                }
96                2 => {
97                    println!("\n{i}: Listing tools for client 3 (sse)");
98                    match clients[2].list_tools(None).await {
99                        Ok(tools) => {
100                            println!("  {i}: -> Got tools, first one: {:?}", tools.tools.first())
101                        }
102                        Err(e) => println!("  {i}: -> Error: {}", e),
103                    }
104                }
105                3 => {
106                    println!("\n{i}: Calling tool for client 3 (sse)");
107                    match clients[2]
108                            .call_tool(
109                                "echo_tool",
110                                serde_json::json!({ "message": "Client with SSE transport - calling a tool" }),
111                            )
112                            .await
113                        {
114                        Ok(result) => println!("  {i}: -> Tool execution result, is_error: {:?}", result.is_error),
115                        Err(e) => println!("  {i}: -> Error: {}", e),
116                    }
117                }
118                _ => unreachable!(),
119            }
120            Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
121        });
122        handles.push(handle);
123    }
124
125    // Wait for all tasks to complete
126    for handle in handles {
127        handle.await.unwrap().unwrap();
128    }
129
130    Ok(())
131}