agentic_reality_mcp/protocol/
handler.rs1use crate::session::SessionManager;
4use crate::tools::ToolRegistry;
5use crate::types::error::McpError;
6use serde_json::Value;
7use std::sync::Arc;
8use tokio::sync::Mutex;
9
10use super::compact;
11
12pub struct ProtocolHandler {
14 session: Arc<Mutex<SessionManager>>,
15}
16
17impl ProtocolHandler {
18 pub fn new(session: Arc<Mutex<SessionManager>>) -> Self {
19 Self { session }
20 }
21
22 pub async fn handle_request(&self, request: Value) -> Value {
24 let method = request
25 .get("method")
26 .and_then(|m| m.as_str())
27 .map_or("", |value| value);
28 let id = request
29 .get("id")
30 .cloned()
31 .map_or(Value::Null, |value| value);
32 let params = request
33 .get("params")
34 .cloned()
35 .map_or(Value::Object(serde_json::Map::new()), |value| value);
36
37 let result = match method {
38 "initialize" => self.handle_initialize(¶ms).await,
39 "tools/list" => self.handle_list_tools().await,
40 "tools/call" => self.handle_tool_call(¶ms).await,
41 "resources/list" => self.handle_list_resources().await,
42 "prompts/list" => self.handle_list_prompts().await,
43 _ => Err(McpError::MethodNotFound {
44 method: method.to_string(),
45 }),
46 };
47
48 match result {
49 Ok(value) => serde_json::json!({
50 "jsonrpc": "2.0",
51 "id": id,
52 "result": value,
53 }),
54 Err(e) => serde_json::json!({
55 "jsonrpc": "2.0",
56 "id": id,
57 "error": {
58 "code": e.code(),
59 "message": e.to_string(),
60 },
61 }),
62 }
63 }
64
65 async fn handle_initialize(&self, _params: &Value) -> Result<Value, McpError> {
66 Ok(serde_json::json!({
67 "protocolVersion": "2024-11-05",
68 "capabilities": {
69 "tools": { "listChanged": false },
70 "resources": { "subscribe": false, "listChanged": false },
71 "prompts": { "listChanged": false },
72 },
73 "serverInfo": {
74 "name": "agentic-reality",
75 "version": env!("CARGO_PKG_VERSION"),
76 },
77 }))
78 }
79
80 async fn handle_list_tools(&self) -> Result<Value, McpError> {
81 let tools = if compact::is_compact_mode() {
82 compact::compact_tool_definitions()
83 } else {
84 ToolRegistry::list_tools()
85 };
86 Ok(serde_json::json!({ "tools": tools }))
87 }
88
89 async fn handle_tool_call(&self, params: &Value) -> Result<Value, McpError> {
90 let name =
91 params
92 .get("name")
93 .and_then(|n| n.as_str())
94 .ok_or_else(|| McpError::InvalidParams {
95 message: "missing tool name".into(),
96 })?;
97 let arguments = params.get("arguments").cloned();
98
99 let (tool_name, arguments) = if compact::is_compact_facade(name) {
101 match compact::normalize_compact_call(&name.to_string(), &arguments) {
102 Some((real_name, real_args)) => (real_name, real_args),
103 None => {
104 return Err(McpError::InvalidParams {
105 message: format!(
106 "invalid operation for compact facade '{}'",
107 name
108 ),
109 });
110 }
111 }
112 } else {
113 (name.to_string(), arguments)
114 };
115
116 ToolRegistry::call(&tool_name, arguments, &self.session).await
117 }
118
119 async fn handle_list_resources(&self) -> Result<Value, McpError> {
120 Ok(serde_json::json!({ "resources": [] }))
121 }
122
123 async fn handle_list_prompts(&self) -> Result<Value, McpError> {
124 Ok(serde_json::json!({ "prompts": [] }))
125 }
126}