feat(gbrain): REST→MCP proxy for bot-rs compatibility

- Add gbrain-rest-proxy.py (REST /api/search → MCP tools/call bridge)
- Binary gbrain v0.42 uses MCP protocol, no REST API
- Proxy listens on :18002, called by aurelio-bot-rs via GBRAIN_URL
- Uses gbrain MCP token for auth
This commit is contained in:
fabiorafaelcoutada 2026-07-16 23:09:46 +01:00
parent 56be25c1ed
commit 6eb893b7a0

View file

@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""REST->MCP proxy for gbrain /api/search endpoint"""
import json, os, urllib.request, urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler
GBRAIN_MCP = os.environ.get("GBRAIN_MCP", "http://127.0.0.1:18001/mcp")
TOKEN = "gbrain_at_e8e1e34e7fa64be5769090c8af03e967e04bc930dce4311b9a8ec951aa8589c9"
def mcp_call(tool, args=None):
params = {"name": tool, "arguments": args or {}}
data = json.dumps({"jsonrpc":"2.0","method":"tools/call","params":params,"id":1})
req = urllib.request.Request(
GBRAIN_MCP,
data=data.encode(),
headers={
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
"Authorization": "Bearer " + TOKEN
}
)
with urllib.request.urlopen(req, timeout=15) as resp:
raw = resp.read().decode()
for line in raw.split("\n"):
line = line.strip()
if line.startswith("data: "):
return json.loads(line[6:])
return json.loads(raw)
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urllib.parse.urlparse(self.path)
if parsed.path == "/api/search":
qs = urllib.parse.parse_qs(parsed.query)
query = qs.get("q", [""])[0]
limit = int(qs.get("limit", ["5"])[0])
try:
result = mcp_call("search", {"query": query, "limit": limit})
# Parse MCP response: result.content[0].text is a JSON string
text_content = ""
content = result.get("result", {}).get("content", [])
for c in content:
if c.get("type") == "text":
text_content = c.get("text", "")
break
# Parse the JSON array from text_content
pages = json.loads(text_content) if text_content else []
text_parts = []
for p in pages[:limit]:
if isinstance(p, dict):
title = p.get("title") or p.get("slug", "?")
snippet = p.get("snippet") or p.get("chunk_text", "") or p.get("text", "") or ""
text_parts.append("*" + title + "*\n" + snippet[:200])
text = "\n\n".join(text_parts) if text_parts else "Sem resultados."
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.end_headers()
self.wfile.write(text.encode())
except Exception as e:
self.send_response(500)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(("Erro: " + str(e)).encode())
else:
self.send_response(404)
self.end_headers()
def log_message(self, fmt, *args):
pass
if __name__ == "__main__":
port = int(os.environ.get("PORT", "18002"))
server = HTTPServer(("0.0.0.0", port), Handler)
print("GBrain REST proxy listening on :" + str(port))
server.serve_forever()