What changes when you enable it
Two things become visible to users, and both are inherent to the model rather than defects to work around. The first call after an idle period pays a cold start. How long depends entirely on the server: a small published image starts in a second or two, while auvx/npx server that clones and installs on boot can take a minute or more.
The call waits for provisioning rather than failing.
Creating a connection no longer verifies it immediately. Verification is
what starts the container and lists its tools, so deferring the start defers the
check. A bad image reference or a missing environment variable surfaces on first
use instead of in the connection form.
If neither trade is acceptable for your users, leave it off. It is off by
default.
Enabling it
Bring-up from nothing
The order below is deliberate: each step is independently useful, and the one genuinely unvalidated question is settled before anything is migrated. 0. Do your MCP images run under gVisor? (half an hour, no new infrastructure) This is the only real unknown. Agentbash() under gVisor is already proven by
whatever you run today; your MCP images are not. On any Linux host with runsc
installed:
io_uring, iptables/nftables, block-device mounts and arbitrary
device files — those are where gVisor’s syscall coverage stops. An image that
fails here needs an escape hatch, and it is much cheaper to learn that now.
1. An execution cluster. gVisor needs no KVM or nested virtualization, so
any ordinary VM will do — you do not need bare metal or a special instance
family. One box is enough to start:
runsc with containerd, and creates the gvisor
RuntimeClass. It refuses to finish unless a pod really ran under gVisor, so a
green run means the substrate works. It leaves a kubeconfig at
./execution-cluster.kubeconfig with the API address rewritten to something
reachable.
2. Point the control plane at it.
KUBERNETES_KUBECONFIG beats in-cluster credentials, so a control plane running
inside its own cluster still schedules onto this one. An unloadable file, or an
unrecognised BACKEND_TYPE, stops the manager rather than silently using
whatever is nearest.
On Helm, put the kubeconfig in a Secret and name it. The chart mounts it into
every process that creates workloads and sets KUBERNETES_KUBECONFIG to the
mounted path:
Which instances are affected
Only instances created while serverless is on. The choice is recorded on each instance when it is created, so enabling the setting later does not retroactively shorten the life of connections that already exist, and turning it off does not strand the ones that were created serverless. Also excluded:- Remote (
url-type) connections — there is no container to start or stop. - Instances that have never been called. An instance with no recorded use is treated as new, not as idle. Reclaiming requires evidence of disuse, not the absence of evidence of use.
How reclaiming works
The MCP proxy records a timestamp when traffic passes through it — it is the only component that sees MCP calls, since the gateway routes to the container directly. Writes are throttled to one per instance per minute, so an active instance does not put the database on the hot path of every tool call. The manager sweeps onsweepInterval. For each instance past its idle window it
stops the workload and marks the instance unprovisioned; the database row, the
credentials, and the tool list are untouched. The next call finds it
unprovisioned and starts it again through the same path that started it the
first time.
Sweeping is serialised with a Postgres advisory lock, so running more than one
manager replica does not mean more than one sweeper. If a manager dies
mid-sweep, its lock is released with its connection — there is nothing to clear
by hand.
Verifying it works
With serverless on, create a container-backed connection and watch the manager:idleTimeout, and
the sweep reports the reclamation:
false or an empty value were created eagerly and are never
reclaimed. Recreate the connection to make it serverless.
Turning it off
Setserverless.enabled: false. Instances already created serverless keep that
property, but nothing reclaims them any more: each one starts on its next call
and then stays up. To make them permanently resident, recreate the connections
with the setting off.