diff --git a/crates/rust-mcp-sdk/src/mcp_macros/tool_box.rs b/crates/rust-mcp-sdk/src/mcp_macros/tool_box.rs index f6d2b3e..3bd2735 100644 --- a/crates/rust-mcp-sdk/src/mcp_macros/tool_box.rs +++ b/crates/rust-mcp-sdk/src/mcp_macros/tool_box.rs @@ -30,7 +30,7 @@ /// // //....... /// // } macro_rules! tool_box { - ($enum_name:ident, [$($tool:ident),*]) => { + ($enum_name:ident, [$($tool:ident),* $(,)?]) => { #[derive(Debug)] pub enum $enum_name { $( diff --git a/crates/rust-mcp-sdk/tests/common/common.rs b/crates/rust-mcp-sdk/tests/common/common.rs index c7e3f19..b72a08f 100644 --- a/crates/rust-mcp-sdk/tests/common/common.rs +++ b/crates/rust-mcp-sdk/tests/common/common.rs @@ -34,3 +34,55 @@ pub fn sse_event(sse_raw: &str) -> String { pub fn sse_data(sse_raw: &str) -> String { sse_raw.replace("data: ", "") } + +pub mod sample_tools { + use rust_mcp_sdk::macros::{mcp_tool, JsonSchema}; + use rust_mcp_sdk::schema::{schema_utils::CallToolError, CallToolResult}; + + //****************// + // SayHelloTool // + //****************// + #[mcp_tool( + name = "say_hello", + description = "Accepts a person's name and says a personalized \"Hello\" to that person", + idempotent_hint = false, + destructive_hint = false, + open_world_hint = false, + read_only_hint = false + )] + #[derive(Debug, ::serde::Deserialize, ::serde::Serialize, JsonSchema)] + pub struct SayHelloTool { + /// The name of the person to greet with a "Hello". + name: String, + } + + impl SayHelloTool { + pub fn call_tool(&self) -> Result { + let hello_message = format!("Hello, {}!", self.name); + Ok(CallToolResult::text_content(hello_message, None)) + } + } + + //******************// + // SayGoodbyeTool // + //******************// + #[mcp_tool( + name = "say_goodbye", + description = "Accepts a person's name and says a personalized \"Goodbye\" to that person.", + idempotent_hint = false, + destructive_hint = false, + open_world_hint = false, + read_only_hint = false + )] + #[derive(Debug, ::serde::Deserialize, ::serde::Serialize, JsonSchema)] + pub struct SayGoodbyeTool { + /// The name of the person to say goodbye to. + name: String, + } + impl SayGoodbyeTool { + pub fn call_tool(&self) -> Result { + let hello_message = format!("Goodbye, {}!", self.name); + Ok(CallToolResult::text_content(hello_message, None)) + } + } +} diff --git a/crates/rust-mcp-sdk/tests/test_tool_box.rs b/crates/rust-mcp-sdk/tests/test_tool_box.rs new file mode 100644 index 0000000..335591b --- /dev/null +++ b/crates/rust-mcp-sdk/tests/test_tool_box.rs @@ -0,0 +1,28 @@ +#[path = "common/common.rs"] +pub mod common; + +use common::sample_tools::{SayGoodbyeTool, SayHelloTool}; +use rust_mcp_sdk::tool_box; + +// Define tool box without trailing comma +tool_box!(FileSystemToolsNoComma, [SayHelloTool, SayGoodbyeTool]); + +// Define tool box with trailing comma +// Related Issue: https://github.com/rust-mcp-stack/rust-mcp-sdk/issues/57 +tool_box!(FileSystemTools, [SayHelloTool, SayGoodbyeTool,]); + +#[test] +fn test_tools_with_trailing_comma() { + let tools = FileSystemTools::tools(); + assert_eq!(tools.len(), 2); + assert_eq!(tools[0].name, "say_hello"); + assert_eq!(tools[1].name, "say_goodbye"); +} + +#[test] +fn test_tools_without_trailing_comma() { + let tools = FileSystemToolsNoComma::tools(); + assert_eq!(tools.len(), 2); + assert_eq!(tools[0].name, "say_hello"); + assert_eq!(tools[1].name, "say_goodbye"); +}