Skip to main content
Glama
Double-wk

ChatGPT Remote SSH MCP

by Double-wk

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
CLOUDFLARED_BINNoPath to the cloudflared binary; set when using an official build for other systems or architectures instead of the bundled Linux x86_64 binary.
GITHUB_CLIENT_IDYesGitHub OAuth App client ID, created in GitHub Developer Settings with callback URI https://<public-domain>/oauth/github/callback.
GITHUB_ALLOWED_IDSYesComma-separated numeric GitHub user IDs allowed to log in. Must be non-empty; the gateway refuses authorization when the allowlist is missing.
GATEWAY_PUBLIC_BASEYesPublic HTTPS root address (without /mcp).
SSH_MCP_PROJECT_DIRNoProject directory used during setup (defaults to $PWD).
GITHUB_CLIENT_SECRETYesGitHub OAuth App client secret, set in the server's private environment.
SSH_MCP_CONDA_PREFIXNoActual path of the chatgpt-ssh-mcp Conda environment, overriding the preset absolute path; also used for the gateway.
CHATGPT_OAUTH_CLIENT_IDNoChatGPT connector client ID. Defaults to chatgpt-remote-ssh.chatgpt-remote-ssh
CHATGPT_OAUTH_REDIRECT_URINoFull callback URI for the ChatGPT connector. The default only matches the previously created connector; for a new connector use the actual value shown on the page.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_serversA

List all configured SSH servers with their groups and descriptions.

Args: group: Optional group name to filter by. Shows all servers if omitted. Use list_groups to see available group names.

Returns: Formatted table of servers with name, groups, and description. An unknown group is reported as a plain "Error: ..." string rather than raised as a tool error, and a group with no members returns "No servers found in group '<name>'".

list_groupsB

List all server groups with descriptions and member counts.

Returns: Formatted table of groups with name, description, and server count.

executeA

Execute a shell command on a single SSH server.

Args: server: Server name (e.g. 'web-prod-01'). Must match a configured server. Use list_servers to see available servers. command: Shell command to execute on the remote server (exactly as it would be typed at a bash prompt). Rejected if it exceeds max_command_bytes (default 65536 encoded UTF-8 bytes). timeout: Command timeout in seconds. Default 30. Not range-checked, and NOT authoritative: a timeout set on the server's entry in servers.toml overrides this argument outright, so a per-server 30 wins over a caller-supplied 600. working_dir: Absolute remote directory to cd into before running the command. Uses the server's default_dir from servers.toml if omitted, or the SSH login directory if neither is set. force: If True, bypass the dangerous-command detection patterns. Use only for audited bulk operations. The block list is ~25 regexes and is broader than "obviously destructive": besides rm -rf /, mkfs, dd-to-disk, chmod 777 /, redirects into /dev/sd* and /etc/{passwd,shadow,gshadow,sudoers}, find -delete / -exec rm, shred / wipefs / blkdiscard / sgdisk on /dev/, partition-table edits, and fork bombs, it also rejects ordinary interpreter wrappers — bash -c ..., python3 -c ... (also perl/ruby -c/-e), eval "...", and base64 -d | sh. Harmless commands in those forms need force=True too. Default False. dry_run: If True, do NOT connect or execute. Return a preview describing what would run (server, command, working_dir, timeout, force). Dangerous-command detection still runs so rejection can be previewed. Useful for LLM plans that want to validate intent before committing. Default False.

Returns: Formatted command execution result with stdout, stderr, and exit code. Long output is truncated at max_output_bytes (default 50 KiB) PER STREAM — stdout and stderr get independent budgets, so the combined worst case is 2x that setting. A truncated stream ends with [... output truncated at N bytes], and hitting the cap TERMINATES the remote process rather than letting it keep writing.

execute_on_groupA

Execute a shell command on all servers in a group in parallel.

Concurrency is capped by the max_parallel_hosts setting (default 10; configure in [settings] of servers.toml, range 1–100). The semaphore is PROCESS-WIDE, not per call: concurrent execute_on_group calls share the same slots and therefore serialise against each other for their share of them.

