use mcpkit_core::capability::{ClientCapabilities, ClientInfo};
use mcpkit_core::error::McpError;
use mcpkit_transport::Transport;
use crate::client::{initialize, Client};
pub struct ClientBuilder {
name: String,
version: String,
capabilities: ClientCapabilities,
}
impl Default for ClientBuilder {
fn default() -> Self {
Self::new()
}
}
impl ClientBuilder {
#[must_use]
pub fn new() -> Self {
Self {
name: "mcp-client".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
capabilities: ClientCapabilities::default(),
}
}
#[must_use]
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
#[must_use]
pub fn version(mut self, version: impl Into<String>) -> Self {
self.version = version.into();
self
}
#[must_use]
pub fn with_sampling(mut self) -> Self {
self.capabilities = self.capabilities.with_sampling();
self
}
#[must_use]
pub fn with_elicitation(mut self) -> Self {
self.capabilities = self.capabilities.with_elicitation();
self
}
#[must_use]
pub fn with_roots(mut self) -> Self {
self.capabilities = self.capabilities.with_roots();
self
}
#[must_use]
pub fn with_roots_and_changes(mut self) -> Self {
self.capabilities = self.capabilities.with_roots_and_changes();
self
}
#[must_use]
pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
self.capabilities = capabilities;
self
}
pub async fn build<T: Transport + 'static>(self, transport: T) -> Result<Client<T>, McpError> {
let client_info = ClientInfo::new(&self.name, &self.version);
let init_result = initialize(&transport, &client_info, &self.capabilities).await?;
Ok(Client::new(
transport,
init_result,
client_info,
self.capabilities,
))
}
pub async fn build_with_handler<
T: Transport + 'static,
H: crate::handler::ClientHandler + 'static,
>(
self,
transport: T,
handler: H,
) -> Result<Client<T, H>, McpError> {
let client_info = ClientInfo::new(&self.name, &self.version);
let init_result = initialize(&transport, &client_info, &self.capabilities).await?;
Ok(Client::with_handler(
transport,
init_result,
client_info,
self.capabilities,
handler,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_defaults() {
let builder = ClientBuilder::new();
assert_eq!(builder.name, "mcp-client");
assert!(!builder.capabilities.has_sampling());
assert!(!builder.capabilities.has_roots());
}
#[test]
fn test_builder_fluent() {
let builder = ClientBuilder::new()
.name("test-client")
.version("1.0.0")
.with_sampling()
.with_roots();
assert_eq!(builder.name, "test-client");
assert_eq!(builder.version, "1.0.0");
assert!(builder.capabilities.has_sampling());
assert!(builder.capabilities.has_roots());
}
}