#!/usr/bin/env python3 import sys import json import urllib.request import argparse def main(): parser = argparse.ArgumentParser(description="MCP Stdio-to-HTTP Bridge for ESP32-S3-RLCD-4.2") parser.add_argument("--ip", required=True, help="IP address of the ESP32 board (e.g. 192.168.1.123)") parser.add_argument("--port", type=int, default=80, help="Port the MCP server is listening on (default 80)") args = parser.parse_args() url = f"http://{args.ip}:{args.port}/api/mcp" sys.stderr.write(f"ESP32 MCP Stdio-to-HTTP Bridge started. Routing stdio to {url}\n") sys.stderr.flush() # Sits in loop reading stdio requests from LLM client and routing them to ESP32 while True: try: line = sys.stdin.readline() if not line: break # Parse request to ensure it's valid JSON req_data = json.loads(line.strip()) # Forward the JSON-RPC request to the ESP32 board via HTTP POST req = urllib.request.Request( url, data=json.dumps(req_data).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST" ) with urllib.request.urlopen(req, timeout=10.0) as response: resp_data = response.read().decode("utf-8") # Write the response back to stdio for the LLM client sys.stdout.write(resp_data + "\n") sys.stdout.flush() except urllib.error.URLError as e: # Send standard JSON-RPC internal error response err_resp = { "jsonrpc": "2.0", "error": { "code": -32000, "message": f"Bridge failed to reach ESP32: {e.reason}" }, "id": req_data.get("id") if "req_data" in locals() else None } sys.stdout.write(json.dumps(err_resp) + "\n") sys.stdout.flush() sys.stderr.write(f"Bridge error: Failed to connect to ESP32 at {url}: {e}\n") sys.stderr.flush() except Exception as e: err_resp = { "jsonrpc": "2.0", "error": { "code": -32603, "message": f"Bridge Internal Error: {str(e)}" }, "id": req_data.get("id") if "req_data" in locals() else None } sys.stdout.write(json.dumps(err_resp) + "\n") sys.stdout.flush() sys.stderr.write(f"Bridge error: {e}\n") sys.stderr.flush() if __name__ == "__main__": main()