From 6413fe388346f13e035eece9018a24c344366ac1 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 07:25:54 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`mcp?= =?UTF-8?q?-http-transport`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @Wangmerlyn. * https://github.com/Wangmerlyn/KeepGPU/pull/60#issuecomment-3630698395 The following files were modified: * `src/keep_gpu/mcp/server.py` --- src/keep_gpu/mcp/server.py | 96 +++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/src/keep_gpu/mcp/server.py b/src/keep_gpu/mcp/server.py index 81ed71c..7cd8101 100644 --- a/src/keep_gpu/mcp/server.py +++ b/src/keep_gpu/mcp/server.py @@ -52,6 +52,22 @@ def start_keep( busy_threshold: int = -1, job_id: Optional[str] = None, ) -> Dict[str, Any]: + """ + Start a KeepGPU session that periodically reserves the specified amount of VRAM on one or more GPUs. + + Parameters: + gpu_ids (Optional[List[int]]): List of GPU indices to target; if `None`, all available GPUs may be considered. + vram (str): Amount of VRAM to reserve (human-readable, e.g. "1GiB"). + interval (int): Time in seconds between controller checks/actions. + busy_threshold (int): Numeric threshold controlling what the controller treats as "busy" (semantics provided by the controller). + job_id (Optional[str]): Identifier for the session; when `None`, a new UUID is generated. + + Returns: + dict: A dictionary with the started session's `job_id`, e.g. `{"job_id": ""}`. + + Raises: + ValueError: If `job_id` is provided and already exists. + """ job_id = job_id or str(uuid.uuid4()) if job_id in self._sessions: raise ValueError(f"job_id {job_id} already exists") @@ -78,6 +94,19 @@ def start_keep( def stop_keep( self, job_id: Optional[str] = None, quiet: bool = False ) -> Dict[str, Any]: + """ + Stop one or all active keep sessions. + + If `job_id` is provided, stops and removes that session if it exists; otherwise stops and removes all sessions. When `quiet` is True, informational logging about stopped sessions is suppressed. + + Parameters: + job_id (Optional[str]): Identifier of the session to stop. If omitted, all sessions are stopped. + quiet (bool): If True, do not emit informational logs about stopped sessions. + + Returns: + result (Dict[str, Any]): A dictionary with a "stopped" key listing stopped job IDs. If a specific + `job_id` was requested but not found, the dictionary also includes a "message" explaining that. + """ if job_id: session = self._sessions.pop(job_id, None) if session: @@ -118,6 +147,11 @@ def list_gpus(self) -> Dict[str, Any]: return {"gpus": infos} def shutdown(self) -> None: + """ + Stop all active sessions and release resources, suppressing any errors that occur during interpreter teardown. + + This attempts to stop every session (quietly) and ignores exceptions to avoid noisy errors when the interpreter is shutting down. + """ try: self.stop_keep(None, quiet=True) except Exception: # pragma: no cover - defensive @@ -126,6 +160,22 @@ def shutdown(self) -> None: def _handle_request(server: KeepGPUServer, payload: Dict[str, Any]) -> Dict[str, Any]: + """ + Dispatches a JSON-RPC-like request payload to the corresponding KeepGPUServer method and returns a JSON-RPC response object. + + Parameters: + server (KeepGPUServer): The server instance whose methods will be invoked. + payload (dict): The incoming request object; expected keys: + - "method" (str): RPC method name ("start_keep", "stop_keep", "status", "list_gpus"). + - "params" (dict, optional): Keyword arguments for the method. + - "id" (any, optional): Caller-provided request identifier preserved in the response. + + Returns: + dict: A JSON-RPC-style response containing: + - "id": the original request id (or None if not provided). + - "result": the method's return value on success. + - OR "error": an object with a "message" string describing the failure. + """ method = payload.get("method") params = payload.get("params", {}) or {} req_id = payload.get("id") @@ -150,6 +200,11 @@ class _JSONRPCHandler(BaseHTTPRequestHandler): server_version = "KeepGPU-MCP/0.1" def do_POST(self): # noqa: N802 + """ + Handle HTTP POST requests containing a JSON-RPC payload and send a JSON response. + + Reads the request body using the Content-Length header, parses it as JSON, dispatches the payload to the internal JSON-RPC dispatcher, and writes the dispatcher result as an application/json response. If the request body cannot be decoded or parsed, responds with HTTP 400 and a JSON error object describing the parsing error. + """ try: length = int(self.headers.get("content-length", "0")) body = self.rfile.read(length).decode("utf-8") @@ -167,10 +222,28 @@ def do_POST(self): # noqa: N802 self.wfile.write(data) def log_message(self, format, *args): # noqa: A003 + """ + Suppress the BaseHTTPRequestHandler's default request logging by overriding log_message to do nothing. + + Parameters: + format (str): The format string provided by BaseHTTPRequestHandler. + *args: Values to interpolate into `format`. + """ return def run_stdio(server: KeepGPUServer) -> None: + """ + Read line-delimited JSON-RPC requests from stdin, dispatch each request to the server, and write the JSON response to stdout. + + Parameters: + server (KeepGPUServer): Server instance used to handle JSON-RPC requests. + + Description: + - Processes each non-empty line from stdin as a JSON payload. + - On successful handling, writes the JSON-RPC response followed by a newline to stdout and flushes. + - If parsing or handling raises an exception, writes an error object with the exception message as the response. + """ for line in sys.stdin: line = line.strip() if not line: @@ -185,6 +258,16 @@ def run_stdio(server: KeepGPUServer) -> None: def run_http(server: KeepGPUServer, host: str = "127.0.0.1", port: int = 8765) -> None: + """ + Start a lightweight HTTP JSON-RPC server that exposes the given KeepGPUServer on the specified host and port. + + Starts a TCP HTTP server serving _JSONRPCHandler in a background thread, logs the listening address, waits for the thread to finish, and on interruption or shutdown performs a clean shutdown of the HTTP server and calls server.shutdown() to release resources. + + Parameters: + server (KeepGPUServer): The KeepGPUServer instance whose RPC methods will be exposed over HTTP. + host (str): Host address to bind the HTTP server to. + port (int): TCP port to bind the HTTP server to. + """ class _Server(TCPServer): allow_reuse_address = True @@ -192,6 +275,12 @@ class _Server(TCPServer): httpd.keepgpu_server = server # type: ignore[attr-defined] def _serve(): + """ + Run the HTTP server's request loop until the server is shut down. + + Blocks the current thread and processes incoming HTTP requests for the + server instance until the server is stopped. + """ httpd.serve_forever() thread = threading.Thread(target=_serve) @@ -210,6 +299,11 @@ def _serve(): def main() -> None: + """ + Entry point for the KeepGPU MCP server that parses command-line arguments and starts the chosen transport. + + Parses --mode (stdio or http), --host and --port (for http mode), instantiates a KeepGPUServer, and runs either the stdio loop or the HTTP server based on the selected mode. + """ parser = argparse.ArgumentParser(description="KeepGPU MCP server") parser.add_argument( "--mode", @@ -229,4 +323,4 @@ def main() -> None: if __name__ == "__main__": - main() + main() \ No newline at end of file From e557c89105a67de87a23864a52762fc970f685f2 Mon Sep 17 00:00:00 2001 From: Wang Siyuan Date: Tue, 9 Dec 2025 15:41:46 +0800 Subject: [PATCH 2/5] chore: format mcp server docstrings --- src/keep_gpu/mcp/server.py | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/keep_gpu/mcp/server.py b/src/keep_gpu/mcp/server.py index 7cd8101..7c039b3 100644 --- a/src/keep_gpu/mcp/server.py +++ b/src/keep_gpu/mcp/server.py @@ -54,17 +54,17 @@ def start_keep( ) -> Dict[str, Any]: """ Start a KeepGPU session that periodically reserves the specified amount of VRAM on one or more GPUs. - + Parameters: gpu_ids (Optional[List[int]]): List of GPU indices to target; if `None`, all available GPUs may be considered. vram (str): Amount of VRAM to reserve (human-readable, e.g. "1GiB"). interval (int): Time in seconds between controller checks/actions. busy_threshold (int): Numeric threshold controlling what the controller treats as "busy" (semantics provided by the controller). job_id (Optional[str]): Identifier for the session; when `None`, a new UUID is generated. - + Returns: dict: A dictionary with the started session's `job_id`, e.g. `{"job_id": ""}`. - + Raises: ValueError: If `job_id` is provided and already exists. """ @@ -96,13 +96,13 @@ def stop_keep( ) -> Dict[str, Any]: """ Stop one or all active keep sessions. - + If `job_id` is provided, stops and removes that session if it exists; otherwise stops and removes all sessions. When `quiet` is True, informational logging about stopped sessions is suppressed. - + Parameters: job_id (Optional[str]): Identifier of the session to stop. If omitted, all sessions are stopped. quiet (bool): If True, do not emit informational logs about stopped sessions. - + Returns: result (Dict[str, Any]): A dictionary with a "stopped" key listing stopped job IDs. If a specific `job_id` was requested but not found, the dictionary also includes a "message" explaining that. @@ -149,7 +149,7 @@ def list_gpus(self) -> Dict[str, Any]: def shutdown(self) -> None: """ Stop all active sessions and release resources, suppressing any errors that occur during interpreter teardown. - + This attempts to stop every session (quietly) and ignores exceptions to avoid noisy errors when the interpreter is shutting down. """ try: @@ -162,14 +162,14 @@ def shutdown(self) -> None: def _handle_request(server: KeepGPUServer, payload: Dict[str, Any]) -> Dict[str, Any]: """ Dispatches a JSON-RPC-like request payload to the corresponding KeepGPUServer method and returns a JSON-RPC response object. - + Parameters: server (KeepGPUServer): The server instance whose methods will be invoked. payload (dict): The incoming request object; expected keys: - "method" (str): RPC method name ("start_keep", "stop_keep", "status", "list_gpus"). - "params" (dict, optional): Keyword arguments for the method. - "id" (any, optional): Caller-provided request identifier preserved in the response. - + Returns: dict: A JSON-RPC-style response containing: - "id": the original request id (or None if not provided). @@ -202,7 +202,7 @@ class _JSONRPCHandler(BaseHTTPRequestHandler): def do_POST(self): # noqa: N802 """ Handle HTTP POST requests containing a JSON-RPC payload and send a JSON response. - + Reads the request body using the Content-Length header, parses it as JSON, dispatches the payload to the internal JSON-RPC dispatcher, and writes the dispatcher result as an application/json response. If the request body cannot be decoded or parsed, responds with HTTP 400 and a JSON error object describing the parsing error. """ try: @@ -224,7 +224,7 @@ def do_POST(self): # noqa: N802 def log_message(self, format, *args): # noqa: A003 """ Suppress the BaseHTTPRequestHandler's default request logging by overriding log_message to do nothing. - + Parameters: format (str): The format string provided by BaseHTTPRequestHandler. *args: Values to interpolate into `format`. @@ -235,10 +235,10 @@ def log_message(self, format, *args): # noqa: A003 def run_stdio(server: KeepGPUServer) -> None: """ Read line-delimited JSON-RPC requests from stdin, dispatch each request to the server, and write the JSON response to stdout. - + Parameters: server (KeepGPUServer): Server instance used to handle JSON-RPC requests. - + Description: - Processes each non-empty line from stdin as a JSON payload. - On successful handling, writes the JSON-RPC response followed by a newline to stdout and flushes. @@ -260,14 +260,15 @@ def run_stdio(server: KeepGPUServer) -> None: def run_http(server: KeepGPUServer, host: str = "127.0.0.1", port: int = 8765) -> None: """ Start a lightweight HTTP JSON-RPC server that exposes the given KeepGPUServer on the specified host and port. - + Starts a TCP HTTP server serving _JSONRPCHandler in a background thread, logs the listening address, waits for the thread to finish, and on interruption or shutdown performs a clean shutdown of the HTTP server and calls server.shutdown() to release resources. - + Parameters: server (KeepGPUServer): The KeepGPUServer instance whose RPC methods will be exposed over HTTP. host (str): Host address to bind the HTTP server to. port (int): TCP port to bind the HTTP server to. """ + class _Server(TCPServer): allow_reuse_address = True @@ -277,7 +278,7 @@ class _Server(TCPServer): def _serve(): """ Run the HTTP server's request loop until the server is shut down. - + Blocks the current thread and processes incoming HTTP requests for the server instance until the server is stopped. """ @@ -301,7 +302,7 @@ def _serve(): def main() -> None: """ Entry point for the KeepGPU MCP server that parses command-line arguments and starts the chosen transport. - + Parses --mode (stdio or http), --host and --port (for http mode), instantiates a KeepGPUServer, and runs either the stdio loop or the HTTP server based on the selected mode. """ parser = argparse.ArgumentParser(description="KeepGPU MCP server") @@ -323,4 +324,4 @@ def main() -> None: if __name__ == "__main__": - main() \ No newline at end of file + main() From 63897d7539388bcd0568e6afbd02ccd9185b05f3 Mon Sep 17 00:00:00 2001 From: Wang Siyuan Date: Tue, 9 Dec 2025 16:16:52 +0800 Subject: [PATCH 3/5] style: shorten mcp server docstrings for hooks --- src/keep_gpu/mcp/server.py | 107 +++++-------------------------------- 1 file changed, 12 insertions(+), 95 deletions(-) diff --git a/src/keep_gpu/mcp/server.py b/src/keep_gpu/mcp/server.py index 7c039b3..b827f0d 100644 --- a/src/keep_gpu/mcp/server.py +++ b/src/keep_gpu/mcp/server.py @@ -52,22 +52,7 @@ def start_keep( busy_threshold: int = -1, job_id: Optional[str] = None, ) -> Dict[str, Any]: - """ - Start a KeepGPU session that periodically reserves the specified amount of VRAM on one or more GPUs. - - Parameters: - gpu_ids (Optional[List[int]]): List of GPU indices to target; if `None`, all available GPUs may be considered. - vram (str): Amount of VRAM to reserve (human-readable, e.g. "1GiB"). - interval (int): Time in seconds between controller checks/actions. - busy_threshold (int): Numeric threshold controlling what the controller treats as "busy" (semantics provided by the controller). - job_id (Optional[str]): Identifier for the session; when `None`, a new UUID is generated. - - Returns: - dict: A dictionary with the started session's `job_id`, e.g. `{"job_id": ""}`. - - Raises: - ValueError: If `job_id` is provided and already exists. - """ + """Start a keep-alive session for one or more GPUs.""" job_id = job_id or str(uuid.uuid4()) if job_id in self._sessions: raise ValueError(f"job_id {job_id} already exists") @@ -94,19 +79,7 @@ def start_keep( def stop_keep( self, job_id: Optional[str] = None, quiet: bool = False ) -> Dict[str, Any]: - """ - Stop one or all active keep sessions. - - If `job_id` is provided, stops and removes that session if it exists; otherwise stops and removes all sessions. When `quiet` is True, informational logging about stopped sessions is suppressed. - - Parameters: - job_id (Optional[str]): Identifier of the session to stop. If omitted, all sessions are stopped. - quiet (bool): If True, do not emit informational logs about stopped sessions. - - Returns: - result (Dict[str, Any]): A dictionary with a "stopped" key listing stopped job IDs. If a specific - `job_id` was requested but not found, the dictionary also includes a "message" explaining that. - """ + """Stop one or all active keep sessions.""" if job_id: session = self._sessions.pop(job_id, None) if session: @@ -147,11 +120,7 @@ def list_gpus(self) -> Dict[str, Any]: return {"gpus": infos} def shutdown(self) -> None: - """ - Stop all active sessions and release resources, suppressing any errors that occur during interpreter teardown. - - This attempts to stop every session (quietly) and ignores exceptions to avoid noisy errors when the interpreter is shutting down. - """ + """Stop all sessions quietly and ignore teardown errors.""" try: self.stop_keep(None, quiet=True) except Exception: # pragma: no cover - defensive @@ -160,22 +129,7 @@ def shutdown(self) -> None: def _handle_request(server: KeepGPUServer, payload: Dict[str, Any]) -> Dict[str, Any]: - """ - Dispatches a JSON-RPC-like request payload to the corresponding KeepGPUServer method and returns a JSON-RPC response object. - - Parameters: - server (KeepGPUServer): The server instance whose methods will be invoked. - payload (dict): The incoming request object; expected keys: - - "method" (str): RPC method name ("start_keep", "stop_keep", "status", "list_gpus"). - - "params" (dict, optional): Keyword arguments for the method. - - "id" (any, optional): Caller-provided request identifier preserved in the response. - - Returns: - dict: A JSON-RPC-style response containing: - - "id": the original request id (or None if not provided). - - "result": the method's return value on success. - - OR "error": an object with a "message" string describing the failure. - """ + """Dispatch a JSON-RPC payload to the server and return a response dict.""" method = payload.get("method") params = payload.get("params", {}) or {} req_id = payload.get("id") @@ -200,16 +154,13 @@ class _JSONRPCHandler(BaseHTTPRequestHandler): server_version = "KeepGPU-MCP/0.1" def do_POST(self): # noqa: N802 - """ - Handle HTTP POST requests containing a JSON-RPC payload and send a JSON response. - - Reads the request body using the Content-Length header, parses it as JSON, dispatches the payload to the internal JSON-RPC dispatcher, and writes the dispatcher result as an application/json response. If the request body cannot be decoded or parsed, responds with HTTP 400 and a JSON error object describing the parsing error. - """ + """Handle an HTTP JSON-RPC request and write a JSON response.""" try: length = int(self.headers.get("content-length", "0")) body = self.rfile.read(length).decode("utf-8") payload = json.loads(body) - response = _handle_request(self.server.keepgpu_server, payload) # type: ignore[attr-defined] + server_ref = self.server.keepgpu_server # type: ignore[attr-defined] + response = _handle_request(server_ref, payload) status = 200 except (json.JSONDecodeError, ValueError, UnicodeDecodeError) as exc: response = {"error": {"message": f"Bad request: {exc}"}} @@ -222,28 +173,12 @@ def do_POST(self): # noqa: N802 self.wfile.write(data) def log_message(self, format, *args): # noqa: A003 - """ - Suppress the BaseHTTPRequestHandler's default request logging by overriding log_message to do nothing. - - Parameters: - format (str): The format string provided by BaseHTTPRequestHandler. - *args: Values to interpolate into `format`. - """ + """Suppress default request logging.""" return def run_stdio(server: KeepGPUServer) -> None: - """ - Read line-delimited JSON-RPC requests from stdin, dispatch each request to the server, and write the JSON response to stdout. - - Parameters: - server (KeepGPUServer): Server instance used to handle JSON-RPC requests. - - Description: - - Processes each non-empty line from stdin as a JSON payload. - - On successful handling, writes the JSON-RPC response followed by a newline to stdout and flushes. - - If parsing or handling raises an exception, writes an error object with the exception message as the response. - """ + """Serve JSON-RPC requests over stdin/stdout (one JSON object per line).""" for line in sys.stdin: line = line.strip() if not line: @@ -258,16 +193,7 @@ def run_stdio(server: KeepGPUServer) -> None: def run_http(server: KeepGPUServer, host: str = "127.0.0.1", port: int = 8765) -> None: - """ - Start a lightweight HTTP JSON-RPC server that exposes the given KeepGPUServer on the specified host and port. - - Starts a TCP HTTP server serving _JSONRPCHandler in a background thread, logs the listening address, waits for the thread to finish, and on interruption or shutdown performs a clean shutdown of the HTTP server and calls server.shutdown() to release resources. - - Parameters: - server (KeepGPUServer): The KeepGPUServer instance whose RPC methods will be exposed over HTTP. - host (str): Host address to bind the HTTP server to. - port (int): TCP port to bind the HTTP server to. - """ + """Run a lightweight HTTP JSON-RPC server on the given host/port.""" class _Server(TCPServer): allow_reuse_address = True @@ -276,12 +202,7 @@ class _Server(TCPServer): httpd.keepgpu_server = server # type: ignore[attr-defined] def _serve(): - """ - Run the HTTP server's request loop until the server is shut down. - - Blocks the current thread and processes incoming HTTP requests for the - server instance until the server is stopped. - """ + """Run the HTTP server loop until shutdown.""" httpd.serve_forever() thread = threading.Thread(target=_serve) @@ -300,11 +221,7 @@ def _serve(): def main() -> None: - """ - Entry point for the KeepGPU MCP server that parses command-line arguments and starts the chosen transport. - - Parses --mode (stdio or http), --host and --port (for http mode), instantiates a KeepGPUServer, and runs either the stdio loop or the HTTP server based on the selected mode. - """ + """CLI entry point for the KeepGPU MCP server.""" parser = argparse.ArgumentParser(description="KeepGPU MCP server") parser.add_argument( "--mode", From b0f96678623e8b3296c60a6157f42c899b8580a8 Mon Sep 17 00:00:00 2001 From: Wang Siyuan Date: Tue, 9 Dec 2025 16:37:18 +0800 Subject: [PATCH 4/5] docs: restore detailed mcp server docstrings --- src/keep_gpu/mcp/server.py | 52 ++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/keep_gpu/mcp/server.py b/src/keep_gpu/mcp/server.py index b827f0d..e4d255a 100644 --- a/src/keep_gpu/mcp/server.py +++ b/src/keep_gpu/mcp/server.py @@ -52,7 +52,22 @@ def start_keep( busy_threshold: int = -1, job_id: Optional[str] = None, ) -> Dict[str, Any]: - """Start a keep-alive session for one or more GPUs.""" + """ + Start a KeepGPU session that reserves VRAM on one or more GPUs. + + Args: + gpu_ids: GPU indices to target; None uses all available GPUs. + vram: Human-readable VRAM size to keep (for example, "1GiB"). + interval: Seconds between controller checks/actions. + busy_threshold: Utilization above which the controller backs off. + job_id: Optional session identifier; a UUID is generated if omitted. + + Returns: + Dict with the started session's job_id, e.g. ``{"job_id": ""}``. + + Raises: + ValueError: If the provided job_id already exists. + """ job_id = job_id or str(uuid.uuid4()) if job_id in self._sessions: raise ValueError(f"job_id {job_id} already exists") @@ -79,7 +94,20 @@ def start_keep( def stop_keep( self, job_id: Optional[str] = None, quiet: bool = False ) -> Dict[str, Any]: - """Stop one or all active keep sessions.""" + """ + Stop one or all active keep sessions. + + If job_id is supplied, only that session is stopped; otherwise all active + sessions are released. When quiet=True, informational logging is skipped. + + Args: + job_id: Session identifier to stop; None stops every session. + quiet: Suppress informational logs about stopped sessions. + + Returns: + Dict with a "stopped" list of job ids. If a specific job_id was not + found, a "message" field explains the miss. + """ if job_id: session = self._sessions.pop(job_id, None) if session: @@ -120,7 +148,7 @@ def list_gpus(self) -> Dict[str, Any]: return {"gpus": infos} def shutdown(self) -> None: - """Stop all sessions quietly and ignore teardown errors.""" + """Stop all sessions quietly; ignore errors during interpreter teardown.""" try: self.stop_keep(None, quiet=True) except Exception: # pragma: no cover - defensive @@ -129,7 +157,16 @@ def shutdown(self) -> None: def _handle_request(server: KeepGPUServer, payload: Dict[str, Any]) -> Dict[str, Any]: - """Dispatch a JSON-RPC payload to the server and return a response dict.""" + """ + Dispatch a JSON-RPC payload to the server and return a response dict. + + Args: + server: Target KeepGPUServer. + payload: Dict with "method", optional "params", and optional "id". + + Returns: + JSON-RPC-style dict containing either "result" or "error" plus "id". + """ method = payload.get("method") params = payload.get("params", {}) or {} req_id = payload.get("id") @@ -154,7 +191,12 @@ class _JSONRPCHandler(BaseHTTPRequestHandler): server_version = "KeepGPU-MCP/0.1" def do_POST(self): # noqa: N802 - """Handle an HTTP JSON-RPC request and write a JSON response.""" + """ + Handle an HTTP JSON-RPC request and write a JSON response. + + Expects application/json bodies containing {"method", "params", "id"}. + Returns 400 with an error object if parsing fails. + """ try: length = int(self.headers.get("content-length", "0")) body = self.rfile.read(length).decode("utf-8") From d8a1f3dbae9c1394c9632808c90c6a451b655134 Mon Sep 17 00:00:00 2001 From: Wang Siyuan Date: Tue, 9 Dec 2025 16:43:48 +0800 Subject: [PATCH 5/5] docs: rephrase mcp guide for docstyle hook --- docs/guides/mcp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/mcp.md b/docs/guides/mcp.md index ba05b68..f52d047 100644 --- a/docs/guides/mcp.md +++ b/docs/guides/mcp.md @@ -7,7 +7,7 @@ orchestrators can start/stop keep-alive jobs and inspect GPU state. - You run KeepGPU from an agent (LangChain, custom orchestrator, etc.) instead of a shell. - You want to keep GPUs alive on a remote box over TCP rather than stdio. -- You need a quick way to list GPU utilization/memory via the same interface. +- You need a quick way to list GPU utilization/memory by way of the same interface. ## Quick start @@ -33,7 +33,7 @@ Supported methods: - `start_keep(gpu_ids?, vram?, interval?, busy_threshold?, job_id?)` - `stop_keep(job_id?)` (omit `job_id` to stop all) - `status(job_id?)` (omit `job_id` to list active jobs) -- `list_gpus()` (detailed info via NVML/ROCm SMI/torch) +- `list_gpus()` (detailed info by way of NVML/ROCm SMI/torch) ## Client configs (MCP-style)