ClientPlugin

Trait ClientPlugin 

Source
pub trait ClientPlugin:
    Send
    + Sync
    + Debug {
    // Required methods
    fn name(&self) -> &str;
    fn version(&self) -> &str;
    fn initialize<'life0, 'life1, 'async_trait>(
        &'life0 self,
        context: &'life1 PluginContext,
    ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn before_request<'life0, 'life1, 'async_trait>(
        &'life0 self,
        context: &'life1 mut RequestContext,
    ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn after_response<'life0, 'life1, 'async_trait>(
        &'life0 self,
        context: &'life1 mut ResponseContext,
    ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn handle_custom<'life0, 'life1, 'async_trait>(
        &'life0 self,
        method: &'life1 str,
        params: Option<Value>,
    ) -> Pin<Box<dyn Future<Output = PluginResult<Option<Value>>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;

    // Provided methods
    fn description(&self) -> Option<&str> { ... }
    fn dependencies(&self) -> Vec<&str> { ... }
    fn cleanup<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait { ... }
}
Expand description

Core trait for client plugins

Plugins can hook into the client lifecycle at various points:

  • initialization: Called when the plugin is registered
  • before_request: Called before sending requests to the server
  • after_response: Called after receiving responses from the server
  • handle_custom: Called for custom method handling

All methods are async and return PluginResult to allow for error handling and async operations like network calls, database access, etc.

§Examples

use turbomcp_client::plugins::{ClientPlugin, PluginContext, RequestContext, ResponseContext, PluginResult};
use async_trait::async_trait;
use serde_json::Value;

#[derive(Debug)]
struct LoggingPlugin;

#[async_trait]
impl ClientPlugin for LoggingPlugin {
    fn name(&self) -> &str {
        "logging"
    }

    fn version(&self) -> &str {
        "1.0.0"
    }

    async fn initialize(&self, context: &PluginContext) -> PluginResult<()> {
        println!("Logging plugin initialized for client: {}", context.client_name);
        Ok(())
    }

    async fn before_request(&self, context: &mut RequestContext) -> PluginResult<()> {
        println!("Request: {} {}", context.method(),
            context.params().unwrap_or(&Value::Null));
        Ok(())
    }

    async fn after_response(&self, context: &mut ResponseContext) -> PluginResult<()> {
        println!("Response: {} took {:?}", context.method(), context.duration);
        Ok(())
    }

    async fn handle_custom(&self, method: &str, params: Option<Value>) -> PluginResult<Option<Value>> {
        if method == "logging.get_stats" {
            Ok(Some(serde_json::json!({"logged_requests": 42})))
        } else {
            Ok(None) // Not handled by this plugin
        }
    }
}

Required Methods§

Source

fn name(&self) -> &str

Plugin name - must be unique across all registered plugins

Source

fn version(&self) -> &str

Plugin version

Source

fn initialize<'life0, 'life1, 'async_trait>( &'life0 self, context: &'life1 PluginContext, ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Initialize the plugin

Called once when the plugin is registered with the client. Use this to set up resources, validate configuration, check dependencies, etc.

§Arguments
  • context - Plugin context with client info, capabilities, and configuration
§Returns

Returns Ok(()) if initialization succeeds, or PluginError if it fails.

Source

fn before_request<'life0, 'life1, 'async_trait>( &'life0 self, context: &'life1 mut RequestContext, ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Hook called before sending a request to the server

This allows plugins to:

  • Modify request parameters
  • Add metadata for tracking
  • Implement features like authentication, request logging, etc.
  • Abort requests by returning an error
§Arguments
  • context - Mutable request context that can be modified
§Returns

Returns Ok(()) to continue processing, or PluginError to abort.

Source

fn after_response<'life0, 'life1, 'async_trait>( &'life0 self, context: &'life1 mut ResponseContext, ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Hook called after receiving a response from the server

This allows plugins to:

  • Process response data
  • Log metrics and performance data
  • Implement features like caching, retry logic, etc.
  • Modify response metadata
§Arguments
  • context - Mutable response context that can be modified
§Returns

Returns Ok(()) if processing succeeds, or PluginError if it fails.

Source

fn handle_custom<'life0, 'life1, 'async_trait>( &'life0 self, method: &'life1 str, params: Option<Value>, ) -> Pin<Box<dyn Future<Output = PluginResult<Option<Value>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Handle custom methods not part of the standard MCP protocol

This allows plugins to implement custom functionality that can be invoked by clients. Each plugin can handle its own set of custom methods.

§Arguments
  • method - The custom method name (e.g., “metrics.get_stats”)
  • params - Optional parameters for the method
§Returns

Returns Some(Value) if the method was handled, None if not handled by this plugin, or PluginError if handling failed.

Provided Methods§

Source

fn description(&self) -> Option<&str>

Optional plugin description

Source

fn dependencies(&self) -> Vec<&str>

Plugin dependencies (other plugins that must be registered first)

Source

fn cleanup<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = PluginResult<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Optional cleanup when plugin is unregistered

Default implementation does nothing. Override to perform cleanup like closing connections, flushing buffers, etc.

Implementors§