Skip to main content

mcp/
builder.rs

1//! Generic builder for MCP-compatible HTTP tool servers.
2
3use crate::builder_utils::{AuthConfig, IpFilter};
4use crate::events::McpEventHandler;
5use crate::http::{HttpServerAdapter, HttpServerConfig, HttpServerInstance};
6use crate::protocol::ToolProtocol;
7use crate::server::UnifiedMcpServer;
8use std::error::Error;
9use std::net::SocketAddr;
10use std::sync::Arc;
11
12/// Builder for creating MCP-compatible HTTP servers with registered tools.
13pub struct MCPServerBuilder {
14    server: UnifiedMcpServer,
15    ip_filter: IpFilter,
16    auth: AuthConfig,
17    adapter: Arc<dyn HttpServerAdapter>,
18    event_handler: Option<Arc<dyn McpEventHandler>>,
19}
20
21impl MCPServerBuilder {
22    /// Create a new empty builder using the default HTTP adapter.
23    pub fn new() -> Self {
24        Self {
25            server: UnifiedMcpServer::new(),
26            ip_filter: IpFilter::new(),
27            auth: AuthConfig::None,
28            adapter: Self::default_adapter(),
29            event_handler: None,
30        }
31    }
32
33    #[cfg(feature = "server")]
34    fn default_adapter() -> Arc<dyn HttpServerAdapter> {
35        Arc::new(crate::http::AxumHttpAdapter)
36    }
37
38    #[cfg(not(feature = "server"))]
39    fn default_adapter() -> Arc<dyn HttpServerAdapter> {
40        panic!(
41            "{}",
42            "MCPServerBuilder requires the 'server' feature to be enabled."
43        )
44    }
45
46    /// Register a custom tool protocol under a tool name.
47    pub async fn with_custom_tool(
48        mut self,
49        tool_name: &str,
50        protocol: Arc<dyn ToolProtocol>,
51    ) -> Self {
52        self.server.register_tool(tool_name, protocol).await;
53        self
54    }
55
56    /// Require bearer token authentication.
57    pub fn with_bearer_token(mut self, token: impl Into<String>) -> Self {
58        self.auth = AuthConfig::bearer(token);
59        self
60    }
61
62    /// Require basic authentication.
63    pub fn with_basic_auth(
64        mut self,
65        username: impl Into<String>,
66        password: impl Into<String>,
67    ) -> Self {
68        self.auth = AuthConfig::basic(username, password);
69        self
70    }
71
72    /// Allow a specific IP address.
73    pub fn allow_ip(mut self, ip: &str) -> Result<Self, String> {
74        self.ip_filter.allow(ip)?;
75        Ok(self)
76    }
77
78    /// Allow a CIDR block.
79    pub fn allow_cidr(mut self, cidr: &str) -> Result<Self, String> {
80        self.ip_filter.allow(cidr)?;
81        Ok(self)
82    }
83
84    /// Restrict access to localhost only.
85    pub fn allow_localhost_only(mut self) -> Self {
86        let _ = self.ip_filter.allow("127.0.0.1");
87        let _ = self.ip_filter.allow("::1");
88        self
89    }
90
91    /// Override the HTTP adapter.
92    pub fn with_adapter(mut self, adapter: Arc<dyn HttpServerAdapter>) -> Self {
93        self.adapter = adapter;
94        self
95    }
96
97    /// Attach an MCP event handler.
98    pub fn with_event_handler(mut self, handler: Arc<dyn McpEventHandler>) -> Self {
99        self.event_handler = Some(handler);
100        self
101    }
102
103    /// Start the server on the supplied port on localhost.
104    pub async fn start_on(
105        self,
106        port: u16,
107    ) -> Result<HttpServerInstance, Box<dyn Error + Send + Sync>> {
108        self.start_at(SocketAddr::from(([127, 0, 0, 1], port)))
109            .await
110    }
111
112    /// Start the server at an explicit socket address.
113    pub async fn start_at(
114        self,
115        addr: SocketAddr,
116    ) -> Result<HttpServerInstance, Box<dyn Error + Send + Sync>> {
117        let bearer_token = match self.auth {
118            AuthConfig::None => None,
119            AuthConfig::Bearer(token) => Some(token),
120            AuthConfig::Basic { .. } => {
121                return Err("Basic auth is not supported by the generic MCP HTTP adapter".into())
122            }
123        };
124
125        self.adapter
126            .start(
127                HttpServerConfig {
128                    addr,
129                    bearer_token,
130                    ip_filter: self.ip_filter,
131                    event_handler: self.event_handler,
132                },
133                Arc::new(self.server),
134            )
135            .await
136    }
137}
138
139impl Default for MCPServerBuilder {
140    fn default() -> Self {
141        Self::new()
142    }
143}