apache/shardingsphere · critical · IOException

Failed to start embedded Tomcat runtime.

Error message

Failed to start embedded Tomcat runtime.

What it means

StreamableHttpMCPServer.start() assembles an embedded Tomcat (connector on the configured port/bind host, temp base dir, transport servlet mapped at the endpoint path) and calls tomcat.start(). A Tomcat LifecycleException — most commonly a bind failure — is caught, stop() is invoked to release partial state, and the error is rethrown as IOException('Failed to start embedded Tomcat runtime.').

Source

Thrown at mcp/bootstrap/src/main/java/org/apache/shardingsphere/mcp/bootstrap/transport/server/http/StreamableHttpMCPServer.java:88

        }
    }
    
    private void startEmbeddedTomcat() throws IOException {
        try {
            tomcat = new Tomcat();
            connector = new Connector();
            connector.setPort(config.getPort());
            connector.setProperty("address", config.getBindHost());
            tomcat.setConnector(connector);
            baseDirectory = Files.createTempDirectory("shardingsphere-mcp-tomcat");
            tomcat.setBaseDir(baseDirectory.toString());
            Context context = tomcat.addContext("", baseDirectory.toString());
            ((StandardContext) context).setClearReferencesRmiTargets(false);
            registerTransportServlet(context);
            tomcat.start();
        } catch (final LifecycleException ex) {
            stop();
            throw new IOException("Failed to start embedded Tomcat runtime.", ex);
        }
    }
    
    private void registerTransportServlet(final Context context) {
        Wrapper servletWrapper = Tomcat.addServlet(context, "mcp-streamable-http", transportServlet);
        servletWrapper.setAsyncSupported(true);
        context.addServletMappingDecoded(config.getEndpointPath(), "mcp-streamable-http");
    }
    
    @Override
    public void stop() {
        closeTomcat();
        closeSyncServer();
        connector = null;
        deleteBaseDirectory();
    }
    
    private void closeTomcat() {

View on GitHub (pinned to e952770a21)

Solutions

  1. Check the IOException's cause — LifecycleException text names bind vs. lifecycle failure.
  2. Free the port (ss -ltnp / lsof -i :<port>) or configure an unused one.
  3. Set bindHost to an address that exists on the machine (127.0.0.1 for local-only use).
  4. Ensure the temp directory is writable and not exhausted; set a writable java.io.tmpdir if needed.
  5. Run only one HTTP MCP server per port/endpoint path.

Example fix

# before
# port 8080 already in use -> IOException "Failed to start embedded Tomcat runtime."

# after
ss -ltnp | grep 8080    # find and stop the conflicting process, or:
java -jar mcp.jar --transport http --bind-host 127.0.0.1 --port 18080
Defensive patterns

Strategy: validation

Validate before calling

// before start: confirm the endpoint address is bindable
try (java.net.ServerSocket probe = new java.net.ServerSocket(port, 1, InetAddress.getByName(bindHost))) { /* bind will succeed */ } catch (final java.net.BindException ex) { throw new IllegalStateException("Port/host unavailable: " + bindHost + ":" + port, ex); }

Try / catch

try { server.start(); } catch (final IOException ex) { Throwable cause = ex.getCause(); /* LifecycleException cause: free the port, fix bindHost, ensure temp dir writable */ }

Prevention

When it happens

Trigger: Launching the MCP HTTP transport when the configured port is already bound, the bindHost address is not assigned to the host, or the temp base directory cannot be created; Tomcat then throws LifecycleException from start(), which this handler converts to IOException.

Common situations: Another MCP instance or unrelated service on the same port; bindHost set to 0.0.0.0-alikes or an interface absent in the container; read-only or full /tmp preventing Files.createTempDirectory; SELinux/AppArmor blocking the embedded Tomcat.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/68e92a8e05dfe08d. Report an issue: GitHub.