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