1use mcpkit_core::capability::{ClientCapabilities, ClientInfo};
7use mcpkit_core::error::McpError;
8use mcpkit_transport::Transport;
9
10use crate::client::{initialize, Client};
11
12pub struct ClientBuilder {
35 name: String,
36 version: String,
37 capabilities: ClientCapabilities,
38}
39
40impl Default for ClientBuilder {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl ClientBuilder {
47 #[must_use]
49 pub fn new() -> Self {
50 Self {
51 name: "mcp-client".to_string(),
52 version: env!("CARGO_PKG_VERSION").to_string(),
53 capabilities: ClientCapabilities::default(),
54 }
55 }
56
57 #[must_use]
59 pub fn name(mut self, name: impl Into<String>) -> Self {
60 self.name = name.into();
61 self
62 }
63
64 #[must_use]
66 pub fn version(mut self, version: impl Into<String>) -> Self {
67 self.version = version.into();
68 self
69 }
70
71 #[must_use]
75 pub fn with_sampling(mut self) -> Self {
76 self.capabilities = self.capabilities.with_sampling();
77 self
78 }
79
80 #[must_use]
84 pub fn with_elicitation(mut self) -> Self {
85 self.capabilities = self.capabilities.with_elicitation();
86 self
87 }
88
89 #[must_use]
93 pub fn with_roots(mut self) -> Self {
94 self.capabilities = self.capabilities.with_roots();
95 self
96 }
97
98 #[must_use]
100 pub fn with_roots_and_changes(mut self) -> Self {
101 self.capabilities = self.capabilities.with_roots_and_changes();
102 self
103 }
104
105 #[must_use]
107 pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
108 self.capabilities = capabilities;
109 self
110 }
111
112 pub async fn build<T: Transport + 'static>(self, transport: T) -> Result<Client<T>, McpError> {
120 let client_info = ClientInfo::new(&self.name, &self.version);
121 let init_result = initialize(&transport, &client_info, &self.capabilities).await?;
122 Ok(Client::new(transport, init_result, client_info, self.capabilities))
123 }
124
125 pub async fn build_with_handler<T: Transport + 'static, H: crate::handler::ClientHandler + 'static>(
133 self,
134 transport: T,
135 handler: H,
136 ) -> Result<Client<T, H>, McpError> {
137 let client_info = ClientInfo::new(&self.name, &self.version);
138 let init_result = initialize(&transport, &client_info, &self.capabilities).await?;
139 Ok(Client::with_handler(transport, init_result, client_info, self.capabilities, handler))
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_builder_defaults() {
149 let builder = ClientBuilder::new();
150 assert_eq!(builder.name, "mcp-client");
151 assert!(!builder.capabilities.has_sampling());
152 assert!(!builder.capabilities.has_roots());
153 }
154
155 #[test]
156 fn test_builder_fluent() {
157 let builder = ClientBuilder::new()
158 .name("test-client")
159 .version("1.0.0")
160 .with_sampling()
161 .with_roots();
162
163 assert_eq!(builder.name, "test-client");
164 assert_eq!(builder.version, "1.0.0");
165 assert!(builder.capabilities.has_sampling());
166 assert!(builder.capabilities.has_roots());
167 }
168}