fastmcp-rs 0.2.0

Rust prototype for the FastMCP server
Documentation
// Helper macros to simplify FastMCP registrations.
// These macros reduce boilerplate when defining tools, resources, and prompts.

// Define a tool with optional metadata fields.
// Usage:
// let tool = mcp_tool!{
//   name: "echo",
//   handler: |_, payload: serde_json::Value| async move {
//     Ok($crate::tool::ToolResponse::new(vec![payload]))
//   },
//   description: "Echoes the payload",
//   summary: "Echo JSON back",
//   parameters: serde_json::json!({ "type": "object" }),
//   annotations: { "category": serde_json::json!("demo") },
// };
#[macro_export]
macro_rules! mcp_tool {
    (
        name: $name:expr,
        handler: $handler:expr
        $(, description: $desc:expr )?
        $(, summary: $summary:expr )?
        $(, parameters: $params:expr )?
        $(, annotations: { $( $akey:literal : $aval:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __def = $crate::tool::ToolDefinition::new($name, $handler);
        $( __def = __def.with_description($desc); )?
        $( __def = __def.with_summary($summary); )?
        $( __def = __def.with_parameters($params); )?
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($akey.to_string(), $aval); )*
            __def = __def.with_annotations(__ann);
        })?
        __def
    }};
    (
        name: $name:expr,
        handler: $handler:expr
        $(, description: $desc:expr )?
        $(, summary: $summary:expr )?
        , parameters_json: { $( $json_params:tt )* }
        $(, annotations: { $( $akey2:literal : $aval2:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __def = $crate::tool::ToolDefinition::new($name, $handler);
        $( __def = __def.with_description($desc); )?
        $( __def = __def.with_summary($summary); )?
        __def = __def.with_parameters(serde_json::json!({ $( $json_params )* }));
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($akey2.to_string(), $aval2); )*
            __def = __def.with_annotations(__ann);
        })?
        __def
    }};
}

// Register multiple tools on a server, unwrapping errors for brevity in examples.
// Usage: mcp_register_tools!(server, [ tool1, tool2, tool3 ]);
#[macro_export]
macro_rules! mcp_register_tools {
    ( $server:expr, [ $( $tool_def:expr ),+ $(,)? ] ) => {{
        $( $server.register_tool( $tool_def ).unwrap(); )+
    }};
}

// Define a static resource with optional metadata.
// Example:
// let res = mcp_resource_static!{
//   uri: "resource://hello",
//   content: $crate::resource::ResourceContent::text("hello"),
//   description: "Greeting resource",
//   annotations: { "kind": serde_json::json!("demo") },
// };
#[macro_export]
macro_rules! mcp_resource_static {
    (
        uri: $uri:expr,
        content: $content:expr
        $(, name: $name:expr )?
        $(, description: $desc:expr )?
        $(, annotations: { $( $key:literal : $val:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __def = $crate::resource::ResourceDefinition::static_resource($uri, $content);
        $( __def = __def.with_name($name); )?
        $( __def = __def.with_description($desc); )?
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($key.to_string(), $val); )*
            __def = __def.with_annotations(__ann);
        })?
        __def
    }};
}

// Register multiple resources on a server.
#[macro_export]
macro_rules! mcp_register_resources {
    ( $server:expr, [ $( $res_def:expr ),+ $(,)? ] ) => {{
        $( $server.register_resource( $res_def ).unwrap(); )+
    }};
}

// Define a simple text prompt (single-message) with optional metadata.
// Example:
// let prompt = mcp_prompt_text!{
//   name: "welcome",
//   role: "system",
//   text: "Hello {{ user }}",
//   description: "Greets a user",
//   parameters: serde_json::json!({
//     "type": "object",
//     "required": ["user"],
//     "properties": { "user": { "type": "string" } }
//   }),
// };
#[macro_export]
macro_rules! mcp_prompt_text {
    (
        name: $name:expr,
        role: $role:expr,
        text: $text:expr
        $(, description: $desc:expr )?
        $(, parameters: $params:expr )?
        $(, annotations: { $( $key:literal : $val:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __tpl = $crate::prompt::PromptTemplate::new(
            $name,
            vec![$crate::prompt::PromptMessage {
                role: $role.into(),
                content: $crate::prompt::PromptMessageContent::Text { text: $text.into() },
            }],
        );
        $( __tpl = __tpl.with_description($desc); )?
        $( __tpl = __tpl.with_parameters($params); )?
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($key.to_string(), $val); )*
            __tpl = __tpl.with_annotations(__ann);
        })?
        __tpl
    }};
}

