mcpkit_server/
builder.rs

1//! Fluent server builder for MCP servers.
2//!
3//! The builder uses the typestate pattern to track registered capabilities
4//! at the type level, ensuring compile-time verification of server configuration.
5//!
6//! # Type Parameters
7//!
8//! - `H`: The base server handler
9//! - `Tools`: Tool handler state (`()` = not registered, `TH: ToolHandler` = registered)
10//! - `Resources`: Resource handler state
11//! - `Prompts`: Prompt handler state
12//! - `Tasks`: Task handler state
13//!
14//! # Example
15//!
16//! ```rust
17//! use mcpkit_server::{ServerBuilder, ServerHandler};
18//! use mcpkit_core::capability::{ServerInfo, ServerCapabilities};
19//!
20//! struct MyHandler;
21//!
22//! impl ServerHandler for MyHandler {
23//!     fn server_info(&self) -> ServerInfo {
24//!         ServerInfo::new("my-server", "1.0.0")
25//!     }
26//! }
27//!
28//! let server = ServerBuilder::new(MyHandler).build();
29//! assert_eq!(server.server_info().name, "my-server");
30//! ```
31//!
32//! # Type-Level Capability Tracking
33//!
34//! The builder tracks which handlers have been registered at the type level.
35//! This means you can't accidentally call a method that requires a handler
36//! that hasn't been registered - the compiler will catch it.
37//!
38//! ```rust
39//! use mcpkit_server::{ServerBuilder, ServerHandler, ToolHandler, Context};
40//! use mcpkit_core::capability::{ServerInfo, ServerCapabilities};
41//! use mcpkit_core::types::{Tool, ToolOutput};
42//! use mcpkit_core::error::McpError;
43//! use serde_json::Value;
44//!
45//! struct MyHandler;
46//! impl ServerHandler for MyHandler {
47//!     fn server_info(&self) -> ServerInfo {
48//!         ServerInfo::new("test", "1.0.0")
49//!     }
50//! }
51//!
52//! struct MyToolHandler;
53//! impl ToolHandler for MyToolHandler {
54//!     async fn list_tools(&self, _ctx: &Context<'_>) -> Result<Vec<Tool>, McpError> {
55//!         Ok(vec![])
56//!     }
57//!     async fn call_tool(&self, _name: &str, _args: Value, _ctx: &Context<'_>) -> Result<ToolOutput, McpError> {
58//!         Ok(ToolOutput::text("done"))
59//!     }
60//! }
61//!
62//! // Tools are registered - this compiles
63//! let server = ServerBuilder::new(MyHandler)
64//!     .with_tools(MyToolHandler)
65//!     .build();
66//!
67//! assert!(server.capabilities().has_tools());
68//! ```
69
70use crate::handler::{PromptHandler, ResourceHandler, ServerHandler, TaskHandler, ToolHandler};
71use mcpkit_core::capability::ServerCapabilities;
72
73/// Marker type indicating no handler is registered for a capability.
74#[derive(Debug, Clone, Copy, Default)]
75pub struct NotRegistered;
76
77/// Marker type indicating a handler is registered for a capability.
78#[derive(Debug)]
79pub struct Registered<T>(pub T);
80
81/// Builder for constructing MCP servers with specific capabilities.
82///
83/// Uses the typestate pattern with 5 type parameters to track registered
84/// handlers at compile time:
85///
86/// - `H`: Base server handler (always required)
87/// - `Tools`: Tool handler state
88/// - `Resources`: Resource handler state
89/// - `Prompts`: Prompt handler state
90/// - `Tasks`: Task handler state
91///
92/// When a capability is not registered, its type parameter is `NotRegistered`.
93/// When registered, it becomes `Registered<T>` where `T` is the handler type.
94pub 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
103// Initial builder with no handlers registered
104impl<H: ServerHandler>
105    ServerBuilder<H, NotRegistered, NotRegistered, NotRegistered, NotRegistered>
106{
107    /// Create a new server builder with the given base handler.
108    ///
109    /// The base handler must implement `ServerHandler` and provides
110    /// the core server identity and configuration.
111    #[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
125// Methods available regardless of which handlers are registered
126impl<H, T, R, P, K> ServerBuilder<H, T, R, P, K>
127where
128    H: ServerHandler,
129{
130    /// Override the capabilities advertised by this server.
131    ///
132    /// By default, capabilities are derived from the base handler.
133    /// Use this to customize or extend those capabilities.
134    #[must_use]
135    pub fn capabilities(mut self, caps: ServerCapabilities) -> Self {
136        self.capabilities = caps;
137        self
138    }
139
140    /// Get a reference to the current capabilities.
141    #[must_use]
142    pub const fn get_capabilities(&self) -> &ServerCapabilities {
143        &self.capabilities
144    }
145}
146
147// Tool handler registration (only when tools are not yet registered)
148impl<H, R, P, K> ServerBuilder<H, NotRegistered, R, P, K>
149where
150    H: ServerHandler,
151{
152    /// Register a tool handler.
153    ///
154    /// This method is only available when no tool handler has been registered yet.
155    /// Attempting to register tools twice will result in a compile error.
156    #[must_use]
157    pub fn with_tools<TH: ToolHandler>(
158        self,
159        tools: TH,
160    ) -> ServerBuilder<H, Registered<TH>, R, P, K> {
161        ServerBuilder {
162            handler: self.handler,
163            tools: Registered(tools),
164            resources: self.resources,
165            prompts: self.prompts,
166            tasks: self.tasks,
167            capabilities: self.capabilities.with_tools(),
168        }
169    }
170}
171
172// Resource handler registration (only when resources are not yet registered)
173impl<H, T, P, K> ServerBuilder<H, T, NotRegistered, P, K>
174where
175    H: ServerHandler,
176{
177    /// Register a resource handler.
178    ///
179    /// This method is only available when no resource handler has been registered yet.
180    #[must_use]
181    pub fn with_resources<RH: ResourceHandler>(
182        self,
183        resources: RH,
184    ) -> ServerBuilder<H, T, Registered<RH>, P, K> {
185        ServerBuilder {
186            handler: self.handler,
187            tools: self.tools,
188            resources: Registered(resources),
189            prompts: self.prompts,
190            tasks: self.tasks,
191            capabilities: self.capabilities.with_resources(),
192        }
193    }
194}
195
196// Prompt handler registration (only when prompts are not yet registered)
197impl<H, T, R, K> ServerBuilder<H, T, R, NotRegistered, K>
198where
199    H: ServerHandler,
200{
201    /// Register a prompt handler.
202    ///
203    /// This method is only available when no prompt handler has been registered yet.
204    #[must_use]
205    pub fn with_prompts<PH: PromptHandler>(
206        self,
207        prompts: PH,
208    ) -> ServerBuilder<H, T, R, Registered<PH>, K> {
209        ServerBuilder {
210            handler: self.handler,
211            tools: self.tools,
212            resources: self.resources,
213            prompts: Registered(prompts),
214            tasks: self.tasks,
215            capabilities: self.capabilities.with_prompts(),
216        }
217    }
218}
219
220// Task handler registration (only when tasks are not yet registered)
221impl<H, T, R, P> ServerBuilder<H, T, R, P, NotRegistered>
222where
223    H: ServerHandler,
224{
225    /// Register a task handler.
226    ///
227    /// Tasks are long-running operations that can be tracked, monitored,
228    /// and cancelled.
229    ///
230    /// This method is only available when no task handler has been registered yet.
231    #[must_use]
232    pub fn with_tasks<KH: TaskHandler>(
233        self,
234        tasks: KH,
235    ) -> ServerBuilder<H, T, R, P, Registered<KH>> {
236        ServerBuilder {
237            handler: self.handler,
238            tools: self.tools,
239            resources: self.resources,
240            prompts: self.prompts,
241            tasks: Registered(tasks),
242            // Note: capabilities.with_tasks() would be added when supported
243            capabilities: self.capabilities,
244        }
245    }
246}
247
248// Build method - available for any combination of handlers
249impl<H, T, R, P, K> ServerBuilder<H, T, R, P, K>
250where
251    H: ServerHandler + Send + Sync + 'static,
252    T: Send + Sync + 'static,
253    R: Send + Sync + 'static,
254    P: Send + Sync + 'static,
255    K: Send + Sync + 'static,
256{
257    /// Build the server.
258    ///
259    /// Returns a `Server` configured with the registered handlers and capabilities.
260    #[must_use]
261    pub fn build(self) -> Server<H, T, R, P, K> {
262        Server {
263            handler: self.handler,
264            tools: self.tools,
265            resources: self.resources,
266            prompts: self.prompts,
267            tasks: self.tasks,
268            capabilities: self.capabilities,
269        }
270    }
271}
272
273/// A configured MCP server ready to serve requests.
274///
275/// The type parameters track which capabilities are available:
276/// - `H`: Base server handler
277/// - `T`: Tool handler (`NotRegistered` or `Registered<TH>`)
278/// - `R`: Resource handler
279/// - `P`: Prompt handler
280/// - `K`: Task handler
281pub struct Server<H, T, R, P, K> {
282    handler: H,
283    tools: T,
284    resources: R,
285    prompts: P,
286    tasks: K,
287    capabilities: ServerCapabilities,
288}
289
290impl<H, T, R, P, K> Server<H, T, R, P, K>
291where
292    H: ServerHandler,
293{
294    /// Get the server's capabilities.
295    #[must_use]
296    pub const fn capabilities(&self) -> &ServerCapabilities {
297        &self.capabilities
298    }
299
300    /// Get a reference to the base handler.
301    #[must_use]
302    pub const fn handler(&self) -> &H {
303        &self.handler
304    }
305
306    /// Get the server info from the base handler.
307    #[must_use]
308    pub fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
309        self.handler.server_info()
310    }
311}
312
313// Methods when tools are registered
314impl<H, TH, R, P, K> Server<H, Registered<TH>, R, P, K>
315where
316    H: ServerHandler,
317    TH: ToolHandler,
318{
319    /// Get a reference to the tool handler.
320    #[must_use]
321    pub const fn tool_handler(&self) -> &TH {
322        &self.tools.0
323    }
324}
325
326// Methods when resources are registered
327impl<H, T, RH, P, K> Server<H, T, Registered<RH>, P, K>
328where
329    H: ServerHandler,
330    RH: ResourceHandler,
331{
332    /// Get a reference to the resource handler.
333    #[must_use]
334    pub const fn resource_handler(&self) -> &RH {
335        &self.resources.0
336    }
337}
338
339// Methods when prompts are registered
340impl<H, T, R, PH, K> Server<H, T, R, Registered<PH>, K>
341where
342    H: ServerHandler,
343    PH: PromptHandler,
344{
345    /// Get a reference to the prompt handler.
346    #[must_use]
347    pub const fn prompt_handler(&self) -> &PH {
348        &self.prompts.0
349    }
350}
351
352// Methods when tasks are registered
353impl<H, T, R, P, KH> Server<H, T, R, P, Registered<KH>>
354where
355    H: ServerHandler,
356    KH: TaskHandler,
357{
358    /// Get a reference to the task handler.
359    #[must_use]
360    pub const fn task_handler(&self) -> &KH {
361        &self.tasks.0
362    }
363}
364
365/// Type alias for a fully-configured server with all handlers.
366pub type FullServer<H, TH, RH, PH, KH> =
367    Server<H, Registered<TH>, Registered<RH>, Registered<PH>, Registered<KH>>;
368
369/// Type alias for a minimal server with no optional handlers.
370pub type MinimalServer<H> = Server<H, NotRegistered, NotRegistered, NotRegistered, NotRegistered>;
371
372#[cfg(test)]
373mod tests {
374    use super::*;
375    use crate::context::Context;
376    use crate::handler::ToolHandler;
377    use mcpkit_core::capability::ServerInfo;
378    use mcpkit_core::error::McpError;
379    use mcpkit_core::types::{Tool, ToolOutput};
380    use serde_json::Value;
381
382    struct TestHandler;
383
384    impl ServerHandler for TestHandler {
385        fn server_info(&self) -> ServerInfo {
386            ServerInfo::new("test", "1.0.0")
387        }
388
389        fn capabilities(&self) -> ServerCapabilities {
390            ServerCapabilities::default()
391        }
392    }
393
394    struct TestToolHandler;
395
396    impl ToolHandler for TestToolHandler {
397        async fn list_tools(&self, _ctx: &Context<'_>) -> Result<Vec<Tool>, McpError> {
398            Ok(vec![])
399        }
400
401        async fn call_tool(
402            &self,
403            _name: &str,
404            _args: Value,
405            _ctx: &Context<'_>,
406        ) -> Result<ToolOutput, McpError> {
407            Ok(ToolOutput::text("test"))
408        }
409    }
410
411    #[test]
412    fn test_server_builder_minimal() {
413        let server = ServerBuilder::new(TestHandler).build();
414
415        assert_eq!(server.server_info().name, "test");
416        assert_eq!(server.server_info().version, "1.0.0");
417    }
418
419    #[test]
420    fn test_server_builder_with_tools() {
421        let server = ServerBuilder::new(TestHandler)
422            .with_tools(TestToolHandler)
423            .build();
424
425        assert!(server.capabilities().has_tools());
426        // This compiles because tools are registered
427        let _tool_handler: &TestToolHandler = server.tool_handler();
428    }
429
430    #[test]
431    fn test_typestate_prevents_double_registration() {
432        // This test verifies the design - double registration would be
433        // a compile error, not a runtime error
434        let _server = ServerBuilder::new(TestHandler)
435            .with_tools(TestToolHandler)
436            // .with_tools(TestToolHandler) // This would NOT compile!
437            .build();
438    }
439
440    #[test]
441    fn test_builder_order_independence() {
442        // Handlers can be registered in any order
443        let server1 = ServerBuilder::new(TestHandler)
444            .with_tools(TestToolHandler)
445            .build();
446
447        // Different order, same result
448        let _server2: Server<
449            TestHandler,
450            Registered<TestToolHandler>,
451            NotRegistered,
452            NotRegistered,
453            NotRegistered,
454        > = ServerBuilder::new(TestHandler)
455            .with_tools(TestToolHandler)
456            .build();
457
458        assert!(server1.capabilities().has_tools());
459    }
460}