Expand description
§UltraFast MCP Macros
Procedural macros for the UltraFast Model Context Protocol (MCP) implementation.
This crate provides convenient procedural macros that simplify MCP development by automatically generating boilerplate code, schemas, and configurations. It reduces the amount of repetitive code needed to implement MCP servers and clients.
§Overview
The UltraFast MCP Macros crate provides:
- Schema Generation: Automatic JSON Schema generation from Rust types
- Tool Registration: Simplified tool definition and registration
- Server Setup: Streamlined server configuration and setup
- Client Configuration: Easy client configuration and setup
- Request/Response: Automatic request and response type generation
- Error Handling: Simplified error type generation
§Key Features
§Automatic Schema Generation
- Type Inference: Automatically infer JSON schemas from Rust types
- Custom Attributes: Fine-tune schema generation with attributes
- Validation: Generate validation rules from type constraints
- Documentation: Preserve Rust documentation in generated schemas
- Nested Types: Handle complex nested structures and enums
§Tool Registration
- Function Attributes: Convert Rust functions into MCP tools
- Automatic Registration: Generate tool registration code
- Schema Generation: Create input/output schemas automatically
- Error Handling: Integrate with MCP error types
- Async Support: Full support for async functions
§Server and Client Setup
- Server Configuration: Simplify server setup and configuration
- Client Configuration: Easy client configuration management
- Capability Management: Automatic capability configuration
- Info Generation: Generate server/client information
- Type Safety: Compile-time type checking and validation
§Macros
§#[derive(McpSchema)] - Schema Generation
Automatically generates JSON schemas from Rust structs and enums.
use ultrafast_mcp_macros::McpSchema;
use serde::{Serialize, Deserialize};
#[derive(McpSchema, Serialize, Deserialize)]
struct UserInput {
name: String,
age: u32,
email: Option<String>,
#[mcp(description = "User preferences")]
preferences: Vec<String>,
}
// The macro generates:
// - JSON schema for the struct
// - Schema validation methods
// - Type conversion utilities§#[mcp_tool] - Tool Definition
Converts Rust functions into MCP tools with automatic schema generation.
use ultrafast_mcp_macros::mcp_tool;
use serde_json::Value;
#[mcp_tool(
name = "greet_user",
description = "Greet a user with a personalized message"
)]
async fn greet_user(input: Value) -> Result<String, Box<dyn std::error::Error>> {
let name = input["name"].as_str().unwrap_or("World");
let greeting = input["greeting"].as_str().unwrap_or("Hello");
Ok(format!("{}, {}!", greeting, name))
}
// The macro generates:
// - Tool registration function
// - Input/output schemas
// - Error handling integration§#[mcp_server] - Server Setup
Simplifies MCP server setup and configuration.
use ultrafast_mcp_macros::mcp_server;
#[mcp_server(
name = "MyGreetingServer",
version = "1.0.0",
description = "A server that provides greeting tools"
)]
struct MyServer;
// The macro generates:
// - Server information
// - Server capabilities
// - Server setup methods§#[mcp_client] - Client Configuration
Simplifies MCP client configuration and setup.
use ultrafast_mcp_macros::mcp_client;
#[mcp_client(
name = "MyClient",
version = "1.0.0",
description = "A client for the greeting server"
)]
struct MyClient;
// The macro generates:
// - Client information
// - Client capabilities
// - Client setup methods§mcp_request! - Request Type Generation
Generates MCP request types with automatic validation.
use ultrafast_mcp_macros::mcp_request;
use ultrafast_mcp_core::protocol::jsonrpc::{JsonRpcRequest, RequestId};
use serde_json::json;
let request = mcp_request! {
method: "tools/list",
params: {},
id: 1
};
assert_eq!(request.method, "tools/list");
assert_eq!(request.id, Some(RequestId::Number(1)));§mcp_response! - Response Type Generation
Generates MCP response types with automatic serialization.
use ultrafast_mcp_macros::mcp_response;
use ultrafast_mcp_core::protocol::jsonrpc::{JsonRpcResponse, RequestId};
use serde_json::json;
let response = mcp_response! {
result: {"status": "ok"},
id: 1
};
assert_eq!(response.id, Some(RequestId::Number(1)));§Usage Examples
§Complete Tool Implementation
use ultrafast_mcp_macros::{mcp_tool, McpSchema};
use serde::{Serialize, Deserialize};
use serde_json::Value;
// Define input/output types with schemas
#[derive(McpSchema, Serialize, Deserialize)]
struct CalculatorInput {
operation: String,
a: f64,
b: f64,
}
#[derive(McpSchema, Serialize, Deserialize)]
struct CalculatorOutput {
result: f64,
operation: String,
}
// Define the tool
#[mcp_tool(
name = "calculate",
description = "Perform basic mathematical operations"
)]
async fn calculate(input: CalculatorInput) -> Result<CalculatorOutput, Box<dyn std::error::Error>> {
let result = match input.operation.as_str() {
"add" => input.a + input.b,
"subtract" => input.a - input.b,
"multiply" => input.a * input.b,
"divide" => {
if input.b == 0.0 {
return Err("Division by zero".into());
}
input.a / input.b
}
_ => return Err("Unknown operation".into()),
};
Ok(CalculatorOutput {
result,
operation: input.operation,
})
}
// Example usage:
// let tool = register_tool();
// assert_eq!(tool.name, "calculate");§Server with Multiple Tools
use ultrafast_mcp_macros::{mcp_server, mcp_tool};
use ultrafast_mcp_server::UltraFastServer;
use ultrafast_mcp_core::types::tools::Tool;
#[mcp_server(
name = "MathServer",
version = "1.0.0",
description = "A server providing mathematical tools"
)]
struct MathServer;
#[mcp_tool(name = "add", description = "Add two numbers")]
async fn add_tool(a: f64, b: f64) -> Result<f64, Box<dyn std::error::Error>> {
Ok(a + b)
}
#[mcp_tool(name = "multiply", description = "Multiply two numbers")]
async fn multiply_tool(a: f64, b: f64) -> Result<f64, Box<dyn std::error::Error>> {
Ok(a * b)
}
// Example server setup (commented out to avoid async main issues in doctest):
// #[tokio::main]
// async fn main() -> anyhow::Result<()> {
// let server_info = MathServer::server_info();
// let server = UltraFastServer::new(server_info, Default::default());
//
// // Register tools using the generated functions
// let add_tool = register_add_tool_tool();
// let multiply_tool = register_multiply_tool_tool();
//
// server.run_stdio().await?;
// Ok(())
// }
// Example usage:
let server_info = MathServer::server_info();
assert_eq!(server_info.name, "MathServer");
assert_eq!(server_info.version, "1.0.0");
// Test the generated tool registration functions
let add_tool = register_add_tool_tool();
let multiply_tool = register_multiply_tool_tool();
assert_eq!(add_tool.name, "add_tool");
assert_eq!(multiply_tool.name, "multiply_tool");§Client with Configuration
use ultrafast_mcp_macros::{mcp_client, mcp_request, mcp_response};
use serde::{Serialize, Deserialize};
use ultrafast_mcp_core::types::tools::ToolCall;
#[mcp_client(
name = "MathClient",
version = "1.0.0",
description = "A client for mathematical operations"
)]
struct MathClient;
#[derive(Serialize, Deserialize)]
struct AddRequest {
a: f64,
b: f64,
}
#[derive(Serialize, Deserialize)]
struct AddResponse {
result: f64,
}
// Example client setup (commented out to avoid async main issues in doctest):
// #[tokio::main]
// async fn main() -> anyhow::Result<()> {
// let client_info = MathClient::client_info();
// let client = ultrafast_mcp_client::UltraFastClient::new(client_info, Default::default());
//
// client.connect_http("http://localhost:8080/mcp").await?;
//
// let request = AddRequest { a: 5.0, b: 3.0 };
// let tool_call = ToolCall {
// name: "add".to_string(),
// arguments: Some(serde_json::to_value(request)?),
// };
// let response = client.call_tool(tool_call).await?;
//
// println!("Result: {:?}", response);
// Ok(())
// }
// Example usage:
// let client_info = MathClient::client_info();
// assert_eq!(client_info.name, "MathClient");§Schema Attributes
The McpSchema derive macro supports various attributes for customizing schema generation:
use ultrafast_mcp_macros::McpSchema;
use serde::{Serialize, Deserialize};
#[derive(McpSchema, Serialize, Deserialize)]
struct User {
#[mcp(description = "User's full name")]
name: String,
#[mcp(minimum = 0, maximum = 150)]
age: u32,
#[mcp(format = "email")]
email: String,
#[mcp(min_length = 8)]
password: String,
#[mcp(required = false)]
bio: Option<String>,
}§Error Handling
The macros integrate seamlessly with MCP error handling:
use ultrafast_mcp_macros::mcp_tool;
use ultrafast_mcp_core::MCPError;
#[mcp_tool(name = "risky_operation")]
async fn risky_operation(input: String) -> Result<String, MCPError> {
if input.is_empty() {
return Err(MCPError::invalid_params("Input cannot be empty".to_string()));
}
if input.len() > 1000 {
return Err(MCPError::invalid_params("Input too long".to_string()));
}
Ok(format!("Processed: {}", input))
}§Performance Considerations
- Compile-time Generation: All code is generated at compile time
- Zero Runtime Overhead: No runtime reflection or dynamic code generation
- Optimized Schemas: Efficient schema generation and validation
- Minimal Allocations: Optimized for minimal memory usage
- Fast Serialization: Efficient serialization/deserialization
§Best Practices
§Schema Design
- Use descriptive field names and types
- Add meaningful descriptions with attributes
- Use appropriate validation constraints
- Keep schemas simple and focused
- Document complex schemas thoroughly
§Tool Implementation
- Use strongly-typed input/output types
- Implement proper error handling
- Add meaningful descriptions
- Keep tools focused and single-purpose
- Test tools thoroughly
§Server/Client Setup
- Use descriptive names and versions
- Provide meaningful descriptions
- Configure appropriate capabilities
- Implement proper error handling
- Follow naming conventions
§Thread Safety
All generated code is designed to be thread-safe:
- Generated types implement
Send + Syncwhere appropriate - No mutable global state is used
- Concurrent access is supported
- Safe for use in async contexts
§Examples
See the examples/ directory for complete working examples:
- Basic tool implementation
- Server with multiple tools
- Client configuration
- Schema customization
- Error handling patterns
Macros§
- mcp_
client_ config - Macro for creating MCP client configurations
- mcp_
error - Macro for creating MCP errors
- mcp_
request - Macro for creating MCP requests
- mcp_
response - Macro for creating MCP responses
Attribute Macros§
- mcp_
client - mcp_
server - Attribute macro for MCP server setup
- mcp_
tool - Attribute macro for defining MCP tools
Derive Macros§
- McpSchema
- Derive macro for automatic JSON Schema generation