mcp_host/server/
handler.rs1use serde_json::Value;
6use std::future::Future;
7use std::pin::Pin;
8
9use crate::protocol::errors::McpError;
10use crate::protocol::methods::McpMethod;
11use crate::protocol::types::{JsonRpcError, JsonRpcRequest, JsonRpcResponse};
12use crate::server::session::Session;
13
14pub type HandlerResult = Result<Value, McpError>;
16
17pub type HandlerFuture = Pin<Box<dyn Future<Output = HandlerResult> + Send>>;
19
20#[derive(Clone)]
22pub struct RequestContext {
23 pub session: Session,
25
26 pub request: JsonRpcRequest,
28}
29
30impl RequestContext {
31 pub fn new(session: Session, request: JsonRpcRequest) -> Self {
33 Self { session, request }
34 }
35
36 pub fn params(&self) -> Option<&Value> {
38 self.request.params.as_ref()
39 }
40
41 pub fn method(&self) -> McpMethod {
43 McpMethod::from(self.request.method.clone())
44 }
45}
46
47pub fn require_initialization(ctx: &RequestContext) -> Result<(), McpError> {
49 let method = ctx.method();
50
51 if matches!(method, McpMethod::Initialize | McpMethod::Ping) {
53 return Ok(());
54 }
55
56 if !ctx.session.is_initialized() {
57 return Err(McpError::validation(
58 "not_initialized",
59 "Session must be initialized first",
60 ));
61 }
62
63 Ok(())
64}
65
66pub fn success_response(request_id: Option<Value>, result: Value) -> JsonRpcResponse {
68 JsonRpcResponse {
69 jsonrpc: "2.0".to_string(),
70 id: request_id.unwrap_or(Value::Null),
71 result: Some(result),
72 error: None,
73 }
74}
75
76pub fn error_response(request_id: Option<Value>, error: JsonRpcError) -> JsonRpcResponse {
78 JsonRpcResponse {
79 jsonrpc: "2.0".to_string(),
80 id: request_id.unwrap_or(Value::Null),
81 result: None,
82 error: Some(error),
83 }
84}
85
86pub fn method_not_found(request_id: Option<Value>, method: &str) -> JsonRpcResponse {
88 error_response(
89 request_id,
90 JsonRpcError {
91 code: -32601,
92 message: format!("Method not found: {}", method),
93 data: None,
94 },
95 )
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_request_context() {
104 let session = Session::new();
105 let request = JsonRpcRequest {
106 jsonrpc: "2.0".to_string(),
107 id: Some(Value::Number(1.into())),
108 method: "tools/list".to_string(),
109 params: Some(serde_json::json!({"cursor": "abc"})),
110 };
111
112 let ctx = RequestContext::new(session.clone(), request.clone());
113
114 assert_eq!(ctx.session.id, session.id);
115 assert_eq!(ctx.request.method, "tools/list");
116 assert_eq!(ctx.method(), McpMethod::ToolsList);
117 assert!(ctx.params().is_some());
118 }
119
120 #[test]
121 fn test_require_initialization() {
122 let session = Session::new();
123
124 let request = JsonRpcRequest {
126 jsonrpc: "2.0".to_string(),
127 id: Some(Value::Number(1.into())),
128 method: "initialize".to_string(),
129 params: None,
130 };
131 let ctx = RequestContext::new(session.clone(), request);
132 assert!(require_initialization(&ctx).is_ok());
133
134 let request = JsonRpcRequest {
136 jsonrpc: "2.0".to_string(),
137 id: Some(Value::Number(2.into())),
138 method: "ping".to_string(),
139 params: None,
140 };
141 let ctx = RequestContext::new(session.clone(), request);
142 assert!(require_initialization(&ctx).is_ok());
143
144 let request = JsonRpcRequest {
146 jsonrpc: "2.0".to_string(),
147 id: Some(Value::Number(3.into())),
148 method: "tools/list".to_string(),
149 params: None,
150 };
151 let ctx = RequestContext::new(session.clone(), request);
152 assert!(require_initialization(&ctx).is_err());
153
154 let mut session = Session::new();
156 session.initialize(
157 crate::protocol::types::Implementation {
158 name: "test".to_string(),
159 version: "1.0".to_string(),
160 },
161 Default::default(),
162 "2025-06-18".to_string(),
163 );
164 let request = JsonRpcRequest {
165 jsonrpc: "2.0".to_string(),
166 id: Some(Value::Number(4.into())),
167 method: "tools/list".to_string(),
168 params: None,
169 };
170 let ctx = RequestContext::new(session, request);
171 assert!(require_initialization(&ctx).is_ok());
172 }
173
174 #[test]
175 fn test_success_response() {
176 let response = success_response(
177 Some(Value::Number(1.into())),
178 serde_json::json!({"status": "ok"}),
179 );
180
181 assert_eq!(response.jsonrpc, "2.0");
182 assert_eq!(response.id, Value::Number(1.into()));
183 assert!(response.result.is_some());
184 assert!(response.error.is_none());
185 }
186
187 #[test]
188 fn test_error_response() {
189 let error = JsonRpcError {
190 code: -32600,
191 message: "Invalid request".to_string(),
192 data: None,
193 };
194 let response = error_response(Some(Value::Number(1.into())), error);
195
196 assert_eq!(response.jsonrpc, "2.0");
197 assert_eq!(response.id, Value::Number(1.into()));
198 assert!(response.result.is_none());
199 assert!(response.error.is_some());
200 assert_eq!(response.error.unwrap().code, -32600);
201 }
202
203 #[test]
204 fn test_method_not_found() {
205 let response = method_not_found(Some(Value::Number(1.into())), "unknown/method");
206
207 assert!(response.error.is_some());
208 let error = response.error.unwrap();
209 assert_eq!(error.code, -32601);
210 assert!(error.message.contains("unknown/method"));
211 }
212}