Args: group: Group name (e.g. 'production', 'web'). Use list_groups to see available groups. command: Shell command to execute on every server in the group. Rejected if it exceeds max_command_bytes (default 65536 encoded UTF-8 bytes). timeout: Per-server command timeout in seconds. Default 30. Not range-checked, and overridden per server by a timeout set on that server's entry in servers.toml. Each server has its own timer; slow servers do NOT extend the per-server limit for others. working_dir: Absolute remote directory to cd into on each server. Uses each server's default_dir if omitted. fail_fast: If True, cancel remaining tasks as soon as any server returns a non-zero exit code or errors. Default False — run all servers to completion and report each result. force: If True, bypass the dangerous-command detection patterns. Use only for audited bulk operations. The same broad block list described under execute applies here — including plain bash -c / python3 -c / eval wrappers. Default False. dry_run: If True, do NOT connect or execute anywhere. Return a per-server preview describing what would run. Dangerous- command detection still applies. Useful for previewing fleet-wide rollouts before committing. Default False.

Returns: Formatted summary showing per-server results, success/failure counts, and aggregate exit status.

upload_fileA

Upload a file to a remote server via SFTP.

Files larger than 100 MiB are refused outright — use rsync or scp for those.

Args: server: Server name (e.g. 'pro-dicentra'). local_path: Path to the local file, RELATIVE to the configured transfer_root (see [settings] in servers.toml, or the SSH_MCP_TRANSFER_ROOT environment variable). Absolute paths, .., . components and embedded NUL bytes are rejected, as is a symlink at ANY component of the path. Sub-directories are allowed (e.g. 'reports/q1.csv'), but every intermediate directory must already exist under transfer_root — upload_file does not create them. transfer_root itself must be a real directory owned by the running user with mode 0700, or every transfer fails. remote_path: Destination path on the remote server — normally absolute, though a relative path is not rejected, just resolved by the remote SFTP server against the SSH login directory. Rejected if it contains .. anywhere (even inside an otherwise legitimate filename) or matches the sensitive-path denylist (/etc/shadow, /etc/passwd, .ssh/*, .aws/credentials, .kube/config, .netrc, …). An existing REGULAR file at the destination is silently OVERWRITTEN — unlike download_file, upload does not no-clobber; an existing non-regular target (symlink, device, FIFO) is refused.

Returns: Confirmation message with file size.

download_fileA

Download a file from a remote server via SFTP.

Args: server: Server name (e.g. 'pro-dicentra'). remote_path: Path to the remote file — normally absolute, though a relative path is not rejected, just resolved by the remote SFTP server against the SSH login directory. Must be a regular file — symlinks, devices, FIFOs, and other non-regular remote files are refused. Rejected if it contains .. anywhere or matches the same sensitive-path denylist upload_file enforces. Size is NOT capped here (upload's 100 MiB limit has no download counterpart) — an oversized transfer only logs a warning, after the bytes are already on disk. local_path: Destination path, RELATIVE to the configured transfer_root (see [settings] in servers.toml, or the SSH_MCP_TRANSFER_ROOT environment variable). Absolute paths, .., . components and embedded NUL bytes are rejected, as is a symlink at any component of the path. Sub-directories are allowed, but every intermediate directory must already exist under transfer_root. NO-CLOBBER: if a file already exists at the destination, the download fails rather than silently overwriting it — remove or rename the existing file first. A failed or cancelled download unlinks the partial file it created, so a retry is not blocked by its own leftovers.

Returns: Confirmation message with file size.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct purpose: group discovery, server discovery, single-host command execution, fleet command execution, upload, and download. There is no meaningful overlap between listing, executing, and transferring operations.

Naming Consistency4/5

All names are snake_case and follow a readable verb pattern. The main minor deviation is that 'execute' is not verb_noun while 'execute_on_group', 'upload_file', and 'download_file' are more explicitly shaped.

Tool Count5/5

Six tools are well-scoped for an SSH MCP server. Each tool earns its place without redundant coverage or obvious filler.

Completeness4/5

The surface covers discovery, single and fleet command execution, and both directions of file transfer. Minor gaps remain around remote file management, such as deleting, listing, or creating remote directories.

Maintenance

ActivityMaintained
ResponsivenessNo issues