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;