1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6use std::sync::Arc;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(tag = "type")]
11pub enum MCPServerConfig {
12 #[serde(rename = "stdio")]
14 Stdio {
15 command: String,
16 #[serde(default)]
17 args: Vec<String>,
18 #[serde(default)]
19 env: HashMap<String, String>,
20 },
21 #[serde(rename = "sse")]
23 Sse {
24 url: String,
25 #[serde(default)]
26 headers: HashMap<String, String>,
27 },
28 #[serde(rename = "http")]
30 Http {
31 url: String,
32 #[serde(default)]
33 headers: HashMap<String, String>,
34 },
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct MCPTool {
40 pub name: String,
41 pub description: String,
42 pub input_schema: Value,
43 pub annotations: Option<MCPToolAnnotations>,
44}
45
46#[derive(Debug, Clone, Default, Serialize, Deserialize)]
48pub struct MCPToolAnnotations {
49 #[serde(default)]
50 pub title: Option<String>,
51 #[serde(default)]
52 pub read_only_hint: bool,
53 #[serde(default)]
54 pub destructive_hint: bool,
55 #[serde(default)]
56 pub idempotent_hint: bool,
57 #[serde(default)]
58 pub open_world_hint: bool,
59 #[serde(default)]
60 pub max_result_size_chars: Option<usize>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(tag = "type")]
66pub enum MCPContent {
67 #[serde(rename = "text")]
68 Text { text: String },
69 #[serde(rename = "image")]
70 Image { data: String, mime_type: String },
71 #[serde(rename = "audio")]
72 Audio { data: String, mime_type: String },
73 #[serde(rename = "resource_link")]
74 ResourceLink {
75 uri: String,
76 name: Option<String>,
77 description: Option<String>,
78 mime_type: Option<String>,
79 },
80 #[serde(rename = "resource")]
81 Resource {
82 uri: String,
83 mime_type: Option<String>,
84 text: Option<String>,
85 },
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct MCPServerStatus {
91 pub name: String,
92 pub status: MCPConnectionStatus,
93 #[serde(default)]
94 pub tools: Vec<MCPTool>,
95 #[serde(default)]
96 pub error: Option<String>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum MCPConnectionStatus {
102 Connected,
103 Disconnected,
104 Error,
105}
106
107type MCPToolHandler = dyn Fn(Value) -> Result<Vec<MCPContent>, String> + Send + Sync;
109
110#[derive(Clone)]
112pub struct SdkMcpTool {
113 pub name: String,
114 pub description: String,
115 pub input_schema: Value,
116 pub annotations: Option<MCPToolAnnotations>,
117 handler: Arc<MCPToolHandler>,
118}
119
120impl std::fmt::Debug for SdkMcpTool {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 f.debug_struct("SdkMcpTool")
123 .field("name", &self.name)
124 .field("description", &self.description)
125 .field("input_schema", &self.input_schema)
126 .field("annotations", &self.annotations)
127 .finish_non_exhaustive()
128 }
129}
130
131impl SdkMcpTool {
132 pub fn new<F>(
133 name: impl Into<String>,
134 description: impl Into<String>,
135 input_schema: Value,
136 annotations: Option<MCPToolAnnotations>,
137 handler: F,
138 ) -> Self
139 where
140 F: Fn(Value) -> Result<Vec<MCPContent>, String> + Send + Sync + 'static,
141 {
142 Self {
143 name: name.into(),
144 description: description.into(),
145 input_schema,
146 annotations,
147 handler: Arc::new(handler),
148 }
149 }
150
151 fn into_parts(self) -> (MCPTool, Arc<MCPToolHandler>) {
152 let tool = MCPTool {
153 name: self.name,
154 description: self.description,
155 input_schema: self.input_schema,
156 annotations: self.annotations,
157 };
158 (tool, self.handler)
159 }
160}
161
162pub fn tool<F>(
164 name: impl Into<String>,
165 description: impl Into<String>,
166 input_schema: Value,
167 handler: F,
168) -> SdkMcpTool
169where
170 F: Fn(Value) -> Result<Vec<MCPContent>, String> + Send + Sync + 'static,
171{
172 SdkMcpTool::new(name, description, input_schema, None, handler)
173}
174
175pub fn tool_with_annotations<F>(
177 name: impl Into<String>,
178 description: impl Into<String>,
179 input_schema: Value,
180 annotations: MCPToolAnnotations,
181 handler: F,
182) -> SdkMcpTool
183where
184 F: Fn(Value) -> Result<Vec<MCPContent>, String> + Send + Sync + 'static,
185{
186 SdkMcpTool::new(name, description, input_schema, Some(annotations), handler)
187}
188
189#[derive(Clone)]
190pub struct SimpleMCPServer {
191 name: String,
192 version: String,
193 tools: HashMap<String, MCPTool>,
194 handlers: HashMap<String, Arc<MCPToolHandler>>,
195}
196
197impl std::fmt::Debug for SimpleMCPServer {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 f.debug_struct("SimpleMCPServer")
200 .field("name", &self.name)
201 .field("tools", &self.tools.keys().collect::<Vec<_>>())
202 .finish()
203 }
204}
205
206impl SimpleMCPServer {
207 pub fn new(name: impl Into<String>) -> Self {
209 Self::with_version(name, "1.0.0")
210 }
211
212 pub fn with_version(name: impl Into<String>, version: impl Into<String>) -> Self {
214 Self {
215 name: name.into(),
216 version: version.into(),
217 tools: HashMap::new(),
218 handlers: HashMap::new(),
219 }
220 }
221
222 pub fn register_tool<F>(&mut self, tool: MCPTool, handler: F)
224 where
225 F: Fn(Value) -> Result<Vec<MCPContent>, String> + Send + Sync + 'static,
226 {
227 let name = tool.name.clone();
228 self.tools.insert(name.clone(), tool);
229 self.handlers.insert(name, Arc::new(handler));
230 }
231
232 pub fn register_sdk_tool(&mut self, tool: SdkMcpTool) {
234 let (tool, handler) = tool.into_parts();
235 let name = tool.name.clone();
236 self.tools.insert(name.clone(), tool);
237 self.handlers.insert(name, handler);
238 }
239
240 pub fn list_tools(&self) -> Vec<&MCPTool> {
242 self.tools.values().collect()
243 }
244
245 pub fn call_tool(&self, name: &str, input: Value) -> Result<Vec<MCPContent>, String> {
247 if let Some(handler) = self.handlers.get(name) {
248 handler(input)
249 } else {
250 Err(format!("Tool '{}' not found", name))
251 }
252 }
253
254 pub fn name(&self) -> &str {
256 &self.name
257 }
258
259 pub fn version(&self) -> &str {
261 &self.version
262 }
263}
264
265pub fn initialize_server(name: impl Into<String>) -> SimpleMCPServer {
267 SimpleMCPServer::new(name)
268}
269
270pub fn create_sdk_mcp_server(name: impl Into<String>, tools: Vec<SdkMcpTool>) -> SimpleMCPServer {
272 create_sdk_mcp_server_with_version(name, "1.0.0", tools)
273}
274
275pub fn create_sdk_mcp_server_with_version(
277 name: impl Into<String>,
278 version: impl Into<String>,
279 tools: Vec<SdkMcpTool>,
280) -> SimpleMCPServer {
281 let mut server = SimpleMCPServer::with_version(name, version);
282 for tool in tools {
283 server.register_sdk_tool(tool);
284 }
285 server
286}