Run approved shell commands on remote computers through AI assistants. The remote machine needs only curl and bash, with no SSH access or installed agent.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Ephemeral HTTP command relay. Push a shell command from any HTTP client; have
it run on a remote machine that has nothing installed but curl and bash.
Useful whenever you need to bounce a command to a shell without opening an SSH port, installing an agent, or deploying anything:
Data on the relay is minimised, not absent: each session gets a small directory holding the pending command/result and a timestamped push history, purged as soon as the idle TTL lapses (default 3h) or on explicit delete. Session keys are 128-bit random.
| Component | Role | First-party code |
|---|---|---|
| nginx | Reverse proxy, TLS, rate limiting, static landing page | Config only |
| PHP-FPM | Session API, runner script generator, file-backed queue | Yes |
| certbot | Automatic TLS issuance + renewal (optional, --profile tls) | No |
No database. No worker. The only persistent state is a flat-file queue under
data/sessions/<KEY>/ (bind-mounted from the host into the container at
/var/data/sessions/<KEY>/), data-minimised and purged on idle TTL or
explicit delete.
The shipped .env.example defaults to a self-consistent local HTTP setup -
no editing required for a first run. After the command above, the API and
the one-liners it hands out are both reachable at http://localhost:49180.
For a public deployment, edit .env first: set DOMAIN to your real
hostname, SCHEME=https, NGINX_MODE=tls, HTTP_PORT=80 (required so
Let's Encrypt's HTTP-01 challenge is reachable) and HTTPS_PORT=443, then:
That's the whole install. Everything else runs in containers.
All knobs live in .env; nothing is hardcoded.
| Var | Default | Meaning |
|---|---|---|
DOMAIN | localhost | Public hostname for the API / landing page |
SCHEME | http | http or https - baked into returned one-liners |
PUBLIC_PORT | 49180 | Port baked into generated URLs. Leave empty for the standard port of SCHEME (80/443) |
NGINX_MODE | http | http or tls. tls requires --profile tls |
HTTP_PORT / HTTPS_PORT | 49180 / 49443 | Host ports published by nginx. Public HTTPS deploy: 80 / 443 (80 is required for the ACME HTTP-01 challenge) |
RATE_LIMIT | 10r/m | Per-IP rate on POST /api/session (nginx limit_req syntax) |
RATE_LIMIT_BURST | 5 | Burst slots before 503 |
PROXY_TIMEOUT | 3600 | Max seconds either side of a pipe waits for the other end. Must comfortably exceed LONGPOLL_MS |
MAX_BODY_SIZE | 25m | Single source of truth for body-size limits: nginx client_max_body_size on the queue endpoints, and the API derives its raw-body cap (post_max_size), memory limit, its gzip zip-bomb decoded-size cap (3x this value), and the runner's output-truncation cap (80% of this value) from it, so none of them can drift apart. 0 = unlimited at the nginx layer (PHP still keeps a finite decoded cap for safety) |
LONGPOLL_MS | 15000 | Long-poll window (ms) GET /cmd-{key} / GET /result-{key} hold an empty slot open before returning 204, so listeners pick up work sub-second instead of on the next poll tick |
FPM_MAX_CHILDREN | 64 | PHP-FPM pool size. Each active session pins ~2 workers for up to LONGPOLL_MS at a time, so this bounds how many sessions can be live concurrently before other requests start queueing |
FPM_MAX_REQUESTS | 500 | Requests a PHP-FPM worker serves before it is recycled, so no slow leak accumulates over a long uptime. 0 = never recycle |
SESSION_TTL | 10800 | Idle TTL for a session (seconds). Every request on the key resets it; expired sessions are purged with their queue + history. |
AUDIT_LOG | 0 | 1 = log key generation to container stderr. Independently of this, nginx's access log masks the key segment of every request line as <key> |
SOURCE_URL | (empty) | Target of the landing page's source link and of GET /source. Empty hides the link |
CERTBOT_EMAIL | (required for tls profile) | Contact address used when requesting certs from the ACME CA |
CERTBOT_STAGING | 0 | 1 = use the ACME staging environment (test-only certs, avoids rate limits) |
The defaults above are a ready-to-run local HTTP setup - cp .env.example .env && docker compose up -d gives a working roundtrip at http://localhost:49180
with no edits. A public HTTPS deploy needs DOMAIN set to your real hostname,
SCHEME=https, NGINX_MODE=tls, HTTP_PORT=80 (for the ACME HTTP-01
challenge) and HTTPS_PORT=443.
Behind your own reverse proxy? Skip the tls profile. Point your proxy at
HTTP_PORT on localhost and terminate TLS there. SCHEME and PUBLIC_PORT
describe what clients see, so behind a proxy on the standard port they are
https and 443 (or empty), not the internal HTTP_PORT.
The CI deploy renders .env with scripts/render-env.sh: .env.example
defaults overridden by same-named CI variables. For a non-localhost DOMAIN
it refuses SCHEME=http unless ALLOW_PLAIN_HTTP=1, and when SCHEME is
given without PUBLIC_PORT it uses the standard port of SCHEME, so a
public deploy cannot silently hand out http://DOMAIN:49180/ one-liners.
POST /api/sessionGenerate a new session. Returns:
key - 32-char hex, 128-bit entropyttl_seconds - idle TTL (default 3h sliding; any request on the key resets it)urls.cmd / urls.result - queue push/pop endpoints for this sessionurls.runner - base URL of the runner script; append ?mode=auto for unattended modeurls.api - /api/session/<key> for re-fetching the payloadremote_quickstart - ready-to-paste one-liner, supervised mode (y/N per command)remote_quickstart_auto - the same line with ?mode=auto, for unattended hosts; show operators both and let them pickexec - one-liner template with a COMMAND placeholder for pushing from any HTTP clientmcp_messages - agent-facing message templates for the MCP client
({version, templates}, from php/app/mcp-messages.json). Serving the
wording from the relay means prompt iterations deploy with the relay instead
of requiring an npm re-publish of remotify-mcp; clients keep baked-in
fallbacks, so the field is optional. Tool names/schemas/descriptions stay in
the npm package deliberately (host approval surface). Omitted if the file is
missing or invalid.GET /api/session/{key}Re-fetch the same payload for a known key. Touches the session (resets its idle timer) without consuming anything queued.
GET /api/session/{key}/statusCheap probe: returns {cmd_queued, result_queued, cmd_in_flight, cmd_in_flight_seconds_ago, listener_seen_seconds_ago} without consuming
anything:
cmd_queued / result_queued - whether a command/result is currently sitting in the hot slot.cmd_in_flight - a command was picked up by the listener and no result has been pushed back yet.cmd_in_flight_seconds_ago - seconds since that pickup (null when nothing is in flight).listener_seen_seconds_ago - seconds since the listener last polled GET /cmd-{key} (null if it never has).Used by the MCP server to detect whether the listener has already picked up the queued command.
Factual signals from GitHub, npm, and our automated checks β not a rating.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/remotify-mcp)<a href="https://allmcps.com/mcp/remotify-mcp"><img src="https://allmcps.com/api/badge/remotify-mcp?style=directory" alt="Remotify MCP on AllMCPs" /></a>