rust-mcp-macros 1.0.0

A procedural macro that derives the MCPToolSchema implementation for structs or enums, generating a tool_input_schema function used with rust_mcp_schema::Tool.
Documentation
# rust-mcp-macros

`rust-mcp-macros` provides procedural macros for the [rust-mcp-sdk](https://github.com/rust-mcp-stack/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](#mcp_tool-macro): Generates a [rust_mcp_schema::Tool](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.Tool.html) instance from a struct.
[mcp_elicit](#mcp_elicit): Generates elicitation logic for gathering user input based on a struct's schema, supporting [Form](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.ElicitRequestFormParams.html) and [URL](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.ElicitRequestUrlParams.html) 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](https://crates.io/crates/rust-mcp-schema) and serde_json for schema handling.


## ➡️ mcp_tool Macro
A procedural macro to generate a [rust_mcp_schema::Tool](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.Tool.html) instance from a struct. The struct must derive **JsonSchema**.


### Generated methods:

- `tool_name()`: Returns the tool's name.
- `tool()`: Returns a [rust_mcp_schema::Tool]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.Tool.html with name, description, input schema, and optional metadata/annotations.
- `request_params()`: Returns a [CallToolRequestParams]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.CallToolRequestParams.html pre-initialized with the tool's name, ready for building a tool call via the builder pattern.


### Attributes

- `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.


### Usage Example

```rust
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()],
    })
}

```


## ➡️ mcp_elicit Macro

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.


### Generated methods:

- `message()`: Returns the elicitation message.
- `elicit_request_params(elicitation_id)`: Returns [ElicitRequestParams]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.ElicitRequestUrlParams.html (FormParams or UrlParams based on mode).
- `from_elicit_result_content(content)`: Parses user input back into the struct.


### Attributes

- `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.

### Supported Field Types

- `String`: Maps to [ElicitResultContentPrimitive::String]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.ElicitResultContentPrimitive.html.
- `bool`: Maps to [ElicitResultContentPrimitive::Boolean]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.ElicitResultContentPrimitive.html.
- `i32`: Maps to [ElicitResultContentPrimitive::Integer]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.ElicitResultContentPrimitive.html (with bounds checking).
- `i64`: Maps to [ElicitResultContentPrimitive::Integer]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.ElicitResultContentPrimitive.html.
- `Vec<String>`: Maps to [ElicitResultContent::StringArray]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.ElicitResultContent.html.
- `Option<T>`: Supported for any of the above types, mapping to `None` if the field is missing.


### Usage Example (Form Mode)

```rust
    #[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(","));    

```


### Usage Example (URL Mode)

```rust
#[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(","));     
```


## ➡️ mcp_resource Macro

A procedural macro attribute that generates utility methods for declaring static resources. It produces a fully populated [rust_mcp_schema::Resource](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.Resource.html) 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]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.Resource.html Constructs and returns the complete Resource struct.

### Attributes

- `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]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.Role.html.
- `icons` :  icons (same format as mcp_tool icons ^^).


### Usage Example


```rs
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](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-sdk/examples/common/resources.rs) and [examples/common/example_server_handler.rs](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-sdk/examples/common/example_server_handler.rs) for a working example with text and blob resources.


## ➡️ mcp_resource_template Macro

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](https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.ResourceTemplate.html) 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]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/struct.ResourceTemplate.html Constructs and returns the complete ResourceTemplate struct.

### Attributes

- `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]https://docs.rs/rust-mcp-schema/latest/rust_mcp_schema/enum.Role.html.
- `icons` :  icons (same format as mcp_tool icons ^^).


👉 Please see [examples/common/resources.rs](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-sdk/examples/common/resources.rs) and [examples/common/example_server_handler.rs](https://github.com/rust-mcp-stack/rust-mcp-sdk/blob/main/crates/rust-mcp-sdk/examples/common/example_server_handler.rs) for a working example showing Pokémon sprites exposed as a dynamic resource.

---

<img align="top" src="assets/rust-mcp-stack-icon.png" width="24" style="border-radius:0.2rem;"> Check out [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk), a high-performance, asynchronous toolkit for building MCP servers and clients. Focus on your app's logic while [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) takes care of the rest!

---