Install
$ agentstack add mcp-rmednitzer-relay-shell ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Relay Shell
[](https://deepwiki.com/rmednitzer/relay-shell)
Status: v0.3.0 · Python 3.12 / 3.13 / 3.14 · transports: stdio and streamable-http · MCP SDK mcp==1.28.1 · last validated against upstream surfaces on 2026-07-15 ([ADR 0005](docs/adr/0005-codebase-validation.md)).
A highly reliable, maximally capable Model Context Protocol server for complete shell and SSH mastery.
relay-shell gives an MCP client (Claude, or any MCP-compatible agent) a robust, auditable interface to operate a Linux host and a fleet of remote hosts over SSH: one-shot command execution, long-lived interactive PTY sessions, scripted runs, SFTP transfer, port forwarding, and host-inventory aware connectivity.
It is designed as operator infrastructure tooling for hosts you own and administer. The default operating posture is native, full access (no sandbox), matching the way real administration is performed, paired with the defensive controls a production operator actually needs: an append-only, output-hashed audit trail; a tiered-authority policy layer; secret redaction; strict resource and timeout bounds; and an optional OAuth 2.1 edge.
The architecture, security model, and deployment patterns are modeled on a mature production MCP gateway and on established operational best practices.
Why
Engineers SSH into hosts and run commands from memory, with no structured reasoning trail and no pre-execution review. A well-built MCP relay improves on that baseline: every action is captured with arguments, an output hash, an exit code, and a tier classification; limits and timeouts are enforced centrally; failure paths never crash the transport. The reasoning layer sits inside the loop and can assess blast radius before acting.
Capabilities
Local shell
| Tool | Purpose | |------|---------| | shell_exec | Run a command. Timeout/output clamps, cwd, env overlay, stdin, exit code. | | shell_script | Run a multi-line script (bash/sh/python), optional set -euo pipefail. | | shell_spawn | Start a persistent PTY session (REPLs, TUIs, prompts, long jobs). |
SSH
| Tool | Purpose | |------|---------| | ssh_exec | Run a command on a remote host (jump host, key/agent, known-hosts policy). | | ssh_spawn | Interactive remote PTY session. | | ssh_upload / ssh_download | SFTP transfer (recursive supported). | | ssh_forward | Local (L), remote (R), or dynamic SOCKS (D) forwarding. | | ssh_forward_list / ssh_forward_close | Manage active forwards. | | ssh_check | Connectivity probe across the inventory or a host list. | | ssh_fanout | Run a command in parallel across hosts; per-host exit codes in one JSON. | | ssh_keyscan | Fetch host public keys via ssh-keyscan (pre-populate known_hosts for strict). | | ssh_hosts | Resolved host inventory (~/.ssh/config + inventory file). |
Sessions (local PTY and SSH PTY, unified)
| Tool | Purpose | |------|---------| | session_send | Send input (optionally with Enter) to a session. | | session_recv | Read buffered/new output, with a short wait. | | session_resize | Resize the PTY (cols x rows). | | session_kill | Signal / terminate a session. | | session_list | List active sessions with metadata. |
Diagnostics
| Tool | Purpose | |------|---------| | server_info | Server version, effective limits, policy mode, audit path. | | audit_tail | Return recent audit records as JSONL, optionally filtered by tool/tier/denied (read-only, Tier 0). | | operation_confirm | Arm a Tier-3 confirmation token (opt-in broker, ADR 0009), then re-issue the call. |
The HTTP transport also exposes GET /metrics (Prometheus text format): relay_shell_tool_calls_total{tool,tier,mode,outcome}, relay_shell_seccomp_notify_events_total{syscall}, and relay_shell_seccomp_notify_overflow_total (counters), plus relay_shell_active_sessions, relay_shell_active_forwards, and relay_shell_audit_degraded (gauges). See [docs/deployment.md](docs/deployment.md) §9a.
Resources
Three MCP resources let clients read inventory and ssh_config views the protocol-native way (no tool call needed):
| URI | meaning | |--------------------------------------|--------------------------------------| | relay-shell://inventory | Flat list of all known hosts (JSON). | | relay-shell://inventory/{host} | One host's resolved spec (JSON). | | relay-shell://ssh-config | ssh_config path + aliases (JSON). |
Resource reads are audited (tier 0). See [docs/tools.md](docs/tools.md) for the full reference.
Prompts
One MCP prompt, operating_guide, carries the detailed "when to use which tool" guidance (one-shot command vs persistent PTY session, the spawn+session workflow, fleet and transfer entry points) — the protocol-native counterpart to the concise instructions string handed to clients at initialize. A fetch is audited (tier 0, prompt:operating_guide) like a resource read; listing is not ([ADR 0008](docs/adr/0008-operating-guidance-prompt.md)).
Full reference: [docs/tools.md](docs/tools.md).
Quickstart
Requires Python 3.12+ (CPython, tested on Ubuntu 24.04).
git clone https://github.com/rmednitzer/relay-shell.git && cd relay-shell
python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
# stdio transport (local agent / Claude Desktop / MCP Inspector)
relay-shell
# HTTP transport (streamable-http on 127.0.0.1:8080)
RELAY_SHELL_TRANSPORT=http relay-shell
# Validate config without starting the transport (useful for image bakes)
relay-shell --check-config
# Drift-detect shipped templates against /etc/... (useful in production cron)
relay-shell --verify-deploy
Register with an MCP client (stdio):
{ "mcpServers": { "relay-shell": { "command": "relay-shell" } } }
Configuration is environment-driven; see [.env.example](.env.example) and [docs/deployment.md](docs/deployment.md).
Compatibility matrix
| Surface | Supported | Notes | |-------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------| | Python | 3.12 / 3.13 / 3.14 | CI runs the full matrix; package floor is >=3.12. | | Host OS (tested) | Ubuntu 24.04 LTS | Validation is run against this image; the systemd + Caddy installers assume it. | | Host OS (dev) | macOS | Unsupported for production; pty/SSH paths work for local development. | | Host OS (other) | Windows | Out of scope — no PTY contract, no systemd integration. | | Transports | stdio, streamable-http | Stdio is the default. HTTP binds loopback and requires a TLS edge (see deployment.md). | | SDK | mcp==1.28.1 | Pinned (ADR 0001); bumps trigger a fresh validation pass. | | SSH library | asyncssh>=2.23.0 (tested at 2.24.0) | Native async; no shell-out to system ssh. |
Security posture
relay-shell runs unsandboxed with the privileges of its service account by design (see [docs/adr/0002-no-sandbox-full-access.md](docs/adr/0002-no-sandbox-full-access.md)): sandboxing the process would defeat the very capability it exists to provide. Safety is achieved with compensating controls, not by crippling the tool:
- Audit - every invocation appended as one JSON line with a SHA-256 hash
of the output (never the output body), byte length, exit code, request and client id, and the assessed tier. Append-only on disk; rotation-safe handler. Optional per-record hash chain (RELAY_SHELL_AUDIT_CHAIN, [ADR 0007](docs/adr/0007-audit-hash-chain.md)) makes edits, insertions, reorders, and interior deletions detectable with relay-shell --verify-audit, which is fail-closed (a missing / empty / head-truncated log fails; --segment accepts a rotation segment; tail-truncation needs the off-host copy).
- Syscall visibility (optional) -
RELAY_SHELL_SECCOMP_NOTIFY
([ADR 0006](docs/adr/0006-seccomp-notify-audit-channel.md)) adds an audit-only seccomp user-notify channel that appends syscall_notify lines for a spawned child's execve / privilege / namespace / mount / write-open / privilege-relevant prctl syscalls — for one-shot commands and for shell_spawn PTY sessions, where the filter rides the session child for the session's whole life. It never blocks a syscall and installs only with CAP_SYS_ADMIN (never latching no_new_privs), so set-uid/sudo posture is preserved verbatim — visibility added, capability untouched.
- Tiered authority - every call is classified Tier 0..3
([docs/adr/0003-tiered-authority.md](docs/adr/0003-tiered-authority.md)). RELAY_SHELL_POLICY_MODE selects open (default), guarded, or readonly.
- Redaction - audited arguments are scrubbed for tokens, keys, and
Authorization material.
- Bounds - timeout and output caps on every tool; bounded session count
and buffers; idle/lifetime reaping.
- Optional OAuth 2.1 - DCR with single-client lockdown, PKCE, file-backed
rotating tokens, lazy expiry (HTTP transport; opt-in, off by default). See [docs/auth.md](docs/auth.md) for the authentication lifecycle.
- Edge - parameterized Caddy config restricts the endpoint to known
CIDRs with security headers and automated TLS (ACME / Let's Encrypt) installed via deploy/install-edge.sh; systemd unit applies resource caps.
This server grants real administrative power. Run it only as a scoped service account, only on hosts you are authorized to administer, behind the network controls in [docs/deployment.md](docs/deployment.md). See [SECURITY.md](SECURITY.md) for the threat model and reporting.
If your use case requires maximum model capability, relay-shell also supports an explicit privileged posture (root/sudo workflows). Use that only on isolated administrative hosts with strict network controls and full audit shipping.
Layout
src/relay_shell/ server, config, audit, policy, redaction, sessions,
shelltools, sshpool, inventory, errors, util, auth
deploy/ systemd unit + hardening drop-in, Caddyfile, logrotate, installers
docs/ architecture, tool reference, deployment, ADRs
tests/ unit + integration (in-process SSH server, no network)
Development
ruff check . && ruff format --check .
mypy
pytest
Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for scope, branch naming, the local development loop, and how security-sensitive PRs are reviewed. [docs/runbook.md](docs/runbook.md) is the canonical procedure for audit, review, validate, enhance, and extend tasks. Participation is governed by the [Code of Conduct](CODEOFCONDUCT.md).
AI contributor guidance
- [
AGENTS.md](AGENTS.md) - repository-wide agent operating contract - [
CLAUDE.md](CLAUDE.md) - Claude-focused development and review guidance - [
docs/runbook.md](docs/runbook.md) - executable audit / review / validate / enhance / extend procedures plus the prioritized backlog
License
Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: rmednitzer
- Source: rmednitzer/relay-shell
- License: Apache-2.0
- Homepage: https://rmednitzer.github.io/relay-shell/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.