- 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
75 lines
3.1 KiB
Python
75 lines
3.1 KiB
Python
#!/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()
|