<< All versions

Skill v1.0.0

currentLLM-judged scan90/100
nightreaver/python-ssh-mcp/ssh-exec-run-streaming
──Details
PublishedOctober 22, 2026 at 12:26 AM
Content Hashsha256:4d9b1ec2c29fd466...
Git SHA52b7d9cb1d02
──Files
Files (1 file, 3.0 KB)
SKILL.md3.0 KBactive
SKILL.md · 79 lines · 3.0 KB

version: "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

nametyperequireddefaultnotes
hoststryes--Alias or hostname
commandstryes--Full shell command. Caller owns quoting.
timeoutintnoSSH_COMMAND_TIMEOUTPer-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

python
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:

bash
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).
All versions