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;