safe-ssh-mcp
A safe, scoped SSH MCP server for running read-only diagnostic commands against remote Linux hosts.
Inspect disks, inodes, mounts, file lists, and dependency lockfiles.
Collect system facts: hostname, distro, kernel, libc, uptime, datetime, and installed packages.
Monitor CPU/memory, top processes, free memory, pressure, vmstat, and top snapshots.
Inspect systemd units, timers, failed services, service status, and journal logs.
Read dmesg, coredumps, successful/failed logins, and crontab tasks.
Check network interfaces, routes, listening sockets, DNS resolution, and TCP connectivity from the remote host.
Inspect Docker containers, images, logs, stats, and curated inspect details.
Inspect Kubernetes logs, describe resources, events, and CRI containers/images/filesystem info.
Support SSH password or private-key authentication, including passphrase via env var or SSH agent/keychain.
Connect via SSH host/user parameters with optional port, timeout, key path, password, and host-key acceptance control.
Provides PHP diagnostics that can check whether Apache is installed and whether mod_php is enabled in its configuration and loaded.
Provides read-only Docker diagnostics on remote hosts via SSH, including listing all containers and images; the README also describes container logs and stats checks.
Provides read-only Kubernetes diagnostics via kubectl and crictl, including cluster events, pod logs, and container runtime process listing.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@safe-ssh-mcp Check disk free space on myserver"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Safe SSH MCP Server
A secure and scoped SSH MCP server for executing read-only diagnostic commands over SSH.
In this project, "safe" refers specifically to host safety: the server is designed to prevent modifications to the remote system and reduce the risk of operational harm. It does NOT attempt to guarantee that command output cannot be misused by external agents.
Badges
- security check
Related MCP server: ssh-remote-mcp
Overview
The core philosophy behind this MCP server is safety first. Instead of providing an AI agent with an unrestricted bash shell, this server exposes only carefully curated, read-only commands for system diagnostics and monitoring.
Available Tools (Partial List)
A few examples from each group; <...> marks a validated parameter.
Disk and filesystems
get_disk_free :
df -hget_disk_usage :
find <path> -mindepth 1 -maxdepth 1 -exec du -sh -- {} + 2>/dev/null | sort -rh | head -n 20get_mounts :
findmnt(orcat /proc/mounts)
CPU, memory and processes
get_top :
top -b -n 1 -cget_vmstat :
vmstat 1 5get_pressure :
cat /proc/pressure/{cpu,io,memory}
Systemd and logs
get_systemd_list_failed :
systemctl list-units --state=failed --no-pagerget_systemd_status :
systemctl status <daemon>get_journal_errors :
journalctl -p warning -n <lines> --no-pagerget_dmesg :
dmesg
Network
get_listening_sockets :
ss -tulpnget_ip_route :
ip route showandip -6 route showget_dns_lookup :
getent ahosts <name>ordig <name> <record_type>check_tcp_connect :
nc -vz -w 3 <target_host> <target_port>
Docker
get_docker_ps_all :
docker ps --allget_docker_logs :
docker logs --tail <lines> <container>get_docker_stats :
docker stats --no-stream
Kubernetes
get_kubectl_events :
kubectl get events --sort-by=.lastTimestampget_kubectl_logs :
kubectl logs --tail=<lines> --namespace=<namespace> <pod>get_crictl_ps :
crictl ps --all
System, logins and crashes
get_distroname_version :
cat /etc/os-releaseget_installed_packages :
dpkg-query -W(with source package),rpm -qaor/lib/apk/db/installed(with origin)get_failed_logins :
lastb -F -n <lines>get_coredumps :
coredumpctl list --no-pager
Click to open full list of available tools
Example of invocation
okay, could u check disk usage on /root/ path with help of safe-ssh-mcp server on a remote myserver.mydomain.pro using root and /Users/myUser/.ssh/id_rsa to login?
Means of connection
The server supports SSH account-password authentication and private-key
authentication. Configure the private-key passphrase source in
mcp_config.ini:
# ENV_VAR (SSH_KEY_PASSPHRASE) or KEYCHAIN (ssh-agent)
ssh_key_passphrase_method=ENV_VARSSH account password: provide
passwordto the MCP tool. Do not use this for a private-key passphrase.Unprotected SSH key: use
key_path. The defaultENV_VARsetting also supports unprotected keys;SSH_KEY_PASSPHRASEis not required.Passphrase-protected SSH key from an environment variable: leave
ssh_key_passphrase_method=ENV_VAR, setSSH_KEY_PASSPHRASEin the environment that starts the MCP server, and providekey_path.export SSH_KEY_PASSPHRASE='your-key-passphrase' safe-ssh-mcpmacOS Keychain / SSH agent: set
ssh_key_passphrase_method=KEYCHAIN, then unlock the key in the same user session that starts the MCP server. The server receives SSH signatures fromssh-agent; it does not read the key passphrase or thekey_path.ssh-add --apple-use-keychain ~/.ssh/id_ed25519 # Optional: make the loaded identity expire after one hour. ssh-add -t 1h ~/.ssh/id_ed25519 # Remove one identity, or clear every loaded identity. ssh-add -d ~/.ssh/id_ed25519 ssh-add -DCursor launched from the macOS Dock: use
KEYCHAIN(recommended). You can runssh-addfrom any Terminal window; it updates the SSH agent for your macOS login session, so Cursor does not need to be started from that Terminal.ssh-add --apple-use-keychain ~/.ssh/id_ed25519 ssh-add -lAfter changing
mcp_config.ini, restart the MCP server in Cursor (or fully quit and reopen Cursor). When invoking a tool inKEYCHAINmode, omitkey_path; the agent selects from its loaded identities.If you must use
ENV_VAR, set it in the macOS launchd session before opening Cursor from the Dock, then fully quit and reopen Cursor:launchctl setenv SSH_KEY_PASSPHRASE 'your-key-passphrase'This value lasts only for the current login session, and putting a passphrase directly in a command may save it in shell history. Prefer
KEYCHAIN.
For KEYCHAIN, the MCP server must inherit SSH_AUTH_SOCK from that user
session. This is normally automatic for a stdio server started from a desktop
application. ENV_VAR stores the passphrase in the server process environment,
so restrict access to the process and avoid putting it in source control.
Changelog
Project Contents
mcp_ssh.py - the SSH MCP server
mcp_config.ini - the server's config
check_health_sse.py - check the server's tools and either it's up (sse transport)
check_health_stdio.py - check the server's tools and either it's up (stdio transport)
Compatibility
Tested manually on Python3.11 running on MacOS against remote Ubuntu server
Autotested with Python 3.11 3.12 3.13 3.14
The MCP Registry
mcp-name: io.github.Areso/safe-ssh-mcp
The License
This project is licensed under the GNU AGPLv3 License.
Why AGPL?
This server acts as core infrastructure and contains no business logic. By using the AGPL license, we ensure that any security improvements, bug fixes, or new diagnostic tools added to the server are shared back with the open-source community.
Note for Client Developers
Because MCP clients communicate with this server via standard Inter-Process Communication (IPC) or network protocols (like HTTP/SSE), the AGPL license does not "infect" or restrict the client applications connecting to it.
You can safely connect proprietary, closed-source, or permissively licensed (e.g., MIT, Apache 2.0) AI agents to this server without violating the license terms.
Available Tools
55 toolscheck_tcp_connectA
Checks FROM a remote Linux host (reached via SSH) whether a TCP connection to target_host:target_port can be opened (nc -vz). USE THIS TOOL to tell whether a service (database, API, another server) is reachable from that host. target_host is a hostname or an IPv4/IPv6 address, target_port is 1-65535. Do not confuse them with host/port, which are the SSH connection to the machine the check runs on. Only the connection is opened and closed, no data is sent. One port per call. ok=True means the port accepted the connection. Otherwise nc's message tells why: 'Connection refused' - the target is reachable but nothing listens on the port; 'timed out' - no answer in 3 seconds, usually a firewall or a routing problem; a name resolution error - check the name with get_dns_lookup. Fails with exit code 127 if nc is not installed on the host.
Inputs: host (required), user (required), target_host (required), target_port (required), +5 more. Returns: object
get_coredumpsA
Inspects crashes (core dumps) recorded by systemd-coredump on a remote Linux host via SSH.
command='list' lists the last lines core dumps (time, PID, signal, executable), below the column header.
When there are no core dumps, coredumpctl exits with code 1 and ok is False - that is not a failure.
command='info' shows details of a core dump (signal, command line, stack trace if available):
of the given pid, or of the most recent one when pid is omitted.
Optional since limits them to a time window: '30 min ago', '2 hours ago', 'today',
'yesterday' or 'YYYY-MM-DD HH:MM:SS'.
Seeing other users' core dumps usually requires root.
Inputs: host (required), user (required), pid, port, +7 more. Returns: object
get_crictl_imagefsinfoB
Collects crictl imagefsinfo output (mountpoint, used bytes and inodes of the CRI image filesystem of a kubernetes node) from a remote Linux host via SSH. USE THIS TOOL to investigate image garbage collection and DiskPressure. Usually requires root.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_crictl_imagesB
Collects crictl images output (image, tag, image ID, size of images present in the CRI runtime of a kubernetes node) from a remote Linux host via SSH. Usually requires root.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_crictl_inspectA
Inspects a SPECIFIC CRI container (crictl inspect, JSON) on a kubernetes node from a remote Linux host via SSH: state, exit code and reason, timestamps, image, mounts, log path, pid and the runtime spec. Use get_crictl_ps first to find the container ID. Usually requires root. Values of environment variables are replaced by ''; their names are kept.
Inputs: host (required), user (required), container_id (required), port, +4 more. Returns: object
get_crictl_inspect_imageA
Inspects a SPECIFIC image (crictl inspecti, JSON) in the CRI runtime of a kubernetes node from a remote Linux host via SSH: repo tags and digests, size, user, entrypoint/cmd, layers. image is an image name ('registry.k8s.io/pause:3.9') or an image ID from get_crictl_images. Usually requires root. Values of environment variables are replaced by ''; their names are kept.
Inputs: host (required), user (required), image (required), port, +4 more. Returns: object
get_crictl_logsA
Gets the last lines log lines (stdout and stderr merged) of a SPECIFIC CRI container on a
kubernetes node from a remote Linux host via SSH. Works when the API server is down.
Use get_crictl_ps first to find the container ID. Usually requires root.
Optional since limits them to a time window: '30 min ago', '2 hours ago', '30m', '1h30m'
or an absolute UTC time 'YYYY-MM-DDTHH:MM:SSZ'.
Inputs: host (required), user (required), container_id (required), port, +6 more. Returns: object
get_crictl_psB
Collects crictl ps --all output (all CRI containers on a kubernetes node, including exited ones: container ID, image, state, name, attempt, pod) from a remote Linux host via SSH. Usually requires root.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_crontab_tasksC
Collects crontab -l (crontab list) output from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_current_datetimeB
Collects current datetime from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_disk_freeC
Collects disk usage (df -h) from a remote Linux host via SSH.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_disk_usageA
Collects disk usage for a specific abs path from a remote Linux host via SSH. Returns the top 20 largest files/folders in the specified directory.
Inputs: host (required), user (required), port, timeout, +4 more. Returns: object
get_distroname_versionC
Collects distr details from os-release from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_dmesgA
Collects dmesg log from a remote Linux host via SSH. Reading the kernel log usually requires root: when the login user is not root, the command is run through passwordless sudo or doas (sudo -n / doas -n). Optional since limits it to recent messages: '30 min ago', '2 hours ago', 'today', 'yesterday' or 'YYYY-MM-DD HH:MM:SS'. It requires util-linux 2.37+ on the remote host; on older hosts dmesg fails with an unrecognized option error - then call without since.
Inputs: host (required), user (required), port, since, +4 more. Returns: object
get_dns_lookupA
Resolves a hostname (or reverse-resolves an IP address) ON a remote Linux host via SSH, and prints its /etc/resolv.conf. USE THIS TOOL to check what a name resolves to from that host. By default uses getent, which resolves exactly like applications on the host do (/etc/hosts, nsswitch.conf, then DNS). A name that does not resolve gives exit code 2. use_dig=True queries the DNS servers directly with dig (bypassing /etc/hosts) and returns the full answer: status (NOERROR, NXDOMAIN, SERVFAIL), CNAME chain, TTLs, the server that answered and query time. It fails with exit code 127 if dig is not installed - then use use_dig=False. The next two parameters require use_dig=True: record_type is one of A (default), AAAA, CNAME, MX, NS, TXT, SOA, PTR, SRV, CAA. server (IP address or hostname, e.g. '8.8.8.8') asks that DNS server instead of the ones in /etc/resolv.conf - compare both answers to tell a broken resolver from a broken record.
Inputs: host (required), name (required), user (required), port, +7 more. Returns: object
get_docker_imagesA
Collects docker images --digests output (repository, tag, digest, image ID, age, size) from a remote Linux host via SSH When the login user cannot reach the docker daemon (not root, not in the docker group), the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_docker_inspectA
Inspects a SPECIFIC docker container, given by name or ID, on a remote Linux host via SSH. Returns a curated subset of docker inspect: image, entrypoint/cmd, state (status, exit code, OOMKilled, start/finish time, health check log), restart count and policy, memory/CPU limits, networks, ports, mounts and log driver. Environment variables are NOT returned. When the login user cannot reach the docker daemon (not root, not in the docker group), the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), container (required), port, +4 more. Returns: object
get_docker_logsA
Gets the last lines log lines (stdout and stderr merged) of a SPECIFIC docker container,
given by name or ID, from a remote Linux host via SSH. Works for stopped containers too.
Use get_docker_ps_all first to find container names.
Optional since limits them to a time window: '30 min ago', '2 hours ago', '30m', '1h30m'
or 'YYYY-MM-DD HH:MM:SS' ('today' and 'yesterday' are not supported here).
When the login user cannot reach the docker daemon (not root, not in the docker group),
the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), container (required), port, +6 more. Returns: object
get_docker_ps_allB
Collects docker ps --all output from a remote Linux host via SSH When the login user cannot reach the docker daemon (not root, not in the docker group), the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_docker_statsA
Collects a one-shot docker stats snapshot from a remote Linux host via SSH: CPU %, memory usage/limit, network and block I/O, PIDs for every RUNNING container. When the login user cannot reach the docker daemon (not root, not in the docker group), the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_failed_loginsA
Lists recent FAILED login attempts (lastb, from btmp) on a remote Linux host via SSH, newest first: attempted user, terminal, source address, time. USE THIS TOOL to check for brute-force attempts. Requires root, since btmp is not world-readable: when the login user is not root, the command is run through passwordless sudo or doas (sudo -n / doas -n). Optional since limits them to a time window: '30 min ago', '2 hours ago', 'today', 'yesterday' or 'YYYY-MM-DD HH:MM:SS'.
Inputs: host (required), user (required), port, lines, +5 more. Returns: object
get_free_memoryC
Returns free memory, swap (total/free), page cache, HugePages and so on
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_hostnameB
Collects the hostname of a remote Linux host via SSH, as the host itself reports it. Output: "hostname: " (the kernel hostname, uname -n), then "fqdn: " (hostname -f) when the host can resolve its fully qualified name; that line is absent otherwise.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_inode_usageC
Collects inode usage (df -i) from a remote Linux host via SSH.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_installed_packagesB
Lists installed packages with versions on a remote Linux host via SSH, using the first available package manager. The FIRST output line starts with '#' and names the package manager and the columns; the rest is one package per line: dpkg (Debian/Ubuntu), tab-separated: package, version, architecture, status ('ii' installed, 'hi' installed and held), source_package, source_version. Security advisories for Debian/Ubuntu are keyed by SOURCE package (openssh, not openssh-server). Removed packages whose config files are left behind (state 'rc') are not listed. rpm (RHEL/Fedora/SUSE): name-version-release.arch, as printed by rpm -qa. apk (Alpine), tab-separated: package, version, architecture, origin. Security advisories for Alpine are keyed by ORIGIN (openssl, not libcrypto3); it has the same version as the package.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_ip_addrC
Collects ip addr show output (network interfaces, their state, MAC, IPv4 and IPv6 addresses) from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_ip_routeA
Collects the IPv4 and IPv6 routing tables (ip route show, ip -6 route show: default gateway, per-interface routes) from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_is_installedC
Checks whether a binary/command is installed and callable on a remote Linux host via SSH.
Inputs: host (required), user (required), port, binary, +4 more. Returns: object
get_journal_errorsA
Gets recent journald entries of priority warning and above (warning, err, crit, alert, emerg)
from ALL units and the kernel. USE THIS TOOL FIRST when you don't know which service is at fault.
With current_boot_only=True only entries since the last boot are returned.
Optional since limits them to a time window: '30 min ago', '2 hours ago', 'today',
'yesterday' or 'YYYY-MM-DD HH:MM:SS' (the last lines entries within it are returned).
Inputs: host (required), user (required), port, lines, +6 more. Returns: object
get_kernel_versionB
Collects kernel name, release, build version and architecture (uname -srvm) from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_kubectl_describeA
Describes a SPECIFIC kubernetes resource (kubectl describe) by running kubectl on a remote Linux host via SSH: status, conditions, containers and its recent events. kubectl must be configured for the SSH user there. resource_type is one of: pod, node, namespace, deployment, statefulset, daemonset, replicaset, job, cronjob, service, endpoints, ingress, networkpolicy, persistentvolumeclaim, persistentvolume, storageclass, horizontalpodautoscaler, poddisruptionbudget (plural and short names like 'po', 'deploy', 'svc' work too). Secrets and configmaps are NOT available. namespace is ignored for cluster-scoped resources (node, namespace, persistentvolume, storageclass).
Inputs: host (required), name (required), user (required), resource_type (required), +6 more. Returns: object
get_kubectl_eventsA
Gets the most recent lines kubernetes events (kubectl get events), oldest first, below the
column header, by running
kubectl on a remote Linux host via SSH. kubectl must be configured for the SSH user there.
USE THIS TOOL FIRST when you don't know what is wrong in a cluster.
Events of ALL namespaces are returned unless namespace is given.
warnings_only=True keeps only events of type Warning (FailedScheduling, BackOff, Unhealthy...).
Inputs: host (required), user (required), port, lines, +6 more. Returns: object
get_kubectl_logsA
Gets the last lines log lines of a SPECIFIC kubernetes pod (kubectl logs) by running
kubectl on a remote Linux host via SSH. kubectl must be configured for the SSH user there.
container selects a container in a multi-container pod.
previous=True returns logs of the previous, crashed instance - use it for CrashLoopBackOff.
Optional since limits them to a time window: '30 min ago', '2 hours ago', '30m', '1h30m'
or an absolute UTC time 'YYYY-MM-DDTHH:MM:SSZ'.
Inputs: pod (required), host (required), user (required), port, +9 more. Returns: object
get_last_loginsA
Lists recent SUCCESSFUL logins (last, from wtmp) to a remote Linux host via SSH, newest first:
user, terminal, source address, login/logout time. Also shows reboots.
For failed login attempts use get_failed_logins.
On BusyBox hosts (Alpine), where last takes no options, the output is plain last
cut to lines rows: its first line starts with '# BusyBox', times have no year,
and since is not supported (the tool fails with a message saying so).
Optional since limits them to a time window: '30 min ago', '2 hours ago', 'today',
'yesterday' or 'YYYY-MM-DD HH:MM:SS'.
Inputs: host (required), user (required), port, lines, +5 more. Returns: object
get_libc_versionB
Collects C library implementation and version (glibc or musl) from a remote Linux host via SSH. Uses ldd --version; musl is detected by the presence of /lib/ld-musl-* loader. The last line, "package: ", is the distro package version (e.g. 2.39-0ubuntu8.9, 2.34-289.el9, 1.2.6-r3) that security data is keyed by; it is taken from dpkg, rpm or apk and is absent on other distros.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_listening_socketsA
Collects ss -tulpn output (open ports and sockets) from a remote Linux host via SSH. If ss is not installed (e.g. Alpine), falls back to netstat -tulnp; the output then starts with a "# ss is not installed: netstat -tulnp" line and has netstat's columns. If the login user is not root, runs through sudo -n / doas -n to get the process names of all sockets; if that is not allowed, runs as the login user and says so in a "# not run as root" line (process names are then shown only for its own sockets).
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_list_of_filesB
Collects list of files for a specific abs path from a remote Linux host via SSH. Returns with -lah option
Inputs: host (required), user (required), port, timeout, +4 more. Returns: object
get_list_of_files_with_filterA
Collects list of files for a specific abs path with filter (grep) applied from a remote Linux host via SSH. -lah option is applied.
Inputs: host (required), user (required), port, filter, +5 more. Returns: object
get_lockfilesA
Finds dependency lockfiles under the given absolute app paths on a remote Linux host via SSH: composer.lock (PHP), package-lock.json, yarn.lock, pnpm-lock.yaml (Node.js), requirements*.txt, poetry.lock, uv.lock, Pipfile.lock (Python), Gemfile.lock (Ruby), go.sum (Go) and Cargo.lock (Rust). Skips node_modules, vendor, .git, venv and .venv directories. Lists the files found with size and mtime (ls -l). With include_contents=True prints the files instead (the first 20 found), each after a '===== ( bytes) =====' line. A file is always printed WHOLE or not at all, never cut: a file over 5 MB, or one that would take the output over 10 MB in total, gets a '===== (skipped: ...) =====' line instead. The output can be several MB - call without include_contents first to see the sizes, then narrow abs_paths to the application you need.
Inputs: host (required), user (required), abs_paths (required), port, +6 more. Returns: object
get_lsblkC
Collects lsblk output from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_memory_pressureA
DEPRECATED: use get_pressure, which returns CPU, I/O and memory pressure in one call. Returns memory pressure if supported
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_mountsA
Lists mounted filesystems with their mount point, source device, filesystem type and mount options (findmnt, as a tree; /proc/mounts if findmnt is not installed). USE THIS TOOL to find a filesystem that was remounted read-only after an error ('ro' in the options), to check options like noexec/nosuid, and to see network (nfs, cifs), overlay and tmpfs mounts. For free space use get_disk_free instead.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_php_infoA
Collects PHP details from a remote Linux host via SSH: CLI version and SAPI, installed CGI (php-cgi) and FPM (php-fpm) binaries with their versions/SAPIs, whether php-fpm or php-cgi processes are currently running, and, if Apache is installed, whether mod_php is enabled in its config and loaded.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_pressureA
Returns Linux pressure stall information (PSI) for CPU, I/O and memory in one call. USE THIS TOOL to tell which resource the host is short of: unlike load average, it shows how much time tasks actually spent waiting for each resource. 'some' = share of time at least one task was stalled, 'full' = all non-idle tasks were stalled at once; avg10/avg60/avg300 are percentages over the last 10, 60 and 300 seconds, total is the cumulative stall time in microseconds. Prints 'PSI not supported' for a resource if the kernel is older than 4.20 or PSI is disabled.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_ps_aux_top_cpu_consumersB
Lists top 10 cpu consumers, CPU desc (ps aux --sort=-%cpu).
On BusyBox hosts (Alpine), where ps cannot sort, the output comes from top -b -n 1
instead: its first line starts with '# BusyBox', the columns differ, and %CPU is the
usage at this moment, not the average over the process lifetime that ps reports.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_ps_aux_top_mem_consumersB
Lists top 10 mem consumers, MEM desc (ps aux --sort=-%mem).
On BusyBox hosts (Alpine), where ps cannot sort and has no %MEM, the output is
ps -o pid,user,rss,vsz,args sorted by RSS instead: its first line starts with
'# BusyBox' and sizes are in KB unless they carry an m or g suffix.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_service_logs_from_journalctlC
Gets recent journald logs for a specific systemd service.
Optional since limits them to a time window: '30 min ago', '2 hours ago', 'today',
'yesterday' or 'YYYY-MM-DD HH:MM:SS' (the last lines entries within it are returned).
Inputs: host (required), user (required), service (required), port, +6 more. Returns: object
get_sshd_effective_configA
Collects the effective sshd configuration (sshd -T) from a remote Linux host via SSH. Shows the final values after defaults, includes and Match blocks are applied. Requires root, since sshd -T reads the host keys: when the login user is not root, the command is run through passwordless sudo or doas (sudo -n / doas -n).
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_systemd_list_allC
Lists all systemd units. USE THIS TOOL to check for running, stopped, or FAILED daemon/service/unit.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_systemd_list_failedA
Lists failed systemd units. USE THIS TOOL to check for FAILED daemons/services/units.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_systemd_list_timersC
Lists all systemd timers. USE THIS TOOL to check for timers.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_systemd_statusC
Gets the detailed status, logs, and error messages for a SPECIFIC systemd daemon/service/unit.
Inputs: host (required), user (required), daemon (required), port, +4 more. Returns: object
get_topB
Collects top's snapshot from a remote Linux host via SSH (top -b -n 1 -c).
On BusyBox hosts (Alpine), where top has no -c, the output is plain top -b -n 1:
its first line starts with '# BusyBox' and the columns differ.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_uptimeA
Collects uptime from a remote Linux host via SSH
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
get_vmstatA
Samples system activity for 4 seconds with vmstat (5 reports, 1 second apart): run queue and blocked processes (r, b), memory, swap-in/out (si, so), block I/O (bi, bo), interrupts and context switches (in, cs) and the CPU split (us, sy, id, wa, st). USE THIS TOOL to see what the host is doing right now: swapping, I/O wait, CPU saturation. The FIRST report line is the average since boot - judge the current state by the other four.
Inputs: host (required), user (required), port, timeout, +3 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 55 tools
Most tools target a clearly distinct command or resource (docker vs crictl vs kubectl logs, df -h vs df -i vs du), and several descriptions explicitly say when to prefer one over another. However, there is a dense cluster of overlapping host-state samplers (get_top, get_vmstat, get_pressure, get_ps_aux_top_cpu_consumers, get_ps_aux_top_mem_consumers, get_free_memory) and near-duplicates like get_list_of_files vs get_list_of_files_with_filter, plus a DEPRECATED get_memory_pressure that shadows get_pressure and should be removed.
Overwhelmingly consistent snake_case with a get_ prefix and noun-qualified names (get_docker_ps_all, get_crictl_inspect_image, get_systemd_list_failed). Minor deviations: check_tcp_connect uses a different verb form, and get_list_of_files_with_filter is unusually verbose compared to its sibling.
At 55 tools for one SSH diagnostic server, the surface is far past the comfortable range and forces the agent to choose among many narrowly splintered variants. The tools are individually meaningful, but several could be merged (deprecated memory_pressure, list_files vs filtered list, the redundant top/vmstat/pressure trio), and the sheer count increases selection cost.
Coverage of Linux host triage is genuinely broad: disk/inode/mounts, memory and pressure, network/routing/DNS/reachability, systemd units and journald, logins and brute-force attempts, packages/libc/kernel, plus docker, crictl and kubectl layers. Gaps are modest: no general file/config reader beyond lockfiles and sshd -T, no full process listing or per-service resource view, and no non-disk-usage inspection of arbitrary application logs.
Maintenance
Related MCP Connectors
Free, read-only security scanner for remote MCP servers, before you connect them.
A free, read-only remote MCP server with templates for a file-based business operating system.
Secure MCP server for exploring incwo CRM data, documents, and email workflows.
Related MCP Servers
- AlicenseBqualityCmaintenanceA server that enables secure interaction with remote SSH hosts through standardized MCP interface, providing functions like listing hosts, executing commands, and transferring files using native SSH tools.7400 npm105MIT
- AlicenseNot gradedqualityDmaintenanceA secure SSH-based MCP server for diagnosing remote servers. It allows AI agents to execute read-only commands and read files automatically, while requiring user confirmation for write operations.MIT
- AlicenseNot gradedqualityDmaintenanceA read-only MCP server for Linux and macOS system administration, diagnostics, and troubleshooting, supporting remote SSH execution and multi-host management.Apache 2.0
- AlicenseAqualityDmaintenanceAn MCP server for SSH/SCP operations with passwordless authentication, enabling remote command execution, file transfer, and session management.1917 npm1MIT