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/callJSON-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
- Consistent Auth: OAuth tokens injected by middleware work in workflows
- Testability: Easy to mock for workflow testing
- No Circular Dependencies: Clean separation of concerns
- Single Source of Truth: One middleware application path for all tools
Required Methods§
Sourcefn 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,
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:
- Request Middleware - Inject credentials, validate permissions, log calls
- Tool Execution - Call the actual tool handler
- Response Middleware - Transform results, add headers, log responses
- Error Middleware - Handle failures, retry logic, error transformation
§Parameters
tool_name- Name of the tool to executeargs- 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 failedError::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 limitsDyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".