Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Conch

English · 简体中文

Conch is an SSH client written in Rust. A single r-shell binary manages saved connections, runs remote commands, opens an interactive shell, transfers files over SFTP, and prints a quick system snapshot.

It also ships an optional MCP server, so AI assistants (Cursor, Claude, and other MCP clients) can work on your servers through one persistent SSH session instead of spawning a fresh ssh process on every step.

There's a desktop app too — a Flutter UI on top of the same Rust core — with a tabbed terminal, file browser, and live monitoring.

Latest releaseRelease buildsPlatformsLanguageLicense: MIT

Screenshots

Conch connections dashboard
Connections dashboard — saved hosts grouped by folder, with a built-in local monitor card.

Conch command-block terminal
Command-block terminal — each command and its output is its own block, with exit code, timing, and a working directory that persists across blocks.

Conch live monitoring
Live monitoring — CPU, memory, disks, and network with real-time charts.

Contents

Features

CommandDescription
connectionsAdd, list, update, and remove saved hosts
execRun a single command on a remote host
shellOpen an interactive PTY shell
lsList a remote directory
upload / downloadCopy files over SFTP
statsOne-shot CPU / memory / disk / network snapshot
mcpStart the local MCP server

The same binary runs on macOS, Linux, and Windows. exec, shell, upload, and download work against any POSIX host; ls and stats expect a Linux host (they rely on GNU ls and /proc).

Install

Desktop app

Prebuilt desktop builds are on the releases page. The runtime is bundled, so there's nothing else to install.

PlatformFile
Windows x64 (installer)Conch-windows-x64-setup.exe
Windows x64 (portable)Conch-windows-x64.zip
macOSConch-macos.zip

The builds aren't code-signed yet. On macOS, right-click Conch.appOpen the first time; on Windows, choose More info → Run anyway if SmartScreen warns.

CLI

PlatformFile
macOS (Apple Silicon)r-shell-macos-apple-silicon.dmg
macOS (Intel)r-shell-macos-intel.dmg
Windows x64r-shell-windows-x64-installer.exe

On macOS, mount the DMG and copy the binary onto your PATH:

sudo cp /Volumes/Conch/r-shell /usr/local/bin/r-shell
sudo chmod +x /usr/local/bin/r-shell
xattr -dr com.apple.quarantine /usr/local/bin/r-shell # clear Gatekeeper quarantine
r-shell --version

On Windows, run the installer (it adds r-shell to your PATH) and open a new terminal.

From source

You need Rust and Cargo (rustup.rs). No OpenSSL or libssh is required — Conch uses the pure-Rust russh stack.

git clone https://github.com/MageGojo/conch.git
cd conch
cargo build --release --manifest-path cli/Cargo.toml
sudo install -m 0755 cli/target/release/r-shell /usr/local/bin/r-shell

Or run it straight from Cargo without installing:

cargo run --manifest-path cli/Cargo.toml -- <command> [options]

Quick start

# save a connection
r-shell connections add --name prod --host 203.0.113.10 --username deploy \
--auth publickey --key-path ~/.ssh/id_ed25519
# use it
r-shell connections list
r-shell exec -c prod -- uptime
r-shell shell -c prod
r-shell upload -c prod ./app.tar.gz /tmp/app.tar.gz
r-shell download -c prod /tmp/app.tar.gz ./app-copy.tar.gz

Every command that talks to a host takes a target: either a saved connection (-c <id|name>) or inline details. If a password is needed but not given, you're prompted for it (input isn't echoed).

Common target flags (exec, shell, ls, upload, download, stats):

FlagAliasDescriptionDefault
--connection <id|name>-cUse a saved connection
--host <host>Ad-hoc host (IP or hostname)
--user <user>-uAd-hoc SSH username
--port <port>-pAd-hoc SSH port22
--password <pw>Ad-hoc password (prefer the prompt)
--key-path <path>Private key path
--passphrase <pp>Passphrase for an encrypted key
--insecureSkip host-key verificationfalse

Commands

Run r-shell --help or r-shell <command> --help for the full list of options.

connections

Saved connections live in a local workspace.json (see Configuration).

r-shell connections list [--json]
r-shell connections add \
--name prod --host 203.0.113.10 --username deploy --port 22 \
--auth publickey --key-path ~/.ssh/id_ed25519 \
--folder Work --description "Production web server"
r-shell connections update <id> --port 2222 --folder Staging
r-shell connections remove <id>

Required flags: --name, --host, --username. --auth is password or publickey (default password); --port defaults to 22; --folder defaults to All Connections. update takes a connection id plus any of the same flags.

exec

Runs one command and prints its output. Everything after -- is sent verbatim.

r-shell exec -c prod -- uname -a
r-shell exec -c prod -- "ls -la /var/www && df -h"
r-shell exec --host 203.0.113.10 --user deploy -- systemctl status nginx

