feat(macros): auto-generate get_info and default router (#785)

* feat(macros): auto-generate get_info and default router

* docs: simplify examples and docs with new defaults

* feat(macros): add tool_router(server_handler) to elide separate #[tool_handler] impl

* docs: add Tools section to README and simplify calculator examples with server_handler
This commit is contained in:
Dale Seo 2026-04-08 15:06:26 -04:00 • committed by GitHub
commit be321a4abe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,7 +1,7 @@
//! Common utilities shared between different macro implementations
use quote::quote;
use syn::{Attribute, Expr, FnArg, ImplItemFn, Signature, Type};
use syn::{Attribute, Expr, FnArg, ImplItem, ImplItemFn, ItemImpl, Signature, Type};
/// Parse a None expression
pub fn none_expr() -> syn::Result<Expr> {
@ -75,3 +75,24 @@ pub fn find_parameters_type_in_sig(sig: &Signature) -> Option<Box<Type>> {
pub fn find_parameters_type_impl(fn_item: &ImplItemFn) -> Option<Box<Type>> {
find_parameters_type_in_sig(&fn_item.sig)
}
/// Check whether an `impl` block already contains a method with the given name.
pub fn has_method(name: &str, item_impl: &ItemImpl) -> bool {
item_impl.items.iter().any(|item| match item {
ImplItem::Fn(func) => func.sig.ident == name,
_ => false,
})
}
/// Check whether an `impl` block carries a sibling handler attribute (e.g.
/// `#[prompt_handler]` visible from within `#[tool_handler]`).
///
/// Matches both bare (`prompt_handler`) and path-qualified (`rmcp::prompt_handler`) forms.
pub fn has_sibling_handler(item_impl: &ItemImpl, handler_name: &str) -> bool {
item_impl.attrs.iter().any(|attr| {
attr.path()
.segments
.last()
.is_some_and(|seg| seg.ident == handler_name)
})
}