Skip to main content

MiddlewareExecutor

Trait MiddlewareExecutor 

Source
pub trait MiddlewareExecutor: Send + Sync {
    // Required method
    fn execute_tool_with_middleware<'life0, 'life1, 'async_trait>(
        &'life0 self,
        tool_name: &'life1 str,
        args: Value,
        extra: RequestHandlerExtra,
    ) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
}
Available on non-WebAssembly only.
Expand description

Trait for executing tools with full middleware chain application.

This trait provides an abstraction for tool execution that ensures middleware (authentication, logging, validation, rate limiting, etc.) is consistently applied regardless of whether the tool is called:

  • Directly via tools/call JSON-RPC requests
  • Server-side during workflow prompt execution

§Architecture

The trait decouples workflow execution from ServerCore, preventing circular dependencies while ensuring consistent middleware application.

┌─────────────────┐
│  WorkflowPrompt │
│    Handler      │
└────────┬────────┘
         │ uses
         ▼
┌─────────────────────┐
│ MiddlewareExecutor  │◄─────── Trait abstraction
│      (trait)        │
└────────────────────┘
         △
         │ implements
         │
┌────────┴────────┐
│   ServerCore    │
│ (with middleware│
│     chains)     │
└─────────────────┘

§Example

ⓘ
use pmcp::server::middleware_executor::MiddlewareExecutor;
use pmcp::server::workflow::WorkflowPromptHandler;
use std::sync::Arc;

// ServerCore implements MiddlewareExecutor
let executor: Arc<dyn MiddlewareExecutor> = Arc::new(server_core);

// Workflow handler uses the abstraction
let handler = WorkflowPromptHandler::new(
    workflow,
    tool_registry,
    executor,  // Pass as trait object
    resource_handler,
);

// When workflow executes tools, middleware runs automatically
let result = handler.handle(args, extra).await?;

§Benefits

  1. Consistent Auth: OAuth tokens injected by middleware work in workflows
  2. Testability: Easy to mock for workflow testing
  3. No Circular Dependencies: Clean separation of concerns
  4. Single Source of Truth: One middleware application path for all tools

Required Methods§

Source

fn execute_tool_with_middleware<'life0, 'life1, 'async_trait>( &'life0 self, tool_name: &'life1 str, args: Value, extra: RequestHandlerExtra, ) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Execute a tool with full middleware chain processing.

This method applies the complete middleware pipeline:

  1. Request Middleware - Inject credentials, validate permissions, log calls
  2. Tool Execution - Call the actual tool handler
  3. Response Middleware - Transform results, add headers, log responses
  4. Error Middleware - Handle failures, retry logic, error transformation
§Parameters
  • tool_name - Name of the tool to execute
  • args - Tool arguments (may be modified by middleware)
  • extra - Request context (auth, cancellation, metadata)
§Returns

The tool’s result after response middleware processing.

§Errors
  • Error::Internal - Tool not found or middleware processing failed
  • Error::Authentication - Authorization check failed
  • Tool-specific errors after middleware transformation
§Example
ⓘ
// In WorkflowPromptHandler::execute_tool_step
let result = self.middleware_executor.execute_tool_with_middleware(
    step.tool().name(),
    params,
    extra,
).await?;

// Middleware has already:
// - Injected OAuth token into extra.metadata
// - Logged the tool call
// - Validated permissions
// - Applied rate limits

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§