turbomcp_server/server/
builder.rs

1//! Server builder pattern for MCP server construction
2//!
3//! Provides a fluent builder API for configuring and constructing MCP servers
4//! with handlers, configuration, and filesystem roots.
5
6use crate::{
7    config::ServerConfig,
8    error::ServerResult,
9    handlers::{PromptHandler, ResourceHandler, ToolHandler},
10    registry::HandlerRegistry,
11};
12
13use super::core::McpServer;
14
15/// Builder for constructing MCP servers with configuration and handlers
16pub struct ServerBuilder {
17    /// Server configuration
18    config: ServerConfig,
19    /// Registry builder
20    registry: HandlerRegistry,
21}
22
23impl std::fmt::Debug for ServerBuilder {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.debug_struct("ServerBuilder")
26            .field("config", &self.config)
27            .finish()
28    }
29}
30
31impl ServerBuilder {
32    /// Create a new server builder
33    #[must_use]
34    pub fn new() -> Self {
35        Self {
36            config: ServerConfig::default(),
37            registry: HandlerRegistry::new(),
38        }
39    }
40
41    /// Set server name
42    pub fn name(mut self, name: impl Into<String>) -> Self {
43        self.config.name = name.into();
44        self
45    }
46
47    /// Set server version
48    pub fn version(mut self, version: impl Into<String>) -> Self {
49        self.config.version = version.into();
50        self
51    }
52
53    /// Set server description
54    pub fn description(mut self, description: impl Into<String>) -> Self {
55        self.config.description = Some(description.into());
56        self
57    }
58
59    /// Add a tool handler
60    ///
61    /// # Errors
62    ///
63    /// Returns [`crate::ServerError::Handler`] if:
64    /// - The handler limit is exceeded
65    /// - Handler validation fails
66    /// - A handler with the same name already exists
67    pub fn tool<T>(self, name: impl Into<String>, handler: T) -> ServerResult<Self>
68    where
69        T: ToolHandler + 'static,
70    {
71        self.registry.register_tool(name, handler)?;
72        Ok(self)
73    }
74
75    /// Add a prompt handler
76    ///
77    /// # Errors
78    ///
79    /// Returns [`crate::ServerError::Handler`] if:
80    /// - The handler limit is exceeded
81    /// - Handler validation fails
82    /// - A handler with the same name already exists
83    pub fn prompt<P>(self, name: impl Into<String>, handler: P) -> ServerResult<Self>
84    where
85        P: PromptHandler + 'static,
86    {
87        self.registry.register_prompt(name, handler)?;
88        Ok(self)
89    }
90
91    /// Add a resource handler
92    ///
93    /// # Errors
94    ///
95    /// Returns [`crate::ServerError::Handler`] if:
96    /// - The handler limit is exceeded
97    /// - Handler validation fails
98    /// - A handler with the same URI already exists
99    pub fn resource<R>(self, name: impl Into<String>, handler: R) -> ServerResult<Self>
100    where
101        R: ResourceHandler + 'static,
102    {
103        self.registry.register_resource(name, handler)?;
104        Ok(self)
105    }
106
107    /// Add a filesystem root
108    pub fn root(self, uri: impl Into<String>, name: Option<String>) -> Self {
109        use turbomcp_protocol::types::Root;
110        self.registry.add_root(Root {
111            uri: uri.into(),
112            name,
113        });
114        self
115    }
116
117    /// Set multiple filesystem roots
118    pub fn roots(self, roots: Vec<turbomcp_protocol::types::Root>) -> Self {
119        self.registry.set_roots(roots);
120        self
121    }
122
123    /// Build the server
124    #[must_use]
125    pub fn build(self) -> McpServer {
126        // Build server with correct registry from the start
127        // This ensures the Tower service stack uses the populated registry
128        McpServer::new_with_registry(self.config, self.registry)
129    }
130}
131
132impl Default for ServerBuilder {
133    fn default() -> Self {
134        Self::new()
135    }
136}