use pmcp::{ServerBuilder, StdioTransport};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
struct GreetingArgs {
name: String,
style: Option<GreetingStyle>,
}
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
enum GreetingStyle {
Formal,
Casual,
Enthusiastic,
}
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
struct CalculatorArgs {
a: f64,
b: f64,
operation: Operation,
}
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
enum Operation {
Add,
Subtract,
Multiply,
Divide,
}
#[tokio::main]
async fn main() -> Result<(), pmcp::Error> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("pmcp=debug".parse().unwrap()),
)
.init();
let server = ServerBuilder::new()
.name("typed-example")
.version("1.0.0")
.tool_typed("greeting", |args: GreetingArgs, _extra| {
Box::pin(async move {
let style = args.style.unwrap_or(GreetingStyle::Casual);
let message = match style {
GreetingStyle::Formal => format!("Good day, {}.", args.name),
GreetingStyle::Casual => format!("Hey {}!", args.name),
GreetingStyle::Enthusiastic => format!("🎉 HELLO {}! 🎉", args.name),
};
Ok(json!({
"message": message,
"timestamp": chrono::Utc::now().to_rfc3339()
}))
})
})
.tool_typed_sync("calculator", |args: CalculatorArgs, _extra| {
if args.operation == Operation::Divide && args.b == 0.0 {
return Err(pmcp::Error::Validation(
"Cannot divide by zero".to_string(),
));
}
let result = match args.operation {
Operation::Add => args.a + args.b,
Operation::Subtract => args.a - args.b,
Operation::Multiply => args.a * args.b,
Operation::Divide => args.a / args.b,
};
Ok(json!({
"result": result,
"operation": format!("{} {} {} = {}",
args.a,
match args.operation {
Operation::Add => "+",
Operation::Subtract => "-",
Operation::Multiply => "*",
Operation::Divide => "/",
},
args.b,
result
)
}))
})
.build()?;
tracing::info!("Server built with typed tools");
let transport = StdioTransport::new();
server.run(transport).await?;
Ok(())
}
impl PartialEq for Operation {
fn eq(&self, other: &Self) -> bool {
matches!(
(self, other),
(Operation::Add, Operation::Add)
| (Operation::Subtract, Operation::Subtract)
| (Operation::Multiply, Operation::Multiply)
| (Operation::Divide, Operation::Divide)
)
}
}