SharedClient

Struct SharedClient 

Source
pub struct SharedClient<T: Transport> { /* private fields */ }
Expand description

Thread-safe wrapper for sharing Client across async tasks

This wrapper encapsulates the Arc/Mutex complexity and provides a clean API for concurrent access to MCP client functionality. It addresses the limitations identified in PR feedback where Client requires &mut self for all operations but needs to be shared across multiple async tasks.

§Design Rationale

All Client methods require &mut self because:

  • MCP connections maintain state (initialized flag, connection status)
  • Request correlation tracking for JSON-RPC requires mutation
  • Handler and plugin registries need mutable access

While Client implements Send + Sync, this only means it’s safe to move/share between threads, not that multiple tasks can mutate it concurrently.

§Examples

use turbomcp_client::{Client, SharedClient};
use turbomcp_transport::stdio::StdioTransport;

let transport = StdioTransport::new();
let client = Client::new(transport);
let shared = SharedClient::new(client);

// Initialize once
shared.initialize().await?;

// Clone for sharing across tasks
let shared1 = shared.clone();
let shared2 = shared.clone();

// Both tasks can use the client concurrently
let handle1 = tokio::spawn(async move {
    shared1.list_tools().await
});

let handle2 = tokio::spawn(async move {
    shared2.list_prompts().await
});

let (tools, prompts) = tokio::try_join!(handle1, handle2).unwrap();

Implementations§

Source§

impl<T: Transport> SharedClient<T>

Source

pub fn new(client: Client<T>) -> Self

Create a new shared client wrapper

Takes ownership of a Client and wraps it for thread-safe sharing. The original client can no longer be accessed directly after this call.

Source

pub async fn initialize(&self) -> Result<InitializeResult>

Initialize the MCP connection

This method should be called once before using any other client operations. It negotiates capabilities with the server and establishes the communication protocol.

Source

pub async fn list_tools(&self) -> Result<Vec<Tool>>

List all available tools from the MCP server

Returns a list of complete tool definitions with schemas that can be used for form generation, validation, and documentation. Tools represent executable functions provided by the server.

Source

pub async fn list_tool_names(&self) -> Result<Vec<String>>

List available tool names from the MCP server

Returns only the tool names for cases where full schemas are not needed. For most use cases, prefer list_tools() which provides complete tool definitions.

Source

pub async fn call_tool( &self, name: &str, arguments: Option<HashMap<String, Value>>, ) -> Result<Value>

Execute a tool with the given name and arguments

Calls a specific tool on the MCP server with the provided arguments. The arguments should match the tool’s expected parameter schema.

Source

pub async fn list_prompts(&self) -> Result<Vec<Prompt>>

List all available prompts from the MCP server

Returns full Prompt objects with metadata including name, title, description, and argument schemas. This information can be used to generate UI forms for prompt parameter collection.

Source

pub async fn get_prompt( &self, name: &str, arguments: Option<PromptInput>, ) -> Result<GetPromptResult>

Get a prompt with optional argument substitution

Retrieves a prompt from the server. If arguments are provided, template parameters (e.g., {parameter}) will be substituted with the given values. Pass None for arguments to get the raw template form.

Source

pub async fn list_resources(&self) -> Result<Vec<String>>

List available resources from the MCP server

Resources represent data or content that can be read by the client. Returns a list of resource identifiers and metadata.

Source

pub async fn read_resource(&self, uri: &str) -> Result<ReadResourceResult>

Read a specific resource from the MCP server

Retrieves the content of a resource identified by its URI. The content format depends on the specific resource type.

Source

pub async fn list_resource_templates(&self) -> Result<Vec<String>>

List resource templates from the MCP server

Resource templates define patterns for generating resource URIs. They allow servers to describe families of related resources.

Source

pub async fn set_log_level(&self, level: LogLevel) -> Result<SetLevelResult>

Set the logging level for the MCP server

Controls the verbosity of logs sent from the server to the client. Higher log levels provide more detailed information.

Source

pub async fn subscribe(&self, uri: &str) -> Result<EmptyResult>

Subscribe to notifications from a specific URI

Registers interest in receiving notifications when the specified resource or endpoint changes. Used for real-time updates.

Source

pub async fn unsubscribe(&self, uri: &str) -> Result<EmptyResult>

Unsubscribe from notifications for a specific URI

Removes a previously registered subscription to stop receiving notifications for the specified resource or endpoint.

Source

pub async fn ping(&self) -> Result<PingResult>

Send a ping to test connection health

Verifies that the MCP connection is still active and responsive. Used for health checking and keepalive functionality.

Source

pub async fn capabilities(&self) -> ClientCapabilities

Get the client’s configured capabilities

Returns the capabilities that this client supports. These are negotiated during initialization.

Source

pub async fn complete( &self, handler_name: &str, argument_value: &str, ) -> Result<CompletionResponse>

Request argument completion from the MCP server

Provides autocompletion suggestions for prompt arguments and resource URIs. This enables rich, IDE-like experiences with contextual suggestions.

§Arguments
  • handler_name - The completion handler name
  • argument_value - The partial value to complete
§Examples
let shared = SharedClient::new(Client::new(StdioTransport::new()));
shared.initialize().await?;

let result = shared.complete("complete_path", "/usr/b").await?;
println!("Completions: {:?}", result.values);
Source

