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