pub trait Handler:
Send
+ Sync
+ 'static {
type Input: JsonSchema + DeserializeOwned + Send;
type Output: JsonSchema + Serialize + Send;
type Error: Into<Error>;
// Required method
fn handle<'life0, 'async_trait>(
&'life0 self,
input: Self::Input,
) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided methods
fn input_schema() -> RootSchema { ... }
fn output_schema() -> RootSchema { ... }
}Expand description
Core handler abstraction - zero-cost, compatible with pmcp TypedTool.
The Handler trait provides a type-safe interface for implementing MCP tools.
It leverages Rust’s type system for compile-time validation and automatic
JSON Schema generation.
§Type Parameters
Input: The input type, must be deserializable and have a JSON schemaOutput: The output type, must be serializable and have a JSON schemaError: Error type that can be converted intopforge_runtime::Error
§Examples
§Basic Handler
use pforge_runtime::{Handler, Result};
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
#[derive(Debug, Deserialize, JsonSchema)]
struct GreetInput {
name: String,
}
#[derive(Debug, Serialize, JsonSchema)]
struct GreetOutput {
message: String,
}
struct GreetHandler;
#[async_trait::async_trait]
impl Handler for GreetHandler {
type Input = GreetInput;
type Output = GreetOutput;
type Error = pforge_runtime::Error;
async fn handle(&self, input: Self::Input) -> Result<Self::Output> {
Ok(GreetOutput {
message: format!("Hello, {}!", input.name),
})
}
}§Handler with Validation
use pforge_runtime::{Handler, Result, Error};
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
#[derive(Debug, Deserialize, JsonSchema)]
struct AgeInput {
age: i32,
}
#[derive(Debug, Serialize, JsonSchema)]
struct AgeOutput {
category: String,
}
struct AgeHandler;
#[async_trait::async_trait]
impl Handler for AgeHandler {
type Input = AgeInput;
type Output = AgeOutput;
type Error = Error;
async fn handle(&self, input: Self::Input) -> Result<Self::Output> {
if input.age < 0 {
return Err(Error::Handler("Age cannot be negative".to_string()));
}
let category = match input.age {
0..=12 => "child",
13..=19 => "teenager",
20..=64 => "adult",
_ => "senior",
}.to_string();
Ok(AgeOutput { category })
}
}Required Associated Types§
Sourcetype Input: JsonSchema + DeserializeOwned + Send
type Input: JsonSchema + DeserializeOwned + Send
Input type for the handler
Sourcetype Output: JsonSchema + Serialize + Send
type Output: JsonSchema + Serialize + Send
Output type for the handler
Required Methods§
Sourcefn handle<'life0, 'async_trait>(
&'life0 self,
input: Self::Input,
) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn handle<'life0, 'async_trait>(
&'life0 self,
input: Self::Input,
) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Execute the handler with type-safe input.
This is the core method where tool logic is implemented. Input is automatically deserialized and output is automatically serialized.
Provided Methods§
Sourcefn input_schema() -> RootSchema
fn input_schema() -> RootSchema
Generate JSON schema for input (override for custom schemas).
By default, this derives the schema from the Input type using schemars.
Override this method to provide custom validation rules or documentation.
Sourcefn output_schema() -> RootSchema
fn output_schema() -> RootSchema
Generate JSON schema for output.
By default, this derives the schema from the Output type using schemars.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.