| 63 | self.proc.stdin.flush() |
| 64 | |
| 65 | def _read_message(self, timeout=60): |
| 66 | result = {} |
| 67 | |
| 68 | def reader(): |
| 69 | try: |
| 70 | result["line"] = self.proc.stdout.readline() |
| 71 | except Exception as ex: |
| 72 | result["exc"] = ex |
| 73 | |
| 74 | th = threading.Thread(target=reader, daemon=True) |
| 75 | th.start() |
| 76 | th.join(timeout) |
| 77 | if th.is_alive(): |
| 78 | raise McpError("timeout after %ss (hang)" % timeout) |
| 79 | if "exc" in result: |
| 80 | raise McpError("read error: %r" % result["exc"]) |
| 81 | line = result.get("line", b"") |
| 82 | if not line: |
| 83 | raise McpError("EOF / server closed stdout") |
| 84 | # strict: an invalid-UTF-8 JSON-RPC response is itself a failure. |
| 85 | return json.loads(line.decode("utf-8", "strict")) |
| 86 | |
| 87 | def request(self, method, params=None, timeout=60): |
| 88 | self._id += 1 |