MCP
Available Tools
The two MCP tools Ternux exposes, and their limits.
list_open_connections
Lists SSH tabs currently open in Ternux — no arguments. Returns each session's session_id, host, port, user, and display name. A session only appears here while its tab is open; closing the tab removes it immediately.
run_command
Runs a shell command on an open SSH connection over a fresh exec channel.
| Argument | Required | Description |
|---|---|---|
session_id | Yes | Must match an id from list_open_connections. Any other value is rejected. |
command | Yes | Shell command to execute. |
stdin | No | Text written to the command's stdin before EOF (e.g. a sudo password). Never written to the audit log. |
timeout_ms | No | Defaults to 30000 (30s), clamped to a max of 300000 (5 min). |
Limits to plan around
- Not your interactive terminal. The command runs over a brand-new SSH connection, not the tab's live PTY — it doesn't share that shell's working directory, exported variables, or activated environments (e.g. a
cdorsource venv/bin/activateyou ran interactively won't apply). - No PTY, no interactive prompts. Anything expecting a tty (password prompts, confirmation dialogs, interactive
sudo) will hang or fail. Feed required input throughstdin, and write commands defensively (e.g.sudo -S -p '' <cmd>,apt-get -y ...). - 5-minute hard ceiling. Long-running jobs (builds, large upgrades) that don't finish in time return as an error — there's no extension, pause, or resume.
- No polling or streaming. Each call is a single blocking request/response; there's no job ID or status endpoint. To track something long-running, start it detached from one call (e.g.
nohup ./upgrade.sh > /tmp/upgrade.log 2>&1 &) and check progress with separate, short calls (tail /tmp/upgrade.log,pgrep -f upgrade.sh). - Can't target new hosts.
session_idis the only way in — the tool never accepts a host, user, or credentials, so it can only reach connections you already opened in Ternux.
Errors
Tool-level failures (session not found, timeout, non-zero exit) come back as {"isError": true, ...} inside a successful JSON-RPC response, not as a protocol-level error — check isError in the result, not just the HTTP status.