prism_mcp_rs/server/
http_server.rs1use crate::core::error::McpResult;
6use crate::protocol::types::{JsonRpcRequest, JsonRpcResponse};
7use crate::server::mcp_server::McpServer;
8use crate::transport::http::HttpServerTransport;
9use crate::transport::traits::ServerTransport;
10use std::sync::Arc;
11use tokio::sync::Mutex;
12
13pub struct HttpMcpServer {
15 server: Arc<Mutex<McpServer>>,
16 transport: Option<HttpServerTransport>,
17}
18
19impl HttpMcpServer {
20 pub fn new(name: String, version: String) -> Self {
22 Self {
23 server: Arc::new(Mutex::new(McpServer::new(name, version))),
24 transport: None,
25 }
26 }
27
28 pub async fn server(&self) -> Arc<Mutex<McpServer>> {
30 self.server.clone()
31 }
32
33 pub async fn start(&mut self, mut transport: HttpServerTransport) -> McpResult<()> {
35 let server_clone = self.server.clone();
37
38 transport
39 .set_request_handler(move |request: JsonRpcRequest| {
40 let server = server_clone.clone();
41 let (tx, rx) = tokio::sync::oneshot::channel();
42
43 tokio::spawn(async move {
44 let server_guard = server.lock().await;
45 let response = server_guard
46 .handle_request(request)
47 .await
48 .unwrap_or_else(|e| {
49 tracing::error!("Error handling HTTP request: {}", e);
50 JsonRpcResponse {
51 jsonrpc: "2.0".to_string(),
52 id: serde_json::Value::Null,
53 result: Some(serde_json::json!({
54 "error": {
55 "code": -32603,
56 "message": e.to_string()
57 }
58 })),
59 }
60 });
61 let _ = tx.send(response);
62 });
63
64 rx
65 })
66 .await;
67
68 transport.start().await?;
70
71 self.transport = Some(transport);
72 Ok(())
73 }
74
75 pub async fn stop(&mut self) -> McpResult<()> {
77 if let Some(transport) = &mut self.transport {
78 transport.stop().await?;
79 }
80 self.transport = None;
81 Ok(())
82 }
83
84 pub fn is_running(&self) -> bool {
86 self.transport.as_ref().is_some_and(|t| t.is_running())
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use serde_json::json;
94 use std::sync::Arc;
95 use tokio::sync::Mutex;
96
97 #[tokio::test]
98 async fn test_http_server_creation() {
99 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
100
101 assert!(!server.is_running());
102 assert!(server.transport.is_none());
103
104 let server_ref = server.server().await;
106 let server_guard = server_ref.lock().await;
107
108 assert!(!server_guard.is_running().await);
110
111 server_guard.initialize().await.unwrap();
113 assert!(server_guard.is_running().await);
114 assert!(server_guard.is_initialized().await);
115 }
116
117 #[tokio::test]
118 async fn test_http_server_initialization() {
119 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
120
121 assert!(!server.is_running());
124
125 let server_ref = server.server().await;
127 let _server_guard = server_ref.lock().await;
128
129 }
131
132 #[tokio::test]
133 async fn test_http_server_stop_when_not_running() {
134 let mut server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
135
136 let result = server.stop().await;
138 assert!(result.is_ok());
139 assert!(!server.is_running());
140 }
141
142 #[tokio::test]
143 async fn test_http_server_state_transitions() {
144 let mut server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
145
146 assert!(!server.is_running());
148
149 let _ = server.stop().await;
151 assert!(!server.is_running());
152
153 assert!(server.transport.is_none());
155 }
156
157 #[tokio::test]
158 async fn test_http_server_concurrent_access() {
159 let server = Arc::new(Mutex::new(HttpMcpServer::new(
160 "test-server".to_string(),
161 "1.0.0".to_string(),
162 )));
163
164 let server1 = server.clone();
165 let server2 = server.clone();
166
167 let handle1 = tokio::spawn(async move {
169 let s = server1.lock().await;
170 s.is_running()
171 });
172
173 let handle2 = tokio::spawn(async move {
174 let s = server2.lock().await;
175 s.server().await
176 });
177
178 let (running, _server_ref) = tokio::join!(handle1, handle2);
179 assert!(!running.unwrap());
180 }
181
182 #[tokio::test]
183 async fn test_http_server_request_handler_setup() {
184 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
185
186 let server_ref = server.server().await;
188 let server_guard = server_ref.lock().await;
189
190 server_guard.initialize().await.unwrap();
192 assert!(server_guard.is_running().await);
193
194 server_guard
196 .add_tool_with_closure(
197 "test-tool",
198 Some("Test tool for request handling"),
199 serde_json::json!({}),
200 |_args| Ok(vec![crate::protocol::types::ContentBlock::text("handled")]),
201 )
202 .await
203 .unwrap();
204
205 assert!(server_guard.has_tool("test-tool").await);
206 }
207
208 #[tokio::test]
209 async fn test_http_server_error_handling() {
210 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
211
212 let server_ref = server.server().await;
216
217 let invalid_request = JsonRpcRequest {
220 jsonrpc: "2.0".to_string(),
221 id: json!("test-id"),
222 method: "invalid/method".to_string(),
223 params: Some(json!({})),
224 };
225
226 let server_guard = server_ref.lock().await;
228 let response = server_guard.handle_request(invalid_request).await;
229
230 match response {
232 Ok(_) => {
233 }
235 Err(_) => {
236 }
238 }
239 }
240
241 #[tokio::test]
242 async fn test_http_server_multiple_requests() {
243 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
244 let server_ref = server.server().await;
245
246 let requests = vec![
248 JsonRpcRequest {
249 jsonrpc: "2.0".to_string(),
250 id: json!(1),
251 method: "ping".to_string(),
252 params: Some(json!({})),
253 },
254 JsonRpcRequest {
255 jsonrpc: "2.0".to_string(),
256 id: json!(2),
257 method: "tools/list".to_string(),
258 params: Some(json!({})),
259 },
260 ];
261
262 for request in requests {
263 let server_guard = server_ref.lock().await;
264 let _response = server_guard.handle_request(request).await;
265 }
267 }
268
269 #[tokio::test]
270 async fn test_http_server_response_format() {
271 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
272 let server_ref = server.server().await;
273
274 let ping_request = JsonRpcRequest {
276 jsonrpc: "2.0".to_string(),
277 id: json!("ping-test"),
278 method: "ping".to_string(),
279 params: Some(json!({})),
280 };
281
282 let server_guard = server_ref.lock().await;
283 let response = server_guard.handle_request(ping_request).await;
284
285 match response {
286 Ok(json_response) => {
287 assert_eq!(json_response.jsonrpc, "2.0");
289 assert_eq!(json_response.id, json!("ping-test"));
290 assert!(json_response.result.is_some());
292 }
293 Err(_) => {
294 }
296 }
297 }
298
299 #[test]
300 fn test_http_server_sync_methods() {
301 let server = HttpMcpServer::new("test-server".to_string(), "1.0.0".to_string());
302
303 assert!(!server.is_running());
305
306 assert!(server.transport.is_none());
308 }
309
310 #[tokio::test]
311 async fn test_http_server_lifecycle() {
312 let mut server = HttpMcpServer::new("lifecycle-test".to_string(), "1.0.0".to_string());
313
314 assert!(!server.is_running());
319
320 let stop_result = server.stop().await;
322 assert!(stop_result.is_ok());
323 assert!(!server.is_running());
324
325 let stop_result2 = server.stop().await;
327 assert!(stop_result2.is_ok());
328 assert!(!server.is_running());
329 }
330}