| Crates.io | rust-mcp-macros |
| lib.rs | rust-mcp-macros |
| version | 0.8.0 |
| created_at | 2025-03-29 22:52:58.912416+00 |
| updated_at | 2026-01-01 16:58:57.658173+00 |
| description | A procedural macro that derives the MCPToolSchema implementation for structs or enums, generating a tool_input_schema function used with rust_mcp_schema::Tool. |
| homepage | |
| repository | https://github.com/rust-mcp-stack/rust-mcp-sdk |
| max_upload_size | |
| id | 1611805 |
| size | 191,047 |
rust-mcp-macros provides procedural macros for the rust-mcp-sdk ecosystem. These macros simplify the generation of tools and elicitation schemas compatible with the latest MCP protocol specifications.
The available macros are:
mcp_tool: Generates a rust_mcp_schema::Tool instance from a struct. mcp_elicit: Generates elicitation logic for gathering user input based on a struct's schema, supporting Form and URL modes. [derive(JsonSchema)]: Derives a JSON Schema representation for structs and enums, used by the other macros for schema generation.
These macros rely on rust_mcp_schema and serde_json for schema handling.
A procedural macro to generate a rust_mcp_schema::Tool instance from a struct. The struct must derive JsonSchema.
tool_name(): Returns the tool's name.
tool(): Returns a rust_mcp_schema::Tool with name, description, input schema, and optional metadata/annotations.
request_params(): Returns a CallToolRequestParams pre-initialized with the tool's name, ready for building a tool call via the builder pattern.
name: Required, non-empty string for the tool's name.
description: Required, a full and detailed description of the tool’s functionality.
title: Optional human readable title for the tools.
description - A description of the tool (required, non-empty string).
meta - An optional JSON string that provides additional metadata for the tool.
execution: Optional, controls task support. Accepted values are "required", "optional", and "forbidden".
icons: Optional array of icons with src (required), mime_type, sizes (array of strings), theme ("light" or "dark").
destructive_hint – Optional boolean, indicates whether the tool may make destructive changes to its environment.
idempotent_hint – Optional boolean, indicates whether repeated calls with the same input have the same effect.
open_world_hint – Optional boolean, indicates whether the tool can interact with external or unknown entities.
read_only_hint – Optional boolean, indicates whether the tool makes no modifications to its environment.
use rust_mcp_macros::{mcp_tool, JsonSchema};
use rust_mcp_schema::Tool;
#[mcp_tool(
name = "write_file",
title = "Write File Tool",
description = "Create or overwrite a file with content.",
destructive_hint = false,
idempotent_hint = false,
open_world_hint = false,
read_only_hint = false,
execution(task_support = "optional"),
icons = [
(src = "https:/mywebsite.com/write.png", mime_type = "image/png", sizes = ["128x128"], theme = "light"),
(src = "https:/mywebsite.com/write_dark.svg", mime_type = "image/svg+xml", sizes = ["64x64","128x128"], theme = "dark")
],
meta = r#"{"key": "value"}"#
)]
#[derive(JsonSchema)]
pub struct WriteFileTool {
/// The target file's path.
pub path: String,
/// The string content to be written to the file
pub content: String,
}
WriteFileTool::request_params().with_arguments(
json!({"path":"./test.txt","content":"hello tool"})
.as_object()
.unwrap()
.clone(),
)
// send a call_tool requeest:
let result = client.request_tool_call( WriteFileTool::request_params().with_arguments(
json!({"path":"./test.txt","content":"hello tool"}).as_object().unwrap().clone(),
))?;
// Handle ListToolsRequest, return list of available tools as ListToolsResult
async fn handle_list_tools_request(
&self,
request: Option<PaginatedRequestParams>,
runtime: Arc<dyn McpServer>,
) -> std::result::Result<ListToolsResult, RpcError> {
Ok(ListToolsResult {
meta: None,
next_cursor: None,
tools: vec![WriteFileTool::tool()],
})
}
The mcp_elicit macro generates implementations for eliciting user input based on the struct's schema. The struct must derive JsonSchema. It supports two modes: form (default) for schema-based forms and url for redirecting the user to an external URL to collect input.
message(): Returns the elicitation message.
elicit_request_params(elicitation_id): Returns ElicitRequestParams (FormParams or UrlParams based on mode).
from_elicit_result_content(content): Parses user input back into the struct.
message : Optional string (or concat!(...)), defaults to empty.mode: Optional, elicitation mode ("form"|"URL), defaults to form.url = "https://example.com/form": Required if mode = url.String: Maps to ElicitResultContentPrimitive::String.
bool: Maps to ElicitResultContentPrimitive::Boolean.
i32: Maps to ElicitResultContentPrimitive::Integer (with bounds checking).
i64: Maps to ElicitResultContentPrimitive::Integer.
Vec<String>: Maps to ElicitResultContent::StringArray.
Option<T>: Supported for any of the above types, mapping to None if the field is missing.
#[mcp_elicit(message = "Please enter your info", mode = form)]
#[derive(JsonSchema)]
pub struct UserInfo {
#[json_schema(title = "Name", min_length = 5, max_length = 100)]
pub name: String,
#[json_schema(title = "Email", format = "email")]
pub email: Option<String>,
#[json_schema(title = "Age", minimum = 15, maximum = 125)]
pub age: i32,
#[json_schema(title = "Tags")]
pub tags: Vec<String>,
}
// Sends a request to the client asking the user to provide input
let result: ElicitResult = server.request_elicitation(UserInfo::elicit_request_params()).await?;
// Convert result.content into a UserInfo instance
let user_info = UserInfo::from_elicit_result_content(result.content)?;
println!("name: {}", user_info.name);
println!("age: {}", user_info.age);
println!("email: {}",user.email.clone().unwrap_or("not provider".into()));
println!("tags: {}", user_info.tags.join(","));
#[mcp_elicit(message = "Complete the form", mode = url, url = "https://example.com/form")]
#[derive(JsonSchema)]
pub struct UserInfo {
#[json_schema(title = "Name", min_length = 5, max_length = 100)]
pub name: String,
#[json_schema(title = "Email", format = "email")]
pub email: Option<String>,
#[json_schema(title = "Age", minimum = 15, maximum = 125)]
pub age: i32,
#[json_schema(title = "Tags")]
pub tags: Vec<String>,
}
let elicit_url = UserInfo::elicit_url_params("elicit_10".into());
// Sends a request to the client asking the user to provide input
let result: ElicitResult = server.request_elicitation(UserInfo::elicit_request_params()).await?;
// Convert result.content into a UserInfo instance
let user_info = UserInfo::from_elicit_result_content(result.content)?;
println!("name: {}", user_info.name);
println!("age: {}", user_info.age);
println!("email: {}", user_info.email.unwrap_or_default();
println!("tags: {}", user_info.tags.join(","));
A procedural macro attribute that generates utility methods for declaring static resources. It produces a fully populated rust_mcp_schema::Resource instance from compile-time metadata. Useful for declaring files, images, documents, or any other static asset that your MCP server wants to expose (e.g., in ListResources responses).
Generated methods
resource_name() → &'static str: Returns the resource name.resource_uri() → &'static str: Returns the resource URI.resource() → rust_mcp_schema::Resource Constructs and returns the complete Resource struct.name : Unique identifier for the resource. Must be non-empty.
description : Human-readable description of what the resource is.
title : Display title
meta : Arbitrary metadata. Must be a valid JSON object string.
mime_type : MIME type of the resource (e.g., "image/png").
size : Size in bytes.
uri : Publicly accessible URI for the resource.
audience : Intended audiences roles (e.g., ["user", "assistant"]). Resource will use them in the resource annotation and rust_mcp_schema::Role.
icons : icons (same format as mcp_tool icons ^^).
use rust_mcp_macros::mcp_resource;
#[mcp_resource(
name = "company-logo",
description = "Official high-resolution company logo",
title = "Company Logo",
mime_type = "image/png",
size = 1024,
uri = "https://example.com/assets/logo.png",
audience = ["user", "assistant"],
meta = r#"{"license": "proprietary", "author": "Design Team"}"#,
icons = [
( src = "logo-192.png", sizes = ["192x192"], mime_type = "image/png" ),
( src = "logo-512.png", sizes = ["512x512"], mime_type = "image/png" )
]
)]
pub struct CompanyLogo{};
// In your server handler:
async fn handle_list_resources(
&self,
_request: Option<PaginatedRequestParams>,
) -> Result<ListResourcesResult, RpcError> {
Ok(ListResourcesResult {
meta: None,
next_cursor: None,
resources: vec![CompanyLogo::resource()],
})
}
// Usage elsewhere:
assert_eq!(CompanyLogo::resource_name(), "company-logo");
assert_eq!(CompanyLogo::resource_uri(), "https://example.com/assets/logo.png");
let res = CompanyLogo::resource();
assert_eq!(res.mime_type.unwrap(), "image/png");
assert_eq!(res.size.unwrap(), 1024);
assert!(res.icons.len() == 2);
👉 Please see examples/common/resources.rs and examples/common/example_server_handler.rs for a working example with text and blob resources.
A procedural macro attribute that generates utility methods for declaring template description for parameterized resources available on the server. It produces a fully populated rust_mcp_schema::ResourceTemplate instance from compile-time metadata. Resource templates allow servers to expose parameterized resources
Generated methods
resource_template_name() → &'static str: Returns the resource template name.resource_template_uri() → &'static str: Returns the resource template URI .resource_template() → rust_mcp_schema::ResourceTemplate Constructs and returns the complete ResourceTemplate struct.name : Unique identifier for the resource. Must be non-empty.
description : Human-readable description of what the resource is.
title : Display title
meta : Arbitrary metadata. Must be a valid JSON object string.
mime_type : MIME type of the resource (e.g., "image/png").
uri_template : Publicly accessible URI for the resource.
audience : Intended audiences roles (e.g., ["user", "assistant"]). Resource will use them in the resource annotation and rust_mcp_schema::Role.
icons : icons (same format as mcp_tool icons ^^).
👉 Please see examples/common/resources.rs and examples/common/example_server_handler.rs for a working example showing Pokémon sprites exposed as a dynamic resource.
Check out rust-mcp-sdk, a high-performance, asynchronous toolkit for building MCP servers and clients. Focus on your app's logic while rust-mcp-sdk takes care of the rest!