synapse_core/
mcp_stdio.rs1use crate::server::semantic_engine::semantic_engine_server::SemanticEngine;
2use crate::server::MySemanticEngine;
3use serde::Deserialize;
4use serde_json::json;
5use std::sync::Arc;
6use tokio::io::{stdin, AsyncBufReadExt, BufReader};
7
8#[derive(Debug, Deserialize)]
9struct JsonRpcRequest {
10 _jsonrpc: String,
11 method: String,
12 params: Option<serde_json::Value>,
13 id: Option<serde_json::Value>,
14}
15
16pub async fn run_mcp_stdio(
17 engine: Arc<MySemanticEngine>,
18) -> Result<(), Box<dyn std::error::Error>> {
19 let mut reader = BufReader::new(stdin()).lines();
20
21 while let Some(line) = reader.next_line().await? {
22 let request: JsonRpcRequest = match serde_json::from_str(&line) {
23 Ok(req) => req,
24 Err(_) => continue,
25 };
26
27 let response = match request.method.as_str() {
28 "initialize" => json!({
29 "jsonrpc": "2.0",
30 "id": request.id,
31 "result": {
32 "protocolVersion": "2024-11-05",
33 "capabilities": {
34 "tools": {}
35 },
36 "serverInfo": {
37 "name": "Synapse-MCP",
38 "version": "0.1.0"
39 }
40 }
41 }),
42 "tools/list" => json!({
43 "jsonrpc": "2.0",
44 "id": request.id,
45 "result": {
46 "tools": [
47 {
48 "name": "query_graph",
49 "description": "Busca triples en el grafo de conocimiento",
50 "inputSchema": {
51 "type": "object",
52 "properties": {
53 "namespace": { "type": "string", "default": "robin_os" }
54 }
55 }
56 },
57 {
58 "name": "ingest_triple",
59 "description": "AƱade un nuevo triple (sujeto, predicado, objeto) al grafo",
60 "inputSchema": {
61 "type": "object",
62 "properties": {
63 "subject": { "type": "string" },
64 "predicate": { "type": "string" },
65 "object": { "type": "string" },
66 "namespace": { "type": "string", "default": "robin_os" }
67 },
68 "required": ["subject", "predicate", "object"]
69 }
70 },
71 {
72 "name": "query_sparql",
73 "description": "Ejecuta una consulta SPARQL sobre el grafo",
74 "inputSchema": {
75 "type": "object",
76 "properties": {
77 "query": { "type": "string" },
78 "namespace": { "type": "string", "default": "robin_os" }
79 },
80 "required": ["query"]
81 }
82 }
83 ]
84 }
85 }),
86 "tools/call" => {
87 let params = request.params.unwrap_or(json!({}));
88 let name = params["name"].as_str().unwrap_or("");
89 let args = ¶ms["arguments"];
90
91 match name {
92 "query_graph" => {
93 let namespace = args["namespace"].as_str().unwrap_or("robin_os");
94 let triples = engine
95 .get_all_triples(tonic::Request::new(
96 crate::server::semantic_engine::EmptyRequest {
97 namespace: namespace.to_string(),
98 },
99 ))
100 .await?;
101
102 let triples_text = triples
103 .into_inner()
104 .triples
105 .into_iter()
106 .map(|t| format!("({}, {}, {})", t.subject, t.predicate, t.object))
107 .collect::<Vec<_>>()
108 .join("\n");
109
110 json!({
111 "jsonrpc": "2.0",
112 "id": request.id,
113 "result": {
114 "content": [{ "type": "text", "text": triples_text }]
115 }
116 })
117 }
118 "ingest_triple" => {
119 let sub = args["subject"].as_str().unwrap_or("");
120 let pred = args["predicate"].as_str().unwrap_or("");
121 let obj = args["object"].as_str().unwrap_or("");
122 let namespace = args["namespace"].as_str().unwrap_or("robin_os");
123
124 let triple = crate::server::semantic_engine::Triple {
125 subject: sub.to_string(),
126 predicate: pred.to_string(),
127 object: obj.to_string(),
128 provenance: None,
129 };
130
131 engine
132 .ingest_triples(tonic::Request::new(
133 crate::server::semantic_engine::IngestRequest {
134 triples: vec![triple],
135 namespace: namespace.to_string(),
136 },
137 ))
138 .await?;
139
140 json!({
141 "jsonrpc": "2.0",
142 "id": request.id,
143 "result": {
144 "content": [{ "type": "text", "text": format!("Triple ({}, {}, {}) ingerido correctamente en Synapse", sub, pred, obj) }]
145 }
146 })
147 }
148 "query_sparql" => {
149 let query = args["query"].as_str().unwrap_or("");
150 let namespace = args["namespace"].as_str().unwrap_or("robin_os");
151
152 let res = engine
153 .query_sparql(tonic::Request::new(
154 crate::server::semantic_engine::SparqlRequest {
155 query: query.to_string(),
156 namespace: namespace.to_string(),
157 },
158 ))
159 .await?;
160
161 json!({
162 "jsonrpc": "2.0",
163 "id": request.id,
164 "result": {
165 "content": [{ "type": "text", "text": res.into_inner().results_json }]
166 }
167 })
168 }
169 _ => json!({
170 "jsonrpc": "2.0",
171 "id": request.id,
172 "error": { "code": -32601, "message": "Tool not found" }
173 }),
174 }
175 }
176 _ => json!({
177 "jsonrpc": "2.0",
178 "id": request.id,
179 "result": {}
180 }),
181 };
182
183 println!("{}", serde_json::to_string(&response)?);
184 }
185
186 Ok(())
187}