use fastmcp_rs::{
FastMcpServer,
run_stdio,
mcp_register_tools,
mcp_prompt_text,
mcp_register_prompts,
mcp_response,
mcp_text,
tool::ToolResponse,
};
use serde_json::{Value, json};
use tokio::signal;
#[fastmcp_rs_macros::mcp_tool(
name = "add",
description = "Adds two numbers",
parameters_json(
"type": "object",
"required": ["a", "b"],
"properties": { "a": { "type": "number" }, "b": { "type": "number" } }
),
annotations(category = json!("math"))
)]
async fn add(_: fastmcp_rs::InvocationContext, payload: Value) -> fastmcp_rs::Result<ToolResponse> {
let a = payload.get("a").and_then(Value::as_f64).ok_or_else(|| fastmcp_rs::FastMcpError::InvalidInvocation("expected float 'a'".into()))?;
let b = payload.get("b").and_then(Value::as_f64).ok_or_else(|| fastmcp_rs::FastMcpError::InvalidInvocation("expected float 'b'".into()))?;
Ok(mcp_response!([ mcp_text!(format!("{} + {} = {}", a, b, a + b)) ]))
}
#[fastmcp_rs_macros::mcp_tool(
name = "multiply",
description = "Multiplies two numbers",
parameters_json(
"type": "object",
"required": ["a", "b"],
"properties": { "a": { "type": "number" }, "b": { "type": "number" } }
),
annotations(category = json!("math"))
)]
async fn multiply(_: fastmcp_rs::InvocationContext, payload: Value) -> fastmcp_rs::Result<ToolResponse> {
let a = payload.get("a").and_then(Value::as_f64).ok_or_else(|| fastmcp_rs::FastMcpError::InvalidInvocation("expected float 'a'".into()))?;
let b = payload.get("b").and_then(Value::as_f64).ok_or_else(|| fastmcp_rs::FastMcpError::InvalidInvocation("expected float 'b'".into()))?;
Ok(mcp_response!([ mcp_text!(format!("{} × {} = {}", a, b, a * b)) ]))
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
let server = FastMcpServer::builder()
.name("MathOps")
.instructions("Use add or multiply tools")
.build()
.into_shared();
mcp_register_tools!(server, [ add_tool(), multiply_tool() ]);
mcp_register_prompts!(server, [
mcp_prompt_text!{
name: "calc",
role: "user",
text: "Please compute {{ a }} op {{ b }}",
description: "Requests a math operation",
parameters: json!({
"type": "object",
"required": ["a", "b", "op"],
"properties": {
"a": { "type": "number" },
"b": { "type": "number" },
"op": { "type": "string", "enum": ["add", "multiply"] }
}
})
}
]);
tokio::select! {
result = run_stdio(server.clone()) => result?,
_ = signal::ctrl_c() => {
tracing::info!("received Ctrl+C, shutting down");
}
}
Ok(())
}