Expand description
§TurboMCP Macros
Zero-overhead procedural macros for ergonomic MCP server development, providing compile-time code generation for MCP protocol handlers with graceful shutdown support.
§Features
§Core Macros
#[server]
- Convert structs into MCP servers with transport methods and graceful shutdown#[tool]
- Mark methods as MCP tool handlers with automatic schema generation#[prompt]
- Mark methods as MCP prompt handlers with template support#[resource]
- Mark methods as MCP resource handlers with URI templates
§Advanced Features (Enhanced in 1.0.3)
- Roots Configuration - Declarative filesystem roots in
#[server]
macro:root = "file:///path:Name"
- Compile-Time Routing - Zero-cost compile-time router generation (experimental)
- Enhanced Context System - Improved async handling and error propagation
- Server Attributes - Support for name, version, description, and roots in server macro
§Helper Macros
mcp_error!
- Ergonomic error creation with formattingmcp_text!
- Text content creation helperstool_result!
- Tool result formattingelicit!
- High-level elicitation macro for interactive user input
§Usage
§Basic Server with Tools
ⓘ
use turbomcp::prelude::*;
#[derive(Clone)]
struct Calculator {
operations: std::sync::Arc<std::sync::atomic::AtomicU64>,
}
#[server(
name = "calculator-server",
version = "1.0.0",
description = "A mathematical calculator service",
root = "file:///workspace:Project Workspace",
root = "file:///tmp:Temporary Files"
)]
impl Calculator {
#[tool("Add two numbers")]
async fn add(&self, ctx: Context, a: i32, b: i32) -> McpResult<i32> {
ctx.info(&format!("Adding {} + {}", a, b)).await?;
self.operations.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Ok(a + b)
}
#[tool("Divide two numbers")]
async fn divide(&self, a: f64, b: f64) -> McpResult<f64> {
if b == 0.0 {
return Err(mcp_error!("Cannot divide by zero"));
}
Ok(a / b)
}
#[resource("calc://history/{operation}")]
async fn history(&self, operation: String) -> McpResult<String> {
Ok(format!("History for {} operations", operation))
}
#[prompt("Generate report for {operation} with {count} operations")]
async fn report(&self, operation: String, count: i32) -> McpResult<String> {
Ok(format!("Generated report for {} ({} operations)", operation, count))
}
}
§Elicitation Support (New in 1.0.3)
ⓘ
use turbomcp::prelude::*;
use turbomcp::elicitation_api::{string, boolean, ElicitationResult};
#[derive(Clone)]
struct InteractiveServer;
#[server]
impl InteractiveServer {
#[tool("Configure with user input")]
async fn configure(&self, ctx: Context) -> McpResult<String> {
let result = elicit!("Configure your preferences")
.field("theme", string()
.enum_values(vec!["light", "dark"])
.build())
.field("auto_save", boolean()
.description("Enable auto-save")
.build())
.send(&ctx.request)
.await?;
match result {
ElicitationResult::Accept(data) => {
let theme = data.get::<String>("theme")?;
Ok(format!("Configured with {} theme", theme))
}
_ => Err(mcp_error!("Configuration cancelled"))
}
}
}
Macros§
- elicit
- Ergonomic elicitation macro for server-initiated user input
- mcp_
error - Helper macro for creating MCP errors
- mcp_
text - Helper macro for creating MCP ContentBlock structures (advanced usage)
- tool_
result - Helper macro for creating CallToolResult structures (advanced usage)
Attribute Macros§
- completion
- Marks a method as a completion handler for argument autocompletion
- elicitation
- Marks a method as an elicitation handler for gathering user input
- ping
- Marks a method as a ping handler for connection health monitoring
- prompt
- Marks a method as a prompt handler
- resource
- Marks a method as a resource handler
- server
- Marks an impl block as a TurboMCP server (idiomatic Rust)
- template
- Marks a method as a resource template handler
- tool
- Marks a method as a tool handler