turbomcp_server/handlers/
utils.rs1use std::collections::HashMap;
8use turbomcp_protocol::RequestContext;
9use turbomcp_protocol::types::{
10 CallToolRequest, CallToolResult, GetPromptRequest, GetPromptResult, Prompt,
11 ReadResourceRequest, ReadResourceResult, Resource, Tool, ToolInputSchema,
12};
13
14use crate::ServerResult;
15use crate::handlers::implementations::FunctionToolHandler;
16use crate::handlers::traits::{PromptHandler, ResourceHandler, ToolHandler};
17
18pub fn tool<F, Fut>(
50 name: impl Into<String>,
51 description: impl Into<String>,
52 handler: F,
53) -> impl ToolHandler
54where
55 F: Fn(CallToolRequest, RequestContext) -> Fut + Send + Sync + 'static,
56 Fut: std::future::Future<Output = ServerResult<CallToolResult>> + Send + 'static,
57{
58 let name = name.into();
59 let description = description.into();
60
61 let tool_def = Tool {
62 name: name.clone(),
63 title: Some(name),
64 description: Some(description),
65 input_schema: ToolInputSchema {
66 schema_type: "object".to_string(),
67 properties: Some(HashMap::new()),
68 required: None,
69 additional_properties: None,
70 },
71 output_schema: None,
72 annotations: None,
73 meta: None,
74 };
75
76 FunctionToolHandler::new(tool_def, handler)
77}
78
79pub fn tool_with_schema<F, Fut>(
91 name: impl Into<String>,
92 description: impl Into<String>,
93 schema: ToolInputSchema,
94 handler: F,
95) -> impl ToolHandler
96where
97 F: Fn(CallToolRequest, RequestContext) -> Fut + Send + Sync + 'static,
98 Fut: std::future::Future<Output = ServerResult<CallToolResult>> + Send + 'static,
99{
100 let name = name.into();
101 let description = description.into();
102
103 let tool_def = Tool {
104 name: name.clone(),
105 title: Some(name),
106 description: Some(description),
107 input_schema: schema,
108 output_schema: None,
109 annotations: None,
110 meta: None,
111 };
112
113 FunctionToolHandler::new(tool_def, handler)
114}
115
116pub struct FunctionPromptHandler {
118 prompt: Prompt,
119 handler: Box<
120 dyn Fn(
121 GetPromptRequest,
122 RequestContext,
123 ) -> futures::future::BoxFuture<'static, ServerResult<GetPromptResult>>
124 + Send
125 + Sync,
126 >,
127}
128
129impl std::fmt::Debug for FunctionPromptHandler {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.debug_struct("FunctionPromptHandler")
132 .field("prompt", &self.prompt)
133 .finish()
134 }
135}
136
137impl FunctionPromptHandler {
138 pub fn new<F, Fut>(prompt: Prompt, handler: F) -> Self
140 where
141 F: Fn(GetPromptRequest, RequestContext) -> Fut + Send + Sync + 'static,
142 Fut: std::future::Future<Output = ServerResult<GetPromptResult>> + Send + 'static,
143 {
144 Self {
145 prompt,
146 handler: Box::new(move |req, ctx| Box::pin(handler(req, ctx))),
147 }
148 }
149}
150
151#[async_trait::async_trait]
152impl PromptHandler for FunctionPromptHandler {
153 async fn handle(
154 &self,
155 request: GetPromptRequest,
156 ctx: RequestContext,
157 ) -> ServerResult<GetPromptResult> {
158 (self.handler)(request, ctx).await
159 }
160
161 fn prompt_definition(&self) -> Prompt {
162 self.prompt.clone()
163 }
164}
165
166pub fn prompt<F, Fut>(
174 name: impl Into<String>,
175 description: impl Into<String>,
176 handler: F,
177) -> impl PromptHandler
178where
179 F: Fn(GetPromptRequest, RequestContext) -> Fut + Send + Sync + 'static,
180 Fut: std::future::Future<Output = ServerResult<GetPromptResult>> + Send + 'static,
181{
182 let name = name.into();
183 let description = description.into();
184
185 let prompt_def = Prompt {
186 name: name.clone(),
187 title: Some(name),
188 description: Some(description),
189 arguments: None,
190 meta: None,
191 };
192
193 FunctionPromptHandler::new(prompt_def, handler)
194}
195
196pub struct FunctionResourceHandler {
198 resource: Resource,
199 handler: Box<
200 dyn Fn(
201 ReadResourceRequest,
202 RequestContext,
203 ) -> futures::future::BoxFuture<'static, ServerResult<ReadResourceResult>>
204 + Send
205 + Sync,
206 >,
207}
208
209impl std::fmt::Debug for FunctionResourceHandler {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 f.debug_struct("FunctionResourceHandler")
212 .field("resource", &self.resource)
213 .finish()
214 }
215}
216
217impl FunctionResourceHandler {
218 pub fn new<F, Fut>(resource: Resource, handler: F) -> Self
220 where
221 F: Fn(ReadResourceRequest, RequestContext) -> Fut + Send + Sync + 'static,
222 Fut: std::future::Future<Output = ServerResult<ReadResourceResult>> + Send + 'static,
223 {
224 Self {
225 resource,
226 handler: Box::new(move |req, ctx| Box::pin(handler(req, ctx))),
227 }
228 }
229}
230
231#[async_trait::async_trait]
232impl ResourceHandler for FunctionResourceHandler {
233 async fn handle(
234 &self,
235 request: ReadResourceRequest,
236 ctx: RequestContext,
237 ) -> ServerResult<ReadResourceResult> {
238 (self.handler)(request, ctx).await
239 }
240
241 fn resource_definition(&self) -> Resource {
242 self.resource.clone()
243 }
244
245 async fn exists(&self, _uri: &str) -> bool {
246 true }
248}
249
250pub fn resource<F, Fut>(
258 uri: impl Into<String>,
259 name: impl Into<String>,
260 handler: F,
261) -> impl ResourceHandler
262where
263 F: Fn(ReadResourceRequest, RequestContext) -> Fut + Send + Sync + 'static,
264 Fut: std::future::Future<Output = ServerResult<ReadResourceResult>> + Send + 'static,
265{
266 let uri = uri.into();
267 let name = name.into();
268
269 let resource_def = Resource {
270 name: name.clone(),
271 title: Some(name),
272 uri,
273 description: None,
274 mime_type: Some("text/plain".to_string()),
275 annotations: None,
276 size: None,
277 meta: None,
278 };
279
280 FunctionResourceHandler::new(resource_def, handler)
281}