"""opencode <-> Serial Studio MCP bridge. Serial Studio exposes a native MCP server on TCP port 7777 speaking JSON-RPC 2.0 (newline-delimited over a raw TCP socket), NOT over HTTP. opencode's "remote" MCP type expects HTTP (streamableHttp / SSE), so it cannot talk to Serial Studio directly. This script is a thin stdio bridge: opencode launches it as a "local" MCP server, reads newline- delimited JSON-RPC from stdin, forwards each request over TCP to Serial Studio on port 7777, and writes the response back to stdout. Usage: python serial_studio_bridge.py [host] [port] Defaults: host=127.0.0.1, port=7777 """ import json import socket import sys DEFAULT_HOST = "127.0.0.1" DEFAULT_PORT = 7777 def main() -> int: if len(sys.argv) > 1: host = sys.argv[1] else: host = DEFAULT_HOST if len(sys.argv) > 2: port = int(sys.argv[2]) else: port = DEFAULT_PORT sock = socket.create_connection((host, port), timeout=10) sock.settimeout(30) buf = b"" def send_json(obj) -> None: line = (json.dumps(obj, separators=(",", ":")) + "\n").encode("utf-8") sock.sendall(line) def read_response(target_id) -> dict: nonlocal buf while True: while b"\n" in buf: line, buf = buf.split(b"\n", 1) line = line.strip() if not line: continue try: resp = json.loads(line.decode("utf-8")) except Exception: continue if resp.get("id") == target_id or target_id is None: return resp sock.settimeout(30) data = sock.recv(65536) if not data: raise ConnectionError("Serial Studio closed connection") buf += data try: for raw in sys.stdin: raw = raw.strip() if not raw: continue try: req = json.loads(raw) except Exception as e: err = { "jsonrpc": "2.0", "id": None, "error": {"code": -32700, "message": f"Parse error: {e}"}, } sys.stdout.write(json.dumps(err) + "\n") sys.stdout.flush() continue if isinstance(req, list): results = [] for sub in req: try: send_json(sub) results.append(read_response(sub.get("id"))) except Exception as e: results.append( { "jsonrpc": "2.0", "id": sub.get("id"), "error": {"code": -32000, "message": str(e)}, } ) sys.stdout.write(json.dumps(results) + "\n") sys.stdout.flush() continue if req.get("jsonrpc") == "2.0" and not req.get("id"): send_json(req) continue try: send_json(req) resp = read_response(req.get("id")) sys.stdout.write(json.dumps(resp) + "\n") sys.stdout.flush() except Exception as e: err = { "jsonrpc": "2.0", "id": req.get("id"), "error": {"code": -32000, "message": str(e)}, } sys.stdout.write(json.dumps(err) + "\n") sys.stdout.flush() finally: try: sock.close() except Exception: pass return 0 if __name__ == "__main__": sys.exit(main())