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