Skip to content

Interrupted stdio health checks leave stranded Docker containers #1631

Description

@vivekkrish

Summary

Refreshing the Executor desktop app triggers a burst of parallel connection health checks and a long-running GET /tools catalog sync. Many in-flight stdio MCP sessions are interrupted with HTTP 499 (InterruptError: All fibers interrupted without error). For Docker-transport integrations registered as docker run -i --rm, the docker run client often keeps running after the request is cancelled. The MCP process inside the container stays up, --rm never fires, and containers accumulate quickly (we observed 17+ growing to 35+ in a few minutes).

Isolated tests (single connection refresh, direct docker run with stdin closed) clean up fine. The problem shows up during app refresh storms: parallel health checks and overlapping /tools sync, with many fibers interrupted before stdio is closed.

Environment

  • Executor: desktop app (local daemon + sidecar, ~v1.5.x)
  • OS: macOS (Apple Silicon)
  • Docker: Docker Desktop
  • MCP integrations: Docker stdio MCPs (e.g. Atlassian, Jama, Loki, SonarQube) via docker run -i --rm

Steps to reproduce

  1. Register several Docker stdio MCP integrations.
  2. Ensure connections exist and tools have been refreshed at least once.
  3. Refresh or reload the Executor desktop app (or navigate in a way that reloads integrations and connections).
  4. Run docker ps and filter by MCP image name or count running containers.

Expected behavior

When a health check or tool-discovery fiber is interrupted (499), Executor tears down the stdio child process and closes stdin/stdout so MCP processes exit and --rm removes containers.

Actual behavior

  • Many containers spawn in a short window (~1–2 minutes).
  • Containers remain Up after the UI refresh completes; count keeps climbing on subsequent refreshes.
  • Stranded count correlates with interrupted health checks, not successful ones.

Example after one app refresh:

MCP serverStranded containersHealth checks (~2 min)Interrupted (499)
Atlassian141212
SonarQube664
Jama565
Loki343

After refresh, stranded containers still have live docker run client processes (tens of seconds to minutes old), parented under the Executor sidecar — the HTTP request is cancelled but the child process is not.

Daemon log excerpts

App refresh triggers:

  • GET /integrations
  • GET /toolsdiscover_tools interrupted (499)
  • Parallel POST /connections/org/*/health for all connections
  • Many health checks interrupted (499) within milliseconds:
InterruptError: All fibers interrupted without error
at mcp.plugin.check_health
http.url: /connections/org/<integration>/<connection>/health
http.status: 499
  • Long-running GET /tools (~109 seconds) with repeated warnings:
executor tool sync preserved catalog {
reason: "plugin returned an incomplete tool catalog",
integration: "<integration_slug>",
connection: "<connection_name>"
}
  • UI polled GET /connections many times in the same window (e.g. 14+ in ~2 minutes).

Notes

  1. Same spawn path for health checks, tool sync, and agent tool calls — all use the integration's registered stdio config (docker run -i --rm).
  2. Interrupt vs clean exit — MCP images exit correctly when stdin is closed in isolated tests. Stranding appears when Executor interrupts fibers during UI refresh bursts without killing the docker run child.
  3. Operational impact — stranded containers (~60–110 MiB each) compound until Docker memory pressure causes MCP discovery timed out after 15000ms. Restarting Executor does not remove the containers.

Suggested fix

  1. On fiber interrupt / 499 for stdio MCP sessions, kill the child process tree (or at least the docker run client) and close stdin/stdout.
  2. Debounce or supersede in-flight health-check batches on UI reload without leaving live stdio children behind.
  3. Document that interrupted check_health / discover_tools can strand Docker stdio children until the client process exits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions