turbomcp_client/
lib.rs

1//! # `TurboMCP` Client
2//!
3//! MCP (Model Context Protocol) client implementation for connecting to MCP servers
4//! and consuming their capabilities (tools, prompts, resources, and sampling).
5//!
6//! ## Features
7//!
8//! - Connection management with automatic reconnection
9//! - Error handling and recovery mechanisms
10//! - Support for all MCP capabilities including bidirectional sampling
11//! - Elicitation response handling for server-initiated user input requests
12//! - Transport-agnostic design (works with any `Transport` implementation)
13//! - Type-safe protocol communication
14//! - Request/response correlation tracking
15//! - Timeout and cancellation support
16//! - Automatic capability negotiation
17//! - Handler support for server-initiated requests (sampling and elicitation)
18//!
19//! ## Architecture
20//!
21//! The client follows a layered architecture:
22//!
23//! ```text
24//! Application Layer
25//!        ↓
26//! Client API (this crate)
27//!        ↓  
28//! Protocol Layer (turbomcp-protocol)
29//!        ↓
30//! Transport Layer (turbomcp-transport)
31//! ```
32//!
33//! ## Usage
34//!
35//! ```rust,no_run
36//! use turbomcp_client::{Client, ClientBuilder};
37//! use turbomcp_transport::stdio::StdioTransport;
38//!
39//! # async fn example() -> turbomcp_protocol::Result<()> {
40//! // Create a client with stdio transport
41//! let transport = StdioTransport::new();
42//! let mut client = Client::new(transport);
43//!
44//! // Initialize connection and negotiate capabilities
45//! let result = client.initialize().await?;
46//! println!("Connected to: {}", result.server_info.name);
47//!
48//! // List and call tools
49//! let tools = client.list_tools().await?;
50//! for tool in tools {
51//!     println!("Tool: {} - {}", tool.name, tool.description.as_deref().unwrap_or("No description"));
52//! }
53//!
54//! // Access resources
55//! let resources = client.list_resources().await?;
56//! for resource in resources {
57//!     println!("Resource: {} ({})", resource.name, resource.uri);
58//! }
59//! # Ok(())
60//! # }
61//! ```
62//!
63//! ## Elicitation Response Handling (New in 1.0.3)
64//!
65//! The client now supports handling server-initiated elicitation requests:
66//!
67//! ```rust,no_run
68//! use turbomcp_client::Client;
69//! use std::collections::HashMap;
70//!
71//! // Simple elicitation handling example
72//! async fn handle_server_elicitation() {
73//!     // When server requests user input, you would:
74//!     // 1. Present the schema to the user
75//!     // 2. Collect their input  
76//!     // 3. Send response back to server
77//!     
78//!     let user_preferences: HashMap<String, String> = HashMap::new();
79//!     // Your UI/CLI interaction logic here
80//!     println!("Server requesting user preferences");
81//! }
82//! ```
83//!
84//! ## Sampling Support (New in 1.0.3)
85//!
86//! Handle server-initiated sampling requests for LLM capabilities:
87//!
88//! ```rust,no_run
89//! use turbomcp_client::Client;
90//! use turbomcp_client::sampling::SamplingHandler;
91//! use turbomcp_protocol::types::{CreateMessageRequest, CreateMessageResult, Role, Content, StopReason, TextContent};
92//! use async_trait::async_trait;
93//!
94//! #[derive(Debug)]
95//! struct MySamplingHandler {
96//!     // Your LLM client would go here
97//! }
98//!
99//! #[async_trait]
100//! impl SamplingHandler for MySamplingHandler {
101//!     async fn handle_create_message(
102//!         &self,
103//!         request_id: String,
104//!         request: CreateMessageRequest
105//!     ) -> Result<CreateMessageResult, Box<dyn std::error::Error + Send + Sync>> {
106//!         // Forward to your LLM provider (OpenAI, Anthropic, etc.)
107//!         // Use request_id for correlation tracking
108//!         // Allows the server to request LLM sampling through the client
109//!         
110//!         Ok(CreateMessageResult {
111//!             role: Role::Assistant,
112//!             content: Content::Text(
113//!                 TextContent {
114//!                     text: "Response from LLM".to_string(),
115//!                     annotations: None,
116//!                     meta: None,
117//!                 }
118//!             ),
119//!              model: "gpt-4".to_string(),
120//!             stop_reason: Some(StopReason::EndTurn),
121//!             _meta: None,
122//!         })
123//!     }
124//! }
125//! ```
126//!
127//! ## Error Handling
128//!
129//! The client provides comprehensive error handling with automatic retry logic:
130//!
131//! ```rust,no_run
132//! # use turbomcp_client::Client;
133//! # use turbomcp_transport::stdio::StdioTransport;
134//! # async fn example() -> turbomcp_protocol::Result<()> {
135//! # let mut client = Client::new(StdioTransport::new());
136//! match client.call_tool("my_tool", None).await {
137//!     Ok(result) => println!("Tool result: {:?}", result),
138//!     Err(e) => eprintln!("Tool call failed: {}", e),
139//! }
140//! # Ok(())
141//! # }
142//! ```
143
144/// TurboMCP Client version from Cargo.toml
145///
146/// This constant provides easy programmatic access to the current version.
147///
148/// # Example
149///
150/// ```rust
151/// println!("TurboMCP Client version: {}", turbomcp_client::VERSION);
152/// ```
153pub const VERSION: &str = env!("CARGO_PKG_VERSION");
154
155/// TurboMCP Client crate name
156pub const CRATE_NAME: &str = env!("CARGO_PKG_NAME");
157
158pub mod client;
159pub mod handlers;
160pub mod plugins;
161pub mod prelude;
162pub mod sampling;
163
164// Re-export key types for convenience
165pub use client::{ConnectionInfo, ConnectionState, ManagerConfig, ServerGroup, SessionManager};
166
167use std::sync::Arc;
168
169use turbomcp_transport::Transport;
170
171// ============================================================================
172// TOP-LEVEL RE-EXPORTS FOR ERGONOMIC IMPORTS
173// ============================================================================
174
175// Result/Error types - re-export from protocol for consistency
176pub use turbomcp_protocol::{Error, Result};
177
178// Handler types (most commonly used)
179pub use handlers::{
180    // Cancellation (MCP 2025-06-18 spec compliant)
181    CancellationHandler,
182    CancelledNotification,
183    ElicitationAction,
184    // Elicitation
185    ElicitationHandler,
186    ElicitationRequest,
187    ElicitationResponse,
188    // Error handling
189    HandlerError,
190    HandlerResult,
191    // Logging (MCP 2025-06-18 spec compliant)
192    LogHandler,
193    LoggingNotification,
194    PromptListChangedHandler,
195    // List changed handlers (MCP 2025-06-18 spec compliant)
196    ResourceListChangedHandler,
197    // Resource updates (MCP 2025-06-18 spec compliant)
198    ResourceUpdateHandler,
199    ResourceUpdatedNotification,
200    // Roots
201    RootsHandler,
202    ToolListChangedHandler,
203};
204
205// Sampling types
206pub use sampling::{SamplingHandler, ServerInfo, UserInteractionHandler};
207
208// Plugin system
209pub use plugins::{
210    CachePlugin, ClientPlugin, MetricsPlugin, PluginConfig, PluginContext, PluginError,
211    PluginResult, RetryPlugin,
212};
213
214// Common protocol types
215pub use turbomcp_protocol::types::{
216    Content, LogLevel, Prompt, Resource, ResourceContents, Role, Tool,
217};
218
219// Transport re-exports (with feature gates)
220#[cfg(feature = "stdio")]
221pub use turbomcp_transport::stdio::StdioTransport;
222
223#[cfg(feature = "http")]
224pub use turbomcp_transport::streamable_http_client::{
225    RetryPolicy, StreamableHttpClientConfig, StreamableHttpClientTransport,
226};
227
228#[cfg(feature = "tcp")]
229pub use turbomcp_transport::tcp::{TcpTransport, TcpTransportBuilder};
230
231#[cfg(feature = "unix")]
232pub use turbomcp_transport::unix::{UnixTransport, UnixTransportBuilder};
233
234#[cfg(feature = "websocket")]
235pub use turbomcp_transport::websocket_bidirectional::{
236    WebSocketBidirectionalConfig, WebSocketBidirectionalTransport,
237};
238
239/// Client capability configuration
240///
241/// Defines the capabilities that this client supports when connecting to MCP servers.
242/// These capabilities are sent during the initialization handshake to negotiate
243/// which features will be available during the session.
244///
245/// # Examples
246///
247/// ```
248/// use turbomcp_client::ClientCapabilities;
249///
250/// let capabilities = ClientCapabilities {
251///     tools: true,
252///     prompts: true,
253///     resources: true,
254///     sampling: false,
255/// };
256/// ```
257#[derive(Debug, Clone, Default)]
258pub struct ClientCapabilities {
259    /// Whether the client supports tool calling
260    pub tools: bool,
261
262    /// Whether the client supports prompts
263    pub prompts: bool,
264
265    /// Whether the client supports resources
266    pub resources: bool,
267
268    /// Whether the client supports sampling
269    pub sampling: bool,
270}
271
272impl ClientCapabilities {
273    /// All capabilities enabled (tools, prompts, resources, sampling)
274    ///
275    /// This is the most comprehensive configuration, enabling full MCP protocol support.
276    ///
277    /// # Example
278    ///
279    /// ```rust
280    /// use turbomcp_client::ClientCapabilities;
281    ///
282    /// let capabilities = ClientCapabilities::all();
283    /// assert!(capabilities.tools);
284    /// assert!(capabilities.prompts);
285    /// assert!(capabilities.resources);
286    /// assert!(capabilities.sampling);
287    /// ```
288    #[must_use]
289    pub fn all() -> Self {
290        Self {
291            tools: true,
292            prompts: true,
293            resources: true,
294            sampling: true,
295        }
296    }
297
298    /// Core capabilities without sampling (tools, prompts, resources)
299    ///
300    /// This is the recommended default for most applications. It enables
301    /// all standard MCP features except server-initiated sampling requests.
302    ///
303    /// # Example
304    ///
305    /// ```rust
306    /// use turbomcp_client::ClientCapabilities;
307    ///
308    /// let capabilities = ClientCapabilities::core();
309    /// assert!(capabilities.tools);
310    /// assert!(capabilities.prompts);
311    /// assert!(capabilities.resources);
312    /// assert!(!capabilities.sampling);
313    /// ```
314    #[must_use]
315    pub fn core() -> Self {
316        Self {
317            tools: true,
318            prompts: true,
319            resources: true,
320            sampling: false,
321        }
322    }
323
324    /// Minimal capabilities (tools only)
325    ///
326    /// Use this for simple tool-calling clients that don't need prompts,
327    /// resources, or sampling support.
328    ///
329    /// # Example
330    ///
331    /// ```rust
332    /// use turbomcp_client::ClientCapabilities;
333    ///
334    /// let capabilities = ClientCapabilities::minimal();
335    /// assert!(capabilities.tools);
336    /// assert!(!capabilities.prompts);
337    /// assert!(!capabilities.resources);
338    /// assert!(!capabilities.sampling);
339    /// ```
340    #[must_use]
341    pub fn minimal() -> Self {
342        Self {
343            tools: true,
344            prompts: false,
345            resources: false,
346            sampling: false,
347        }
348    }
349
350    /// Only tools enabled
351    ///
352    /// Same as `minimal()`, provided for clarity.
353    #[must_use]
354    pub fn only_tools() -> Self {
355        Self::minimal()
356    }
357
358    /// Only resources enabled
359    ///
360    /// Use this for resource-focused clients that don't need tools or prompts.
361    ///
362    /// # Example
363    ///
364    /// ```rust
365    /// use turbomcp_client::ClientCapabilities;
366    ///
367    /// let capabilities = ClientCapabilities::only_resources();
368    /// assert!(!capabilities.tools);
369    /// assert!(!capabilities.prompts);
370    /// assert!(capabilities.resources);
371    /// ```
372    #[must_use]
373    pub fn only_resources() -> Self {
374        Self {
375            tools: false,
376            prompts: false,
377            resources: true,
378            sampling: false,
379        }
380    }
381
382    /// Only prompts enabled
383    ///
384    /// Use this for prompt-focused clients that don't need tools or resources.
385    ///
386    /// # Example
387    ///
388    /// ```rust
389    /// use turbomcp_client::ClientCapabilities;
390    ///
391    /// let capabilities = ClientCapabilities::only_prompts();
392    /// assert!(!capabilities.tools);
393    /// assert!(capabilities.prompts);
394    /// assert!(!capabilities.resources);
395    /// ```
396    #[must_use]
397    pub fn only_prompts() -> Self {
398        Self {
399            tools: false,
400            prompts: true,
401            resources: false,
402            sampling: false,
403        }
404    }
405
406    /// Only sampling enabled
407    ///
408    /// Use this for clients that exclusively handle server-initiated sampling requests.
409    #[must_use]
410    pub fn only_sampling() -> Self {
411        Self {
412            tools: false,
413            prompts: false,
414            resources: false,
415            sampling: true,
416        }
417    }
418}
419
420/// JSON-RPC protocol handler for MCP communication
421// Note: ProtocolClient implementation moved to client/protocol.rs for better modularity
422/// MCP client for communicating with servers
423///
424/// The `Client` struct provides a beautiful, ergonomic interface for interacting with MCP servers.
425/// It handles all protocol complexity internally, exposing only clean, type-safe methods.
426///
427/// # Type Parameters
428///
429/// * `T` - The transport implementation used for communication
430///
431/// # Examples
432///
433/// ```rust,no_run
434/// use turbomcp_client::Client;
435/// use turbomcp_transport::stdio::StdioTransport;
436///
437/// # async fn example() -> turbomcp_protocol::Result<()> {
438/// let transport = StdioTransport::new();
439/// let mut client = Client::new(transport);
440///
441/// // Initialize and start using the client
442/// client.initialize().await?;
443/// # Ok(())
444/// # }
445/// ```
446// Re-export Client from the core module
447pub use client::core::Client;
448
449// Thread-safe wrapper for sharing Client across async tasks
450//
451// This wrapper encapsulates the Arc/Mutex complexity and provides a clean API
452// for concurrent access to MCP client functionality. It addresses the limitations
453// identified in PR feedback where Client requires `&mut self` for all operations
454// but needs to be shared across multiple async tasks.
455//
456// # Design Rationale
457//
458// All Client methods require `&mut self` because:
459// - MCP connections maintain state (initialized flag, connection status)
460// - Request correlation tracking for JSON-RPC requires mutation
461// - Handler and plugin registries need mutable access
462//
463// Note: SharedClient has been removed in v2 - Client is now directly cloneable via Arc
464
465// ----------------------------------------------------------------------------
466// Re-exports
467// ----------------------------------------------------------------------------
468
469#[doc = "Result of client initialization"]
470#[doc = ""]
471#[doc = "Contains information about the server and the negotiated capabilities"]
472#[doc = "after a successful initialization handshake."]
473pub use client::config::InitializeResult;
474
475// ServerCapabilities is now imported from turbomcp_protocol::types
476
477/// Connection configuration for the client
478#[derive(Debug, Clone)]
479pub struct ConnectionConfig {
480    /// Request timeout in milliseconds
481    pub timeout_ms: u64,
482
483    /// Maximum number of retry attempts
484    pub max_retries: u32,
485
486    /// Retry delay in milliseconds
487    pub retry_delay_ms: u64,
488
489    /// Keep-alive interval in milliseconds
490    pub keepalive_ms: u64,
491}
492
493impl Default for ConnectionConfig {
494    fn default() -> Self {
495        Self {
496            timeout_ms: 30_000,    // 30 seconds
497            max_retries: 3,        // 3 attempts
498            retry_delay_ms: 1_000, // 1 second
499            keepalive_ms: 60_000,  // 60 seconds
500        }
501    }
502}
503
504/// Builder for configuring and creating MCP clients
505///
506/// Provides a fluent interface for configuring client options before creation.
507/// The enhanced builder pattern supports comprehensive configuration including:
508/// - Protocol capabilities
509/// - Plugin registration
510/// - Handler registration
511/// - Connection settings
512/// - Resilience configuration
513///
514/// # Examples
515///
516/// Basic usage:
517/// ```rust,no_run
518/// use turbomcp_client::ClientBuilder;
519/// use turbomcp_transport::stdio::StdioTransport;
520///
521/// # async fn example() -> turbomcp_protocol::Result<()> {
522/// let client = ClientBuilder::new()
523///     .with_tools(true)
524///     .with_prompts(true)
525///     .with_resources(false)
526///     .build(StdioTransport::new());
527/// # Ok(())
528/// # }
529/// ```
530///
531/// Advanced configuration:
532/// ```rust,no_run
533/// use turbomcp_client::{ClientBuilder, ConnectionConfig};
534/// use turbomcp_client::plugins::{MetricsPlugin, PluginConfig};
535/// use turbomcp_transport::stdio::StdioTransport;
536/// use std::sync::Arc;
537///
538/// # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
539/// let client = ClientBuilder::new()
540///     .with_tools(true)
541///     .with_prompts(true)
542///     .with_resources(true)
543///     .with_sampling(true)
544///     .with_connection_config(ConnectionConfig {
545///         timeout_ms: 60_000,
546///         max_retries: 5,
547///         retry_delay_ms: 2_000,
548///         keepalive_ms: 30_000,
549///     })
550///     .with_plugin(Arc::new(MetricsPlugin::new(PluginConfig::Metrics)))
551///     .build(StdioTransport::new())
552///     .await?;
553/// # Ok(())
554/// # }
555/// ```
556#[derive(Debug, Default)]
557pub struct ClientBuilder {
558    capabilities: ClientCapabilities,
559    connection_config: ConnectionConfig,
560    plugins: Vec<Arc<dyn crate::plugins::ClientPlugin>>,
561    elicitation_handler: Option<Arc<dyn crate::handlers::ElicitationHandler>>,
562    log_handler: Option<Arc<dyn crate::handlers::LogHandler>>,
563    resource_update_handler: Option<Arc<dyn crate::handlers::ResourceUpdateHandler>>,
564    // Robustness configuration
565    enable_resilience: bool,
566    retry_config: Option<turbomcp_transport::resilience::RetryConfig>,
567    circuit_breaker_config: Option<turbomcp_transport::resilience::CircuitBreakerConfig>,
568    health_check_config: Option<turbomcp_transport::resilience::HealthCheckConfig>,
569}
570
571// Default implementation is now derived
572
573impl ClientBuilder {
574    /// Create a new client builder
575    ///
576    /// Returns a new builder with default configuration.
577    #[must_use]
578    pub fn new() -> Self {
579        Self::default()
580    }
581
582    // ============================================================================
583    // CAPABILITY CONFIGURATION
584    // ============================================================================
585
586    /// Enable or disable tool support
587    ///
588    /// # Arguments
589    ///
590    /// * `enabled` - Whether to enable tool support
591    #[must_use]
592    pub fn with_tools(mut self, enabled: bool) -> Self {
593        self.capabilities.tools = enabled;
594        self
595    }
596
597    /// Enable or disable prompt support
598    ///
599    /// # Arguments
600    ///
601    /// * `enabled` - Whether to enable prompt support
602    #[must_use]
603    pub fn with_prompts(mut self, enabled: bool) -> Self {
604        self.capabilities.prompts = enabled;
605        self
606    }
607
608    /// Enable or disable resource support
609    ///
610    /// # Arguments
611    ///
612    /// * `enabled` - Whether to enable resource support
613    #[must_use]
614    pub fn with_resources(mut self, enabled: bool) -> Self {
615        self.capabilities.resources = enabled;
616        self
617    }
618
619    /// Enable or disable sampling support
620    ///
621    /// # Arguments
622    ///
623    /// * `enabled` - Whether to enable sampling support
624    #[must_use]
625    pub fn with_sampling(mut self, enabled: bool) -> Self {
626        self.capabilities.sampling = enabled;
627        self
628    }
629
630    /// Configure all capabilities at once
631    ///
632    /// # Arguments
633    ///
634    /// * `capabilities` - The capabilities configuration
635    #[must_use]
636    pub fn with_capabilities(mut self, capabilities: ClientCapabilities) -> Self {
637        self.capabilities = capabilities;
638        self
639    }
640
641    // ============================================================================
642    // CONNECTION CONFIGURATION
643    // ============================================================================
644
645    /// Configure connection settings
646    ///
647    /// # Arguments
648    ///
649    /// * `config` - The connection configuration
650    #[must_use]
651    pub fn with_connection_config(mut self, config: ConnectionConfig) -> Self {
652        self.connection_config = config;
653        self
654    }
655
656    /// Set request timeout
657    ///
658    /// # Arguments
659    ///
660    /// * `timeout_ms` - Timeout in milliseconds
661    #[must_use]
662    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
663        self.connection_config.timeout_ms = timeout_ms;
664        self
665    }
666
667    /// Set maximum retry attempts
668    ///
669    /// # Arguments
670    ///
671    /// * `max_retries` - Maximum number of retries
672    #[must_use]
673    pub fn with_max_retries(mut self, max_retries: u32) -> Self {
674        self.connection_config.max_retries = max_retries;
675        self
676    }
677
678    /// Set retry delay
679    ///
680    /// # Arguments
681    ///
682    /// * `delay_ms` - Retry delay in milliseconds
683    #[must_use]
684    pub fn with_retry_delay(mut self, delay_ms: u64) -> Self {
685        self.connection_config.retry_delay_ms = delay_ms;
686        self
687    }
688
689    /// Set keep-alive interval
690    ///
691    /// # Arguments
692    ///
693    /// * `interval_ms` - Keep-alive interval in milliseconds
694    #[must_use]
695    pub fn with_keepalive(mut self, interval_ms: u64) -> Self {
696        self.connection_config.keepalive_ms = interval_ms;
697        self
698    }
699
700    // ============================================================================
701    // ROBUSTNESS & RESILIENCE CONFIGURATION
702    // ============================================================================
703
704    /// Enable resilient transport with circuit breaker, retry, and health checking
705    ///
706    /// When enabled, the transport layer will automatically:
707    /// - Retry failed operations with exponential backoff
708    /// - Use circuit breaker pattern to prevent cascade failures
709    /// - Perform periodic health checks
710    /// - Deduplicate messages
711    ///
712    /// # Examples
713    ///
714    /// ```rust,no_run
715    /// use turbomcp_client::ClientBuilder;
716    /// use turbomcp_transport::stdio::StdioTransport;
717    ///
718    /// let client = ClientBuilder::new()
719    ///     .enable_resilience()
720    ///     .build(StdioTransport::new());
721    /// ```
722    #[must_use]
723    pub fn enable_resilience(mut self) -> Self {
724        self.enable_resilience = true;
725        self
726    }
727
728    /// Configure retry behavior for resilient transport
729    ///
730    /// # Arguments
731    ///
732    /// * `config` - Retry configuration
733    ///
734    /// # Examples
735    ///
736    /// ```rust,no_run
737    /// use turbomcp_client::ClientBuilder;
738    /// use turbomcp_transport::resilience::RetryConfig;
739    /// use turbomcp_transport::stdio::StdioTransport;
740    /// use std::time::Duration;
741    ///
742    /// let client = ClientBuilder::new()
743    ///     .enable_resilience()
744    ///     .with_retry_config(RetryConfig {
745    ///         max_attempts: 5,
746    ///         base_delay: Duration::from_millis(100),
747    ///         max_delay: Duration::from_secs(30),
748    ///         backoff_multiplier: 2.0,
749    ///         jitter_factor: 0.1,
750    ///         retry_on_connection_error: true,
751    ///         retry_on_timeout: true,
752    ///         custom_retry_conditions: Vec::new(),
753    ///     })
754    ///     .build(StdioTransport::new());
755    /// ```
756    #[must_use]
757    pub fn with_retry_config(
758        mut self,
759        config: turbomcp_transport::resilience::RetryConfig,
760    ) -> Self {
761        self.retry_config = Some(config);
762        self.enable_resilience = true; // Auto-enable resilience
763        self
764    }
765
766    /// Configure circuit breaker for resilient transport
767    ///
768    /// # Arguments
769    ///
770    /// * `config` - Circuit breaker configuration
771    ///
772    /// # Examples
773    ///
774    /// ```rust,no_run
775    /// use turbomcp_client::ClientBuilder;
776    /// use turbomcp_transport::resilience::CircuitBreakerConfig;
777    /// use turbomcp_transport::stdio::StdioTransport;
778    /// use std::time::Duration;
779    ///
780    /// let client = ClientBuilder::new()
781    ///     .enable_resilience()
782    ///     .with_circuit_breaker_config(CircuitBreakerConfig {
783    ///         failure_threshold: 5,
784    ///         success_threshold: 2,
785    ///         timeout: Duration::from_secs(60),
786    ///         rolling_window_size: 100,
787    ///         minimum_requests: 10,
788    ///     })
789    ///     .build(StdioTransport::new());
790    /// ```
791    #[must_use]
792    pub fn with_circuit_breaker_config(
793        mut self,
794        config: turbomcp_transport::resilience::CircuitBreakerConfig,
795    ) -> Self {
796        self.circuit_breaker_config = Some(config);
797        self.enable_resilience = true; // Auto-enable resilience
798        self
799    }
800
801    /// Configure health checking for resilient transport
802    ///
803    /// # Arguments
804    ///
805    /// * `config` - Health check configuration
806    ///
807    /// # Examples
808    ///
809    /// ```rust,no_run
810    /// use turbomcp_client::ClientBuilder;
811    /// use turbomcp_transport::resilience::HealthCheckConfig;
812    /// use turbomcp_transport::stdio::StdioTransport;
813    /// use std::time::Duration;
814    ///
815    /// let client = ClientBuilder::new()
816    ///     .enable_resilience()
817    ///     .with_health_check_config(HealthCheckConfig {
818    ///         interval: Duration::from_secs(30),
819    ///         timeout: Duration::from_secs(5),
820    ///         failure_threshold: 3,
821    ///         success_threshold: 1,
822    ///         custom_check: None,
823    ///     })
824    ///     .build(StdioTransport::new());
825    /// ```
826    #[must_use]
827    pub fn with_health_check_config(
828        mut self,
829        config: turbomcp_transport::resilience::HealthCheckConfig,
830    ) -> Self {
831        self.health_check_config = Some(config);
832        self.enable_resilience = true; // Auto-enable resilience
833        self
834    }
835
836    // ============================================================================
837    // PLUGIN SYSTEM CONFIGURATION
838    // ============================================================================
839
840    /// Register a plugin with the client
841    ///
842    /// Plugins provide middleware functionality for request/response processing,
843    /// metrics collection, retry logic, caching, and other cross-cutting concerns.
844    ///
845    /// # Arguments
846    ///
847    /// * `plugin` - The plugin implementation
848    ///
849    /// # Examples
850    ///
851    /// ```rust,no_run
852    /// use turbomcp_client::{ClientBuilder, ConnectionConfig};
853    /// use turbomcp_client::plugins::{MetricsPlugin, RetryPlugin, PluginConfig, RetryConfig};
854    /// use std::sync::Arc;
855    ///
856    /// let client = ClientBuilder::new()
857    ///     .with_plugin(Arc::new(MetricsPlugin::new(PluginConfig::Metrics)))
858    ///     .with_plugin(Arc::new(RetryPlugin::new(PluginConfig::Retry(RetryConfig {
859    ///         max_retries: 5,
860    ///         base_delay_ms: 1000,
861    ///         max_delay_ms: 30000,
862    ///         backoff_multiplier: 2.0,
863    ///         retry_on_timeout: true,
864    ///         retry_on_connection_error: true,
865    ///     }))));
866    /// ```
867    pub fn with_plugin(mut self, plugin: Arc<dyn crate::plugins::ClientPlugin>) -> Self {
868        self.plugins.push(plugin);
869        self
870    }
871
872    /// Register multiple plugins at once
873    ///
874    /// # Arguments
875    ///
876    /// * `plugins` - Vector of plugin implementations
877    #[must_use]
878    pub fn with_plugins(mut self, plugins: Vec<Arc<dyn crate::plugins::ClientPlugin>>) -> Self {
879        self.plugins.extend(plugins);
880        self
881    }
882
883    // ============================================================================
884    // HANDLER REGISTRATION
885    // ============================================================================
886
887    /// Register an elicitation handler for processing user input requests
888    ///
889    /// # Arguments
890    ///
891    /// * `handler` - The elicitation handler implementation
892    pub fn with_elicitation_handler(
893        mut self,
894        handler: Arc<dyn crate::handlers::ElicitationHandler>,
895    ) -> Self {
896        self.elicitation_handler = Some(handler);
897        self
898    }
899
900    /// Register a log handler for processing server log messages
901    ///
902    /// # Arguments
903    ///
904    /// * `handler` - The log handler implementation
905    pub fn with_log_handler(mut self, handler: Arc<dyn crate::handlers::LogHandler>) -> Self {
906        self.log_handler = Some(handler);
907        self
908    }
909
910    /// Register a resource update handler for processing resource change notifications
911    ///
912    /// # Arguments
913    ///
914    /// * `handler` - The resource update handler implementation
915    pub fn with_resource_update_handler(
916        mut self,
917        handler: Arc<dyn crate::handlers::ResourceUpdateHandler>,
918    ) -> Self {
919        self.resource_update_handler = Some(handler);
920        self
921    }
922
923    // ============================================================================
924    // BUILD METHODS
925    // ============================================================================
926
927    /// Build a client with the configured options
928    ///
929    /// Creates a new client instance with all the configured options. The client
930    /// will be initialized with the registered plugins, handlers, and providers.
931    ///
932    /// # Arguments
933    ///
934    /// * `transport` - The transport to use for the client
935    ///
936    /// # Returns
937    ///
938    /// Returns a configured `Client` instance wrapped in a Result for async setup.
939    ///
940    /// # Examples
941    ///
942    /// ```rust,no_run
943    /// use turbomcp_client::ClientBuilder;
944    /// use turbomcp_transport::stdio::StdioTransport;
945    ///
946    /// # async fn example() -> turbomcp_protocol::Result<()> {
947    /// let client = ClientBuilder::new()
948    ///     .with_tools(true)
949    ///     .with_prompts(true)
950    ///     .build(StdioTransport::new())
951    ///     .await?;
952    /// # Ok(())
953    /// # }
954    /// ```
955    pub async fn build<T: Transport + 'static>(self, transport: T) -> Result<Client<T>> {
956        // Create base client with capabilities
957        let client = Client::with_capabilities(transport, self.capabilities);
958
959        // Register handlers
960        if let Some(handler) = self.elicitation_handler {
961            client.set_elicitation_handler(handler);
962        }
963        if let Some(handler) = self.log_handler {
964            client.set_log_handler(handler);
965        }
966        if let Some(handler) = self.resource_update_handler {
967            client.set_resource_update_handler(handler);
968        }
969
970        // Apply connection configuration (store for future use in actual connections)
971        // Note: The current Client doesn't expose connection config setters,
972        // so we'll store this for when the transport supports it
973
974        // Register plugins with the client
975        let has_plugins = !self.plugins.is_empty();
976        for plugin in self.plugins {
977            client.register_plugin(plugin).await?;
978        }
979
980        // Initialize plugins after registration
981        if has_plugins {
982            client.initialize_plugins().await?;
983        }
984
985        Ok(client)
986    }
987
988    /// Build a client with resilient transport (circuit breaker, retry, health checking)
989    ///
990    /// When resilience features are enabled via `enable_resilience()` or any resilience
991    /// configuration method, this wraps the transport in a `TurboTransport` that provides:
992    /// - Automatic retry with exponential backoff
993    /// - Circuit breaker pattern for fast failure
994    /// - Health checking and monitoring
995    /// - Message deduplication
996    ///
997    /// # Arguments
998    ///
999    /// * `transport` - The base transport to wrap with resilience features
1000    ///
1001    /// # Returns
1002    ///
1003    /// Returns a configured `Client<TurboTransport>` instance.
1004    ///
1005    /// # Errors
1006    ///
1007    /// Returns an error if plugin initialization fails.
1008    ///
1009    /// # Examples
1010    ///
1011    /// ```rust,no_run
1012    /// use turbomcp_client::ClientBuilder;
1013    /// use turbomcp_transport::stdio::StdioTransport;
1014    /// use turbomcp_transport::resilience::{RetryConfig, CircuitBreakerConfig, HealthCheckConfig};
1015    /// use std::time::Duration;
1016    ///
1017    /// # async fn example() -> turbomcp_protocol::Result<()> {
1018    /// let client = ClientBuilder::new()
1019    ///     .with_retry_config(RetryConfig {
1020    ///         max_attempts: 5,
1021    ///         base_delay: Duration::from_millis(200),
1022    ///         ..Default::default()
1023    ///     })
1024    ///     .with_circuit_breaker_config(CircuitBreakerConfig {
1025    ///         failure_threshold: 3,
1026    ///         timeout: Duration::from_secs(30),
1027    ///         ..Default::default()
1028    ///     })
1029    ///     .with_health_check_config(HealthCheckConfig {
1030    ///         interval: Duration::from_secs(15),
1031    ///         timeout: Duration::from_secs(5),
1032    ///         ..Default::default()
1033    ///     })
1034    ///     .build_resilient(StdioTransport::new())
1035    ///     .await?;
1036    /// # Ok(())
1037    /// # }
1038    /// ```
1039    pub async fn build_resilient<T: Transport + 'static>(
1040        self,
1041        transport: T,
1042    ) -> Result<Client<turbomcp_transport::resilience::TurboTransport>> {
1043        use turbomcp_transport::resilience::TurboTransport;
1044
1045        // Get configurations or use defaults
1046        let retry_config = self.retry_config.unwrap_or_default();
1047        let circuit_config = self.circuit_breaker_config.unwrap_or_default();
1048        let health_config = self.health_check_config.unwrap_or_default();
1049
1050        // Wrap transport in TurboTransport
1051        let robust_transport = TurboTransport::new(
1052            Box::new(transport),
1053            retry_config,
1054            circuit_config,
1055            health_config,
1056        );
1057
1058        // Create client with resilient transport
1059        let client = Client::with_capabilities(robust_transport, self.capabilities);
1060
1061        // Register handlers
1062        if let Some(handler) = self.elicitation_handler {
1063            client.set_elicitation_handler(handler);
1064        }
1065        if let Some(handler) = self.log_handler {
1066            client.set_log_handler(handler);
1067        }
1068        if let Some(handler) = self.resource_update_handler {
1069            client.set_resource_update_handler(handler);
1070        }
1071
1072        // Register plugins
1073        let has_plugins = !self.plugins.is_empty();
1074        for plugin in self.plugins {
1075            client.register_plugin(plugin).await?;
1076        }
1077
1078        if has_plugins {
1079            client.initialize_plugins().await?;
1080        }
1081
1082        Ok(client)
1083    }
1084
1085    /// Build a client synchronously with basic configuration only
1086    ///
1087    /// This is a convenience method for simple use cases where no async setup
1088    /// is required. For advanced features like plugins, use `build()` instead.
1089    ///
1090    /// # Arguments
1091    ///
1092    /// * `transport` - The transport to use for the client
1093    ///
1094    /// # Returns
1095    ///
1096    /// Returns a configured `Client` instance.
1097    ///
1098    /// # Examples
1099    ///
1100    /// ```rust,no_run
1101    /// use turbomcp_client::ClientBuilder;
1102    /// use turbomcp_transport::stdio::StdioTransport;
1103    ///
1104    /// let client = ClientBuilder::new()
1105    ///     .with_tools(true)
1106    ///     .build_sync(StdioTransport::new());
1107    /// ```
1108    pub fn build_sync<T: Transport + 'static>(self, transport: T) -> Client<T> {
1109        let client = Client::with_capabilities(transport, self.capabilities);
1110
1111        // Register synchronous handlers only
1112        if let Some(handler) = self.elicitation_handler {
1113            client.set_elicitation_handler(handler);
1114        }
1115        if let Some(handler) = self.log_handler {
1116            client.set_log_handler(handler);
1117        }
1118        if let Some(handler) = self.resource_update_handler {
1119            client.set_resource_update_handler(handler);
1120        }
1121
1122        client
1123    }
1124
1125    // ============================================================================
1126    // CONFIGURATION ACCESS
1127    // ============================================================================
1128
1129    /// Get the current capabilities configuration
1130    #[must_use]
1131    pub fn capabilities(&self) -> &ClientCapabilities {
1132        &self.capabilities
1133    }
1134
1135    /// Get the current connection configuration
1136    #[must_use]
1137    pub fn connection_config(&self) -> &ConnectionConfig {
1138        &self.connection_config
1139    }
1140
1141    /// Get the number of registered plugins
1142    #[must_use]
1143    pub fn plugin_count(&self) -> usize {
1144        self.plugins.len()
1145    }
1146
1147    /// Check if any handlers are registered
1148    #[must_use]
1149    pub fn has_handlers(&self) -> bool {
1150        self.elicitation_handler.is_some()
1151            || self.log_handler.is_some()
1152            || self.resource_update_handler.is_some()
1153    }
1154}
1155
1156// Re-export types for public API
1157pub use turbomcp_protocol::types::ServerCapabilities as PublicServerCapabilities;