Skip to content

[bug] Tool subprocesses stay alive with no sessions #1917

Description

@nateberkopec

Executor version

1.6.7

How do you run Executor?

Self-host (Docker)

Operating system

macOS (Apple Silicon)

Integration involved

No response

What happened

I have a workflow where I start ~hundreds of agents connecting to a single executor server. They connect, do some work, and exit. I noticed that the number of PIDs on the machine was growing without limit.

Now, clanker speaking:

Executor creates one scoped executor for each MCP session. The scoped executor owns resources such as Tool subprocesses and connection pools.

The MCP session store does not keep a reference to the scoped executor. When it removes an idle session, it closes the MCP server and execution engine. However, it cannot close the scoped executor. A Tool subprocess can stay alive after its session no longer exists.

We confirmed this behavior:

  1. Open an MCP session.
  2. Call a fake stdio Tool and record its process ID.
  3. Wait for Executor to remove the idle session.
  4. Confirm that the session returns HTTP 404.
  5. Confirm that the Tool process is still alive.

What you expected

Sessions which disconnect should release their resources in a timely manner back to the host.

Steps to reproduce

  1. Open an MCP session.
  2. Call a fake stdio Tool and record its process ID.
  3. Wait for Executor to remove the idle session.
  4. Confirm that the session returns HTTP 404.
  5. Confirm that the Tool process is still alive.

Diagnostics / logs

Fresh isolated self-host MCP session leak reproduction
data_dir=/var/folders/nc/xm6rz4hd1g5741fhmwfznf0w0000gn/T/executor-session-leak-repro-zOmzB3/data
session_id=284197b3-ae22-4808-8bdc-248e49c263ef
tool_pid=21007
session_after_idle_http_status=404
session_after_idle_body={"jsonrpc":"2.0","error":{"code":-32001,"message":"Session not found"},"id":null}
tool_process_alive_after_session_eviction=true
executor_log=/var/folders/nc/xm6rz4hd1g5741fhmwfznf0w0000gn/T/executor-session-leak-repro-zOmzB3/executor.log

Executor host log:
tsr.routes.ts (2:30) �[33m[UNRESOLVED_IMPORT] Warning:�[0m Could not resolve '@executor-js/react/console-routes' in tsr.routes.ts
�[38;5;246m╭�[0m�[38;5;246m─�[0m�[38;5;246m[�[0m tsr.routes.ts:2:31 �[38;5;246m]�[0m
�[38;5;246m│�[0m
�[38;5;246m2 │�[0m �[38;5;249mi�[0m�[38;5;249mm�[0m�[38;5;249mp�[0m�[38;5;249mo�[0m�[38;5;249mr�[0m�[38;5;249mt�[0m�[38;5;249m �[0m�[38;5;249m{�[0m�[38;5;249m �[0m�[38;5;249mc�[0m�[38;5;249mo�[0m�[38;5;249mn�[0m�[38;5;249ms�[0m�[38;5;249mo�[0m�[38;5;249ml�[0m�[38;5;249me�[0m�[38;5;249mR�[0m�[38;5;249mo�[0m�[38;5;249mu�[0m�[38;5;249mt�[0m�[38;5;249me�[0m�[38;5;249ms�[0m�[38;5;249m �[0m�[38;5;249m}�[0m�[38;5;249m �[0m�[38;5;249mf�[0m�[38;5;249mr�[0m�[38;5;249mo�[0m�[38;5;249mm�[0m�[38;5;249m �[0m"@executor-js/react/console-routes"�[38;5;249m;�[0m
�[38;5;240m │�[0m ─────────────────┬─────────────────
�[38;5;240m │�[0m ╰─────────────────── Module not found, treating it as an external dependency
�[38;5;246m───╯�[0m

VITE v8.0.8 ready in 486 ms

➜ Local: http://localhost:4897/
➜ Network: use --host to expose
[executor] generated a secret-encryption key at /var/folders/nc/xm6rz4hd1g5741fhmwfznf0w0000gn/T/executor-session-leak-repro-zOmzB3/data/secret.key. Set EXECUTOR_SECRET_KEY to manage it explicitly (and to keep secrets readable across data-dir changes).
[19:21:36.226] INFO (#40) http.span.1=79ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/api/auth/sign-in/email",
"http.status": 200,
}
[19:21:36.805] INFO (#42) http.span.2=570ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/api/mcp/servers",
"http.status": 200,
}
[19:21:36.836] INFO (#66) http.span.3=25ms: Sent HTTP response {
"http.method": "GET",
"http.url": "/api/tools",
"http.status": 200,
}
[19:21:36.861] INFO (#79) http.span.4=21ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/api/toolkits",
"http.status": 200,
}
[19:21:36.886] INFO (#90) http.span.5=21ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/api/toolkits/tk_7fk9cfvljx8mtiip6fv/connections",
"http.status": 200,
}
[19:21:36.911] INFO (#101) http.span.6=21ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/api/toolkits/tk_7fk9cfvljx8mtiip6fv/policies",
"http.status": 200,
}
[executor] MCP session mode {"clientCapabilities":null,"elicitationSupport":{"form":false,"url":false},"elicitationMode":"model","resumeEnabled":true}
[19:21:36.945] INFO (#112) http.span.7=30ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/mcp/toolkits/fresh-session-leak-repro",
"http.status": 200,
}
[19:21:37.006] INFO (#128) http.span.8=57ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/mcp/toolkits/fresh-session-leak-repro",
"http.status": 200,
}
[19:22:44.023] INFO (#151) http.span.9=9ms: Sent HTTP response {
"http.method": "POST",
"http.url": "/mcp/toolkits/fresh-session-leak-repro",
"http.status": 404,
}

Before you submit

  • I searched the open issues for a duplicate.
  • I removed all keys, tokens, and credentials from this report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions