Skip to main content

mcp_utils/
testing.rs

1use crate::transport::create_in_memory_transport;
2use rmcp::{
3    RoleClient, RoleServer, Service,
4    model::ClientInfo,
5    serve_client, serve_server,
6    service::{ClientInitializeError, RunningService, ServerInitializeError},
7};
8
9/// Helper function to connect an MCP server and client via in-memory transport
10/// This handles the initialization handshake by running both concurrently
11pub async fn connect<S>(
12    server: S,
13    client_info: ClientInfo,
14) -> Result<(RunningService<RoleServer, S>, RunningService<RoleClient, ClientInfo>), ConnectError>
15where
16    S: Service<RoleServer>,
17{
18    let (client_transport, server_transport) = create_in_memory_transport();
19
20    let (server_result, client_result) =
21        tokio::join!(serve_server(server, server_transport), serve_client(client_info, client_transport));
22
23    let server = server_result.map_err(ConnectError::ServerInit)?;
24    let client = client_result.map_err(ConnectError::ClientInit)?;
25
26    Ok((server, client))
27}
28
29#[derive(Debug)]
30pub enum ConnectError {
31    ServerInit(ServerInitializeError),
32    ClientInit(ClientInitializeError),
33}
34
35impl std::fmt::Display for ConnectError {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            ConnectError::ServerInit(e) => write!(f, "Server initialization failed: {e}"),
39            ConnectError::ClientInit(e) => write!(f, "Client initialization failed: {e}"),
40        }
41    }
42}
43
44impl std::error::Error for ConnectError {}