@@ -177,30 +177,114 @@ pub(crate) fn tool(attr: TokenStream, input: TokenStream) -> syn::Result<TokenSt
177177pub ( crate ) fn tool_impl_item ( attr : TokenStream , mut input : ItemImpl ) -> syn:: Result < TokenStream > {
178178 let tool_impl_attr: ToolImplItemAttrs = syn:: parse2 ( attr) ?;
179179 let tool_box_ident = tool_impl_attr. tool_box ;
180+
181+ // get all tool function ident
182+ let mut tool_fn_idents = Vec :: new ( ) ;
183+ for item in & input. items {
184+ if let syn:: ImplItem :: Fn ( method) = item {
185+ for attr in & method. attrs {
186+ if attr. path ( ) . is_ident ( TOOL_IDENT ) {
187+ tool_fn_idents. push ( method. sig . ident . clone ( ) ) ;
188+ }
189+ }
190+ }
191+ }
192+
193+ // handle different cases
180194 if input. trait_ . is_some ( ) {
181195 if let Some ( ident) = tool_box_ident {
182- input. items . push ( parse_quote ! (
183- rmcp:: tool_box!( @derive #ident) ;
184- ) ) ;
196+ // check if there are generic parameters
197+ if !input. generics . params . is_empty ( ) {
198+ // for trait implementation with generic parameters, directly use the already generated *_inner method
199+
200+ // generate call_tool method
201+ input. items . push ( parse_quote ! {
202+ async fn call_tool(
203+ & self ,
204+ request: rmcp:: model:: CallToolRequestParam ,
205+ context: rmcp:: service:: RequestContext <rmcp:: RoleServer >,
206+ ) -> Result <rmcp:: model:: CallToolResult , rmcp:: Error > {
207+ self . call_tool_inner( request, context) . await
208+ }
209+ } ) ;
210+
211+ // generate list_tools method
212+ input. items . push ( parse_quote ! {
213+ async fn list_tools(
214+ & self ,
215+ request: rmcp:: model:: PaginatedRequestParam ,
216+ context: rmcp:: service:: RequestContext <rmcp:: RoleServer >,
217+ ) -> Result <rmcp:: model:: ListToolsResult , rmcp:: Error > {
218+ self . list_tools_inner( request, context) . await
219+ }
220+ } ) ;
221+ } else {
222+ // if there are no generic parameters, add tool box derive
223+ input. items . push ( parse_quote ! (
224+ rmcp:: tool_box!( @derive #ident) ;
225+ ) ) ;
226+ }
185227 }
186228 } else if let Some ( ident) = tool_box_ident {
187- let mut tool_fn_idents = Vec :: new ( ) ;
188- for item in & input. items {
189- if let syn:: ImplItem :: Fn ( method) = item {
190- for attr in & method. attrs {
191- if attr. path ( ) . is_ident ( TOOL_IDENT ) {
192- tool_fn_idents. push ( method. sig . ident . clone ( ) ) ;
229+ // if it is a normal impl block
230+ if !input. generics . params . is_empty ( ) {
231+ // if there are generic parameters, not use tool_box! macro, but generate code directly
232+
233+ // create call code for each tool function
234+ let match_arms = tool_fn_idents. iter ( ) . map ( |ident| {
235+ let attr_fn = Ident :: new ( & format ! ( "{}_tool_attr" , ident) , ident. span ( ) ) ;
236+ let call_fn = Ident :: new ( & format ! ( "{}_tool_call" , ident) , ident. span ( ) ) ;
237+ quote ! {
238+ name if name == Self :: #attr_fn( ) . name => {
239+ Self :: #call_fn( tcc) . await
193240 }
194241 }
195- }
242+ } ) ;
243+
244+ let tool_attrs = tool_fn_idents. iter ( ) . map ( |ident| {
245+ let attr_fn = Ident :: new ( & format ! ( "{}_tool_attr" , ident) , ident. span ( ) ) ;
246+ quote ! { Self :: #attr_fn( ) }
247+ } ) ;
248+
249+ // implement call_tool method
250+ input. items . push ( parse_quote ! {
251+ async fn call_tool_inner(
252+ & self ,
253+ request: rmcp:: model:: CallToolRequestParam ,
254+ context: rmcp:: service:: RequestContext <rmcp:: RoleServer >,
255+ ) -> Result <rmcp:: model:: CallToolResult , rmcp:: Error > {
256+ let tcc = rmcp:: handler:: server:: tool:: ToolCallContext :: new( self , request, context) ;
257+ match tcc. name( ) {
258+ #( #match_arms, ) *
259+ _ => Err ( rmcp:: Error :: invalid_params( "tool not found" , None ) ) ,
260+ }
261+ }
262+ } ) ;
263+
264+ // implement list_tools method
265+ input. items . push ( parse_quote ! {
266+ async fn list_tools_inner(
267+ & self ,
268+ _: rmcp:: model:: PaginatedRequestParam ,
269+ _: rmcp:: service:: RequestContext <rmcp:: RoleServer >,
270+ ) -> Result <rmcp:: model:: ListToolsResult , rmcp:: Error > {
271+ Ok ( rmcp:: model:: ListToolsResult {
272+ next_cursor: None ,
273+ tools: vec![ #( #tool_attrs) , * ] ,
274+ } )
275+ }
276+ } ) ;
277+ } else {
278+ // if there are no generic parameters, use the original tool_box! macro
279+ let this_type_ident = & input. self_ty ;
280+ input. items . push ( parse_quote ! (
281+ rmcp:: tool_box!( #this_type_ident {
282+ #( #tool_fn_idents) , *
283+ } #ident) ;
284+ ) ) ;
196285 }
197- let this_type_ident = & input. self_ty ;
198- input. items . push ( parse_quote ! (
199- rmcp:: tool_box!( #this_type_ident {
200- #( #tool_fn_idents) , *
201- } #ident) ;
202- ) ) ;
203286 }
287+
204288 Ok ( quote ! {
205289 #input
206290 } )
0 commit comments