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