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:
parent
56be25c1ed
commit
6eb893b7a0
1 changed files with 75 additions and 0 deletions
75
scripts/gbrain-rest-proxy.py
Normal file
75
scripts/gbrain-rest-proxy.py
Normal 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()
|
||||
Loading…
Reference in a new issue