// Register multiple prompts on a server.
#[macro_export]
macro_rules! mcp_register_prompts {
    ( $server:expr, [ $( $prompt_def:expr ),+ $(,)? ] ) => {{
        $( $server.register_prompt( $prompt_def ).unwrap(); )+
    }};
}

// Convenience: build a server with common attributes and return Arc<FastMcpServer>.
// Example:
// let server = mcp_server! { name: "Demo", instructions: "Use tools" };
#[macro_export]
macro_rules! mcp_server {
    (
        name: $name:expr
        $(, instructions: $instructions:expr )?
        $(, version: $version:expr )?
        $(, tool_duplicates: $td:expr )?
        $(, resource_duplicates: $rd:expr )?
        $(, prompt_duplicates: $pd:expr )?
        $(,)?
    ) => {{
        let mut __builder = $crate::server::FastMcpServer::builder().name($name);
        $( __builder = __builder.instructions($instructions); )?
        $( __builder = __builder.version($version); )?
        $( __builder = __builder.tool_duplicates($td); )?
        $( __builder = __builder.resource_duplicates($rd); )?
        $( __builder = __builder.prompt_duplicates($pd); )?
        __builder.build().into_shared()
    }};
}

// Content helpers for ToolResponse payloads.
#[macro_export]
macro_rules! mcp_text {
    ( $text:expr ) => { serde_json::json!({ "type": "text", "text": $text }) };
}

#[macro_export]
macro_rules! mcp_json_content {
    ( $value:expr ) => { serde_json::json!({ "type": "json", "value": $value }) };
}

// Build ToolResponse from a list of content values.
#[macro_export]
macro_rules! mcp_response {
    ( [ $( $content:expr ),* $(,)? ] ) => {{
        $crate::tool::ToolResponse::new(vec![ $( $content ),* ])
    }};
}

// Define a JSON prompt content message.
#[macro_export]
macro_rules! mcp_prompt_json {
    (
        name: $name:expr,
        role: $role:expr,
        value: $value:expr
        $(, description: $desc:expr )?
        $(, parameters_json: { $( $json_params:tt )* } )?
        $(, annotations: { $( $key:literal : $val:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __tpl = $crate::prompt::PromptTemplate::new(
            $name,
            vec![$crate::prompt::PromptMessage {
                role: $role.into(),
                content: $crate::prompt::PromptMessageContent::Json { value: $value },
            }],
        );
        $( __tpl = __tpl.with_description($desc); )?
        $( __tpl = __tpl.with_parameters(serde_json::json!({ $( $json_params )* })); )?
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($key.to_string(), $val); )*
            __tpl = __tpl.with_annotations(__ann);
        })?
        __tpl
    }};
}

// Define a dynamic resource with a resolver instance.
#[macro_export]
macro_rules! mcp_resource_dynamic {
    (
        uri: $uri:expr,
        resolver: $resolver:expr
        $(, name: $name:expr )?
        $(, description: $desc:expr )?
        $(, annotations: { $( $key:literal : $val:expr ),* $(,)? } )?
        $(,)?
    ) => {{
        let mut __def = $crate::resource::ResourceDefinition::dynamic($uri, $resolver);
        $( __def = __def.with_name($name); )?
        $( __def = __def.with_description($desc); )?
        $({
            let mut __ann = serde_json::Map::<String, serde_json::Value>::new();
            $( __ann.insert($key.to_string(), $val); )*
            __def = __def.with_annotations(__ann);
        })?
        __def
    }};
}