pub async fn complete_prompt( &self, prompt_name: &str, argument_name: &str, argument_value: &str, context: Option<CompletionContext>, ) -> Result<CompletionResponse>

Complete a prompt argument with full MCP protocol support

This method provides access to the complete MCP completion protocol, allowing specification of argument names, prompt references, and context.

§Arguments
  • prompt_name - Name of the prompt to complete for
  • argument_name - Name of the argument being completed
  • argument_value - Current value for completion matching
  • context - Optional context with previously resolved arguments
§Examples
let shared = SharedClient::new(Client::new(StdioTransport::new()));
shared.initialize().await?;

// Complete with context
let mut context_args = HashMap::new();
context_args.insert("language".to_string(), "rust".to_string());
let context = CompletionContext { arguments: Some(context_args) };

let completions = shared.complete_prompt(
    "code_review",
    "framework",
    "tok",
    Some(context)
).await?;

for completion in completions.values {
    println!("Suggestion: {}", completion);
}
Source

pub async fn complete_resource( &self, resource_uri: &str, argument_name: &str, argument_value: &str, context: Option<CompletionContext>, ) -> Result<CompletionResponse>

Complete a resource template URI with full MCP protocol support

This method provides completion for resource template URIs, allowing servers to suggest values for URI template variables.

§Arguments
  • resource_uri - Resource template URI (e.g., “/files/{path}”)
  • argument_name - Name of the argument being completed
  • argument_value - Current value for completion matching
  • context - Optional context with previously resolved arguments
§Examples
let shared = SharedClient::new(Client::new(StdioTransport::new()));
shared.initialize().await?;

let completions = shared.complete_resource(
    "/files/{path}",
    "path",
    "/home/user/doc",
    None
).await?;

for completion in completions.values {
    println!("Path suggestion: {}", completion);
}
Source

pub async fn list_roots(&self) -> Result<Vec<String>>

List filesystem roots available to the server

Returns filesystem root directories that the server has access to. This helps servers understand their operating boundaries and available resources within the filesystem.

§Examples
let shared = SharedClient::new(Client::new(StdioTransport::new()));
shared.initialize().await?;

let roots = shared.list_roots().await?;
for root_uri in roots {
    println!("Available root: {}", root_uri);
}
Source

pub async fn on_elicitation(&self, handler: Arc<dyn ElicitationHandler>)

Register an elicitation handler for processing server requests for user information

Elicitation handlers respond to server requests for additional information from users during interactions. This enables interactive workflows where servers can gather necessary information dynamically.

§Arguments
  • handler - The elicitation handler implementation
§Examples
use turbomcp_client::{Client, SharedClient};
use turbomcp_client::handlers::{ElicitationHandler, ElicitationRequest, ElicitationResponse, ElicitationAction, HandlerResult};
use turbomcp_transport::stdio::StdioTransport;
use async_trait::async_trait;
use std::sync::Arc;

#[derive(Debug)]
struct MyElicitationHandler;

#[async_trait]
impl ElicitationHandler for MyElicitationHandler {
    async fn handle_elicitation(&self, request: ElicitationRequest) -> HandlerResult<ElicitationResponse> {
        // Process user input request and return response
        Ok(ElicitationResponse {
            action: ElicitationAction::Accept,
            content: Some(serde_json::json!({"name": "example"})),
        })
    }
}

let shared = SharedClient::new(Client::new(StdioTransport::new()));
shared.on_elicitation(Arc::new(MyElicitationHandler)).await;
Source

pub async fn on_progress(&self, handler: Arc<dyn ProgressHandler>)

Register a progress handler for processing server progress notifications

Progress handlers receive updates about long-running operations on the server. This enables progress bars, status updates, and better user experience during extended operations.

§Arguments
  • handler - The progress handler implementation
Source

pub async fn on_log(&self, handler: Arc<dyn LogHandler>)

Register a log handler for processing server log messages

Log handlers receive log messages from the server and can route them to the client’s logging system. This is useful for debugging and maintaining a unified log across client and server.

§Arguments
  • handler - The log handler implementation
Source

pub async fn on_resource_update(&self, handler: Arc<dyn ResourceUpdateHandler>)

Register a resource update handler for processing resource change notifications

Resource update handlers receive notifications when subscribed resources change on the server. This enables reactive updates to cached data or UI refreshes when server-side resources change.

§Arguments
  • handler - The resource update handler implementation
Source

pub async fn has_elicitation_handler(&self) -> bool

Check if an elicitation handler is registered

Source

pub async fn has_progress_handler(&self) -> bool

Check if a progress handler is registered

Source

pub async fn has_log_handler(&self) -> bool

Check if a log handler is registered

Source

pub async fn has_resource_update_handler(&self) -> bool

Check if a resource update handler is registered

Trait Implementations§

Source§

impl<T: Transport> Clone for SharedClient<T>

Source§

fn clone(&self) -> Self

Clone the shared client for use in multiple async tasks

This creates a new reference to the same underlying client, allowing multiple tasks to share access safely.

1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl<T> Freeze for SharedClient<T>

§

impl<T> !RefUnwindSafe for SharedClient<T>

§

impl<T> Send for SharedClient<T>

§

impl<T> Sync for SharedClient<T>

§

impl<T> Unpin for SharedClient<T>

§

impl<T> !UnwindSafe for SharedClient<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more