use rmcp::service::ServiceExt;
use rmcp::{
handler::server::{router::tool::ToolRouter, wrapper::Parameters},
model::{ServerCapabilities, ServerInfo},
schemars, tool, tool_handler, tool_router, ServerHandler,
};
use serde::Deserialize;
use unia::model::{Message, Part};
use unia::providers::{OpenAI, Provider};
use unia::Agent;
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct WeatherArgs {
#[schemars(description = "The location to get the weather for")]
pub location: String,
#[schemars(description = "The unit (celsius or fahrenheit)")]
pub unit: String,
}
#[derive(Debug, Clone)]
pub struct WeatherTools {
tool_router: ToolRouter<Self>,
}
#[tool_router]
impl WeatherTools {
pub fn new() -> Self {
Self {
tool_router: Self::tool_router(),
}
}
#[tool(description = "Get the current weather for a location")]
fn get_weather(
&self,
Parameters(WeatherArgs { location, unit }): Parameters<WeatherArgs>,
) -> String {
println!("> Tool called: get_weather({}, {})", location, unit);
let response = serde_json::json!({
"temperature": 22,
"condition": "Sunny",
"location": location,
"unit": unit
});
response.to_string()
}
}
#[tool_handler]
impl ServerHandler for WeatherTools {
fn get_info(&self) -> ServerInfo {
ServerInfo {
server_info: rmcp::model::Implementation {
name: "weather-server".into(),
version: "1.0".into(),
..Default::default()
},
capabilities: ServerCapabilities::builder().enable_tools().build(),
..Default::default()
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY must be set");
let client = OpenAI::create(api_key, "gpt-5".to_string());
let agent = Agent::new(client);
let tools_handler = WeatherTools::new();
let (client_transport, server_transport) = tokio::io::duplex(1024);
tokio::spawn(async move {
let service = tools_handler
.serve(server_transport)
.await
.expect("Failed to start server");
service.waiting().await.expect("Server error");
});
let tools = ().serve(client_transport).await?;
let agent = agent.with_server(tools);
let response = agent
.chat(vec![Message::User(vec![Part::Text {
content: "What is the weather in Tokyo in celsius?".to_string(),
finished: true,
}])])
.await?;
let content = response
.data
.last()
.and_then(|m| m.content())
.unwrap_or_default();
println!("Agent: {}", content);
Ok(())
}