**Bug description** If MCP server process exits - this is not detected by an StdioClientTransport that launches said process, or any other code. The initialization of MCP server just times out waiting for stdio response from a process that's no longer running **Environment** Spring AI 2.0.0-M5, mcp-core-2.0.0-M2.jar, macOS Tahoe 26.3.1 **Steps to reproduce** Configured chrome-devtools MCP server **application.yaml**: ``` spring: ai: mcp: client: stdio: servers-configuration: classpath:mcp-servers.json ``` **mcp-servers.json**: ``` { "mcpServers": { "chrome-devtools": { "command": "/opt/homebrew/bin/npx", "args": [ "chrome-devtools-mcp@latest", "--autoConnect" ], "env":{ "PATH": "/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin" } } } } ``` Without the PATH variable explicitly listing paths, the PATH provided by Spring AI is not sufficient for Node/NPX to launch, the command exits with exit code 127 - which is not detected by Spring AI at all, instead initialize command is sent and response is awaited for default 20 seconds **Expected behavior** In case process exits, there should be no wait for response from it, instead exception should be thrown logging exit code of the process **Minimal Complete Reproducible example** Use above files with this main method in `@SpringBootApplication` ``` public static void main(String[] args) { List<McpSyncClient> clients = SpringApplication.run(AiagorcApplication.class, args) .getBean("mcpSyncClients", List.class); System.out.println("Clients: " + clients.get(0).listTools()); } ``` Note: if process exits immediately or quickly, supposedly this can be detected right away in the `StdioClientTransport`: ``` ProcessBuilder processBuilder = this.getProcessBuilder(); processBuilder.command(fullCommand); processBuilder.environment().putAll(params.getEnv()); // Start the process try { this.process = processBuilder.start(); } catch (IOException e) { throw new RuntimeException("Failed to start process with command: " + fullCommand, e); } // Validate process streams if (this.process.getInputStream() == null || process.getOutputStream() == null) { this.process.destroy(); throw new RuntimeException("Process input or output stream is null"); } ``` Debug has shown here the this.process has PID and exit code, but no IOException is thrown - because process ran, it just exited. Alternatively, the input/output streams of exited process are probably closed - and this can be detected in Lambdas created in `startInboundProcessing`/`startOutboundProcessing` methods of `StdioClientTransport`