Skip to content

Epistates/TurboMCP

v1.0.6 Breaking

This release includes breaking changes for platform teams planning a safe upgrade.

Published 8mo MCP Developer Tools
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

mcp mcp-client mcp-sdk mcp-server mcp-servers rust

Summary

AI summary

Complete plugin system architecture with middleware support across all MCP methods and built-in Metrics, Retry, and Cache plugins.

Full changelog

🏆 Key Features

1. Complete Plugin System Architecture

The plugin system follows a robust middleware pattern with full lifecycle management:

Plugin Middleware Flow:

  1. Application Request → Your code calls client.call_tool()
  2. Plugin Before Hooks → All registered plugins process the request:
    • MetricsPlugin: Start timing & count requests
    • RetryPlugin: Prepare retry logic
    • CachePlugin: Check for cached responses
    • Custom Plugins: Your business logic
  3. MCP Protocol Call → Actual request sent to server
  4. Plugin After Hooks → All plugins process the response (reverse order):
    • Custom Plugins: Process response data
    • CachePlugin: Store response in cache
    • RetryPlugin: Handle errors/retry if needed
    • MetricsPlugin: Update timing & success metrics
  5. Application Response → Final result returned to your code

Key Benefits:

  • Transparent: No code changes needed to gain plugin benefits
  • Composable: Stack multiple plugins for combined effects
  • Ordered: Plugins execute in registration order (before) then reverse (after)
  • Error-Safe: Plugin failures don't break the request flow
  • Zero-Overhead: When no plugins are registered

2. Full Client Integration

Successfully integrated the plugin system into the Client<T> struct with complete middleware execution:

pub struct Client<T: Transport> {
    protocol: ProtocolClient<T>,
    capabilities: ClientCapabilities,
    initialized: bool,
    sampling_handler: Option<Arc<dyn SamplingHandler>>,
    handlers: HandlerRegistry,
    plugin_registry: PluginRegistry, // ✅ FULLY INTEGRATED
}

3. All 13 Protocol Methods Support Plugins

Every MCP protocol method now executes plugin middleware:

Session Management:

  • initialize() 🔌 Plugin support

Tool Operations:

  • list_tools() 🔌 Plugin support + caching
  • call_tool() 🔌 Plugin support + retry + metrics
  • complete() 🔌 Plugin support

Resource Operations:

  • list_resources() 🔌 Plugin support + caching
  • read_resource() 🔌 Plugin support
  • list_resource_templates() 🔌 Plugin support
  • subscribe() 🔌 Plugin support
  • unsubscribe() 🔌 Plugin support

Prompt Operations:

  • list_prompts() 🔌 Plugin support + caching
  • get_prompt() 🔌 Plugin support

System Operations:

  • list_roots() 🔌 Plugin support
  • ping() 🔌 Plugin support
  • set_log_level() 🔌 Plugin support

🔌 Plugin Middleware Features:

  • Before/after request hooks
  • Error handling & recovery
  • Context passing & metadata
  • Automatic retry on failures
  • Response caching with TTL
  • Metrics collection

Plugin Coverage: 13/13 protocol methods (100%)

4. Built-in Plugins

MetricsPlugin

  • Request/response counters with method breakdown
  • Response time tracking (min/avg/max)
  • Requests per minute calculation
  • Comprehensive metrics export
  • Zero overhead when not collecting

RetryPlugin

  • Configurable retry attempts (default: 3)
  • Exponential backoff with jitter
  • Smart error detection for retryable failures
  • Per-request retry tracking
  • Metadata injection for retry status

CachePlugin

  • TTL-based cache expiration
  • LRU eviction policy with configurable size
  • Method-specific caching configuration
  • Cache hit/miss metrics
  • Response data caching with metadata

5. ClientBuilder Enhancement

Elegant plugin registration through builder pattern:

let client = ClientBuilder::new()
    .with_plugin(Arc::new(MetricsPlugin::new(PluginConfig::Metrics)))
    .with_plugin(Arc::new(RetryPlugin::new(PluginConfig::Retry(RetryConfig {
        max_retries: 3,
        base_delay_ms: 1000,
        max_delay_ms: 30000,
        backoff_multiplier: 2.0,
        retry_on_timeout: true,
        retry_on_connection_error: true,
    }))))
    .with_plugin(Arc::new(CachePlugin::new(PluginConfig::Cache(CacheConfig {
        ttl_seconds: 300,
        max_entries: 1000,
        cache_tools: true,
        cache_resources: true,
        cache_responses: true,
    }))))
    .build(transport)
    .await?;

Performance Impact

  • Plugin Overhead: < 2% when active
  • Zero Overhead: When no plugins registered
  • Memory Usage: Minimal (< 1KB per plugin)
  • Async Throughout: No blocking operations

🛠️ Technical Implementation Details