shell

A full interactive PTY in raw mode (vim, htop, less, …). Press Ctrl-] to force-quit the local loop if a session hangs.

r-shell shell -c prod

ls

r-shell ls -c prod /var/log
r-shell ls -c prod /var/log --json
r-shell ls -c prod # defaults to the home directory

Columns: kind (DIR/FILE/LNK), permissions, size, modified time, name. (Linux hosts.)

upload / download

Single-file transfers over SFTP.

r-shell upload -c prod ./local.tar.gz /tmp/remote.tar.gz
r-shell download -c prod /tmp/remote.log ./local.log

stats

Takes two quick samples and prints a snapshot (Linux hosts; relies on /proc).

r-shell stats -c prod
OS: Linux 6.1.0
Uptime: 12d 4h 31m
CPU: 7.4% (8 cores, load 0.42)
Memory: 61.2% (4.9/7.8 GB)
Disk: 40.0% (3.8/9.5 GB)
Network: down 1.5 KB/s up 320 B/s

mcp

Starts the local MCP server (see below).

r-shell mcp
# Conch MCP server listening on http://127.0.0.1:9123/mcp

MCP server

r-shell mcp starts a local Model Context Protocol server over Streamable HTTP, bound to 127.0.0.1 only. Point an MCP client at http://127.0.0.1:9123/mcp:

{
"mcpServers": {
"r-shell": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}

For Cursor this goes in ~/.cursor/mcp.json. Claude Desktop and other clients add the same URL as a Streamable HTTP server, then restart.

The server keeps one SSH session alive across calls, so an assistant can run commands and read or write files without reconnecting each time. Sessions live in memory only, for as long as r-shell mcp is running.

Session tools:

ToolDescription
ssh_session_openOpen or reuse a session; returns a session_id
ssh_execRun a command on the session
ssh_read_fileRead a remote file (UTF-8, or base64 for binary)
ssh_write_fileCreate or overwrite a remote file
ssh_list_dirList a remote directory
ssh_sessions_list / ssh_session_closeList or close live sessions

Connection tools (operate on workspace.json):

ToolDescription
r_shell_ssh_connections_listList saved connections (credentials removed)
r_shell_ssh_connection_create / _update / _deleteManage saved connections

Credentials are never returned — list calls only expose booleans such as has_password. The endpoint requires a loopback Host header (and a loopback Origin, if one is present); cross-origin and DNS-rebound requests get 403.

Authentication

  • Password--auth password with --password, or omit it to be prompted at connect time.
  • Public key--auth publickey with --key-path (and --passphrase for an encrypted key). Paths starting with ~/ are expanded.

Host keys are verified against ~/.ssh/known_hosts on a trust-on-first-use basis. The first connection records the key; later connections must match. A mismatch aborts the connection (a possible man-in-the-middle) until you remove the offending line from known_hosts. --insecure skips the check entirely — use it only for throwaway or local test hosts.

Configuration

Saved connections are stored as JSON:

OSPath
macOS~/Library/Application Support/r-shell/workspace.json
Linux~/.local/share/r-shell/workspace.json
Windows%LOCALAPPDATA%\r-shell\workspace.json

On Unix the file and its directory are created with owner-only permissions (0600 / 0700).

Security

  • Host keys are verified against known_hosts (trust-on-first-use); a changed key aborts the connection unless --insecure is passed.
  • Passwords, private keys, and passphrases are never printed or returned by MCP calls — list responses only expose has_password / has_private_key_path.
  • Password prompts don't echo input.
  • workspace.json is owner-only on Unix.
  • The MCP server binds to localhost and rejects non-loopback Host/Origin (defeating DNS rebinding and cross-origin access).

Development

The root package.json is a thin wrapper around Cargo:

pnpm dev # cargo run -- --help
pnpm check # cargo check
pnpm test# cargo test
pnpm build # cargo build
pnpm fmt # cargo fmt

Or call Cargo directly with --manifest-path cli/Cargo.toml. Version bumps go through pnpm version:patch|minor|major, which update package.json, cli/Cargo.toml, cli/Cargo.lock, and CHANGELOG.md.

Project layout

conch/
├── cli/ # r-shell: the CLI + MCP server (Rust)
├── core/ # shared SSH / MCP core library
├── desktop/ # desktop app (Flutter UI + Rust core)
├── packaging/ # macOS .dmg and Windows installer scripts
├── scripts/ # version-bump helpers
└── .github/ # CI: tests and release builds

License

MIT — see LICENSE. Maintained by the team at ApiZero. Issues and pull requests are welcome on GitHub.

About

R-Shell: a Rust command-line SSH workspace — saved connections, remote exec, interactive shell, SFTP transfer, system stats, and a local MCP server.

Resources

Code of conduct

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages