turbomcp_server/handlers/implementations/
function_tool.rs

1//! Function-based tool handler implementation
2
3use async_trait::async_trait;
4use std::sync::Arc;
5use turbomcp_protocol::RequestContext;
6use turbomcp_protocol::types::{CallToolRequest, CallToolResult, Tool};
7
8use crate::ServerResult;
9use crate::handlers::traits::ToolHandler;
10
11type BoxFuture<T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send>>;
12
13/// Function-based tool handler
14pub struct FunctionToolHandler {
15    /// Tool definition
16    tool: Tool,
17    /// Handler function
18    handler: Arc<
19        dyn Fn(CallToolRequest, RequestContext) -> BoxFuture<ServerResult<CallToolResult>>
20            + Send
21            + Sync,
22    >,
23    /// Allowed roles (RBAC)
24    allowed_roles: Option<Vec<String>>,
25}
26
27impl std::fmt::Debug for FunctionToolHandler {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        f.debug_struct("FunctionToolHandler")
30            .field("tool", &self.tool)
31            .finish()
32    }
33}
34
35impl FunctionToolHandler {
36    /// Create a new function-based tool handler
37    pub fn new<F, Fut>(tool: Tool, handler: F) -> Self
38    where
39        F: Fn(CallToolRequest, RequestContext) -> Fut + Send + Sync + 'static,
40        Fut: std::future::Future<Output = ServerResult<CallToolResult>> + Send + 'static,
41    {
42        Self::new_with_roles(tool, handler, None)
43    }
44
45    /// Create a new function-based tool handler with RBAC roles
46    pub fn new_with_roles<F, Fut>(
47        tool: Tool,
48        handler: F,
49        allowed_roles: Option<Vec<String>>,
50    ) -> Self
51    where
52        F: Fn(CallToolRequest, RequestContext) -> Fut + Send + Sync + 'static,
53        Fut: std::future::Future<Output = ServerResult<CallToolResult>> + Send + 'static,
54    {
55        let handler =
56            Arc::new(move |req, ctx| Box::pin(handler(req, ctx)) as futures::future::BoxFuture<_>);
57        Self {
58            tool,
59            handler,
60            allowed_roles,
61        }
62    }
63}
64
65#[async_trait]
66impl ToolHandler for FunctionToolHandler {
67    async fn handle(
68        &self,
69        request: CallToolRequest,
70        ctx: RequestContext,
71    ) -> ServerResult<CallToolResult> {
72        (self.handler)(request, ctx).await
73    }
74
75    fn tool_definition(&self) -> Tool {
76        self.tool.clone()
77    }
78
79    fn allowed_roles(&self) -> Option<&[String]> {
80        self.allowed_roles.as_deref()
81    }
82}