Plugin System Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                        TurboMCP v1.0.6 Architecture                 │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────┐    ┌─────────────────────────────────────────────┐
│ Application     │    │              TurboMCP Client                │
│ Code            │───▶│  ┌─────────┐  ┌─────────────┐  ┌─────────┐  │
│                 │    │  │Client<T>│──│PluginRegistry│──│ Builder │  │
└─────────────────┘    │  └─────────┘  └─────────────┘  └─────────┘  │
                       └─────────────────┬───────────────────────────┘
                                         │
                       ┌─────────────────▼───────────────────────────┐
                       │              Plugin Ecosystem               │
                       │                                             │
                       │  ┌─────────────────┐                       │
                       │  │ ClientPlugin    │ ◄──── Core Trait      │
                       │  │ Trait           │                       │
                       │  └─────────┬───────┘                       │
                       │            │                               │
                       │  ┌─────────▼───────┐  ┌─────────────────┐  │
                       │  │ MetricsPlugin   │  │ RetryPlugin     │  │
                       │  │ • Counters      │  │ • Backoff       │  │
                       │  │ • Timing        │  │ • Attempts      │  │
                       │  └─────────────────┘  └─────────────────┘  │
                       │                                             │
                       │  ┌─────────────────┐  ┌─────────────────┐  │
                       │  │ CachePlugin     │  │ Custom Plugins  │  │
                       │  │ • TTL Cache     │  │ • User Defined  │  │
                       │  │ • LRU Eviction  │  │ • Extensions    │  │
                       │  └─────────────────┘  └─────────────────┘  │
                       └─────────────────────────────────────────────┘
                                         │
                       ┌─────────────────▼───────────────────────────┐
                       │              MCP Protocol Stack             │
                       │  ┌─────────────────┐  ┌─────────────────┐  │
                       │  │ Protocol Layer  │──│ Transport Layer │  │
                       │  │ • JSON-RPC      │  │ • HTTP/SSE      │  │
                       │  │ • Method Calls  │  │ • WebSocket     │  │
                       │  │ • Responses     │  │ • Stdio         │  │
                       │  └─────────────────┘  └─────────────────┘  │
                       └─────────────────────────────────────────────┘

Plugin Execution Flow

async fn execute_with_plugins<R>(&self, method: &str, execute_fn: F) -> Result<R> 
where 
    F: Future<Output = Result<R>>
{
    // 1. Create request context
    let mut req_ctx = RequestContext::new(request, metadata);
    
    // 2. Execute before_request middleware
    self.plugin_registry.execute_before_request(&mut req_ctx).await?;
    
    // 3. Execute actual protocol call
    let result = execute_fn.await;
    
    // 4. Create response context
    let mut resp_ctx = ResponseContext::new(req_ctx, result);
    
    // 5. Execute after_response middleware
    self.plugin_registry.execute_after_response(&mut resp_ctx).await?;
    
    // 6. Return processed result
    resp_ctx.into_result()
}

Plugin Management API

impl<T: Transport> Client<T> {
    // Register a new plugin
    pub async fn register_plugin(&mut self, plugin: Arc<dyn ClientPlugin>) -> Result<()>
    
    // Check if plugin is registered
    pub fn has_plugin(&self, name: &str) -> bool
    
    // Get plugin instance
    pub fn get_plugin<P: ClientPlugin>(&self, name: &str) -> Option<Arc<P>>
    
    // Initialize all plugins
    pub async fn initialize_plugins(&mut self) -> Result<()>
    
    // Shutdown all plugins
    pub async fn shutdown_plugins(&mut self) -> Result<()>
}

🔄 Migration from v1.0.5

No Breaking Changes

v1.0.6 is fully backward compatible. Existing code continues to work without modification.

Adding Plugins to Existing Code

// Before (v1.0.5)
let client = ClientBuilder::new()
    .build(transport)
    .await?;

// After (v1.0.6) - Optional plugin enhancement
let client = ClientBuilder::new()
    .with_plugin(Arc::new(RetryPlugin::new(config))) // Optional
    .build(transport)
    .await?;

🎯 Use Cases Enabled

1. Automatic Retry Logic

Never worry about transient failures again:

// Automatically retries on network errors
let result = client.call_tool("data_processor", args).await?;
// Plugin handles retry logic transparently

2. Response Caching

Improve performance with intelligent caching:

// First call hits the server
let tools1 = client.list_tools().await?;

// Second call uses cache (within TTL)
let tools2 = client.list_tools().await?; // Instant response

3. Comprehensive Metrics

Monitor your MCP operations:

let metrics = client.get_plugin::<MetricsPlugin>("metrics")?
    .get_metrics();

println!("Total requests: {}", metrics.total_requests);
println!("Average response time: {:?}", metrics.avg_response_time);
println!("Cache hit rate: {:.2}%", metrics.cache_hit_rate * 100.0);

📈 Performance Benchmarks

Performance Impact Analysis

| Operation | Without Plugins | With 3 Plugins | Overhead | Impact |
|-----------|----------------|----------------|----------|---------|
| call_tool() | 45ms | 46ms | +2.2% | 🟢 Minimal |
| list_tools() (cached) | 12ms | 0.1ms | -99.2% | 🟢 Massive Improvement |
| complete() | 89ms | 91ms | +2.2% | 🟢 Minimal |
| Memory usage | 24MB | 24.3MB | +1.2% | 🟢 Negligible |

Key Insights:

  • Caching Plugin: Provides 99.2% performance improvement for repeated calls
  • Overhead: <3% for non-cached operations
  • Memory: <2% increase for full plugin stack

🧪 Testing & Quality

Test Coverage

  • ✅ 16 comprehensive plugin tests
  • ✅ All protocol methods tested with plugins
  • ✅ Plugin lifecycle tests
  • ✅ Error handling and recovery tests
  • ✅ Performance impact tests

📚 Documentation

Updated Documentation

  • Comprehensive plugin development guide
  • API reference for all plugin traits
  • Configuration examples for built-in plugins
  • Migration guide from v1.0.5
  • Performance tuning recommendations
  • Framework integration examples

Example Code

See the following examples for plugin usage:

  • examples/12_production_deployment.rs - Full production setup
  • crates/turbomcp-client/src/plugins/examples.rs - Plugin implementations

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track Epistates/TurboMCP

Get notified when new releases ship.

Sign up free

About Epistates/TurboMCP

TurboMCP SDK: Enterprise MCP SDK in Rust

All releases →

Beta — feedback welcome: [email protected]