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/// Builder for `McpServer` — the main entry point for configuring your server.
20pub struct McpServerBuilder {
21    name: String,
22    version: String,
23    instructions: Option<String>,
24    router: Router,
25}
26
27impl McpServerBuilder {
28    pub fn new() -> Self {
29        Self {
30            name: "mcp-server".to_owned(),
31            version: "0.1.0".to_owned(),
32            instructions: None,
33            router: Router::new(),
34        }
35    }
36
37    /// Set the server name (shown to clients during handshake)
38    pub fn name(mut self, name: impl Into<String>) -> Self {
39        self.name = name.into();
40        self
41    }
42
43    /// Set the server version
44    pub fn version(mut self, version: impl Into<String>) -> Self {
45        self.version = version.into();
46        self
47    }
48
49    /// Human-readable instructions for how to use this server
50    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
51        self.instructions = Some(instructions.into());
52        self
53    }
54
55    // ─── Tool registration ────────────────────────────────────────────────────
56
57    /// Register a tool with an explicit `Tool` descriptor and a handler function.
58    pub fn tool<M>(mut self, tool: Tool, handler: impl ToolHandler<M>) -> Self {
59        self.router.add_tool(tool, handler.into_handler_fn());
60        self
61    }
62
63    /// Register a tool using a pre-built `ToolDef` (from the `#[tool]` macro).
64    pub fn tool_def(mut self, def: ToolDef) -> Self {
65        self.router.add_tool(def.tool, def.handler);
66        self
67    }
68
69    /// Convenience: register a no-parameter tool.
70    pub fn tool_fn<M>(
71        mut self,
72        name: impl Into<String>,
73        description: impl Into<String>,
74        handler: impl ToolHandler<M>,
75    ) -> Self {
76        self.router.add_tool(
77            Tool::no_params(name, description),
78            handler.into_handler_fn(),
79        );
80        self
81    }
82
83    // ─── Resource registration ────────────────────────────────────────────────
84
85    /// Register a static resource (exact URI match).
86    pub fn resource<M>(mut self, resource: Resource, handler: impl ResourceHandler<M>) -> Self {
87        self.router
88            .add_resource(resource, handler.into_handler_fn());
89        self
90    }
91
92    /// Register a URI-template resource (e.g. `"file://{path}"`).
93    pub fn resource_template<M>(
94        mut self,
95        template: ResourceTemplate,
96        handler: impl ResourceHandler<M>,
97    ) -> Self {
98        self.router
99            .add_resource_template(template, handler.into_handler_fn());
100        self
101    }
102
103    /// Register a resource using a pre-built `ResourceDef` (from the `#[resource]` macro).
104    pub fn resource_def(mut self, def: ResourceDef) -> Self {
105        match def {
106            ResourceDef::Static { resource, handler } => {
107                self.router.add_resource(resource, handler);
108            }
109            ResourceDef::Template { template, handler } => {
110                self.router.add_resource_template(template, handler);
111            }
112        }
113        self
114    }
115
116    // ─── Prompt registration ──────────────────────────────────────────────────
117
118    /// Register a prompt template.
119    pub fn prompt<M>(mut self, prompt: Prompt, handler: impl PromptHandler<M>) -> Self {
120        self.router.add_prompt(prompt, handler.into_handler_fn());
121        self
122    }
123
124    /// Register a prompt using a pre-built `PromptDef` (from the `#[prompt]` macro).
125    pub fn prompt_def(mut self, def: PromptDef) -> Self {
126        self.router.add_prompt(def.prompt, def.handler);
127        self
128    }
129
130    // ─── Build ────────────────────────────────────────────────────────────────
131
132    pub fn build(self) -> McpServer {
133        McpServer {
134            info: ServerInfo::new(self.name, self.version),
135            instructions: self.instructions,
136            router: Arc::new(self.router),
137        }
138    }
139}
140
141impl Default for McpServerBuilder {
142    fn default() -> Self {
143        Self::new()
144    }
145}
146
147// ─── ToolDef ─────────────────────────────────────────────────────────────────
148
149/// A fully-described tool produced by the `#[tool]` proc macro.
150pub struct ToolDef {
151    pub tool: Tool,
152    pub handler: ToolHandlerFn,
153}
154
155impl ToolDef {
156    pub fn new(tool: Tool, handler: ToolHandlerFn) -> Self {
157        Self { tool, handler }
158    }
159}
160
161// ─── ResourceDef ─────────────────────────────────────────────────────────────
162
163/// A fully-described resource produced by the `#[resource]` proc macro.
164pub enum ResourceDef {
165    Static {
166        resource: Resource,
167        handler: ResourceHandlerFn,
168    },
169    Template {
170        template: ResourceTemplate,
171        handler: ResourceHandlerFn,
172    },
173}
174
175impl ResourceDef {
176    pub fn new_static(resource: Resource, handler: ResourceHandlerFn) -> Self {
177        Self::Static { resource, handler }
178    }
179
180    pub fn new_template(template: ResourceTemplate, handler: ResourceHandlerFn) -> Self {
181        Self::Template { template, handler }
182    }
183}
184
185// ─── PromptDef ───────────────────────────────────────────────────────────────
186
187/// A fully-described prompt produced by the `#[prompt]` proc macro.
188pub struct PromptDef {
189    pub prompt: Prompt,
190    pub handler: PromptHandlerFn,
191}
192
193impl PromptDef {
194    pub fn new(prompt: Prompt, handler: PromptHandlerFn) -> Self {
195        Self { prompt, handler }
196    }
197}