Skip to main content

mcp_kit/server/
builder.rs

1use std::sync::Arc;
2
3use crate::types::{
4    prompt::Prompt,
5    resource::{Resource, ResourceTemplate},
6    tool::Tool,
7    ServerInfo,
8};
9
10use crate::server::{
11    core::McpServer,
12    handler::{
13        PromptHandler, PromptHandlerFn, ResourceHandler, ResourceHandlerFn, ToolHandler,
14        ToolHandlerFn,
15    },
16    router::Router,
17};
18
19#[cfg(feature = "auth")]
20use crate::auth::DynAuthProvider;
21
22/// Builder for `McpServer` — the main entry point for configuring your server.
23pub struct McpServerBuilder {
24    name: String,
25    version: String,
26    instructions: Option<String>,
27    router: Router,
28    #[cfg(feature = "auth")]
29    auth_provider: Option<DynAuthProvider>,
30    #[cfg(feature = "auth")]
31    require_auth: bool,
32}
33
34impl McpServerBuilder {
35    pub fn new() -> Self {
36        Self {
37            name: "mcp-server".to_owned(),
38            version: "0.1.0".to_owned(),
39            instructions: None,
40            router: Router::new(),
41            #[cfg(feature = "auth")]
42            auth_provider: None,
43            #[cfg(feature = "auth")]
44            require_auth: true,
45        }
46    }
47
48    /// Set the server name (shown to clients during handshake)
49    pub fn name(mut self, name: impl Into<String>) -> Self {
50        self.name = name.into();
51        self
52    }
53
54    /// Set the server version
55    pub fn version(mut self, version: impl Into<String>) -> Self {
56        self.version = version.into();
57        self
58    }
59
60    /// Human-readable instructions for how to use this server
61    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
62        self.instructions = Some(instructions.into());
63        self
64    }
65
66    // ─── Auth configuration ───────────────────────────────────────────────────
67
68    /// Require authentication on all requests using the given provider.
69    ///
70    /// Requests with no or invalid credentials receive HTTP 401 on SSE/HTTP
71    /// transports. Stdio transport is unaffected (it relies on process-level
72    /// access control).
73    ///
74    /// # Example
75    /// ```rust,no_run
76    /// use mcp_kit::prelude::*;
77    /// use mcp_kit::auth::BearerTokenProvider;
78    /// use std::sync::Arc;
79    ///
80    /// McpServer::builder()
81    ///     .name("my-server")
82    ///     .version("1.0")
83    ///     .auth(Arc::new(BearerTokenProvider::new(["secret"])))
84    ///     .build();
85    /// ```
86    #[cfg(feature = "auth")]
87    pub fn auth(mut self, provider: DynAuthProvider) -> Self {
88        self.auth_provider = Some(provider);
89        self.require_auth = true;
90        self
91    }
92
93    /// Accept an auth provider but allow unauthenticated requests through.
94    ///
95    /// Authenticated requests have an identity available via `Auth`; unauthenticated
96    /// requests have no identity and may reach handlers with `None`.
97    #[cfg(feature = "auth")]
98    pub fn optional_auth(mut self, provider: DynAuthProvider) -> Self {
99        self.auth_provider = Some(provider);
100        self.require_auth = false;
101        self
102    }
103
104    // ─── Tool registration ────────────────────────────────────────────────────
105
106    /// Register a tool with an explicit `Tool` descriptor and a handler function.
107    pub fn tool<M>(mut self, tool: Tool, handler: impl ToolHandler<M>) -> Self {
108        self.router.add_tool(tool, handler.into_handler_fn());
109        self
110    }
111
112    /// Register a tool using a pre-built `ToolDef` (from the `#[tool]` macro).
113    pub fn tool_def(mut self, def: ToolDef) -> Self {
114        self.router.add_tool(def.tool, def.handler);
115        self
116    }
117
118    /// Convenience: register a no-parameter tool.
119    pub fn tool_fn<M>(
120        mut self,
121        name: impl Into<String>,
122        description: impl Into<String>,
123        handler: impl ToolHandler<M>,
124    ) -> Self {
125        self.router.add_tool(
126            Tool::no_params(name, description),
127            handler.into_handler_fn(),
128        );
129        self
130    }
131
132    // ─── Resource registration ────────────────────────────────────────────────
133
134    /// Register a static resource (exact URI match).
135    pub fn resource<M>(mut self, resource: Resource, handler: impl ResourceHandler<M>) -> Self {
136        self.router
137            .add_resource(resource, handler.into_handler_fn());
138        self
139    }
140
141    /// Register a URI-template resource (e.g. `"file://{path}"`).
142    pub fn resource_template<M>(
143        mut self,
144        template: ResourceTemplate,
145        handler: impl ResourceHandler<M>,
146    ) -> Self {
147        self.router
148            .add_resource_template(template, handler.into_handler_fn());
149        self
150    }
151
152    /// Register a resource using a pre-built `ResourceDef` (from the `#[resource]` macro).
153    pub fn resource_def(mut self, def: ResourceDef) -> Self {
154        match def {
155            ResourceDef::Static { resource, handler } => {
156                self.router.add_resource(resource, handler);
157            }
158            ResourceDef::Template { template, handler } => {
159                self.router.add_resource_template(template, handler);
160            }
161        }
162        self
163    }
164
165    // ─── Prompt registration ──────────────────────────────────────────────────
166
167    /// Register a prompt template.
168    pub fn prompt<M>(mut self, prompt: Prompt, handler: impl PromptHandler<M>) -> Self {
169        self.router.add_prompt(prompt, handler.into_handler_fn());
170        self
171    }
172
173    /// Register a prompt using a pre-built `PromptDef` (from the `#[prompt]` macro).
174    pub fn prompt_def(mut self, def: PromptDef) -> Self {
175        self.router.add_prompt(def.prompt, def.handler);
176        self
177    }
178
179    // ─── Build ────────────────────────────────────────────────────────────────
180
181    pub fn build(self) -> McpServer {
182        McpServer {
183            info: ServerInfo::new(self.name, self.version),
184            instructions: self.instructions,
185            router: Arc::new(self.router),
186            #[cfg(feature = "auth")]
187            auth_provider: self.auth_provider,
188            #[cfg(feature = "auth")]
189            require_auth: self.require_auth,
190        }
191    }
192}
193
194impl Default for McpServerBuilder {
195    fn default() -> Self {
196        Self::new()
197    }
198}
199
200// ─── ToolDef ─────────────────────────────────────────────────────────────────
201
202/// A fully-described tool produced by the `#[tool]` proc macro.
203pub struct ToolDef {
204    pub tool: Tool,
205    pub handler: ToolHandlerFn,
206}
207
208impl ToolDef {
209    pub fn new(tool: Tool, handler: ToolHandlerFn) -> Self {
210        Self { tool, handler }
211    }
212}
213
214// ─── ResourceDef ─────────────────────────────────────────────────────────────
215
216/// A fully-described resource produced by the `#[resource]` proc macro.
217pub enum ResourceDef {
218    Static {
219        resource: Resource,
220        handler: ResourceHandlerFn,
221    },
222    Template {
223        template: ResourceTemplate,
224        handler: ResourceHandlerFn,
225    },
226}
227
228impl ResourceDef {
229    pub fn new_static(resource: Resource, handler: ResourceHandlerFn) -> Self {
230        Self::Static { resource, handler }
231    }
232
233    pub fn new_template(template: ResourceTemplate, handler: ResourceHandlerFn) -> Self {
234        Self::Template { template, handler }
235    }
236}
237
238// ─── PromptDef ───────────────────────────────────────────────────────────────
239
240/// A fully-described prompt produced by the `#[prompt]` proc macro.
241pub struct PromptDef {
242    pub prompt: Prompt,
243    pub handler: PromptHandlerFn,
244}
245
246impl PromptDef {
247    pub fn new(prompt: Prompt, handler: PromptHandlerFn) -> Self {
248        Self { prompt, handler }
249    }
250}