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
64//!
65//! The client 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
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: Some("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///     max_concurrent_handlers: 100,
256/// };
257/// ```
258#[derive(Debug, Clone)]
259pub struct ClientCapabilities {
260    /// Whether the client supports tool calling
261    pub tools: bool,
262
263    /// Whether the client supports prompts
264    pub prompts: bool,
265
266    /// Whether the client supports resources
267    pub resources: bool,
268
269    /// Whether the client supports sampling
270    pub sampling: bool,
271
272    /// Maximum concurrent request/notification handlers (default: 100)
273    ///
274    /// This limits how many server-initiated requests/notifications can be processed simultaneously.
275    /// Provides automatic backpressure when the limit is reached.
276    ///
277    /// **Tuning Guide:**
278    /// - Low-resource clients: 50
279    /// - Standard clients: 100 (default)
280    /// - High-performance: 200-500
281    /// - Maximum recommended: 1000
282    pub max_concurrent_handlers: usize,
283}
284
285impl Default for ClientCapabilities {
286    fn default() -> Self {
287        Self {
288            tools: false,
289            prompts: false,
290            resources: false,
291            sampling: false,
292            max_concurrent_handlers: 100,
293        }
294    }
295}
296
297impl ClientCapabilities {
298    /// All capabilities enabled (tools, prompts, resources, sampling)
299    ///
300    /// This is the most comprehensive configuration, enabling full MCP protocol support.
301    ///
302    /// # Example
303    ///
304    /// ```rust
305    /// use turbomcp_client::ClientCapabilities;
306    ///
307    /// let capabilities = ClientCapabilities::all();
308    /// assert!(capabilities.tools);
309    /// assert!(capabilities.prompts);
310    /// assert!(capabilities.resources);
311    /// assert!(capabilities.sampling);
312    /// ```
313    #[must_use]
314    pub fn all() -> Self {
315        Self {
316            tools: true,
317            prompts: true,
318            resources: true,
319            sampling: true,
320            max_concurrent_handlers: 100,
321        }
322    }
323
324    /// Core capabilities without sampling (tools, prompts, resources)
325    ///
326    /// This is the recommended default for most applications. It enables
327    /// all standard MCP features except server-initiated sampling requests.
328    ///
329    /// # Example
330    ///
331    /// ```rust
332    /// use turbomcp_client::ClientCapabilities;
333    ///
334    /// let capabilities = ClientCapabilities::core();
335    /// assert!(capabilities.tools);
336    /// assert!(capabilities.prompts);
337    /// assert!(capabilities.resources);
338    /// assert!(!capabilities.sampling);
339    /// ```
340    #[must_use]
341    pub fn core() -> Self {
342        Self {
343            tools: true,
344            prompts: true,
345            resources: true,
346            sampling: false,
347            max_concurrent_handlers: 100,
348        }
349    }
350
351    /// Minimal capabilities (tools only)
352    ///
353    /// Use this for simple tool-calling clients that don't need prompts,
354    /// resources, or sampling support.
355    ///
356    /// # Example
357    ///
358    /// ```rust
359    /// use turbomcp_client::ClientCapabilities;
360    ///
361    /// let capabilities = ClientCapabilities::minimal();
362    /// assert!(capabilities.tools);
363    /// assert!(!capabilities.prompts);
364    /// assert!(!capabilities.resources);
365    /// assert!(!capabilities.sampling);
366    /// ```
367    #[must_use]
368    pub fn minimal() -> Self {
369        Self {
370            tools: true,
371            prompts: false,
372            resources: false,
373            sampling: false,
374            max_concurrent_handlers: 100,
375        }
376    }
377
378    /// Only tools enabled
379    ///
380    /// Same as `minimal()`, provided for clarity.
381    #[must_use]
382    pub fn only_tools() -> Self {
383        Self::minimal()
384    }
385
386    /// Only resources enabled
387    ///
388    /// Use this for resource-focused clients that don't need tools or prompts.
389    ///
390    /// # Example
391    ///
392    /// ```rust
393    /// use turbomcp_client::ClientCapabilities;
394    ///
395    /// let capabilities = ClientCapabilities::only_resources();
396    /// assert!(!capabilities.tools);
397    /// assert!(!capabilities.prompts);
398    /// assert!(capabilities.resources);
399    /// ```
400    #[must_use]
401    pub fn only_resources() -> Self {
402        Self {
403            tools: false,
404            prompts: false,
405            resources: true,
406            sampling: false,
407            max_concurrent_handlers: 100,
408        }
409    }
410
411    /// Only prompts enabled
412    ///
413    /// Use this for prompt-focused clients that don't need tools or resources.
414    ///
415    /// # Example
416    ///
417    /// ```rust
418    /// use turbomcp_client::ClientCapabilities;
419    ///
420    /// let capabilities = ClientCapabilities::only_prompts();
421    /// assert!(!capabilities.tools);
422    /// assert!(capabilities.prompts);
423    /// assert!(!capabilities.resources);
424    /// ```
425    #[must_use]
426    pub fn only_prompts() -> Self {
427        Self {
428            tools: false,
429            prompts: true,
430            resources: false,
431            sampling: false,
432            max_concurrent_handlers: 100,
433        }
434    }
435
436    /// Only sampling enabled
437    ///
438    /// Use this for clients that exclusively handle server-initiated sampling requests.
439    #[must_use]
440    pub fn only_sampling() -> Self {
441        Self {
442            tools: false,
443            prompts: false,
444            resources: false,
445            sampling: true,
446            max_concurrent_handlers: 100,
447        }
448    }
449}
450
451/// JSON-RPC protocol handler for MCP communication
452// Note: ProtocolClient implementation moved to client/protocol.rs for better modularity
453/// MCP client for communicating with servers
454///
455/// The `Client` struct provides an ergonomic interface for interacting with MCP servers.
456/// It handles protocol complexity internally, exposing clean, type-safe methods.
457///
458/// # Type Parameters
459///
460/// * `T` - The transport implementation used for communication
461///
462/// # Examples
463///
464/// ```rust,no_run
465/// use turbomcp_client::Client;
466/// use turbomcp_transport::stdio::StdioTransport;
467///
468/// # async fn example() -> turbomcp_protocol::Result<()> {
469/// let transport = StdioTransport::new();
470/// let mut client = Client::new(transport);
471///
472/// // Initialize and start using the client
473/// client.initialize().await?;
474/// # Ok(())
475/// # }
476/// ```
477// Re-export Client from the core module
478pub use client::core::Client;
479
480// Thread-safe wrapper for sharing Client across async tasks
481//
482// This wrapper encapsulates the Arc/Mutex complexity and provides a clean API
483// for concurrent access to MCP client functionality. It addresses the limitations
484// identified in PR feedback where Client requires `&mut self` for all operations
485// but needs to be shared across multiple async tasks.
486//
487// # Design Rationale
488//
489// All Client methods require `&mut self` because:
490// - MCP connections maintain state (initialized flag, connection status)
491// - Request correlation tracking for JSON-RPC requires mutation
492// - Handler and plugin registries need mutable access
493//
494// Note: SharedClient has been removed in v2 - Client is now directly cloneable via Arc
495
496// ----------------------------------------------------------------------------
497// Re-exports
498// ----------------------------------------------------------------------------
499
500#[doc = "Result of client initialization"]
501#[doc = ""]
502#[doc = "Contains information about the server and the negotiated capabilities"]
503#[doc = "after a successful initialization handshake."]
504pub use client::config::InitializeResult;
505
506// ServerCapabilities is now imported from turbomcp_protocol::types
507
508/// Connection configuration for the client
509#[derive(Debug, Clone)]
510pub struct ConnectionConfig {
511    /// Request timeout in milliseconds
512    pub timeout_ms: u64,
513
514    /// Maximum number of retry attempts
515    pub max_retries: u32,
516
517    /// Retry delay in milliseconds
518    pub retry_delay_ms: u64,
519
520    /// Keep-alive interval in milliseconds
521    pub keepalive_ms: u64,
522}
523
524impl Default for ConnectionConfig {
525    fn default() -> Self {
526        Self {
527            timeout_ms: 30_000,    // 30 seconds
528            max_retries: 3,        // 3 attempts
529            retry_delay_ms: 1_000, // 1 second
530            keepalive_ms: 60_000,  // 60 seconds
531        }
532    }
533}
534
535/// Builder for configuring and creating MCP clients
536///
537/// Provides a fluent interface for configuring client options before creation.
538/// The enhanced builder pattern supports comprehensive configuration including:
539/// - Protocol capabilities
540/// - Plugin registration
541/// - Handler registration
542/// - Connection settings
543/// - Resilience configuration
544///
545/// # Examples
546///
547/// Basic usage:
548/// ```rust,no_run
549/// use turbomcp_client::ClientBuilder;
550/// use turbomcp_transport::stdio::StdioTransport;
551///
552/// # async fn example() -> turbomcp_protocol::Result<()> {
553/// let client = ClientBuilder::new()
554///     .with_tools(true)
555///     .with_prompts(true)
556///     .with_resources(false)
557///     .build(StdioTransport::new());
558/// # Ok(())
559/// # }
560/// ```
561///
562/// Advanced configuration:
563/// ```rust,no_run
564/// use turbomcp_client::{ClientBuilder, ConnectionConfig};
565/// use turbomcp_client::plugins::{MetricsPlugin, PluginConfig};
566/// use turbomcp_transport::stdio::StdioTransport;
567/// use std::sync::Arc;
568///
569/// # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
570/// let client = ClientBuilder::new()
571///     .with_tools(true)
572///     .with_prompts(true)
573///     .with_resources(true)
574///     .with_sampling(true)
575///     .with_connection_config(ConnectionConfig {
576///         timeout_ms: 60_000,
577///         max_retries: 5,
578///         retry_delay_ms: 2_000,
579///         keepalive_ms: 30_000,
580///     })
581///     .with_plugin(Arc::new(MetricsPlugin::new(PluginConfig::Metrics)))
582///     .build(StdioTransport::new())
583///     .await?;
584/// # Ok(())
585/// # }
586/// ```
587#[derive(Debug, Default)]
588pub struct ClientBuilder {
589    capabilities: ClientCapabilities,
590    connection_config: ConnectionConfig,
591    plugins: Vec<Arc<dyn crate::plugins::ClientPlugin>>,
592    elicitation_handler: Option<Arc<dyn crate::handlers::ElicitationHandler>>,
593    log_handler: Option<Arc<dyn crate::handlers::LogHandler>>,
594    resource_update_handler: Option<Arc<dyn crate::handlers::ResourceUpdateHandler>>,
595    // Robustness configuration
596    enable_resilience: bool,
597    retry_config: Option<turbomcp_transport::resilience::RetryConfig>,
598    circuit_breaker_config: Option<turbomcp_transport::resilience::CircuitBreakerConfig>,
599    health_check_config: Option<turbomcp_transport::resilience::HealthCheckConfig>,
600}
601
602// Default implementation is now derived
603
604impl ClientBuilder {
605    /// Create a new client builder
606    ///
607    /// Returns a new builder with default configuration.
608    #[must_use]
609    pub fn new() -> Self {
610        Self::default()
611    }
612
613    // ============================================================================
614    // CAPABILITY CONFIGURATION
615    // ============================================================================
616
617    /// Enable or disable tool support
618    ///
619    /// # Arguments
620    ///
621    /// * `enabled` - Whether to enable tool support
622    #[must_use]
623    pub fn with_tools(mut self, enabled: bool) -> Self {
624        self.capabilities.tools = enabled;
625        self
626    }
627
628    /// Enable or disable prompt support
629    ///
630    /// # Arguments
631    ///
632    /// * `enabled` - Whether to enable prompt support
633    #[must_use]
634    pub fn with_prompts(mut self, enabled: bool) -> Self {
635        self.capabilities.prompts = enabled;
636        self
637    }
638
639    /// Enable or disable resource support
640    ///
641    /// # Arguments
642    ///
643    /// * `enabled` - Whether to enable resource support
644    #[must_use]
645    pub fn with_resources(mut self, enabled: bool) -> Self {
646        self.capabilities.resources = enabled;
647        self
648    }
649
650    /// Enable or disable sampling support
651    ///
652    /// # Arguments
653    ///
654    /// * `enabled` - Whether to enable sampling support
655    #[must_use]
656    pub fn with_sampling(mut self, enabled: bool) -> Self {
657        self.capabilities.sampling = enabled;
658        self
659    }
660
661    /// Set maximum concurrent request/notification handlers
662    ///
663    /// This limits how many server-initiated requests/notifications can be processed simultaneously.
664    /// Provides automatic backpressure when the limit is reached.
665    ///
666    /// # Arguments
667    ///
668    /// * `limit` - Maximum concurrent handlers (default: 100)
669    ///
670    /// # Tuning Guide
671    ///
672    /// - Low-resource clients: 50
673    /// - Standard clients: 100 (default)
674    /// - High-performance: 200-500
675    /// - Maximum recommended: 1000
676    ///
677    /// # Example
678    ///
679    /// ```rust,no_run
680    /// use turbomcp_client::ClientBuilder;
681    /// # use turbomcp_transport::StdioTransport;
682    ///
683    /// let builder = ClientBuilder::new()
684    ///     .with_max_concurrent_handlers(200);
685    /// ```
686    #[must_use]
687    pub fn with_max_concurrent_handlers(mut self, limit: usize) -> Self {
688        self.capabilities.max_concurrent_handlers = limit;
689        self
690    }
691
692    /// Configure all capabilities at once
693    ///
694    /// # Arguments
695    ///
696    /// * `capabilities` - The capabilities configuration
697    #[must_use]
698    pub fn with_capabilities(mut self, capabilities: ClientCapabilities) -> Self {
699        self.capabilities = capabilities;
700        self
701    }
702
703    // ============================================================================
704    // CONNECTION CONFIGURATION
705    // ============================================================================
706
707    /// Configure connection settings
708    ///
709    /// # Arguments
710    ///
711    /// * `config` - The connection configuration
712    #[must_use]
713    pub fn with_connection_config(mut self, config: ConnectionConfig) -> Self {
714        self.connection_config = config;
715        self
716    }
717
718    /// Set request timeout
719    ///
720    /// # Arguments
721    ///
722    /// * `timeout_ms` - Timeout in milliseconds
723    #[must_use]
724    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
725        self.connection_config.timeout_ms = timeout_ms;
726        self
727    }
728
729    /// Set maximum retry attempts
730    ///
731    /// # Arguments
732    ///
733    /// * `max_retries` - Maximum number of retries
734    #[must_use]
735    pub fn with_max_retries(mut self, max_retries: u32) -> Self {
736        self.connection_config.max_retries = max_retries;
737        self
738    }
739
740    /// Set retry delay
741    ///
742    /// # Arguments
743    ///
744    /// * `delay_ms` - Retry delay in milliseconds
745    #[must_use]
746    pub fn with_retry_delay(mut self, delay_ms: u64) -> Self {
747        self.connection_config.retry_delay_ms = delay_ms;
748        self
749    }
750
751    /// Set keep-alive interval
752    ///
753    /// # Arguments
754    ///
755    /// * `interval_ms` - Keep-alive interval in milliseconds
756    #[must_use]
757    pub fn with_keepalive(mut self, interval_ms: u64) -> Self {
758        self.connection_config.keepalive_ms = interval_ms;
759        self
760    }
761
762    // ============================================================================
763    // ROBUSTNESS & RESILIENCE CONFIGURATION
764    // ============================================================================
765
766    /// Enable resilient transport with circuit breaker, retry, and health checking
767    ///
768    /// When enabled, the transport layer will automatically:
769    /// - Retry failed operations with exponential backoff
770    /// - Use circuit breaker pattern to prevent cascade failures
771    /// - Perform periodic health checks
772    /// - Deduplicate messages
773    ///
774    /// # Examples
775    ///
776    /// ```rust,no_run
777    /// use turbomcp_client::ClientBuilder;
778    /// use turbomcp_transport::stdio::StdioTransport;
779    ///
780    /// let client = ClientBuilder::new()
781    ///     .enable_resilience()
782    ///     .build(StdioTransport::new());
783    /// ```
784    #[must_use]
785    pub fn enable_resilience(mut self) -> Self {
786        self.enable_resilience = true;
787        self
788    }
789
790    /// Configure retry behavior for resilient transport
791    ///
792    /// # Arguments
793    ///
794    /// * `config` - Retry configuration
795    ///
796    /// # Examples
797    ///
798    /// ```rust,no_run
799    /// use turbomcp_client::ClientBuilder;
800    /// use turbomcp_transport::resilience::RetryConfig;
801    /// use turbomcp_transport::stdio::StdioTransport;
802    /// use std::time::Duration;
803    ///
804    /// let client = ClientBuilder::new()
805    ///     .enable_resilience()
806    ///     .with_retry_config(RetryConfig {
807    ///         max_attempts: 5,
808    ///         base_delay: Duration::from_millis(100),
809    ///         max_delay: Duration::from_secs(30),
810    ///         backoff_multiplier: 2.0,
811    ///         jitter_factor: 0.1,
812    ///         retry_on_connection_error: true,
813    ///         retry_on_timeout: true,
814    ///         custom_retry_conditions: Vec::new(),
815    ///     })
816    ///     .build(StdioTransport::new());
817    /// ```
818    #[must_use]
819    pub fn with_retry_config(
820        mut self,
821        config: turbomcp_transport::resilience::RetryConfig,
822    ) -> Self {
823        self.retry_config = Some(config);
824        self.enable_resilience = true; // Auto-enable resilience
825        self
826    }
827
828    /// Configure circuit breaker for resilient transport
829    ///
830    /// # Arguments
831    ///
832    /// * `config` - Circuit breaker configuration
833    ///
834    /// # Examples
835    ///
836    /// ```rust,no_run
837    /// use turbomcp_client::ClientBuilder;
838    /// use turbomcp_transport::resilience::CircuitBreakerConfig;
839    /// use turbomcp_transport::stdio::StdioTransport;
840    /// use std::time::Duration;
841    ///
842    /// let client = ClientBuilder::new()
843    ///     .enable_resilience()
844    ///     .with_circuit_breaker_config(CircuitBreakerConfig {
845    ///         failure_threshold: 5,
846    ///         success_threshold: 2,
847    ///         timeout: Duration::from_secs(60),
848    ///         rolling_window_size: 100,
849    ///         minimum_requests: 10,
850    ///     })
851    ///     .build(StdioTransport::new());
852    /// ```
853    #[must_use]
854    pub fn with_circuit_breaker_config(
855        mut self,
856        config: turbomcp_transport::resilience::CircuitBreakerConfig,
857    ) -> Self {
858        self.circuit_breaker_config = Some(config);
859        self.enable_resilience = true; // Auto-enable resilience
860        self
861    }
862
863    /// Configure health checking for resilient transport
864    ///
865    /// # Arguments
866    ///
867    /// * `config` - Health check configuration
868    ///
869    /// # Examples
870    ///
871    /// ```rust,no_run
872    /// use turbomcp_client::ClientBuilder;
873    /// use turbomcp_transport::resilience::HealthCheckConfig;
874    /// use turbomcp_transport::stdio::StdioTransport;
875    /// use std::time::Duration;
876    ///
877    /// let client = ClientBuilder::new()
878    ///     .enable_resilience()
879    ///     .with_health_check_config(HealthCheckConfig {
880    ///         interval: Duration::from_secs(30),
881    ///         timeout: Duration::from_secs(5),
882    ///         failure_threshold: 3,
883    ///         success_threshold: 1,
884    ///         custom_check: None,
885    ///     })
886    ///     .build(StdioTransport::new());
887    /// ```
888    #[must_use]
889    pub fn with_health_check_config(
890        mut self,
891        config: turbomcp_transport::resilience::HealthCheckConfig,
892    ) -> Self {
893        self.health_check_config = Some(config);
894        self.enable_resilience = true; // Auto-enable resilience
895        self
896    }
897
898    // ============================================================================
899    // PLUGIN SYSTEM CONFIGURATION
900    // ============================================================================
901
902    /// Register a plugin with the client
903    ///
904    /// Plugins provide middleware functionality for request/response processing,
905    /// metrics collection, retry logic, caching, and other cross-cutting concerns.
906    ///
907    /// # Arguments
908    ///
909    /// * `plugin` - The plugin implementation
910    ///
911    /// # Examples
912    ///
913    /// ```rust,no_run
914    /// use turbomcp_client::{ClientBuilder, ConnectionConfig};
915    /// use turbomcp_client::plugins::{MetricsPlugin, RetryPlugin, PluginConfig, RetryConfig};
916    /// use std::sync::Arc;
917    ///
918    /// let client = ClientBuilder::new()
919    ///     .with_plugin(Arc::new(MetricsPlugin::new(PluginConfig::Metrics)))
920    ///     .with_plugin(Arc::new(RetryPlugin::new(PluginConfig::Retry(RetryConfig {
921    ///         max_retries: 5,
922    ///         base_delay_ms: 1000,
923    ///         max_delay_ms: 30000,
924    ///         backoff_multiplier: 2.0,
925    ///         retry_on_timeout: true,
926    ///         retry_on_connection_error: true,
927    ///     }))));
928    /// ```
929    pub fn with_plugin(mut self, plugin: Arc<dyn crate::plugins::ClientPlugin>) -> Self {
930        self.plugins.push(plugin);
931        self
932    }
933
934    /// Register multiple plugins at once
935    ///
936    /// # Arguments
937    ///
938    /// * `plugins` - Vector of plugin implementations
939    #[must_use]
940    pub fn with_plugins(mut self, plugins: Vec<Arc<dyn crate::plugins::ClientPlugin>>) -> Self {
941        self.plugins.extend(plugins);
942        self
943    }
944
945    // ============================================================================
946    // HANDLER REGISTRATION
947    // ============================================================================
948
949    /// Register an elicitation handler for processing user input requests
950    ///
951    /// # Arguments
952    ///
953    /// * `handler` - The elicitation handler implementation
954    pub fn with_elicitation_handler(
955        mut self,
956        handler: Arc<dyn crate::handlers::ElicitationHandler>,
957    ) -> Self {
958        self.elicitation_handler = Some(handler);
959        self
960    }
961
962    /// Register a log handler for processing server log messages
963    ///
964    /// # Arguments
965    ///
966    /// * `handler` - The log handler implementation
967    pub fn with_log_handler(mut self, handler: Arc<dyn crate::handlers::LogHandler>) -> Self {
968        self.log_handler = Some(handler);
969        self
970    }
971
972    /// Register a resource update handler for processing resource change notifications
973    ///
974    /// # Arguments
975    ///
976    /// * `handler` - The resource update handler implementation
977    pub fn with_resource_update_handler(
978        mut self,
979        handler: Arc<dyn crate::handlers::ResourceUpdateHandler>,
980    ) -> Self {
981        self.resource_update_handler = Some(handler);
982        self
983    }
984
985    // ============================================================================
986    // BUILD METHODS
987    // ============================================================================
988
989    /// Build a client with the configured options
990    ///
991    /// Creates a new client instance with all the configured options. The client
992    /// will be initialized with the registered plugins, handlers, and providers.
993    ///
994    /// # Arguments
995    ///
996    /// * `transport` - The transport to use for the client
997    ///
998    /// # Returns
999    ///
1000    /// Returns a configured `Client` instance wrapped in a Result for async setup.
1001    ///
1002    /// # Examples
1003    ///
1004    /// ```rust,no_run
1005    /// use turbomcp_client::ClientBuilder;
1006    /// use turbomcp_transport::stdio::StdioTransport;
1007    ///
1008    /// # async fn example() -> turbomcp_protocol::Result<()> {
1009    /// let client = ClientBuilder::new()
1010    ///     .with_tools(true)
1011    ///     .with_prompts(true)
1012    ///     .build(StdioTransport::new())
1013    ///     .await?;
1014    /// # Ok(())
1015    /// # }
1016    /// ```
1017    pub async fn build<T: Transport + 'static>(self, transport: T) -> Result<Client<T>> {
1018        // Create base client with capabilities
1019        let client = Client::with_capabilities(transport, self.capabilities);
1020
1021        // Register handlers
1022        if let Some(handler) = self.elicitation_handler {
1023            client.set_elicitation_handler(handler);
1024        }
1025        if let Some(handler) = self.log_handler {
1026            client.set_log_handler(handler);
1027        }
1028        if let Some(handler) = self.resource_update_handler {
1029            client.set_resource_update_handler(handler);
1030        }
1031
1032        // Apply connection configuration (store for future use in actual connections)
1033        // Note: The current Client doesn't expose connection config setters,
1034        // so we'll store this for when the transport supports it
1035
1036        // Register plugins with the client
1037        let has_plugins = !self.plugins.is_empty();
1038        for plugin in self.plugins {
1039            client.register_plugin(plugin).await?;
1040        }
1041
1042        // Initialize plugins after registration
1043        if has_plugins {
1044            client.initialize_plugins().await?;
1045        }
1046
1047        Ok(client)
1048    }
1049
1050    /// Build a client with resilient transport (circuit breaker, retry, health checking)
1051    ///
1052    /// When resilience features are enabled via `enable_resilience()` or any resilience
1053    /// configuration method, this wraps the transport in a `TurboTransport` that provides:
1054    /// - Automatic retry with exponential backoff
1055    /// - Circuit breaker pattern for fast failure
1056    /// - Health checking and monitoring
1057    /// - Message deduplication
1058    ///
1059    /// # Arguments
1060    ///
1061    /// * `transport` - The base transport to wrap with resilience features
1062    ///
1063    /// # Returns
1064    ///
1065    /// Returns a configured `Client<TurboTransport>` instance.
1066    ///
1067    /// # Errors
1068    ///
1069    /// Returns an error if plugin initialization fails.
1070    ///
1071    /// # Examples
1072    ///
1073    /// ```rust,no_run
1074    /// use turbomcp_client::ClientBuilder;
1075    /// use turbomcp_transport::stdio::StdioTransport;
1076    /// use turbomcp_transport::resilience::{RetryConfig, CircuitBreakerConfig, HealthCheckConfig};
1077    /// use std::time::Duration;
1078    ///
1079    /// # async fn example() -> turbomcp_protocol::Result<()> {
1080    /// let client = ClientBuilder::new()
1081    ///     .with_retry_config(RetryConfig {
1082    ///         max_attempts: 5,
1083    ///         base_delay: Duration::from_millis(200),
1084    ///         ..Default::default()
1085    ///     })
1086    ///     .with_circuit_breaker_config(CircuitBreakerConfig {
1087    ///         failure_threshold: 3,
1088    ///         timeout: Duration::from_secs(30),
1089    ///         ..Default::default()
1090    ///     })
1091    ///     .with_health_check_config(HealthCheckConfig {
1092    ///         interval: Duration::from_secs(15),
1093    ///         timeout: Duration::from_secs(5),
1094    ///         ..Default::default()
1095    ///     })
1096    ///     .build_resilient(StdioTransport::new())
1097    ///     .await?;
1098    /// # Ok(())
1099    /// # }
1100    /// ```
1101    pub async fn build_resilient<T: Transport + 'static>(
1102        self,
1103        transport: T,
1104    ) -> Result<Client<turbomcp_transport::resilience::TurboTransport>> {
1105        use turbomcp_transport::resilience::TurboTransport;
1106
1107        // Get configurations or use defaults
1108        let retry_config = self.retry_config.unwrap_or_default();
1109        let circuit_config = self.circuit_breaker_config.unwrap_or_default();
1110        let health_config = self.health_check_config.unwrap_or_default();
1111
1112        // Wrap transport in TurboTransport
1113        let robust_transport = TurboTransport::new(
1114            Box::new(transport),
1115            retry_config,
1116            circuit_config,
1117            health_config,
1118        );
1119
1120        // Create client with resilient transport
1121        let client = Client::with_capabilities(robust_transport, self.capabilities);
1122
1123        // Register handlers
1124        if let Some(handler) = self.elicitation_handler {
1125            client.set_elicitation_handler(handler);
1126        }
1127        if let Some(handler) = self.log_handler {
1128            client.set_log_handler(handler);
1129        }
1130        if let Some(handler) = self.resource_update_handler {
1131            client.set_resource_update_handler(handler);
1132        }
1133
1134        // Register plugins
1135        let has_plugins = !self.plugins.is_empty();
1136        for plugin in self.plugins {
1137            client.register_plugin(plugin).await?;
1138        }
1139
1140        if has_plugins {
1141            client.initialize_plugins().await?;
1142        }
1143
1144        Ok(client)
1145    }
1146
1147    /// Build a client synchronously with basic configuration only
1148    ///
1149    /// This is a convenience method for simple use cases where no async setup
1150    /// is required. For advanced features like plugins, use `build()` instead.
1151    ///
1152    /// # Arguments
1153    ///
1154    /// * `transport` - The transport to use for the client
1155    ///
1156    /// # Returns
1157    ///
1158    /// Returns a configured `Client` instance.
1159    ///
1160    /// # Examples
1161    ///
1162    /// ```rust,no_run
1163    /// use turbomcp_client::ClientBuilder;
1164    /// use turbomcp_transport::stdio::StdioTransport;
1165    ///
1166    /// let client = ClientBuilder::new()
1167    ///     .with_tools(true)
1168    ///     .build_sync(StdioTransport::new());
1169    /// ```
1170    pub fn build_sync<T: Transport + 'static>(self, transport: T) -> Client<T> {
1171        let client = Client::with_capabilities(transport, self.capabilities);
1172
1173        // Register synchronous handlers only
1174        if let Some(handler) = self.elicitation_handler {
1175            client.set_elicitation_handler(handler);
1176        }
1177        if let Some(handler) = self.log_handler {
1178            client.set_log_handler(handler);
1179        }
1180        if let Some(handler) = self.resource_update_handler {
1181            client.set_resource_update_handler(handler);
1182        }
1183
1184        client
1185    }
1186
1187    // ============================================================================
1188    // CONFIGURATION ACCESS
1189    // ============================================================================
1190
1191    /// Get the current capabilities configuration
1192    #[must_use]
1193    pub fn capabilities(&self) -> &ClientCapabilities {
1194        &self.capabilities
1195    }
1196
1197    /// Get the current connection configuration
1198    #[must_use]
1199    pub fn connection_config(&self) -> &ConnectionConfig {
1200        &self.connection_config
1201    }
1202
1203    /// Get the number of registered plugins
1204    #[must_use]
1205    pub fn plugin_count(&self) -> usize {
1206        self.plugins.len()
1207    }
1208
1209    /// Check if any handlers are registered
1210    #[must_use]
1211    pub fn has_handlers(&self) -> bool {
1212        self.elicitation_handler.is_some()
1213            || self.log_handler.is_some()
1214            || self.resource_update_handler.is_some()
1215    }
1216}
1217
1218// Re-export types for public API
1219pub use turbomcp_protocol::types::ServerCapabilities as PublicServerCapabilities;