rust_mcp_sdk/mcp_runtimes/client_runtime/
mcp_client_runtime.rs

1use std::sync::Arc;
2
3use crate::schema::{
4    schema_utils::{
5        ClientMessage, ClientMessages, MessageFromClient, NotificationFromServer,
6        RequestFromServer, ResultFromClient, ServerMessage, ServerMessages,
7    },
8    InitializeRequestParams, RpcError, ServerNotification, ServerRequest,
9};
10use async_trait::async_trait;
11use rust_mcp_transport::Transport;
12
13use crate::{
14    error::SdkResult, mcp_client::ClientHandler, mcp_traits::mcp_handler::McpClientHandler,
15    McpClient,
16};
17
18use super::ClientRuntime;
19
20/// Creates a new MCP client runtime with the specified configuration.
21///
22/// This function initializes a client for (MCP) by accepting , client details, a transport ,
23/// and a handler for client-side logic.
24///
25/// The resulting `ClientRuntime` is wrapped in an `Arc` for shared ownership across threads.
26///
27/// # Arguments
28/// * `client_details` - Client name , version and capabilities.
29/// * `transport` - An implementation of the `Transport` trait facilitating communication with the MCP server.
30/// * `handler` - An implementation of the `ClientHandler` trait that defines the client's
31///   core behavior and response logic.
32///
33/// # Returns
34/// An `Arc<ClientRuntime>` representing the initialized client, enabling shared access and
35/// asynchronous operation.
36///
37/// # Examples
38/// You can find a detailed example of how to use this function in the repository:
39///
40/// [Repository Example](https://github.com/rust-mcp-stack/rust-mcp-sdk/tree/main/examples/simple-mcp-client)
41pub fn create_client(
42    client_details: InitializeRequestParams,
43    transport: impl Transport<
44        ServerMessages,
45        MessageFromClient,
46        ServerMessage,
47        ClientMessages,
48        ClientMessage,
49    >,
50    handler: impl ClientHandler,
51) -> Arc<ClientRuntime> {
52    Arc::new(ClientRuntime::new(
53        client_details,
54        transport,
55        Box::new(ClientInternalHandler::new(Box::new(handler))),
56    ))
57}
58
59/// Internal handler that wraps a `ClientHandler` trait object.
60/// This is used to handle incoming requests and notifications for the client.
61struct ClientInternalHandler<H> {
62    handler: H,
63}
64impl ClientInternalHandler<Box<dyn ClientHandler>> {
65    pub fn new(handler: Box<dyn ClientHandler>) -> Self {
66        Self { handler }
67    }
68}
69
70/// Implementation of the `McpClientHandler` trait for `ClientInternalHandler`.
71/// This handles requests, notifications, and errors from the server by calling proper function of self.handler
72#[async_trait]
73impl McpClientHandler for ClientInternalHandler<Box<dyn ClientHandler>> {
74    /// Handles a request received from the server by passing the request to self.handler
75    async fn handle_request(
76        &self,
77        server_jsonrpc_request: RequestFromServer,
78        runtime: &dyn McpClient,
79    ) -> std::result::Result<ResultFromClient, RpcError> {
80        match server_jsonrpc_request {
81            RequestFromServer::ServerRequest(request) => match request {
82                ServerRequest::PingRequest(ping_request) => self
83                    .handler
84                    .handle_ping_request(ping_request, runtime)
85                    .await
86                    .map(|value| value.into()),
87                ServerRequest::CreateMessageRequest(create_message_request) => self
88                    .handler
89                    .handle_create_message_request(create_message_request, runtime)
90                    .await
91                    .map(|value| value.into()),
92                ServerRequest::ListRootsRequest(list_roots_request) => self
93                    .handler
94                    .handle_list_roots_request(list_roots_request, runtime)
95                    .await
96                    .map(|value| value.into()),
97                #[cfg(feature = "2025_06_18")]
98                ServerRequest::ElicitRequest(elicit_request) => self
99                    .handler
100                    .handle_elicit_request(elicit_request, runtime)
101                    .await
102                    .map(|value| value.into()),
103            },
104            // Handles custom notifications received from the server by passing the request to self.handler
105            RequestFromServer::CustomRequest(custom_request) => self
106                .handler
107                .handle_custom_request(custom_request, runtime)
108                .await
109                .map(|value| value.into()),
110        }
111    }
112
113    /// Handles errors received from the server by passing the request to self.handler
114    async fn handle_error(
115        &self,
116        jsonrpc_error: &RpcError,
117        runtime: &dyn McpClient,
118    ) -> SdkResult<()> {
119        self.handler.handle_error(jsonrpc_error, runtime).await?;
120        Ok(())
121    }
122
123    /// Handles notifications received from the server by passing the request to self.handler
124    async fn handle_notification(
125        &self,
126        server_jsonrpc_notification: NotificationFromServer,
127        runtime: &dyn McpClient,
128    ) -> SdkResult<()> {
129        match server_jsonrpc_notification {
130            NotificationFromServer::ServerNotification(server_notification) => {
131                match server_notification {
132                    ServerNotification::CancelledNotification(cancelled_notification) => {
133                        self.handler
134                            .handle_cancelled_notification(cancelled_notification, runtime)
135                            .await?;
136                    }
137                    ServerNotification::ProgressNotification(progress_notification) => {
138                        self.handler
139                            .handle_progress_notification(progress_notification, runtime)
140                            .await?;
141                    }
142                    ServerNotification::ResourceListChangedNotification(
143                        resource_list_changed_notification,
144                    ) => {
145                        self.handler
146                            .handle_resource_list_changed_notification(
147                                resource_list_changed_notification,
148                                runtime,
149                            )
150                            .await?;
151                    }
152                    ServerNotification::ResourceUpdatedNotification(
153                        resource_updated_notification,
154                    ) => {
155                        self.handler
156                            .handle_resource_updated_notification(
157                                resource_updated_notification,
158                                runtime,
159                            )
160                            .await?;
161                    }
162                    ServerNotification::PromptListChangedNotification(
163                        prompt_list_changed_notification,
164                    ) => {
165                        self.handler
166                            .handle_prompt_list_changed_notification(
167                                prompt_list_changed_notification,
168                                runtime,
169                            )
170                            .await?;
171                    }
172                    ServerNotification::ToolListChangedNotification(
173                        tool_list_changed_notification,
174                    ) => {
175                        self.handler
176                            .handle_tool_list_changed_notification(
177                                tool_list_changed_notification,
178                                runtime,
179                            )
180                            .await?;
181                    }
182                    ServerNotification::LoggingMessageNotification(
183                        logging_message_notification,
184                    ) => {
185                        self.handler
186                            .handle_logging_message_notification(
187                                logging_message_notification,
188                                runtime,
189                            )
190                            .await?;
191                    }
192                }
193            }
194            // Handles custom notifications received from the server by passing the request to self.handler
195            NotificationFromServer::CustomNotification(custom_notification) => {
196                self.handler
197                    .handle_custom_notification(custom_notification, runtime)
198                    .await?;
199            }
200        }
201        Ok(())
202    }
203
204    /// Handles process errors received from the server over stderr
205    async fn handle_process_error(
206        &self,
207        error_message: String,
208        runtime: &dyn McpClient,
209    ) -> SdkResult<()> {
210        self.handler
211            .handle_process_error(error_message, runtime)
212            .await
213            .map_err(|err| err.into())
214    }
215}