From 94a0da367b09cbe25667152d71125e52a34a54c9 Mon Sep 17 00:00:00 2001 From: illusion_autumn <13393387+yao-linqing@user.noreply.gitee.com> Date: Thu, 8 May 2025 03:28:16 +0800 Subject: [PATCH 1/4] fix toml ref and no-default-features->default-features --- examples/simple-chat-client/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/simple-chat-client/Cargo.toml b/examples/simple-chat-client/Cargo.toml index 5387e9245..cae4da1e7 100644 --- a/examples/simple-chat-client/Cargo.toml +++ b/examples/simple-chat-client/Cargo.toml @@ -13,9 +13,9 @@ thiserror = "1.0" async-trait = "0.1" futures = "0.3" toml = "0.8" -rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", features = [ +rmcp = {path="../../crates/rmcp", features = [ "client", "transport-child-process", "transport-sse", -], no-default-features = true } +], default-features = false } clap = { version = "4.0", features = ["derive"] } \ No newline at end of file From d9232cf185287bef0c45553a8a7bf4565f99d7b6 Mon Sep 17 00:00:00 2001 From: illusion_autumn <13393387+yao-linqing@user.noreply.gitee.com> Date: Thu, 8 May 2025 03:49:41 +0800 Subject: [PATCH 2/4] # Simplify rcmp-macros Usage ## Changes Simplified the usage of rcmp-macros with the following changes: ### Before ```rust #[tool(tool_box)] impl Calculator { #[tool(description = "Calculate the sum of two numbers")] fn sum(&self, #[tool(aggr)] SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the difference of two numbers")] fn sub( &self, #[tool(param)] #[schemars(description = "the left hand side number")] a: i32, #[tool(param)] #[schemars(description = "the right hand side number")] b: i32, ) -> Json { Json(a - b) } } ``` ### After ```rust #[tool(tool_box)] impl Calculator { #[tool(description = "Calculate the sum of two numbers",aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the difference of two numbers")] fn sub( &self, #[schemars(description = "the left hand side number")] a: i32, #[schemars(description = "the right hand side number")] b: i32, ) -> Json { Json(a - b) } } ``` ## Improvements 1. Moved parameter-level `#[tool(aggr)]` attribute to the function level 2. Removed redundant `#[tool(param)]` markers 3. Maintained the same functionality while making the code more concise and readable --- crates/rmcp-macros/src/tool.rs | 51 ++++++++++--------- crates/rmcp/tests/common/calculator.rs | 6 +-- crates/rmcp/tests/test_complex_schema.rs | 4 +- crates/rmcp/tests/test_tool_macros.rs | 2 +- examples/servers/src/common/calculator.rs | 6 +-- examples/servers/src/common/counter.rs | 5 +- .../servers/src/common/generic_service.rs | 2 +- examples/transport/src/common/calculator.rs | 6 +-- examples/wasi/src/calculator.rs | 6 +-- 9 files changed, 41 insertions(+), 47 deletions(-) diff --git a/crates/rmcp-macros/src/tool.rs b/crates/rmcp-macros/src/tool.rs index 5425412ce..e81cc2218 100644 --- a/crates/rmcp-macros/src/tool.rs +++ b/crates/rmcp-macros/src/tool.rs @@ -45,6 +45,7 @@ struct ToolFnItemAttrs { name: Option, description: Option, vis: Option, + aggr: bool, } impl Parse for ToolFnItemAttrs { @@ -52,10 +53,16 @@ impl Parse for ToolFnItemAttrs { let mut name = None; let mut description = None; let mut vis = None; + let mut aggr = false; while !input.is_empty() { let key: Ident = input.parse()?; + let key_str = key.to_string(); + if key_str == AGGREGATED_IDENT { + aggr = true; + continue; + } input.parse::()?; - match key.to_string().as_str() { + match key_str.as_str() { "name" => { let value: Expr = input.parse()?; name = Some(value); @@ -82,6 +89,7 @@ impl Parse for ToolFnItemAttrs { name, description, vis, + aggr, }) } } @@ -346,29 +354,7 @@ pub(crate) fn tool_fn_item(attr: TokenStream, mut input_fn: ItemFn) -> syn::Resu for attr in raw_attrs { match &attr.meta { syn::Meta::List(meta_list) => { - if meta_list.path.is_ident(TOOL_IDENT) { - let pat_type = pat_type.clone(); - let marker = meta_list.parse_args::()?; - match marker { - ParamMarker::Param => { - let Some(arg_ident) = arg_ident.take() else { - return Err(syn::Error::new( - proc_macro2::Span::call_site(), - "input param must have an ident as name", - )); - }; - caught.replace(Caught::Param(ToolFnParamAttrs { - serde_meta: Vec::new(), - schemars_meta: Vec::new(), - ident: arg_ident, - rust_type: pat_type.ty.clone(), - })); - } - ParamMarker::Aggregated => { - caught.replace(Caught::Aggregated(pat_type.clone())); - } - } - } else if meta_list.path.is_ident(SERDE_IDENT) { + if meta_list.path.is_ident(SERDE_IDENT) { serde_metas.push(meta_list.clone()); } else if meta_list.path.is_ident(SCHEMARS_IDENT) { schemars_metas.push(meta_list.clone()); @@ -381,6 +367,23 @@ pub(crate) fn tool_fn_item(attr: TokenStream, mut input_fn: ItemFn) -> syn::Resu } } } + let pat_type = pat_type.clone(); + if tool_macro_attrs.fn_item.aggr{ + caught.replace(Caught::Aggregated(pat_type.clone())); + }else{ + let Some(arg_ident) = arg_ident.take() else { + return Err(syn::Error::new( + proc_macro2::Span::call_site(), + "input param must have an ident as name", + )); + }; + caught.replace(Caught::Param(ToolFnParamAttrs { + serde_meta: Vec::new(), + schemars_meta: Vec::new(), + ident: arg_ident, + rust_type: pat_type.ty.clone(), + })); + } match caught { Some(Caught::Param(mut param)) => { param.serde_meta = serde_metas; diff --git a/crates/rmcp/tests/common/calculator.rs b/crates/rmcp/tests/common/calculator.rs index e179f2583..ba75cb7d1 100644 --- a/crates/rmcp/tests/common/calculator.rs +++ b/crates/rmcp/tests/common/calculator.rs @@ -13,18 +13,16 @@ pub struct SumRequest { pub struct Calculator; #[tool(tool_box)] impl Calculator { - #[tool(description = "Calculate the sum of two numbers")] - fn sum(&self, #[tool(aggr)] SumRequest { a, b }: SumRequest) -> String { + #[tool(description = "Calculate the sum of two numbers",aggr)] + fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[tool(param)] #[schemars(description = "the left hand side number")] a: i32, - #[tool(param)] #[schemars(description = "the right hand side number")] b: i32, ) -> String { diff --git a/crates/rmcp/tests/test_complex_schema.rs b/crates/rmcp/tests/test_complex_schema.rs index b9370fcec..c73095dcf 100644 --- a/crates/rmcp/tests/test_complex_schema.rs +++ b/crates/rmcp/tests/test_complex_schema.rs @@ -30,10 +30,10 @@ impl Demo { Self } - #[tool(description = "LLM")] + #[tool(description = "LLM",aggr)] async fn chat( &self, - #[tool(aggr)] chat_request: ChatRequest, + chat_request: ChatRequest, ) -> Result { let content = Content::json(chat_request)?; Ok(CallToolResult::success(vec![content])) diff --git a/crates/rmcp/tests/test_tool_macros.rs b/crates/rmcp/tests/test_tool_macros.rs index daa5ee3d4..cbea1f272 100644 --- a/crates/rmcp/tests/test_tool_macros.rs +++ b/crates/rmcp/tests/test_tool_macros.rs @@ -30,7 +30,7 @@ pub struct Server {} impl Server { /// This tool is used to get the weather of a city. #[tool(name = "get-weather", description = "Get the weather of a city.", vis = )] - pub async fn get_weather(&self, #[tool(param)] city: String) -> String { + pub async fn get_weather(&self, city: String) -> String { drop(city); "rain".to_string() } diff --git a/examples/servers/src/common/calculator.rs b/examples/servers/src/common/calculator.rs index 68beecc0c..16536d2dd 100644 --- a/examples/servers/src/common/calculator.rs +++ b/examples/servers/src/common/calculator.rs @@ -15,18 +15,16 @@ pub struct SumRequest { pub struct Calculator; #[tool(tool_box)] impl Calculator { - #[tool(description = "Calculate the sum of two numbers")] - fn sum(&self, #[tool(aggr)] SumRequest { a, b }: SumRequest) -> String { + #[tool(description = "Calculate the sum of two numbers",aggr)] + fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the difference of two numbers")] fn sub( &self, - #[tool(param)] #[schemars(description = "the left hand side number")] a: i32, - #[tool(param)] #[schemars(description = "the right hand side number")] b: i32, ) -> Json { diff --git a/examples/servers/src/common/counter.rs b/examples/servers/src/common/counter.rs index 7bed523ab..b72f1d04a 100644 --- a/examples/servers/src/common/counter.rs +++ b/examples/servers/src/common/counter.rs @@ -64,17 +64,16 @@ impl Counter { #[tool(description = "Repeat what you say")] fn echo( &self, - #[tool(param)] #[schemars(description = "Repeat what you say")] saying: String, ) -> Result { Ok(CallToolResult::success(vec![Content::text(saying)])) } - #[tool(description = "Calculate the sum of two numbers")] + #[tool(description = "Calculate the sum of two numbers",aggr)] fn sum( &self, - #[tool(aggr)] StructRequest { a, b }: StructRequest, + StructRequest { a, b }: StructRequest, ) -> Result { Ok(CallToolResult::success(vec![Content::text( (a + b).to_string(), diff --git a/examples/servers/src/common/generic_service.rs b/examples/servers/src/common/generic_service.rs index 433a4308f..0060fc63d 100644 --- a/examples/servers/src/common/generic_service.rs +++ b/examples/servers/src/common/generic_service.rs @@ -56,7 +56,7 @@ impl GenericService { } #[tool(description = "set memory to service")] - pub async fn set_data(&self, #[tool(param)] data: String) -> String { + pub async fn set_data(&self, data: String) -> String { let new_data = data.clone(); format!("Current memory: {}", new_data) } diff --git a/examples/transport/src/common/calculator.rs b/examples/transport/src/common/calculator.rs index 99b7314a1..156298c87 100644 --- a/examples/transport/src/common/calculator.rs +++ b/examples/transport/src/common/calculator.rs @@ -9,18 +9,16 @@ pub struct SumRequest { #[derive(Debug, Clone)] pub struct Calculator; impl Calculator { - #[tool(description = "Calculate the sum of two numbers")] - fn sum(&self, #[tool(aggr)] SumRequest { a, b }: SumRequest) -> String { + #[tool(description = "Calculate the sum of two numbers",aggr)] + fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[tool(param)] #[schemars(description = "the left hand side number")] a: i32, - #[tool(param)] #[schemars(description = "the right hand side number")] b: i32, ) -> String { diff --git a/examples/wasi/src/calculator.rs b/examples/wasi/src/calculator.rs index f1c35eeac..8435c6c30 100644 --- a/examples/wasi/src/calculator.rs +++ b/examples/wasi/src/calculator.rs @@ -13,18 +13,16 @@ pub struct SumRequest { #[derive(Debug, Clone)] pub struct Calculator; impl Calculator { - #[tool(description = "Calculate the sum of two numbers")] - fn sum(&self, #[tool(aggr)] SumRequest { a, b }: SumRequest) -> String { + #[tool(description = "Calculate the sum of two numbers",aggr)] + fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[tool(param)] #[schemars(description = "the left hand side number")] a: i32, - #[tool(param)] #[schemars(description = "the right hand side number")] b: i32, ) -> String { From ea299d9b578992cb50eea7d8e710020b1911288d Mon Sep 17 00:00:00 2001 From: illusion_autumn <13393387+yao-linqing@user.noreply.gitee.com> Date: Thu, 8 May 2025 04:19:04 +0800 Subject: [PATCH 3/4] # rmcp-macros Usage Simplification ## Changes This modification simplifies the usage of rmcp-macros, with the following key changes: ### 1. Merged Toolbox Declaration and Description **Reference Example:** Original code: ```rust #[tool(tool_box)] impl Calculator { // Tool method implementations } #[tool(tool_box)] impl ServerHandler for Calculator { fn get_info(&self) -> ServerInfo { ServerInfo { instructions: Some("A simple calculator".into()), capabilities: ServerCapabilities::builder().enable_tools().build(), ..Default::default() } } } ``` Simplified: ```rust #[tool(tool_box,description = "A simple calculator")] impl Calculator { // Tool method implementations } ``` ### 2. Simplified Implementation Process - No longer requires separate implementation of the `ServerHandler` trait - Tool descriptions are provided directly through macro parameters - Reduces redundant code, improving maintainability ## Advantages 1. More concise code 2. Reduced boilerplate 3. More intuitive API usage 4. Lower barrier to entry --- crates/rmcp-macros/src/tool.rs | 131 ++++++++++++++++-- crates/rmcp/tests/common/calculator.rs | 13 +- examples/servers/src/common/calculator.rs | 17 +-- examples/servers/src/common/counter.rs | 2 +- .../servers/src/common/generic_service.rs | 14 +- 5 files changed, 124 insertions(+), 53 deletions(-) diff --git a/crates/rmcp-macros/src/tool.rs b/crates/rmcp-macros/src/tool.rs index e81cc2218..08080c6b3 100644 --- a/crates/rmcp-macros/src/tool.rs +++ b/crates/rmcp-macros/src/tool.rs @@ -3,18 +3,21 @@ use std::collections::HashSet; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{ - Expr, FnArg, Ident, ItemFn, ItemImpl, MetaList, PatType, Token, Type, Visibility, parse::Parse, - parse_quote, spanned::Spanned, + parse::{discouraged::Speculative, Parse}, parse_quote, spanned::Spanned, Expr, FnArg, Ident, ItemFn, ItemImpl, MetaList, PatType, Token, Type, Visibility }; #[derive(Default)] -struct ToolImplItemAttrs { +pub(crate) struct ToolImplItemAttrs { tool_box: Option>, + default_build: bool, + description: Option, } impl Parse for ToolImplItemAttrs { fn parse(input: syn::parse::ParseStream) -> syn::Result { let mut tool_box = None; + let mut default = true; + let mut description = None; while !input.is_empty() { let key: Ident = input.parse()?; match key.to_string().as_str() { @@ -26,6 +29,32 @@ impl Parse for ToolImplItemAttrs { tool_box = Some(Some(value)); } } + "default_build" => { + if input.lookahead1().peek(Token![=]) { + input.parse::()?; + let value: Expr = input.parse()?; + match value.to_token_stream().to_string().as_str() { + "true" => { + default = true; + } + "false" => { + default = false; + } + _ => { + return Err(syn::Error::new(key.span(), "unknown attribute")); + } + } + } else { + default = true; + } + } + "description" => { + if input.lookahead1().peek(Token![=]) { + input.parse::()?; + let value: Expr = input.parse()?; + description = Some(value); + } + } _ => { return Err(syn::Error::new(key.span(), "unknown attribute")); } @@ -36,7 +65,11 @@ impl Parse for ToolImplItemAttrs { input.parse::()?; } - Ok(ToolImplItemAttrs { tool_box }) + Ok(ToolImplItemAttrs { + tool_box, + default_build: default, + description, + }) } } @@ -163,14 +196,20 @@ pub enum ToolItem { impl Parse for ToolItem { fn parse(input: syn::parse::ParseStream) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(Token![impl]) { - let item = input.parse::()?; - Ok(ToolItem::Impl(item)) - } else { - let item = input.parse::()?; - Ok(ToolItem::Fn(item)) + let fork=input.fork(); + if let Ok(item) = fork.parse::() { + input.advance_to(&fork); + return Ok(ToolItem::Impl(item)); } + let fork=input.fork(); + if let Ok(item) = fork.parse::() { + input.advance_to(&fork); + return Ok(ToolItem::Fn(item)); + } + Err(syn::Error::new( + input.span(), + "expected function or impl block", + )) } } @@ -186,7 +225,22 @@ pub(crate) fn tool(attr: TokenStream, input: TokenStream) -> syn::Result syn::Result { let tool_impl_attr: ToolImplItemAttrs = syn::parse2(attr)?; let tool_box_ident = tool_impl_attr.tool_box; - + let mut extend_quote = None; + let description = if let Some(expr) = tool_impl_attr.description { + // Use explicitly provided description if available + expr + } else { + // Try to extract documentation comments + let doc_content = input + .attrs + .iter() + .filter_map(extract_doc_line) + .collect::>() + .join("\n"); + parse_quote! { + #doc_content.trim().to_string() + } + }; // get all tool function ident let mut tool_fn_idents = Vec::new(); for item in &input.items { @@ -288,6 +342,37 @@ pub(crate) fn tool_impl_item(attr: TokenStream, mut input: ItemImpl) -> syn::Res }) } }); + + if tool_impl_attr.default_build { + let struct_name = input.self_ty.clone(); + let generic = &input.generics; + let extend = quote! { + impl #generic rmcp::handler::server::ServerHandler for #struct_name { + async fn call_tool( + &self, + request: rmcp::model::CallToolRequestParam, + context: rmcp::service::RequestContext, + ) -> Result { + self.call_tool_inner(request, context).await + } + async fn list_tools( + &self, + request: Option, + context: rmcp::service::RequestContext, + ) -> Result { + self.list_tools_inner(request.unwrap_or_default(), context).await + } + fn get_info(&self) -> rmcp::model::ServerInfo { + rmcp::model::ServerInfo { + instructions: Some(#description.into()), + capabilities: rmcp::model::ServerCapabilities::builder().enable_tools().build(), + ..Default::default() + } + } + } + }; + extend_quote.replace(extend); + } } else { // if there are no generic parameters, use the original tool_box! macro let this_type_ident = &input.self_ty; @@ -296,11 +381,31 @@ pub(crate) fn tool_impl_item(attr: TokenStream, mut input: ItemImpl) -> syn::Res #(#tool_fn_idents),* } #ident); )); + if tool_impl_attr.default_build{ + let struct_name = input.self_ty.clone(); + let generic = &input.generics; + let extend = quote! { + impl #generic rmcp::handler::server::ServerHandler for #struct_name { + rmcp::tool_box!(@derive #ident); + + fn get_info(&self) -> rmcp::model::ServerInfo { + rmcp::model::ServerInfo { + instructions: Some(#description.into()), + capabilities: rmcp::model::ServerCapabilities::builder().enable_tools().build(), + ..Default::default() + } + } + } + }; + extend_quote.replace(extend); + } + } } Ok(quote! { #input + #extend_quote }) } @@ -441,7 +546,6 @@ pub(crate) fn tool_fn_item(attr: TokenStream, mut input_fn: ItemFn) -> syn::Resu .filter_map(extract_doc_line) .collect::>() .join("\n"); - parse_quote! { #doc_content.trim().to_string() } @@ -706,6 +810,7 @@ mod test { // The output should contain the description from doc comments let result_str = result.to_string(); + println!("result: {:#}", result_str); assert!(result_str.contains("This is a test description from doc comments")); assert!(result_str.contains("with multiple lines")); diff --git a/crates/rmcp/tests/common/calculator.rs b/crates/rmcp/tests/common/calculator.rs index ba75cb7d1..c6972c003 100644 --- a/crates/rmcp/tests/common/calculator.rs +++ b/crates/rmcp/tests/common/calculator.rs @@ -11,7 +11,7 @@ pub struct SumRequest { } #[derive(Debug, Clone, Default)] pub struct Calculator; -#[tool(tool_box)] +#[tool(tool_box,description = "A simple calculator")] impl Calculator { #[tool(description = "Calculate the sum of two numbers",aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { @@ -29,14 +29,3 @@ impl Calculator { (a - b).to_string() } } - -#[tool(tool_box)] -impl ServerHandler for Calculator { - fn get_info(&self) -> ServerInfo { - ServerInfo { - instructions: Some("A simple calculator".into()), - capabilities: ServerCapabilities::builder().enable_tools().build(), - ..Default::default() - } - } -} diff --git a/examples/servers/src/common/calculator.rs b/examples/servers/src/common/calculator.rs index 16536d2dd..b16e22c1f 100644 --- a/examples/servers/src/common/calculator.rs +++ b/examples/servers/src/common/calculator.rs @@ -1,7 +1,5 @@ use rmcp::{ - ServerHandler, handler::server::wrapper::Json, - model::{ServerCapabilities, ServerInfo}, schemars, tool, }; @@ -13,7 +11,7 @@ pub struct SumRequest { } #[derive(Debug, Clone)] pub struct Calculator; -#[tool(tool_box)] +#[tool(tool_box,description = "A simple calculator")] impl Calculator { #[tool(description = "Calculate the sum of two numbers",aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { @@ -30,15 +28,4 @@ impl Calculator { ) -> Json { Json(a - b) } -} - -#[tool(tool_box)] -impl ServerHandler for Calculator { - fn get_info(&self) -> ServerInfo { - ServerInfo { - instructions: Some("A simple calculator".into()), - capabilities: ServerCapabilities::builder().enable_tools().build(), - ..Default::default() - } - } -} +} \ No newline at end of file diff --git a/examples/servers/src/common/counter.rs b/examples/servers/src/common/counter.rs index b72f1d04a..b439bbf82 100644 --- a/examples/servers/src/common/counter.rs +++ b/examples/servers/src/common/counter.rs @@ -17,7 +17,7 @@ pub struct StructRequest { pub struct Counter { counter: Arc>, } -#[tool(tool_box)] +#[tool(tool_box,default_build=false)] impl Counter { #[allow(dead_code)] pub fn new() -> Self { diff --git a/examples/servers/src/common/generic_service.rs b/examples/servers/src/common/generic_service.rs index 0060fc63d..ba2e28bbc 100644 --- a/examples/servers/src/common/generic_service.rs +++ b/examples/servers/src/common/generic_service.rs @@ -42,7 +42,7 @@ pub struct GenericService { data_service: Arc, } -#[tool(tool_box)] +#[tool(tool_box,description="generic data service")] impl GenericService { pub fn new(data_service: DS) -> Self { Self { @@ -60,14 +60,4 @@ impl GenericService { let new_data = data.clone(); format!("Current memory: {}", new_data) } -} - -impl ServerHandler for GenericService { - fn get_info(&self) -> ServerInfo { - ServerInfo { - instructions: Some("generic data service".into()), - capabilities: ServerCapabilities::builder().enable_tools().build(), - ..Default::default() - } - } -} +} \ No newline at end of file From ac1931630111830d08a79d7a28d8f5ef1f7a7c9d Mon Sep 17 00:00:00 2001 From: illusion_autumn <13393387+yao-linqing@user.noreply.gitee.com> Date: Thu, 8 May 2025 16:25:09 +0800 Subject: [PATCH 4/4] fix cli warn --- crates/rmcp-macros/src/tool.rs | 16 +++++++++------- crates/rmcp/Cargo.toml | 2 +- crates/rmcp/tests/common/calculator.rs | 16 +++++----------- crates/rmcp/tests/test_complex_schema.rs | 7 ++----- examples/servers/src/common/calculator.rs | 17 ++++++----------- examples/servers/src/common/counter.rs | 12 ++++-------- examples/servers/src/common/generic_service.rs | 11 ++++------- examples/transport/src/common/calculator.rs | 8 +++----- examples/wasi/src/calculator.rs | 8 +++----- 9 files changed, 37 insertions(+), 60 deletions(-) diff --git a/crates/rmcp-macros/src/tool.rs b/crates/rmcp-macros/src/tool.rs index 08080c6b3..60ae9b73f 100644 --- a/crates/rmcp-macros/src/tool.rs +++ b/crates/rmcp-macros/src/tool.rs @@ -3,7 +3,10 @@ use std::collections::HashSet; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{ - parse::{discouraged::Speculative, Parse}, parse_quote, spanned::Spanned, Expr, FnArg, Ident, ItemFn, ItemImpl, MetaList, PatType, Token, Type, Visibility + Expr, FnArg, Ident, ItemFn, ItemImpl, MetaList, PatType, Token, Type, Visibility, + parse::{Parse, discouraged::Speculative}, + parse_quote, + spanned::Spanned, }; #[derive(Default)] @@ -196,12 +199,12 @@ pub enum ToolItem { impl Parse for ToolItem { fn parse(input: syn::parse::ParseStream) -> syn::Result { - let fork=input.fork(); + let fork = input.fork(); if let Ok(item) = fork.parse::() { input.advance_to(&fork); return Ok(ToolItem::Impl(item)); } - let fork=input.fork(); + let fork = input.fork(); if let Ok(item) = fork.parse::() { input.advance_to(&fork); return Ok(ToolItem::Fn(item)); @@ -381,7 +384,7 @@ pub(crate) fn tool_impl_item(attr: TokenStream, mut input: ItemImpl) -> syn::Res #(#tool_fn_idents),* } #ident); )); - if tool_impl_attr.default_build{ + if tool_impl_attr.default_build { let struct_name = input.self_ty.clone(); let generic = &input.generics; let extend = quote! { @@ -399,7 +402,6 @@ pub(crate) fn tool_impl_item(attr: TokenStream, mut input: ItemImpl) -> syn::Res }; extend_quote.replace(extend); } - } } @@ -473,9 +475,9 @@ pub(crate) fn tool_fn_item(attr: TokenStream, mut input_fn: ItemFn) -> syn::Resu } } let pat_type = pat_type.clone(); - if tool_macro_attrs.fn_item.aggr{ + if tool_macro_attrs.fn_item.aggr { caught.replace(Caught::Aggregated(pat_type.clone())); - }else{ + } else { let Some(arg_ident) = arg_ident.take() else { return Err(syn::Error::new( proc_macro2::Span::call_site(), diff --git a/crates/rmcp/Cargo.toml b/crates/rmcp/Cargo.toml index 088c72fb2..bb80b0606 100644 --- a/crates/rmcp/Cargo.toml +++ b/crates/rmcp/Cargo.toml @@ -55,7 +55,7 @@ rand = { version = "0.9", optional = true } tokio-stream = { version = "0.1", optional = true } # macro -rmcp-macros = { version = "0.1", workspace = true, optional = true } +rmcp-macros = { workspace = true, optional = true } [features] default = ["base64", "macros", "server"] diff --git a/crates/rmcp/tests/common/calculator.rs b/crates/rmcp/tests/common/calculator.rs index c6972c003..7efd3f8e2 100644 --- a/crates/rmcp/tests/common/calculator.rs +++ b/crates/rmcp/tests/common/calculator.rs @@ -1,8 +1,4 @@ -use rmcp::{ - ServerHandler, - model::{ServerCapabilities, ServerInfo}, - schemars, tool, -}; +use rmcp::{schemars, tool}; #[derive(Debug, serde::Deserialize, schemars::JsonSchema)] pub struct SumRequest { #[schemars(description = "the left hand side number")] @@ -11,9 +7,9 @@ pub struct SumRequest { } #[derive(Debug, Clone, Default)] pub struct Calculator; -#[tool(tool_box,description = "A simple calculator")] +#[tool(tool_box, description = "A simple calculator")] impl Calculator { - #[tool(description = "Calculate the sum of two numbers",aggr)] + #[tool(description = "Calculate the sum of two numbers", aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } @@ -21,10 +17,8 @@ impl Calculator { #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[schemars(description = "the left hand side number")] - a: i32, - #[schemars(description = "the right hand side number")] - b: i32, + #[schemars(description = "the left hand side number")] a: i32, + #[schemars(description = "the right hand side number")] b: i32, ) -> String { (a - b).to_string() } diff --git a/crates/rmcp/tests/test_complex_schema.rs b/crates/rmcp/tests/test_complex_schema.rs index c73095dcf..b0a52b967 100644 --- a/crates/rmcp/tests/test_complex_schema.rs +++ b/crates/rmcp/tests/test_complex_schema.rs @@ -30,11 +30,8 @@ impl Demo { Self } - #[tool(description = "LLM",aggr)] - async fn chat( - &self, - chat_request: ChatRequest, - ) -> Result { + #[tool(description = "LLM", aggr)] + async fn chat(&self, chat_request: ChatRequest) -> Result { let content = Content::json(chat_request)?; Ok(CallToolResult::success(vec![content])) } diff --git a/examples/servers/src/common/calculator.rs b/examples/servers/src/common/calculator.rs index b16e22c1f..0e856785b 100644 --- a/examples/servers/src/common/calculator.rs +++ b/examples/servers/src/common/calculator.rs @@ -1,7 +1,4 @@ -use rmcp::{ - handler::server::wrapper::Json, - schemars, tool, -}; +use rmcp::{handler::server::wrapper::Json, schemars, tool}; #[derive(Debug, serde::Deserialize, schemars::JsonSchema)] pub struct SumRequest { @@ -11,9 +8,9 @@ pub struct SumRequest { } #[derive(Debug, Clone)] pub struct Calculator; -#[tool(tool_box,description = "A simple calculator")] +#[tool(tool_box, description = "A simple calculator")] impl Calculator { - #[tool(description = "Calculate the sum of two numbers",aggr)] + #[tool(description = "Calculate the sum of two numbers", aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } @@ -21,11 +18,9 @@ impl Calculator { #[tool(description = "Calculate the difference of two numbers")] fn sub( &self, - #[schemars(description = "the left hand side number")] - a: i32, - #[schemars(description = "the right hand side number")] - b: i32, + #[schemars(description = "the left hand side number")] a: i32, + #[schemars(description = "the right hand side number")] b: i32, ) -> Json { Json(a - b) } -} \ No newline at end of file +} diff --git a/examples/servers/src/common/counter.rs b/examples/servers/src/common/counter.rs index b439bbf82..a447d4317 100644 --- a/examples/servers/src/common/counter.rs +++ b/examples/servers/src/common/counter.rs @@ -17,7 +17,7 @@ pub struct StructRequest { pub struct Counter { counter: Arc>, } -#[tool(tool_box,default_build=false)] +#[tool(tool_box, default_build = false)] impl Counter { #[allow(dead_code)] pub fn new() -> Self { @@ -64,17 +64,13 @@ impl Counter { #[tool(description = "Repeat what you say")] fn echo( &self, - #[schemars(description = "Repeat what you say")] - saying: String, + #[schemars(description = "Repeat what you say")] saying: String, ) -> Result { Ok(CallToolResult::success(vec![Content::text(saying)])) } - #[tool(description = "Calculate the sum of two numbers",aggr)] - fn sum( - &self, - StructRequest { a, b }: StructRequest, - ) -> Result { + #[tool(description = "Calculate the sum of two numbers", aggr)] + fn sum(&self, StructRequest { a, b }: StructRequest) -> Result { Ok(CallToolResult::success(vec![Content::text( (a + b).to_string(), )])) diff --git a/examples/servers/src/common/generic_service.rs b/examples/servers/src/common/generic_service.rs index ba2e28bbc..a45d3674c 100644 --- a/examples/servers/src/common/generic_service.rs +++ b/examples/servers/src/common/generic_service.rs @@ -1,10 +1,6 @@ use std::sync::Arc; -use rmcp::{ - ServerHandler, - model::{ServerCapabilities, ServerInfo}, - schemars, tool, -}; +use rmcp::{schemars, tool}; #[allow(dead_code)] pub trait DataService: Send + Sync + 'static { @@ -42,8 +38,9 @@ pub struct GenericService { data_service: Arc, } -#[tool(tool_box,description="generic data service")] +#[tool(tool_box, description = "generic data service")] impl GenericService { + #[allow(dead_code)] pub fn new(data_service: DS) -> Self { Self { data_service: Arc::new(data_service), @@ -60,4 +57,4 @@ impl GenericService { let new_data = data.clone(); format!("Current memory: {}", new_data) } -} \ No newline at end of file +} diff --git a/examples/transport/src/common/calculator.rs b/examples/transport/src/common/calculator.rs index 156298c87..6f99a08c7 100644 --- a/examples/transport/src/common/calculator.rs +++ b/examples/transport/src/common/calculator.rs @@ -9,7 +9,7 @@ pub struct SumRequest { #[derive(Debug, Clone)] pub struct Calculator; impl Calculator { - #[tool(description = "Calculate the sum of two numbers",aggr)] + #[tool(description = "Calculate the sum of two numbers", aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } @@ -17,10 +17,8 @@ impl Calculator { #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[schemars(description = "the left hand side number")] - a: i32, - #[schemars(description = "the right hand side number")] - b: i32, + #[schemars(description = "the left hand side number")] a: i32, + #[schemars(description = "the right hand side number")] b: i32, ) -> String { (a - b).to_string() } diff --git a/examples/wasi/src/calculator.rs b/examples/wasi/src/calculator.rs index 8435c6c30..e28b4fc16 100644 --- a/examples/wasi/src/calculator.rs +++ b/examples/wasi/src/calculator.rs @@ -13,7 +13,7 @@ pub struct SumRequest { #[derive(Debug, Clone)] pub struct Calculator; impl Calculator { - #[tool(description = "Calculate the sum of two numbers",aggr)] + #[tool(description = "Calculate the sum of two numbers", aggr)] fn sum(&self, SumRequest { a, b }: SumRequest) -> String { (a + b).to_string() } @@ -21,10 +21,8 @@ impl Calculator { #[tool(description = "Calculate the sub of two numbers")] fn sub( &self, - #[schemars(description = "the left hand side number")] - a: i32, - #[schemars(description = "the right hand side number")] - b: i32, + #[schemars(description = "the left hand side number")] a: i32, + #[schemars(description = "the right hand side number")] b: i32, ) -> String { (a - b).to_string() }