Skip to main content

mcp_utils/
testing.rs

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