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