turbomcp_server/handlers/implementations/
function_tool.rs1use 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
13pub struct FunctionToolHandler {
15 tool: Tool,
17 handler: Arc<
19 dyn Fn(CallToolRequest, RequestContext) -> BoxFuture<ServerResult<CallToolResult>>
20 + Send
21 + Sync,
22 >,
23 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 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 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}