Skill v1.0.0
currentLLM-judged scan90/100version: "1.0.0" description: Long-running command with streamed progress; FastMCP background task
ssh_exec_run_streaming
Tier: dangerous | Group: exec | Tags: {dangerous, group:exec} Task mode: optional (sync for short calls, background for long ones)
Same shape as ssh_exec_run, but uses asyncssh.create_process so the MCP server reads stdout/stderr incrementally. Each chunk is forwarded to the FastMCP Progress channel -- clients that surface task progress (Claude Desktop, Claude Code) show the latest output line while the command runs.
task=TaskConfig(mode="optional", poll_interval=3s) -- the client can call this synchronously for a short command or invoke as a background task and poll for progress over the MCP task protocol.
Inputs
| name | type | required | default | notes | |
|---|---|---|---|---|---|
host | str | yes | -- | Alias or hostname | |
command | str | yes | -- | Full shell command. Caller owns quoting. | |
timeout | int | no | SSH_COMMAND_TIMEOUT | Per-call timeout in seconds. Set this generously for long-running commands. |
Returns
Same ExecResult shape as ssh_exec_run, including `output_warnings` (INC-057). Streamed output is sanitizer-checked at the chunk boundary, so warnings reflect the full captured stream, not just the final chunk.
When to call it
- Builds, deploys, restores -- anything that runs minutes, not seconds.
tail-style commands when you want to see partial output flowing.- Bulk operations (rsync, restic, big SQL imports).
When NOT to call it
- A short command that returns in under a second -- use
ssh_exec_run. - Anything where you don't want the partial output streamed to clients.
- Production deployments without a Redis docket backend -- task state lives in memory and is lost on MCP server restart. The lifespan emits a WARNING for this combination; set
FASTMCP_DOCKET_URL=redis://...to fix.
Example
ssh_exec_run_streaming(host="web01",command="apt-get -y upgrade",timeout=600,)# As it runs, the client sees progress messages like "stdout: Setting up libfoo (1.2-3) ..."
Backend note
In-memory tasks survive only the lifetime of the MCP server process. For long-running operations you can't afford to lose, configure Redis:
export FASTMCP_DOCKET_URL=redis://localhost:6379
The lifespan logs a WARNING when ALLOW_DANGEROUS_TOOLS=true and the docket backend is in-memory. See DECISIONS.md ADR-0011.
Common failures
CommandNotAllowed-- first token isn't on the allowlist.timed_out=true-- terminate + pkill attempted; partial output preserved up to the cap.ConnectError-- transport failure mid-stream.
Related
- `ssh_exec_run` -- synchronous, simpler, no progress.
- `ssh_exec_script` -- for scripted long-runners (use streaming + script-via-stdin pattern by combining concepts; this tool takes a single command).