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            },
92            // Handles custom notifications received from the server by passing the request to self.handler
93            RequestFromServer::CustomRequest(custom_request) => self
94                .handler
95                .handle_custom_request(custom_request, runtime)
96                .await
97                .map(|value| value.into()),
98        }
99    }
100
101    /// Handles errors received from the server by passing the request to self.handler
102    async fn handle_error(
103        &self,
104        jsonrpc_error: RpcError,
105        runtime: &dyn McpClient,
106    ) -> SdkResult<()> {
107        self.handler.handle_error(jsonrpc_error, runtime).await?;
108        Ok(())
109    }
110
111    /// Handles notifications received from the server by passing the request to self.handler
112    async fn handle_notification(
113        &self,
114        server_jsonrpc_notification: NotificationFromServer,
115        runtime: &dyn McpClient,
116    ) -> SdkResult<()> {
117        match server_jsonrpc_notification {
118            NotificationFromServer::ServerNotification(server_notification) => {
119                match server_notification {
120                    ServerNotification::CancelledNotification(cancelled_notification) => {
121                        self.handler
122                            .handle_cancelled_notification(cancelled_notification, runtime)
123                            .await?;
124                    }
125                    ServerNotification::ProgressNotification(progress_notification) => {
126                        self.handler
127                            .handle_progress_notification(progress_notification, runtime)
128                            .await?;
129                    }
130                    ServerNotification::ResourceListChangedNotification(
131                        resource_list_changed_notification,
132                    ) => {
133                        self.handler
134                            .handle_resource_list_changed_notification(
135                                resource_list_changed_notification,
136                                runtime,
137                            )
138                            .await?;
139                    }
140                    ServerNotification::ResourceUpdatedNotification(
141                        resource_updated_notification,
142                    ) => {
143                        self.handler
144                            .handle_resource_updated_notification(
145                                resource_updated_notification,
146                                runtime,
147                            )
148                            .await?;
149                    }
150                    ServerNotification::PromptListChangedNotification(
151                        prompt_list_changed_notification,
152                    ) => {
153                        self.handler
154                            .handle_prompt_list_changed_notification(
155                                prompt_list_changed_notification,
156                                runtime,
157                            )
158                            .await?;
159                    }
160                    ServerNotification::ToolListChangedNotification(
161                        tool_list_changed_notification,
162                    ) => {
163                        self.handler
164                            .handle_tool_list_changed_notification(
165                                tool_list_changed_notification,
166                                runtime,
167                            )
168                            .await?;
169                    }
170                    ServerNotification::LoggingMessageNotification(
171                        logging_message_notification,
172                    ) => {
173                        self.handler
174                            .handle_logging_message_notification(
175                                logging_message_notification,
176                                runtime,
177                            )
178                            .await?;
179                    }
180                }
181            }
182            // Handles custom notifications received from the server by passing the request to self.handler
183            NotificationFromServer::CustomNotification(custom_notification) => {
184                self.handler
185                    .handle_custom_notification(custom_notification, runtime)
186                    .await?;
187            }
188        }
189        Ok(())
190    }
191
192    /// Handles process errors received from the server over stderr
193    async fn handle_process_error(
194        &self,
195        error_message: String,
196        runtime: &dyn McpClient,
197    ) -> SdkResult<()> {
198        self.handler
199            .handle_process_error(error_message, runtime)
200            .await
201            .map_err(|err| err.into())
202    }
203}