1use crate::handler::{PromptHandler, ResourceHandler, ServerHandler, TaskHandler, ToolHandler};
71use mcpkit_core::capability::ServerCapabilities;
72
73#[derive(Debug, Clone, Copy, Default)]
75pub struct NotRegistered;
76
77#[derive(Debug)]
79pub struct Registered<T>(pub T);
80
81pub struct ServerBuilder<H, Tools, Resources, Prompts, Tasks> {
95 handler: H,
96 tools: Tools,
97 resources: Resources,
98 prompts: Prompts,
99 tasks: Tasks,
100 capabilities: ServerCapabilities,
101}
102
103impl<H: ServerHandler>
105 ServerBuilder<H, NotRegistered, NotRegistered, NotRegistered, NotRegistered>
106{
107 #[must_use]
112 pub fn new(handler: H) -> Self {
113 let capabilities = handler.capabilities();
114 Self {
115 handler,
116 tools: NotRegistered,
117 resources: NotRegistered,
118 prompts: NotRegistered,
119 tasks: NotRegistered,
120 capabilities,
121 }
122 }
123}
124
125impl<H, T, R, P, K> ServerBuilder<H, T, R, P, K>
127where
128 H: ServerHandler,
129{
130 #[must_use]
135 pub fn capabilities(mut self, caps: ServerCapabilities) -> Self {
136 self.capabilities = caps;
137 self
138 }
139
140 #[must_use]
142 pub const fn get_capabilities(&self) -> &ServerCapabilities {
143 &self.capabilities
144 }
145}
146
147impl<H, R, P, K> ServerBuilder<H, NotRegistered, R, P, K>
149where
150 H: ServerHandler,
151{
152 #[must_use]
157 pub fn with_tools<TH: ToolHandler>(
158 self,
159 tools: TH,
160 ) -> ServerBuilder<H, Registered<TH>, R, P, K> {
161 let mut capabilities = self.capabilities.with_tools();
164 if capabilities.tasks.is_some() {
165 capabilities = capabilities.with_task_tools();
166 }
167 ServerBuilder {
168 handler: self.handler,
169 tools: Registered(tools),
170 resources: self.resources,
171 prompts: self.prompts,
172 tasks: self.tasks,
173 capabilities,
174 }
175 }
176}
177
178#[cfg(feature = "schema-validation")]
183impl<H, TH, R, P, K> ServerBuilder<H, Registered<TH>, R, P, K>
184where
185 H: ServerHandler,
186 TH: ToolHandler,
187{
188 #[must_use]
196 pub fn validate_tool_io(
197 self,
198 ) -> ServerBuilder<H, Registered<crate::validation::ValidatingToolHandler<TH>>, R, P, K> {
199 self.wrap_tool_validation(crate::validation::ValidationMode::both())
200 }
201
202 #[must_use]
204 pub fn validate_tool_inputs(
205 self,
206 ) -> ServerBuilder<H, Registered<crate::validation::ValidatingToolHandler<TH>>, R, P, K> {
207 self.wrap_tool_validation(crate::validation::ValidationMode::inputs_only())
208 }
209
210 #[must_use]
212 pub fn validate_tool_outputs(
213 self,
214 ) -> ServerBuilder<H, Registered<crate::validation::ValidatingToolHandler<TH>>, R, P, K> {
215 self.wrap_tool_validation(crate::validation::ValidationMode::outputs_only())
216 }
217
218 fn wrap_tool_validation(
219 self,
220 mode: crate::validation::ValidationMode,
221 ) -> ServerBuilder<H, Registered<crate::validation::ValidatingToolHandler<TH>>, R, P, K> {
222 ServerBuilder {
223 handler: self.handler,
224 tools: Registered(crate::validation::ValidatingToolHandler::new(
225 self.tools.0,
226 mode,
227 )),
228 resources: self.resources,
229 prompts: self.prompts,
230 tasks: self.tasks,
231 capabilities: self.capabilities,
232 }
233 }
234}
235
236impl<H, T, P, K> ServerBuilder<H, T, NotRegistered, P, K>
238where
239 H: ServerHandler,
240{
241 #[must_use]
245 pub fn with_resources<RH: ResourceHandler>(
246 self,
247 resources: RH,
248 ) -> ServerBuilder<H, T, Registered<RH>, P, K> {
249 ServerBuilder {
250 handler: self.handler,
251 tools: self.tools,
252 resources: Registered(resources),
253 prompts: self.prompts,
254 tasks: self.tasks,
255 capabilities: self.capabilities.with_resources(),
256 }
257 }
258}
259
260impl<H, T, R, K> ServerBuilder<H, T, R, NotRegistered, K>
262where
263 H: ServerHandler,
264{
265 #[must_use]
269 pub fn with_prompts<PH: PromptHandler>(
270 self,
271 prompts: PH,
272 ) -> ServerBuilder<H, T, R, Registered<PH>, K> {
273 ServerBuilder {
274 handler: self.handler,
275 tools: self.tools,
276 resources: self.resources,
277 prompts: Registered(prompts),
278 tasks: self.tasks,
279 capabilities: self.capabilities.with_prompts(),
280 }
281 }
282}
283
284impl<H, T, R, P> ServerBuilder<H, T, R, P, NotRegistered>
286where
287 H: ServerHandler,
288{
289 #[must_use]
296 pub fn with_tasks<KH: TaskHandler>(
297 self,
298 tasks: KH,
299 ) -> ServerBuilder<H, T, R, P, Registered<KH>> {
300 let mut capabilities = self.capabilities.with_tasks();
303 if capabilities.tools.is_some() {
304 capabilities = capabilities.with_task_tools();
305 }
306 ServerBuilder {
307 handler: self.handler,
308 tools: self.tools,
309 resources: self.resources,
310 prompts: self.prompts,
311 tasks: Registered(tasks),
312 capabilities,
313 }
314 }
315}
316
317impl<H, T, R, P, K> ServerBuilder<H, T, R, P, K>
319where
320 H: ServerHandler + Send + Sync + 'static,
321 T: Send + Sync + 'static,
322 R: Send + Sync + 'static,
323 P: Send + Sync + 'static,
324 K: Send + Sync + 'static,
325{
326 #[must_use]
330 pub fn build(self) -> Server<H, T, R, P, K> {
331 Server {
332 handler: self.handler,
333 tools: self.tools,
334 resources: self.resources,
335 prompts: self.prompts,
336 tasks: self.tasks,
337 capabilities: self.capabilities,
338 list_page_size: None,
339 completion: None,
340 }
341 }
342}
343
344pub struct Server<H, T, R, P, K> {
353 handler: H,
354 pub(crate) tools: T,
355 pub(crate) resources: R,
356 pub(crate) prompts: P,
357 pub(crate) tasks: K,
358 capabilities: ServerCapabilities,
359 pub(crate) list_page_size: Option<usize>,
362 pub(crate) completion: Option<std::sync::Arc<dyn crate::dispatch::DynCompletionHandler>>,
366}
367
368impl<H, T, R, P, K> Server<H, T, R, P, K>
369where
370 H: ServerHandler,
371{
372 #[must_use]
374 pub const fn capabilities(&self) -> &ServerCapabilities {
375 &self.capabilities
376 }
377
378 #[must_use]
386 pub const fn list_page_size(mut self, page_size: usize) -> Self {
387 self.list_page_size = Some(page_size);
388 self
389 }
390
391 #[must_use]
397 pub fn with_completion<C: crate::handler::CompletionHandler + 'static>(
398 mut self,
399 completion: C,
400 ) -> Self {
401 self.completion = Some(std::sync::Arc::new(completion));
402 self.capabilities = self.capabilities.with_completions();
403 self
404 }
405
406 #[must_use]
408 pub const fn handler(&self) -> &H {
409 &self.handler
410 }
411
412 #[must_use]
414 pub fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
415 self.handler.server_info()
416 }
417}
418
419impl<H, TH, R, P, K> Server<H, Registered<TH>, R, P, K>
421where
422 H: ServerHandler,
423 TH: ToolHandler,
424{
425 #[must_use]
427 pub const fn tool_handler(&self) -> &TH {
428 &self.tools.0
429 }
430}
431
432impl<H, T, RH, P, K> Server<H, T, Registered<RH>, P, K>
434where
435 H: ServerHandler,
436 RH: ResourceHandler,
437{
438 #[must_use]
440 pub const fn resource_handler(&self) -> &RH {
441 &self.resources.0
442 }
443}
444
445impl<H, T, R, PH, K> Server<H, T, R, Registered<PH>, K>
447where
448 H: ServerHandler,
449 PH: PromptHandler,
450{
451 #[must_use]
453 pub const fn prompt_handler(&self) -> &PH {
454 &self.prompts.0
455 }
456}
457
458impl<H, T, R, P, KH> Server<H, T, R, P, Registered<KH>>
460where
461 H: ServerHandler,
462 KH: TaskHandler,
463{
464 #[must_use]
466 pub const fn task_handler(&self) -> &KH {
467 &self.tasks.0
468 }
469}
470
471pub type FullServer<H, TH, RH, PH, KH> =
473 Server<H, Registered<TH>, Registered<RH>, Registered<PH>, Registered<KH>>;
474
475pub type MinimalServer<H> = Server<H, NotRegistered, NotRegistered, NotRegistered, NotRegistered>;
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481 use crate::context::Context;
482 use crate::handler::ToolHandler;
483 use mcpkit_core::capability::ServerInfo;
484 use mcpkit_core::error::McpError;
485 use mcpkit_core::types::{Tool, ToolOutput};
486 use serde_json::Value;
487
488 struct TestHandler;
489
490 impl ServerHandler for TestHandler {
491 fn server_info(&self) -> ServerInfo {
492 ServerInfo::new("test", "1.0.0")
493 }
494
495 fn capabilities(&self) -> ServerCapabilities {
496 ServerCapabilities::default()
497 }
498 }
499
500 struct TestToolHandler;
501
502 impl ToolHandler for TestToolHandler {
503 async fn list_tools(&self, _ctx: &Context<'_>) -> Result<Vec<Tool>, McpError> {
504 Ok(vec![])
505 }
506
507 async fn call_tool(
508 &self,
509 _name: &str,
510 _args: serde_json::Map<String, Value>,
511 _ctx: &Context<'_>,
512 ) -> Result<ToolOutput, McpError> {
513 Ok(ToolOutput::text("test"))
514 }
515 }
516
517 #[test]
518 fn test_server_builder_minimal() {
519 let server = ServerBuilder::new(TestHandler).build();
520
521 assert_eq!(server.server_info().name, "test");
522 assert_eq!(server.server_info().version, "1.0.0");
523 }
524
525 #[test]
526 fn test_server_builder_with_tools() {
527 let server = ServerBuilder::new(TestHandler)
528 .with_tools(TestToolHandler)
529 .build();
530
531 assert!(server.capabilities().has_tools());
532 let _tool_handler: &TestToolHandler = server.tool_handler();
534 }
535
536 struct TestTaskHandler;
537
538 impl crate::handler::TaskHandler for TestTaskHandler {
539 async fn list_tasks(
540 &self,
541 _ctx: &Context<'_>,
542 ) -> Result<mcpkit_core::types::ListTasksResult, McpError> {
543 Ok(vec![].into())
544 }
545 async fn get_task(
546 &self,
547 _id: &mcpkit_core::types::TaskId,
548 _ctx: &Context<'_>,
549 ) -> Result<Option<mcpkit_core::types::GetTaskResult>, McpError> {
550 Ok(None)
551 }
552 async fn cancel_task(
553 &self,
554 _id: &mcpkit_core::types::TaskId,
555 _ctx: &Context<'_>,
556 ) -> Result<Option<mcpkit_core::types::CancelTaskResult>, McpError> {
557 Ok(None)
558 }
559 }
560
561 #[test]
562 fn test_server_builder_with_tasks_advertises_capability() {
563 let server = ServerBuilder::new(TestHandler)
565 .with_tasks(TestTaskHandler)
566 .build();
567
568 assert!(server.capabilities().has_tasks());
569 }
570
571 #[test]
572 fn tasks_capability_shape_is_registration_order_independent() {
573 fn tools_call(caps: &mcpkit_core::capability::ServerCapabilities) -> serde_json::Value {
576 serde_json::to_value(caps).unwrap()["tasks"].clone()
577 }
578
579 let tasks_first = ServerBuilder::new(TestHandler)
580 .with_tasks(TestTaskHandler)
581 .with_tools(TestToolHandler)
582 .build();
583 let tools_first = ServerBuilder::new(TestHandler)
584 .with_tools(TestToolHandler)
585 .with_tasks(TestTaskHandler)
586 .build();
587
588 let expected = serde_json::json!({
589 "list": {},
590 "cancel": {},
591 "requests": { "tools": { "call": {} } }
592 });
593 assert_eq!(tools_call(tasks_first.capabilities()), expected);
594 assert_eq!(tools_call(tools_first.capabilities()), expected);
595
596 let tasks_only = ServerBuilder::new(TestHandler)
598 .with_tasks(TestTaskHandler)
599 .build();
600 assert_eq!(
601 tools_call(tasks_only.capabilities()),
602 serde_json::json!({ "list": {}, "cancel": {} })
603 );
604 }
605
606 #[test]
607 fn test_typestate_prevents_double_registration() {
608 let _server = ServerBuilder::new(TestHandler)
611 .with_tools(TestToolHandler)
612 .build();
614 }
615
616 #[test]
617 fn test_builder_order_independence() {
618 let server1 = ServerBuilder::new(TestHandler)
620 .with_tools(TestToolHandler)
621 .build();
622
623 let _server2: Server<
625 TestHandler,
626 Registered<TestToolHandler>,
627 NotRegistered,
628 NotRegistered,
629 NotRegistered,
630 > = ServerBuilder::new(TestHandler)
631 .with_tools(TestToolHandler)
632 .build();
633
634 assert!(server1.capabilities().has_tools());
635 }
636}