1use mcpkit_core::capability::{ClientCapabilities, ClientInfo};
7use mcpkit_core::error::McpError;
8use mcpkit_transport::Transport;
9
10use crate::client::{Client, initialize};
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(
123 transport,
124 init_result,
125 client_info,
126 self.capabilities,
127 ))
128 }
129
130 pub async fn build_with_handler<
138 T: Transport + 'static,
139 H: crate::handler::ClientHandler + 'static,
140 >(
141 self,
142 transport: T,
143 handler: H,
144 ) -> Result<Client<T, H>, McpError> {
145 let client_info = ClientInfo::new(&self.name, &self.version);
146 let init_result = initialize(&transport, &client_info, &self.capabilities).await?;
147 Ok(Client::with_handler(
148 transport,
149 init_result,
150 client_info,
151 self.capabilities,
152 handler,
153 ))
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_builder_defaults() {
163 let builder = ClientBuilder::new();
164 assert_eq!(builder.name, "mcp-client");
165 assert!(!builder.capabilities.has_sampling());
166 assert!(!builder.capabilities.has_roots());
167 }
168
169 #[test]
170 fn test_builder_fluent() {
171 let builder = ClientBuilder::new()
172 .name("test-client")
173 .version("1.0.0")
174 .with_sampling()
175 .with_roots();
176
177 assert_eq!(builder.name, "test-client");
178 assert_eq!(builder.version, "1.0.0");
179 assert!(builder.capabilities.has_sampling());
180 assert!(builder.capabilities.has_roots());
181 }
182}