use rmcp::handler::server::router::tool::{AsyncTool, ToolRouter};
pub struct ToolSpec<H: Send + Sync + 'static> {
register: fn(ToolRouter<H>) -> ToolRouter<H>,
pinned: bool,
read_only: bool,
}
impl<H: Send + Sync + 'static> std::fmt::Debug for ToolSpec<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ToolSpec")
.field("pinned", &self.pinned)
.field("read_only", &self.read_only)
.finish_non_exhaustive()
}
}
impl<H: Send + Sync + 'static> ToolSpec<H> {
#[must_use]
pub const fn async_tool<T: AsyncTool<H> + 'static>(pinned: bool, read_only: bool) -> Self {
Self {
register: ToolRouter::with_async_tool::<T>,
pinned,
read_only,
}
}
}
pub trait ToolRouterExt<H: Send + Sync + 'static>: Sized {
#[must_use]
fn from_specs(specs: &[ToolSpec<H>], read_only: bool, pinned: bool) -> Self;
}
impl<H: Send + Sync + 'static> ToolRouterExt<H> for ToolRouter<H> {
fn from_specs(specs: &[ToolSpec<H>], read_only: bool, pinned: bool) -> Self {
specs
.iter()
.filter(|spec| (!spec.read_only || !read_only) && spec.pinned == pinned)
.fold(ToolRouter::new(), |router, spec| (spec.register)(router))
}
}