
Kubernetes Ephemeral Job
io.github.inhumanPublished by GitHub account inhumanv0.7.1Updated Oct 24, 2026
Runs a command in a throwaway Kubernetes pod and returns exit code, output and artifacts.
Overview
An MCP server that runs a command in a throwaway Kubernetes pod from an allowlisted image and returns exit code, output and artifacts.
- What you can do
- Run a command in a fresh ephemeral pod and get exit code, combined output, duration and inline artifacts, with the pod deleted afterwards. Submit long jobs in the background and fetch their results later, with optional long-polling. Optionally clone a git repository into the working directory before the command runs. Pass input files, environment variables, resource limits, a working directory and a timeout per job.
- When to use it
- Useful when an assistant needs to execute builds, test suites or scripts in a real container with a chosen toolchain, network access for dependencies, and file outputs, without leaving pods behind. Fits teams already running Kubernetes that want a namespace-scoped, allowlisted execution sandbox for agents.
- Requirements
- Runs locally as a Docker image over stdio (or http/sse). Needs access to a Kubernetes cluster via a mounted kubeconfig (MCP_K8S_KUBECONFIG) or in-cluster credentials, a namespace (MCP_K8S_NAMESPACE) with Role/RoleBinding for jobs, pods and logs, and a non-empty image allowlist (MCP_K8S_ALLOWED_IMAGES). Optional clone support needs MCP_K8S_CLONE_IMAGE and MCP_K8S_CLONE_SECRET.
Installation
In SourceWeft
- Open Kubernetes Ephemeral Job in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
mcp-k8s-ephemeral-job
English | Русский
[Version] [MCP Registry] [Docker Pulls] [Docker Image Version] [Build] [Go Version] [Go Report Card] [License: MIT] [Issues] [Last Commit]
Public OSS MCP server (Go, MIT) that spawns an ephemeral Kubernetes Job/pod from a
caller-chosen image, runs a command inside it, returns exit_code / stdout / artifacts, and
deletes the pod. The server builds the pod manifest in code — the caller passes parameters
only, never raw YAML.
It is the "operating room" counterpart to mcp-exec (the
"scalpel"): where mcp-exec runs a single Python file in a locked-down, network-less sandbox in
milliseconds, this one spins up a full pod with the toolchain/image you choose, controlled
network (clone repos, pull deps), long tasks and file artifacts out. They complement each
other.
Works over three transports — stdio / HTTP / SSE — with an identical tool set everywhere
(official modelcontextprotocol/go-sdk).
Tools
run_job — run and wait
Input: { image (required), command (required), files?, env?, limits?, timeout_s?, workdir?, clone? }
Output: { exit_code, stdout, stderr, duration_ms, status, artifacts, truncated }
statusis one ofsucceeded/failed/timeout/error. A non-zeroexit_codeor atimeoutis a normal result, not a tool error. Only invalid input (empty image/command, image not in the allowlist, bad file path) is a tool-call error.stdoutcarries the container's combined stdout+stderr — Kubernetes merges the two streams in pod logs.stderris reserved and always empty, so adding stream separation later stays backward-compatible.- Artifacts (files from the working directory) come back inline (base64) under a size cap.
Exceeding a cap never loses data silently: the matching
truncatedflag is set. - The manifest is built deterministically by the server — no raw YAML from the caller.
submit_job / fetch_job — run in the background
submit_job takes the same arguments as run_job but returns a job_token immediately;
fetch_job collects the result later. This is what lets an agent start a long job (a full test
battery, a build) and keep working instead of idling inside one synchronous call for its whole
wall-clock time.
fetch_jobreturnsstatus=runningwhile the job is in flight; passwait_s(≤120) to long-poll instead of hammering. It answers as soon as the job is done rather than sitting out the full wait.- Results are retained for 60 minutes and can be fetched more than once.
- Arguments are validated at submit time, so a bad image fails the submit while the caller can still fix it.
- Handles live in memory (the server is single-replica by design): a restart drops pending tokens and the caller simply resubmits.
Cloning a repository
With clone: { repo_url, ref, subdir? } an init container checks the repo out into the working
directory before the command runs. The caller never handles credentials: the server holds a
secret with one token per git host, mounts it only on the cloner, and the token is masked in
.git/config afterwards — the main container never sees it. The clone field is accepted only when
the operator has configured MCP_K8S_CLONE_IMAGE + MCP_K8S_CLONE_SECRET.
Security model (invariants)
Per run: a fresh ephemeral pod, deleted afterwards (success / failure / timeout). The server's
RBAC is namespace-scoped (Role/RoleBinding, never ClusterRole) — create/delete jobs,pods
plus pods/log, pods/exec in one namespace. Spawned pods run with cap-drop=ALL,
no-privilege-escalation, seccomp RuntimeDefault. The blast radius is that one namespace:
LimitRange (per-pod default+max) + ResourceQuota (namespace ceiling) + wall-clock timeout
(→ kill) + TTL/owner-reference GC + a concurrency cap. Images must pass a strict allowlist
(MCP_K8S_ALLOWED_IMAGES; empty = nothing runs). Caller data (command / files / output /
artifacts) is never persisted and never logged in full — only metadata.
run_jobis the most powerful surface there is (it creates pods). When embedding it in an agent, gate it behind that agent's tool-policy (trusted roles only).
Network note: the pod's network is not disabled (it's needed to clone repos / pull deps).
Egress is controlled by a namespace NetworkPolicy (allowlist) as a deployment concern, not a
right baked into the code. The invariant is ephemerality + deletion, not the absence of network.
Resources: the server's MCP_K8S_DEFAULT_CPU/MEMORY are pod requests (the scheduler's
reservation). Limits are set only when the caller passes limits; otherwise the ceiling comes from
the namespace LimitRange. Passing limits.memory also raises the memory request to match, since
memory is incompressible and the pod must land on a node that actually has it.
Run
Published in the MCP Registry as
io.github.inhuman/mcp-k8s-ephemeral-job; the image is on Docker Hub as
idconstruct/mcp-k8s-ephemeral-job.
From source, against a dev cluster, over stdio:
In production the server runs in-cluster as a Deployment with its own ServiceAccount +
Role/RoleBinding on the ephemeral namespace + ResourceQuota/LimitRange (+ optional egress
NetworkPolicy), usually on the http transport.
Example call (run_job)
Returns exit_code, captured output, and out.png inline in artifacts. Afterwards the pod is
gone (kubectl get jobs,pods -n $NS is empty).
Optional auth (HTTP/SSE)
Set MCP_K8S_AUTH_TOKEN to require every HTTP/SSE request to carry a matching X-MCP-AUTH header
(constant-time compare; 401 otherwise). Empty token disables it. Not applicable to stdio.
Configuration
Both cache variables must be set together for the cache to mount. The PVC itself is provisioned out-of-band (helm/manifest); the server only references it by name and fails fast at startup if it is missing.
Not implemented
PVC / object-storage delivery for artifacts too large to inline, multi-cluster support, and proxying other MCP servers into the pod.
License
MIT.
Source: README.md at commit 1623e64
Tools
0Version history
1- v0.7.1LatestSep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts