// mcp-proxy - stable forwarder for the mcp-wrapper. // // Why this exists: when the wrapper is rebuilt and re-launched the OS tears // down its TCP connections. Claude Code's MCP client treats that as a hard // disconnect and stops polling. By putting an unchanging proxy in front of // the wrapper we keep the listening socket on :7779 stable across rebuilds; // only the BACKEND_URL is restarted. Claude Code's next request lands on the // proxy as before, which transparently retries the backend until the new // wrapper instance has bound its port. // // Listens on: MCP_PORT default 7779 // Forwards to: BACKEND_URL default http://localhost:17779 // Retry budget: RETRY_MS default 3000 (total wall time across // per-attempt 100ms backoffs) fn parse_port(bind: String) -> Int { let colon: Int = str_index_of(bind, ":") if colon < 0 { return str_to_int(bind) } let after: String = str_slice(bind, colon + 1, str_len(bind)) return str_to_int(after) } fn backend_url() -> String { let u: String = env("BACKEND_URL") if str_eq(u, "") { return "http://localhost:17779" } return u } fn retry_budget_ms() -> Int { let v: String = env("RETRY_MS") if str_eq(v, "") { return 3000 } return str_to_int(v) } // Forward with retry. Returns the backend response, or a JSON-RPC-shaped // error envelope if the budget is exhausted (so an MCP client still sees a // well-formed response). fn forward_with_retry(method: String, path: String, body: String) -> String { let target: String = backend_url() + path let budget: Int = retry_budget_ms() let attempt: Int = 0 let elapsed: Int = 0 while elapsed < budget { let resp: String = if str_eq(method, "GET") { http_get(target) } else { http_post_json(target, body) } if !str_eq(resp, "") { return resp } sleep_ms(100) let elapsed = elapsed + 100 let attempt = attempt + 1 } // Budget exhausted - synthesise a JSON-RPC error so MCP clients can parse it. return "{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32000,\"message\":\"backend unreachable after " + int_to_str(budget) + "ms\"}}" } fn handle_request(method: String, path: String, body: String) -> String { if str_eq(method, "GET") && (str_eq(path, "/health") || str_eq(path, "/proxy/health")) { return "{\"status\":\"ok\",\"service\":\"neuron-mcp-proxy\",\"backend\":\"" + backend_url() + "\"}" } return forward_with_retry(method, path, body) } let bind_str: String = env("MCP_PORT") if str_eq(bind_str, "") { let bind_str = "7779" } let port: Int = parse_port(bind_str) println("[mcp-proxy] listening on :" + int_to_str(port)) println("[mcp-proxy] backend=" + backend_url()) http_serve(port, "handle_request")