rust_mcp_sdk/mcp_runtimes/client_runtime/
mcp_client_runtime.rs

1use std::sync::Arc;
2
3use crate::schema::{
4    schema_utils::{
5        MessageFromClient, NotificationFromServer, RequestFromServer, ResultFromClient,
6        ServerMessage,
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<ServerMessage, MessageFromClient>,
44    handler: impl ClientHandler,
45) -> Arc<ClientRuntime> {
46    Arc::new(ClientRuntime::new(
47        client_details,
48        transport,
49        Box::new(ClientInternalHandler::new(Box::new(handler))),
50    ))
51}
52
53/// Internal handler that wraps a `ClientHandler` trait object.
54/// This is used to handle incoming requests and notifications for the client.
55struct ClientInternalHandler<H> {
56    handler: H,
57}
58impl ClientInternalHandler<Box<dyn ClientHandler>> {
59    pub fn new(handler: Box<dyn ClientHandler>) -> Self {
60        Self { handler }
61    }
62}
63
64/// Implementation of the `McpClientHandler` trait for `ClientInternalHandler`.
65/// This handles requests, notifications, and errors from the server by calling proper function of self.handler
66#[async_trait]
67impl McpClientHandler for ClientInternalHandler<Box<dyn ClientHandler>> {
68    /// Handles a request received from the server by passing the request to self.handler
69    async fn handle_request(
70        &self,
71        server_jsonrpc_request: RequestFromServer,
72        runtime: &dyn McpClient,
73    ) -> std::result::Result<ResultFromClient, RpcError> {
74        match server_jsonrpc_request {
75            RequestFromServer::ServerRequest(request) => match request {
76                ServerRequest::PingRequest(ping_request) => self
77                    .handler
78                    .handle_ping_request(ping_request, runtime)
79                    .await
80                    .map(|value| value.into()),
81                ServerRequest::CreateMessageRequest(create_message_request) => self
82                    .handler
83                    .handle_create_message_request(create_message_request, runtime)
84                    .await
85                    .map(|value| value.into()),
86                ServerRequest::ListRootsRequest(list_roots_request) => self
87                    .handler
88                    .handle_list_roots_request(list_roots_request, runtime)
89                    .await
90                    .map(|value| value.into()),
91                #[cfg(feature = "2025_06_18")]
92                ServerRequest::ElicitRequest(elicit_request) => self
93                    .handler
94                    .handle_elicit_request(elicit_request, runtime)
95                    .await
96                    .map(|value| value.into()),
97            },
98            // Handles custom notifications received from the server by passing the request to self.handler
99            RequestFromServer::CustomRequest(custom_request) => self
100                .handler
101                .handle_custom_request(custom_request, runtime)
102                .await
103                .map(|value| value.into()),
104        }
105    }
106
107    /// Handles errors received from the server by passing the request to self.handler
108    async fn handle_error(
109        &self,
110        jsonrpc_error: RpcError,
111        runtime: &dyn McpClient,
112    ) -> SdkResult<()> {
113        self.handler.handle_error(jsonrpc_error, runtime).await?;
114        Ok(())
115    }
116
117    /// Handles notifications received from the server by passing the request to self.handler
118    async fn handle_notification(
119        &self,
120        server_jsonrpc_notification: NotificationFromServer,
121        runtime: &dyn McpClient,
122    ) -> SdkResult<()> {
123        match server_jsonrpc_notification {
124            NotificationFromServer::ServerNotification(server_notification) => {
125                match server_notification {
126                    ServerNotification::CancelledNotification(cancelled_notification) => {
127                        self.handler
128                            .handle_cancelled_notification(cancelled_notification, runtime)
129                            .await?;
130                    }
131                    ServerNotification::ProgressNotification(progress_notification) => {
132                        self.handler
133                            .handle_progress_notification(progress_notification, runtime)
134                            .await?;
135                    }
136                    ServerNotification::ResourceListChangedNotification(
137                        resource_list_changed_notification,
138                    ) => {
139                        self.handler
140                            .handle_resource_list_changed_notification(
141                                resource_list_changed_notification,
142                                runtime,
143                            )
144                            .await?;
145                    }
146                    ServerNotification::ResourceUpdatedNotification(
147                        resource_updated_notification,
148                    ) => {
149                        self.handler
150                            .handle_resource_updated_notification(
151                                resource_updated_notification,
152                                runtime,
153                            )
154                            .await?;
155                    }
156                    ServerNotification::PromptListChangedNotification(
157                        prompt_list_changed_notification,
158                    ) => {
159                        self.handler
160                            .handle_prompt_list_changed_notification(
161                                prompt_list_changed_notification,
162                                runtime,
163                            )
164                            .await?;
165                    }
166                    ServerNotification::ToolListChangedNotification(
167                        tool_list_changed_notification,
168                    ) => {
169                        self.handler
170                            .handle_tool_list_changed_notification(
171                                tool_list_changed_notification,
172                                runtime,
173                            )
174                            .await?;
175                    }
176                    ServerNotification::LoggingMessageNotification(
177                        logging_message_notification,
178                    ) => {
179                        self.handler
180                            .handle_logging_message_notification(
181                                logging_message_notification,
182                                runtime,
183                            )
184                            .await?;
185                    }
186                }
187            }
188            // Handles custom notifications received from the server by passing the request to self.handler
189            NotificationFromServer::CustomNotification(custom_notification) => {
190                self.handler
191                    .handle_custom_notification(custom_notification, runtime)
192                    .await?;
193            }
194        }
195        Ok(())
196    }
197
198    /// Handles process errors received from the server over stderr
199    async fn handle_process_error(
200        &self,
201        error_message: String,
202        runtime: &dyn McpClient,
203    ) -> SdkResult<()> {
204        self.handler
205            .handle_process_error(error_message, runtime)
206            .await
207            .map_err(|err| err.into())
208    }
209}