luftpause
This MCP server runs and manages pooled-model sub-agent runs with tools, approvals, budgets, and one-pass classification.
Spawn asynchronous sub-agent runs with a task, model, allowed tools, system prompt, parent run, service class, max tokens, max tool calls, parallel tool calls, and subtree budgets for tokens, tool calls, and wall-clock seconds.
Run a sub-agent and block until it finishes, with MCP Tasks support when the client opts in.
Await one, all, or any run handles with a timeout and collect results, statuses, token usage, tool-call counts, errors, and pending approvals.
Inspect a run’s current status, answer, error, parent/children, budget use, and pending approval details.
Cancel a run and all runs spawned under it.
Approve or decline tool calls that are waiting because they are destructive or explicitly require approval.
List the tools available to sub-agents, including their source servers.
Make one-pass typed decisions, returning labels with probabilities, optionally scoring caller-provided labels.
Integrates with a local Ollama instance as the LLM engine, routing sub-agent turns to Ollama models while managing run scheduling, tool calls, and fairness across runs.
Provides an OpenAI-compatible proxy that routes Chat Completions requests to OpenAI or other OpenAI-compatible endpoints, enabling agents to use luftpause's run scheduling, continuation prioritization, and fair queuing.
luftpause
The runtime layer under your agent harness. Every tool call is an await; the
engine forgets the run, luftpause keeps it.
Tool calls split an agent into turns. To an inference engine each turn is a new request from nobody: when the tool returns, the continuation queues behind every batch request that arrived while it waited, and its KV cache may be gone. luftpause sits between the harness and the engines and keeps the run:
Continuations go first. A run paused on a tool call resumes ahead of batch work; batch turns leave room for the interactive runs that will come back.
A run stays where its prefix is. While a run is generating or paused on a tool, its turns go only to the replica that holds its KV cache; new turns are admitted by the engine's own queue.
One caller cannot starve another. Held turns drain fairly across callers.
Any harness, two doors. Point
base_urlat it (OpenAI-compatible, your own loop), or connect over MCP and getspawn/awaitsub-agents that survive a restart.
Measured on one 8 GB laptop GPU, engines saturated (48 batch runs flooding, 4 interactive runs beside them):
Throughput | Latency | What it costs | |
Agents with their own loop, through luftpause vs straight to the SGLang router | 2.0× interactive (12.7 vs 6.4 runs/min) | interactive p50 19 s instead of 36 s | batch −9 % |
Sub-agents over MCP, luftpause vs the runtime straight to the router | 2.7× interactive (8.0 vs 3.0 runs/min) | interactive p50 27 s instead of 58 s | batch unchanged |
Fan-out, 16 sub-agents, vs one at a time | 5.3× (all 16 in 23 s instead of 120 s) | per sub-agent p50 15–22 s, the same as through the router | nothing: the router alone takes 21.5 s |
Claude Code as the client, six Wikipedia look-ups | 2.9× (12.5 s instead of 36 s back to back, unprompted) | 70B sub-agents: all six in one round, 9.3 s | 0 failed tool calls, 0 re-spawns |
Try it
docker compose up -d # fake engines, no GPU needed
claude mcp add --transport http --scope local luftpause http://localhost:7000/mcpdocker compose up -d pulls the published images; add --build to build them from source instead (first build takes a few minutes). It pulls latest; pin a release with LUFTPAUSE_VERSION=v0.1.4 docker compose up -d. The runtime is also listed in the official MCP Registry as io.github.vmedvedovskiy/luftpause.
Claude Code now has spawn, await, run, status, cancel, approve, tools and decide. The fake
engines answer with filler, and the sub-agents' only tools are fake-mcp's lookup and deep_search,
which wait a random second or so and return filler too — enough to see the fan-out. For real answers from
an Ollama already on your machine, with Wikipedia as the sub-agents' tool instead of the fake ones:
docker compose -f compose.yaml -f compose.ollama.yaml up -d scheduler dataplane runtimeWikipedia's API rate-limits anonymous callers, so a tool call can take tens of seconds while wikipedia-mcp retries.
Llama 3.2 1B sometimes passes a tool's schema instead of its arguments; the runtime rejects the call and the
sub-agent may answer without it, so ask again or pull a larger model.
Ollama needs the model pulled (ollama pull llama3.2:1b, or set OLLAMA_MODEL)
and must listen beyond loopback (OLLAMA_HOST=0.0.0.0) unless Docker Desktop
already reaches it (it does on Windows and macOS with the default loopback
binding). Ollama serves one request at a time unless OLLAMA_NUM_PARALLEL is
raised, so sub-agents queue behind each other there; luftpause sees no queue
metric from it and does not cap it. SGLang on your GPU (compose.testbed.yaml) or any
OpenAI-compatible endpoint (compose.runpod.yaml shows a hosted vLLM pod) work
the same way.
Related MCP server: AgentPrism Workflows
How it differs
Routers place requests on a GPU pool; MCP servers delegate a sub-task to a local model. Neither knows what a run is. luftpause does: it sees every turn and every tool call of every run, through either door, and schedules them on one shared pool with three facts an engine never has: that a paused run will come back, what class of work it is, and who is asking.
The gains come from admission, not from routing. Routing alone ties SGLang's cache-aware router (below); with the engines idle, every arm ties. The difference appears when the engines are saturated, which is when it matters.
Two ways in
OpenAI-compatible proxy — an agent that keeps its own loop points its
base_urlat luftpause. It sendsx-luftpause-run-idper run and, optionally,x-luftpause-classandx-luftpause-caller; every tool call in its loop is then a scheduled await.MCP runtime — an agent such as Claude Code connects over MCP and gets
spawn/await. luftpause runs each sub-agent's loop through the same proxy: LLM turns on the pool, tool calls to upstream MCP servers, the MCP session as the caller, and a journal so the runs outlive the process.
examples/ has three own-loop agents that set all three headers: the openai
package, the OpenAI Agents SDK and LangGraph.
Connect from
A harness that cannot set a header per run still works through the proxy: the run
is recognised by the tool_call_ids it echoes back, and a fixed
x-luftpause-caller is enough for fairness.
Tool | MCP door | Proxy door |
Claude Code |
| n/a: speaks the Anthropic Messages API, not Chat Completions |
Codex CLI |
| n/a: |
Gemini CLI |
| n/a: speaks the Gemini API (unverified) |
Goose |
|
|
Cursor |
| n/a: "Override OpenAI Base URL" is called from Cursor's servers, which cannot reach localhost (unverified) |
Zed |
|
|
OpenHands | Settings → MCP Servers → add | Settings → LLM → Advanced: Custom Model |
Cline / Roo Code | Cline | Provider "OpenAI Compatible", Base URL |
Architecture
%%{init: {"themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif"}, "flowchart": {"wrappingWidth": 260}}}%%
flowchart LR
mcp["Claude Code<br/>or any MCP client"]
own["Agents with<br/>their own loop"]
subgraph lp["luftpause"]
runtime["<b>runtime</b> · .NET<br/>spawn · await · journal<br/>sub-agent loops"]
dp["<b>dataplane</b> · Rust<br/>OpenAI-compatible proxy"]
sched["<b>scheduler</b> · .NET<br/>decide(state, event)"]
end
tools[("MCP tool<br/>servers")]
subgraph pool["Engine pool"]
direction TB
engines["SGLang · vLLM"]
router["SGLang router"]
hosted["Hosted OpenAI-<br/>compatible APIs"]
end
mcp -- MCP --> runtime
own -- "HTTP / SSE" --> dp
runtime -- "tool calls" --> tools
runtime -- "LLM turns" --> dp
dp -- "turns" --> pool
sched <-- "Admit · Report · run ended" --> dp
sched -. "health · load" .-> poolruntime (
runtime/) — MCP server. Each spawned run is a .NETTaskrunning the agent loop; tool calls go to the configured MCP servers. Every run is journaled toruns.jsonland resumed on restart; a finished run is reported to the dataplane (DELETE /v1/runs/{id}) so the scheduler forgets it at once.dataplane (
dataplane/crates/dataplane) — tokio/axum proxy. Resolves the run (header or tool-call ids), reads the class and caller headers, asks the scheduler where the turn goes, streams the engine's response through unchanged and reports first token, usage and finish reason.scheduler (
scheduler/) — the decision core is pure functions over immutable state (Luftpause.Scheduling); the gRPC host executes the actions.test kit —
fake-engine(OpenAI +/classifywith simulated latency),fake-mcp(alookupand a slowdeep_searchtool),tools/loadgen(agents, sub-agent fan-out over MCP, closed-loop throughput runs).
What it does
Capability | How |
|
|
Durable runs | every run is journaled ( |
Run tree |
|
Budgets |
|
Tool approval | a sub-agent's tool call waits for the harness user when its server marks the tool |
MCP Tasks |
|
Status | the scheduler's |
Caller fairness | each turn carries |
Tools apart from turns | a run waiting on a tool holds no turn slot; tool calls run in the runtime against MCP servers over HTTP or stdio; with |
Admission by engine load | an engine takes turns while it reports no waiting queue (SGLang and vLLM |
Strict run affinity | a run that is generating or paused on a tool is admitted only to the replica that served its last turn, where its prefix is cached, even when another replica has room; a run whose replica is unhealthy, or that is idle, may move. Measured below: this is where the interactive gain comes from, and an estimate of KV memory on top of it cost throughput and was removed |
Service classes | batch turns leave room on an engine for each interactive run paused on a tool there, since it will come back; turns held by luftpause go out |
Routers as backends | a replica can be a router (e.g. the SGLang router) that picks the engine; its load is read from the engines behind it ( |
Routing by model | endpoints declare the models they serve; a turn only goes to a replica serving its model; an unknown model gets 404 at once |
Hosted endpoints | any OpenAI-compatible API (vLLM on RunPod, OpenAI, OpenRouter, …) as a replica: API key from an environment variable, health path per endpoint, https |
Scheduler restart | the dataplane keeps every run's last replica, phase, class and caller (idle runs dropped after 30 min) and every turn in flight; on startup and after any reconnect it sends them to the scheduler ( |
Health |
|
Tool-call hygiene | arguments coerced to the schema's scalar types, validated, and rejected with the expected shape instead of a silent bad call; calls written as text are recovered |
Run identity |
|
Single-pass engines |
|
Tracing | with |
Auth | with |
Failure semantics
What happens to a turn through the dataplane (/v1/chat/completions, /v1/decide)
when something fails. Error bodies are {"error": {"message": "..."}}; every response
except the scheduler-unreachable one carries x-luftpause-run-id. A failed turn frees
its slot at once and leaves its run idle, never paused on a tool, so a retry is
admitted like any next turn of that run. Retrying with the same x-luftpause-run-id
keeps the run's affinity and fairness standing.
Case | What the client sees | What luftpause does | What an own-loop agent should do |
Client disconnects while its turn is held | nothing (it left) | cancels the scheduler call; the turn leaves the wait queue ( | if it gave up on a client-side timeout, send the turn again with the same run id: it never ran |
Client disconnects mid-stream | nothing (it left) | closes the engine request, which stops generation; reports the turn failed | send the turn again with the same run id; the partial reply is not kept anywhere |
Engine unreachable |
| reports the turn started and failed; the replica stays in rotation until its health probe fails (2 s period) | retry with the same run id after a short pause; the retry may go to the same replica until the probe marks it down |
Engine fails mid-stream |
| reports the turn failed | treat the reply as lost, discard it, retry the whole turn with the same run id |
Engine refuses at once (429, 5xx) | the engine's status and body, unchanged, with its | reports the turn started and failed | on 429, wait |
Unknown model |
| refuses before queueing; no engine request, no turn recorded | give up: fix the model name or the endpoint config; a retry gets the same answer |
Scheduler unreachable or restarting | nothing: the turn is held, as if queued, until the scheduler answers or the client disconnects | retries the admission every second under the same turn id; on reconnect resyncs runs and turns in flight before admitting again; no engine request until then | nothing; a client-side timeout shorter than the outage behaves like any held turn's: retry with the same run id |
Constants
luftpause keeps few fixed numbers. There is no queue deadline and no turn limit: a held turn waits as it would in the engine's own queue, and a run ends when its tool budget is spent. What is left:
Constant | Value | What it does | Where |
Reply length | 256 tokens per turn, set per run with | SGLang reserves memory for the longest reply a request may write; without a limit it batched a seventh as many requests (6 vs 42 runs/min on the test bed) and runaway replies broke Llama's one-call-per-reply format |
|
Tool-call budget | 8 per run, set per run with | Once spent, the model is offered no tools and must answer; this also bounds a run's turns at budget + 1 |
|
| 60 s by default, 600 s at most | How long one |
|
Turn timeout | 10 min | A turn whose completion is never reported (dataplane crashed mid-turn) is dropped and its slot freed |
|
Run idle expiry | 30 min | A run with no turn for this long is forgotten; its next turn starts without affinity. The runtime reports its sub-agents' ends; agents with their own loop never say they are done, so their state needs an end |
|
Probe period | 2 s | Engine health and load ( |
|
Clock tick | 1 s | Drives the two expiries above |
|
Runtime → dataplane timeout | 10 min | Longest a single turn may take, queue wait included, before the run fails; the same as the OpenAI and Anthropic clients' default |
|
429 retry delay | the response's | The runtime retries a turn an engine rejects with 429 (a hosted API's rate limit) until the run is cancelled |
|
Engine connect timeout | 2 s | The dataplane gives up connecting to an engine after this |
|
Report reconnect | 1 s | The dataplane reconnects its event stream to the scheduler after this pause |
|
Tool-call id memory | 30 min, pruned every 60 s | How long the dataplane can recognise a run by the |
|
Run journal |
| Where |
|
Caller header |
| Identifies the caller for fairness; absent means one shared anonymous caller |
|
Running it
docker compose up -d --build # scheduler, dataplane, runtime, fake engines, fake MCP tools
dotnet run --project tools/loadgen -- --spawn 10 # fan 10 sub-agents out over MCP and await them
dotnet run --project tools/loadgen -- --agents 8 --duration-s 60 --class batch --caller me # 8 own-loop agents through the proxy, closed loop
tools/check.sh # both .NET test projects, loadgen, cargo test (when cargo is installed), image buildsReleasing: tools/release.sh vX.Y.Z builds, tags and pushes the three images to ghcr.io/luftpause (LUFTPAUSE_REGISTRY overrides) and creates the git tag; DRY_RUN=1 prints the commands only.
With a token: LUFTPAUSE_TOKEN=<token> docker compose up -d, then claude mcp add --transport http luftpause http://localhost:7000/mcp --header "Authorization: Bearer <token>".
An Ollama on the host as the only replica (model from OLLAMA_MODEL, default llama3.2:1b):
docker compose -f compose.yaml -f compose.ollama.yaml up -d scheduler dataplane runtimeOn one GPU, two SGLang replicas of Llama-3.2-1B FP8 (the test bed used below):
docker compose -f compose.yaml -f compose.testbed.yaml up -d --build scheduler dataplane runtime fake-mcp sglang-a sglang-bTraces in Jaeger: add compose.otel.yaml, which starts jaegertracing/all-in-one and points the three services' OTEL_EXPORTER_OTLP_ENDPOINT at it; a harness that sends traceparent on its MCP calls sees its sub-agents, their turns and the scheduler's admission inside its own trace. The UI is on http://localhost:16686.
docker compose -f compose.yaml -f compose.otel.yaml up -d --buildA hosted vLLM pod as an extra replica (key and pod id from the environment):
RUNPOD_POD_ID=<pod-id> RUNPOD_KEY=<key> docker compose -f compose.yaml -f compose.testbed.yaml -f compose.runpod.yaml up -d scheduler runtimeMeasurements
One laptop, RTX 4060 Laptop 8 GB, two SGLang replicas of Llama-3.2-1B-Instruct FP8
unless stated. Repeats are noted per table; differences inside the spread are
noise. The flood tables come from tools/bench/flood.sh (sub-agents over MCP)
and tools/bench/proxy-flood.sh (own-loop agents); each takes the git revisions
to compare as arms and builds them into their own image tags.
Fan-out: spawn × 16 + await all vs one sub-agent at a time (3 repeats)
16 sub-agents, ~2.8k-token tasks, lookup tool fixed at 2 s, up to 3 calls each.
Time for all 16 | vs sequential | |
sequential (spawn, await, next) | 120.5 s | — |
luftpause fan-out | 22.9 s | 5.3× |
fan-out straight to the SGLang router | 21.5 s | 5.6× |
Per sub-agent, fan-out and router take the same time (p50 15–22 s); the 1.4 s difference is inside the run-to-run spread.
Interactive runs under a batch flood (2 repeats, both shown)
48 batch runs flooding the replicas, 4 interactive runs beside them, 3 minutes per
window, 8000-character contexts, up to 3 tool calls per run, closed loop (a finished
run is replaced at once). Both engines queued requests in the no-scheduler arm, so
the pool was saturated. SGLang runs with --enable-priority-scheduling in every
row; no priorities are sent.
Agents with their own loop, base_url at luftpause (tools/loadgen --agents):
Interactive runs/min | Interactive run time p50 | Batch runs/min | |
straight to the SGLang router, class-blind | 6.0 / 6.7 | 38.5 s / 33.6 s | 83.7 / 82.3 |
luftpause, engine-load admission, runs free to move (0afb28a) | 8.7 / 9.0 | 23.2 s / 25.9 s | 79.3 / 79.0 |
luftpause, engine-load admission with strict run affinity | 12.0 / 13.3 | 18.5 s / 19.8 s | 75.7 / 76.0 |
luftpause, KV-memory estimate on top (removed) | 13.0 / 10.7 | 17.8 s / 20.8 s | 76.3 / 76.0 |
Sub-agents over MCP (tools/loadgen --spawn):
Interactive runs/min | Interactive run time p50 | Batch runs/min | |
runtime straight to the SGLang router | 3.0 / 3.0 | 56.6 s / 59.5 s | 39.2 / 36.5 |
luftpause, engine-load admission, runs free to move (0afb28a) | 4.0 / 5.0, 4.3 / 5.6 | 44.4 s / 36.7 s | 35.5 / 36.6 |
luftpause, engine-load admission with strict run affinity | 8.0 / 8.0 (and 8.0 / 8.0, 7.3 / 9.3 on the bench branch) | 29.2 s / 25.2 s | 36.2 / 38.5 |
luftpause, KV-memory estimate on top (removed) | 6.3 / 6.6, 6.0 / 7.3 | 29.7 s / 35.4 s | 35.5 / 35.5 |
Interactive throughput is 2× the class-blind router through the proxy and 2.7× over MCP; batch gives up 9 % through the proxy and nothing over MCP. The rows differ in admission only. Letting runs move between replicas moved 39 of 48 batch runs mid-run and lost their prefix cache; pinning a generating or paused run to its replica is the whole gain. An estimate of each turn's KV memory on top of that, checked against the engine's reported pool, cost about a fifth of interactive throughput over MCP and nothing through the proxy, so it was removed. With light load (2000-character contexts, 24 batch runs) the engines never queue and all rows tie at about 14 interactive runs/min.
Claude Code as the client
Told to fan out six river look-ups, Claude Code spawned six runs and awaited them in one call: 12.5 s for the whole fan-out including its own round trips, against 36 s for the same runs back to back.
In a fresh session, asked only to "research these six rivers using the local sub-agents", it listed the sub-agent tools, restricted the runs to the Wikipedia tools, spawned six, awaited them in one call and re-spawned the weak answers. Tools: wikipedia-mcp over stdio.
Sub-agents | Claude's re-spawns | Tool calls rejected | Outcome |
1B local, before argument coercion | 4 | 38 of 46 | answers mostly from model memory |
3B local, with coercion | 2 | 0 of 20 | lengths and mouths right, country lists unreliable |
Llama 3.3 70B AWQ on a RunPod vLLM pod | 0 | 0 of 6 | all six from Wikipedia in one round (9.3 s) |
The 70B pod sat in the same pool as the local 3B replica: turns asking for
llama-3.3-70b went to the pod over https with its API key, everything else stayed
local. failedToolCalls in await tells the caller when an answer did not come
from tools.
Routing (N = 8 sub-agents in flight, 4 repeats)
Runs/min | Prompt tokens from cache | |
luftpause affinity | 30.1 ± 1.7 | 44.6 % |
SGLang router, | 30.1 ± 0.5 | 44.6 % |
SGLang router, | 28.2 ± 0.5 | 25.7 % |
Affinity equals the SGLang router's cache-aware routing and beats round-robin by 7–15 % at moderate load; at 16–24 runs in flight the caches churn and policy stops mattering.
Single-pass (vLLM classifier, RoBERTa-base)
luftpause serves two kinds of model on one pool. A generative engine (SGLang,
vLLM, a hosted API) runs an agent's turns: it decodes token by token, keeps a KV
cache per run, and a turn may end in tool calls that pause the run. A
single-pass engine answers in one forward pass: an encoder or classifier
(RoBERTa-style, served by vLLM's /classify) returns typed labels with
probabilities, no decoding, no stream, no state between calls. Agents use it for
the decisions that do not need a generated reply, such as routing a request,
scoring a tool result or choosing the next step, at a few milliseconds instead of a
generated turn. Sub-agents reach it through the decide MCP tool; own-loop agents
through POST /v1/decide. Single-pass turns are placed on their own replicas and
never enter run state, so they neither hold nor wait for a generative slot. For a label set
the classifier was not trained on, decide(labels: [...]) scores the labels from a
generative replica's first-token logprobs instead, at the cost of one one-token turn.
On the 1B test bed it sorts "the server returned 500 three times and the on-call
phone is ringing" into urgent at 0.89 and a population question into lookup at
0.99, but also calls "2 + 2" and "thanks, that's all" lookup: the mechanism works,
the 1B model leans on the first label. Use a larger model or calibrate the scores.
Load | Latency at the data plane |
one call at a time | p50 20.6 ms |
20 concurrent agents | p50 85 ms, p99 180 ms |
License
Business Source License 1.1, converting to the Apache License 2.0 four years after each version is published. In practice: use it, change it, ship it inside your product or your company, redistribute it, all free, with no copyleft on your own code. The one thing you may not do until the conversion is offer luftpause itself to third parties as a hosted or managed service. That makes it source-available, not OSI open source, and we say so plainly. The reason is the usual one for infrastructure: a small team cannot compete with a cloud provider that wraps the project in a console and sells it, and that outcome would end the project rather than fund it. The change date is the answer to "will it ever be open source": yes, on a date written in the license, version by version. If the restriction blocks something you want to do before then, open an issue; a per-case grant is easy. Contributions are accepted under the same terms (see CONTRIBUTING.md).
Available Tools
8 toolsapproveAIdempotent
Answer a run waiting with status AwaitingApproval when the client was not asked through elicitation: allow=true runs the pending tool call, allow=false tells the sub-agent the user declined it. Find waiting runs with await or status, whose pendingApproval shows the tool and its arguments. Returns {handle, decided}; decided is false when the handle is unknown or the run has no pending approval.
| Name | Required | Description | Default |
|---|---|---|---|
| allow | Yes | true to run the tool call, false to decline it. | |
| handle | Yes | Handle of the waiting run. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare openWorldHint=false and idempotentHint=true, so the description carries most behavioral disclosure. It explains that allow=true runs the pending tool call, allow=false tells the sub-agent the user declined it, and that decided is false when the handle is unknown or no pending approval exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loaded: the primary action and condition come first, followed by discovery guidance and return semantics. Every clause contributes useful information without wasted setup.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and sparse annotations, the description supplies the missing context: how to find waiting runs, what the two allow outcomes mean, and how to interpret the returned decided flag. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already defines both parameters. The description still adds meaning by explaining the downstream effect of allow=true versus allow=false on the sub-agent and by clarifying that handle refers to a waiting run.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action (answer a run waiting with status AwaitingApproval) and distinguishes the approval case from elicitation-based approval. It also names the discovery siblings (await, status) for finding waiting runs, so an agent can tell it apart from those tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear condition for use (run is waiting with AwaitingApproval and the client was not asked through elicitation) and points to await or status for locating waiting runs. It stops short of explicitly naming the decide sibling and when that alternative should be used instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
awaitA
Wait for runs to finish. mode=all waits for every handle, mode=any returns when at least one is done; use status to look without waiting. Returns every known handle's state, with the same fields as status, including runs still in progress after the timeout; unknown handles are left out. failedToolCalls counts tool calls that returned an error; when it equals toolCalls, the answer came from the model's own memory, not from tools. A run about to call a destructive tool waits for approval: clients with elicitation are asked here, others get the run back with status AwaitingApproval and pendingApproval {tool, arguments} and answer with approve.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | all (default) or any. | all |
| handles | Yes | Handles returned by spawn. | |
| timeoutSeconds | No | Longest time to wait, in seconds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare openWorldHint=false and destructiveHint=false; the description goes well beyond them by disclosing what is returned (every known handle's state, same fields as status), that in-progress runs are still included after timeout, that unknown handles are silently omitted, and that a run nearing a destructive call blocks for approval with a specific AwaitingApproval/pendingApproval contract. That is unusually rich disclosure for a non-mutating tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The waiting behavior and mode semantics are front-loaded where they matter most, and the sentences are dense with distinct facts rather than filler. It runs long and the failedToolCalls/toolCalls explanation is a slight tangent for a wait tool, but nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-shape burden and does so by referencing status's fields and enumerating the special cases (unknown handles, in-progress runs, pendingApproval). The one gap is that "same fields as status" forces the agent to consult a sibling tool to know the actual field list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds genuine meaning by explaining what mode=all and mode=any actually do behaviorally rather than just restating the enum values. It also clarifies that timeoutSeconds ends the wait without ending the runs, which goes beyond the schema's "Longest time to wait".
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Wait for runs to finish" states a specific verb (wait) and resource (runs), and the description immediately differentiates itself from the sibling `status` by contrasting blocking vs looking. An agent can distinguish `await` from `status`, `run`, and `spawn` without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative explicitly ("use status to look without waiting") and gives the condition that selects each mode (all vs any), plus a follow-up path (`approve`) for the approval case. What it does not cover is when to prefer awaiting versus polling with status repeatedly, or how to pick a timeoutSeconds value, leaving that to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancelADestructiveIdempotent
Stop a run and every run spawned under it. It cannot be undone: each stopped run ends as Cancelled without an answer. Returns {handle, cancelled}; cancelled is true when the run or one of its descendants was still in progress, false when the handle is unknown or everything had already finished, so calling it again is harmless. Use status or await to read the final state.
| Name | Required | Description | Default |
|---|---|---|---|
| handle | Yes | Handle returned by spawn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructive and idempotent, and the description corroborates and deepens them: cascade to descendants, irreversibility with no answer produced, and a precise explanation of why re-calling is harmless (cancelled=false when handle unknown or already finished). That is context structured fields cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences: action and scope first, then irreversibility, then return semantics and the harmless-retry note, then the alternative. No sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by specifying the return shape ({handle, cancelled}) and the meaning of each value. Combined with the follow-up pointer to status/await, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with 100% schema coverage ('Handle returned by spawn'), so the schema already carries the semantics. The description adds no format or sourcing detail beyond what the schema states, making baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Stop') and resource ('a run and every run spawned under it'), including the cascade scope. An agent can distinguish it from status/await/approve siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the consequence (cannot be undone, runs end as Cancelled) and redirects to 'status or await' for reading final state. No explicit when-not-to-use case, but the destructive framing plus the alternative pointer covers most routing decisions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
decideARead-only
One-pass typed decision: returns labels with probabilities for the input. Without labels, a single-pass model answers with its own label set. With labels, a generative model scores them by the logprob of its first answer token.
| Name | Required | Description | Default |
|---|---|---|---|
| input | Yes | Text or state to classify. | |
| model | No | Model; defaults to the runtime's decision model without labels and its generative model with labels. | |
| labels | No | 2 to 20 labels to choose from, each with a distinct first word; omit to use the single-pass model's labels. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description adds substantive behavior beyond that: the two inference paths, that scoring is by logprob of the model's first answer token, and what is returned (labels with probabilities). With no output schema, this return-value disclosure carries real weight. It doesn't cover limits such as cost, latency, or what happens with an oversized label set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences that front-load what the tool returns, then the two operating modes. No filler, no restatement of the tool name, and the parallel 'Without labels / With labels' structure makes the branch scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter read-only classifier with a fully documented schema and no output schema, the description supplies the one thing the schema can't: the shape of the result and the inference mechanism. Minor gaps remain around probability normalization and edge cases (label count limits, model behavior), but nothing blocks correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes further by explaining the consequence of supplying versus omitting labels — the semantic switch that the schema only states mechanically. It adds the mechanism behind the model default rather than repeating the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"One-pass typed decision: returns labels with probabilities for the input" gives a specific verb (classify/decide) and an explicit return shape, which none of the siblings (status, run, cancel, await, approve, spawn, tools) provide. It doesn't explicitly say it differs from those siblings, but no sibling is a classifier so confusion is unlikely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly branches on the labels parameter: omit labels for the single-pass model's own label set, supply labels to have a generative model score them. That is real mode-selection guidance. It stops short of stating exclusions (e.g., when not to use this versus a heavier job-running tool), so it isn't a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
runA
Spawn a sub-agent run and wait in the same call until it finishes; takes the same arguments as spawn and returns the run as await does. Clients that opt into MCP Tasks get a task to poll instead, and an approval inside the run arrives as the task's input request. Other clients are asked approvals the way await asks them; without elicitation the call returns the run with status AwaitingApproval. Cancelling the call cancels the run.
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | What the sub-agent should do. | |
| model | No | Model to run on; defaults to the runtime's model. | |
| tools | No | Names of the tools this run may use; all configured tools when omitted. | |
| parent | No | Handle of the run this one belongs to; cancelling the parent cancels it. | |
| system | No | Optional system prompt for the sub-agent. | |
| maxTokens | No | Longest reply per model turn, in tokens; 0 leaves it to the engine. Engines that reserve memory per request (SGLang) batch far fewer requests without it. | |
| approveTools | No | Tools whose every call waits for the user's approval, on top of tools their server marks destructive. | |
| budgetTokens | No | Prompt plus completion tokens this run and every run under it may use; over it, the subtree is cancelled. | |
| maxToolCalls | No | Tool calls allowed before the sub-agent must answer without tools. | |
| serviceClass | No | interactive (default) or batch. Batch runs yield to interactive ones. | interactive |
| budgetSeconds | No | Wall-clock seconds this run may take, its subtree included; when they pass, the subtree is cancelled. | |
| budgetToolCalls | No | Tool calls this run and every run under it may make; over it, the subtree is cancelled. | |
| parallelToolCalls | No | Let the model ask for several tool calls in one reply, run at once. Off by default: Llama 3.x takes one call per reply. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only cover openWorldHint/idempotentHint/destructiveHint, so the description carries the interesting burden and does so well: blocking semantics, cancellation propagation ('cancelling the call cancels the run'), and the fallback behavior of returning status AwaitingApproval when elicitation is unavailable. It leaves the shape of the returned run object implicit by deferring to await.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the primary action and blocking behavior lead, followed by the Tasks-client variant, the approval path, and cancellation. Every clause carries distinct operational information, though the middle sentences pack three separate client-behavior branches into a single paragraph.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter orchestration tool with no output schema and thin annotations, the description covers the hard parts an agent would otherwise get wrong — that the call blocks, that cancellation propagates, and that approval may surface as either an input request or an AwaitingApproval status. The composition of the returned run is left to the await sibling rather than spelled out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% across all 13 parameters, so the schema does the heavy lifting for task, model, tools, budgets, and serviceClass. The description adds nothing parameter-specific beyond 'takes the same arguments as spawn', which is the correct baseline when the schema is fully documented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific compound action — spawn a sub-agent run and block until it finishes — and immediately positions it against siblings by noting it takes spawn's arguments and returns what await returns. An agent can tell this apart from spawn and await without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly frames this as the combined spawn+wait path and explains that MCP-Tasks-opted clients instead get a pollable task, which is real routing guidance. It stops short of explicitly telling the agent when to prefer bare spawn (fire-and-forget) or await over this call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
spawnA
Start a sub-agent run on the pooled models and return {handle} at once, without waiting for it; use run instead to start one and block until it finishes. The sub-agent loops over model turns and calls the configured tool servers (list them with tools). Collect results with await, look at one run with status, stop it with cancel. A tool call that needs approval pauses the run as AwaitingApproval until it is answered in await or with approve. An unknown parent handle or invalid arguments fail the call; a run that later fails, runs out of budget or is cancelled keeps its handle and reports Failed or Cancelled with an error.
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | What the sub-agent should do. | |
| model | No | Model to run on; defaults to the runtime's model. | |
| tools | No | Names of the tools this run may use; all configured tools when omitted. | |
| parent | No | Handle of the run this one belongs to; cancelling the parent cancels it. | |
| system | No | Optional system prompt for the sub-agent. | |
| maxTokens | No | Longest reply per model turn, in tokens; 0 leaves it to the engine. Engines that reserve memory per request (SGLang) batch far fewer requests without it. | |
| approveTools | No | Tools whose every call waits for the user's approval, on top of tools their server marks destructive. | |
| budgetTokens | No | Prompt plus completion tokens this run and every run under it may use; over it, the subtree is cancelled. | |
| maxToolCalls | No | Tool calls allowed before the sub-agent must answer without tools. | |
| serviceClass | No | interactive (default) or batch. Batch runs yield to interactive ones. | interactive |
| budgetSeconds | No | Wall-clock seconds this run may take, its subtree included; when they pass, the subtree is cancelled. | |
| budgetToolCalls | No | Tool calls this run and every run under it may make; over it, the subtree is cancelled. | |
| parallelToolCalls | No | Let the model ask for several tool calls in one reply, run at once. Off by default: Llama 3.x takes one call per reply. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (openWorldHint, non-idempotent, non-destructive), the description discloses behavior the agent cannot get from structured fields: the call is non-blocking, a run can park in AwaitingApproval, an unknown parent handle or invalid arguments fail synchronously, and a run that later fails or exceeds budget keeps its handle and reports Failed/Cancelled with an error. Parent cancellation propagation is also stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The non-blocking return and the `run` contrast are front-loaded in the first sentence, and each subsequent sentence carries distinct lifecycle or failure information. It is dense and long-sentenced for a 13-parameter tool, but almost no clause is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an asynchronous, 13-parameter orchestration tool with no output schema, the description covers the return value ({handle}), the approval pause path, budget and cancellation semantics, and the error modes. An agent has enough to invoke it correctly and to know which sibling handles the next step.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter meaning the schema does not: budget exhaustion cancels the whole subtree, approval pausing ties to approveTools, and parent linkage determines cancellation. It does not walk through individual parameters such as maxTokens or serviceClass, so it stops short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Start a sub-agent run') plus its defining property: it returns {handle} immediately instead of blocking. It explicitly names the sibling `run` as the blocking alternative, so the agent can discriminate between the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use/when-not rule ('use run instead to start one and block until it finishes') and then maps the rest of the lifecycle onto named siblings: collect with `await`, inspect with `status`, stop with `cancel`, list tool servers with `tools`, answer approvals with `approve`. Nothing about selection is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusARead-onlyIdempotent
Read one run's current state at once, without waiting; use await to block until runs finish. Returns handle, status (Running, AwaitingApproval, Completed, Failed or Cancelled), answer once Completed, error once Failed or Cancelled, parent and children handles, turns, toolCalls, failedToolCalls, prompt, cached and completion tokens, elapsedSeconds, budget when one was set, and pendingApproval {tool, arguments} while AwaitingApproval. An unknown handle returns {handle, error: "unknown handle"}.
| Name | Required | Description | Default |
|---|---|---|---|
| handle | Yes | Handle returned by spawn. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and closed-world, so the safety profile is covered. The description adds real value on top: the full return payload, the meaning of each status value, and the exact failure shape for an unknown handle. Minor gap: no mention of timing/consistency or cost of polling repeatedly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose and the await alternative before the return enumeration. The long comma-separated field list is dense but every item is load-bearing given there is no output schema; bullets would read better.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly enumerates the return fields and conditional fields (answer on Completed, pendingApproval on AwaitingApproval). Success and error paths are both covered for a one-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and defines the single required handle parameter, so the baseline is 3. The description goes beyond it by specifying the error contract for an unknown handle ('{handle, error: "unknown handle"}'), which changes how an agent should handle bad input.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read one run's current state') plus the key behavioral qualifier ('at once, without waiting'), and explicitly contrasts itself with the await sibling. An agent can distinguish it from await/spawn without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit rule: use this for non-blocking reads, use await to block until runs finish. That names the alternative tool and the condition that selects it, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
toolsARead-onlyIdempotent
List the tools sub-agents can use, with the server each comes from. Pass names to spawn(tools: [...]) to restrict a run.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so safety is covered; the description adds genuinely new behavioral context by disclosing that results include server provenance and are intended as input to spawn. It omits output shape (flat list? grouped by server?) and any size/truncation behavior, which is the only remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with what is returned, followed by the actionable use. No filler, no restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing returns and does so at a high level (names + originating server). For a zero-parameter listing tool this is nearly sufficient; only the exact return structure is left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4; the schema is empty and fully described by construction. The description's only parameter-adjacent content explains how the returned values feed spawn(tools: [...]), which is useful consumption semantics rather than input-parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb 'List' plus a precisely scoped resource ('the tools sub-agents can use'), and it states what each entry carries ('with the server each comes from'). It also separates itself from the sibling spawn by naming it and describing the relationship, so an agent can tell the two apart without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the follow-up action: pass the returned names to spawn(tools: [...]) to restrict a run, which effectively identifies the alternative/next step in the workflow. It stops short of when-not-to-use guidance (e.g., that spawn without this list runs unrestricted), but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.3- First observed
approve - First observed
await - First observed
cancel - First observed
decide - First observed
run - First observed
spawn - First observed
status - First observed
tools
TDQS
Scored across 8 tools
The lifecycle tools (spawn/run/await/status) share a surface area but are sharply delineated: spawn is fire-and-forget, run is spawn+wait, await waits on existing handles, status is non-blocking peek. The only outlier is decide, which is a one-pass classification tool unrelated to sub-agent runs and could be mistaken for nothing else, so it is distinct rather than ambiguous. Minor risk of confusion between run and spawn/await only for a rushed reader.
All eight names are single lowercase words with no case or separator drift, which is highly consistent. However the set mixes nouns (status, tools) with verbs (spawn, cancel, await, approve) and 'run' reads as both, so there is no strict verb_noun pattern to anchor intent. Still readable and predictable.
Eight tools is well within the sweet spot and each maps to a genuine lifecycle step: start, inspect, wait, approve, stop, enumerate tools (plus run as the blocking variant). Nothing feels padded or missing for an async sub-agent runner.
The run lifecycle is fully covered: spawn/run to start, status/await to observe, approve for the AwaitingApproval gate, cancel to terminate, and tools to discover capabilities. Gaps are minor: no way to inspect a finished run's turn-by-turn transcript or individual tool call results beyond counts, and no dedicated list-runs tool (await implicitly enumerates known handles).
Maintenance
Related MCP Connectors
Hosted runtime for persistent agent teams, durable workflows, memory, schedules, and goals.
AI cloud for agents: launch GPUs, run jobs that stop their own billing, schedule runs.
Durable background job execution, async task scheduling, and state persistence for AI agents.
GPU compute for agents: run commands on an L4/A100/H100, watch logs, billed per second.
Related MCP Servers
- AlicenseAqualityAmaintenanceThe infrastructure for AI teams: a self-hosted server that gives a fleet of agents shared semantic memory, tasks, direct messages, and session handoff. Any agent that speaks HTTP participates: Claude Code, AutoGen, raw API scripts, anything.479MIT
- AlicenseNot gradedqualityAmaintenanceRun dynamic, multi-agent workflow scripts — agent(), parallel(), pipeline() — over real coding agents (Claude Code and OpenAI Codex), with deterministic journaling, resume, token budgets, and git-worktree isolation.7Apache 2.0
- AlicenseNot gradedqualityCmaintenanceA production-grade multi-agent workflow orchestrator built on the Model Context Protocol, featuring planner/executor/critic agents, durable run state, and replayable traces.15MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to manage GPU training end-to-end through natural language, including submitting and scheduling jobs, monitoring logs and metrics, diagnosing failures, comparing runs, and recommending the best checkpoints.Apache 2.0